diff --git a/backend/tests/test_uploads.py b/backend/tests/test_uploads.py index 7234765..90c8045 100644 --- a/backend/tests/test_uploads.py +++ b/backend/tests/test_uploads.py @@ -2,6 +2,8 @@ import inspect import io +import re +from pathlib import Path import pytest from fastapi import UploadFile @@ -62,6 +64,26 @@ def test_the_archive_cap_is_the_one_that_dominates(): assert parsed.max_request_bytes == 50_000 + MULTIPART_OVERHEAD_BYTES +NGINX_CONF = Path(__file__).resolve().parents[2] / "frontend" / "nginx.conf" +NGINX_UNITS = {"": 1, "k": 1024, "m": 1024**2, "g": 1024**3} + + +@pytest.mark.skipif(not NGINX_CONF.exists(), reason="needs the whole repository") +def test_the_proxy_admits_the_largest_body_the_api_accepts(): + """nginx sits in front of the API, so its cap has to be the looser one. + + Below the API's, a full export archive is refused by nginx with an HTML + page before FastAPI sees it — which is how a 24m cap once stopped every + archive over 24 MiB while the API was ready to take 200. + """ + match = re.search(r"client_max_body_size\s+(\d+)([kmg]?);", NGINX_CONF.read_text(), re.I) + assert match, "nginx.conf no longer sets client_max_body_size" + proxy_limit = int(match[1]) * NGINX_UNITS[match[2].lower()] + defaults = Settings(_env_file=None, database_url="sqlite://") + + assert proxy_limit >= defaults.max_request_bytes + + def test_cors_origins_accept_a_comma_separated_string(): parsed = Settings(_env_file=None, database_url="sqlite://", cors_origins="http://a,http://b") diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 8695767..8cd76ba 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -7,7 +7,10 @@ server { # Uploads go through here: keep this above the API's own limit so the # request reaches FastAPI and gets a JSON 413 rather than an nginx page. - client_max_body_size 24m; + # That limit is the largest thing any route accepts — an export archive, + # MAX_ARCHIVE_BYTES (200 MiB) plus 1 MiB of framing — not a single file. + # test_uploads.py fails if the two drift apart. + client_max_body_size 210m; gzip on; gzip_types text/css application/javascript application/json image/svg+xml;