From 01554a62ebdbf531a50e3f9f9df3d243318439eb Mon Sep 17 00:00:00 2001 From: Mohamed El Amine BOUKERFA Date: Sun, 15 Mar 2026 16:24:23 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(backend)=20strip=20whitespace=20fr?= =?UTF-8?q?om=20media=20URLs=20in=20CORS=20proxy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When exporting a document to PDF, having whitespace before or after the media URL causes the image to not be downloaded via the CORS proxy, resulting in missing images in the exported PDF. Signed-off-by: Mohamed El Amine BOUKERFA --- src/backend/core/api/viewsets.py | 2 +- .../test_api_documents_cors_proxy.py | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 7d19f7c030..6d053d18fa 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -2268,7 +2268,7 @@ def cors_proxy(self, request, *args, **kwargs): GET /api/v1.0/documents//cors-proxy Act like a proxy to fetch external resources and bypass CORS restrictions. """ - url = request.query_params.get("url") + url = request.query_params.get("url", "").strip() if not url: return drf.response.Response( {"detail": "Missing 'url' query parameter"}, diff --git a/src/backend/core/tests/documents/test_api_documents_cors_proxy.py b/src/backend/core/tests/documents/test_api_documents_cors_proxy.py index a5753c37b5..4a06e976eb 100644 --- a/src/backend/core/tests/documents/test_api_documents_cors_proxy.py +++ b/src/backend/core/tests/documents/test_api_documents_cors_proxy.py @@ -55,6 +55,31 @@ def test_api_docs_cors_proxy_valid_url(mock_getaddrinfo): assert response.streaming_content +@unittest.mock.patch("core.api.viewsets.socket.getaddrinfo") +@responses.activate +def test_api_docs_cors_proxy_url_with_surrounding_whitespace(mock_getaddrinfo): + """ + URLs with leading or trailing whitespace must still be proxied successfully, + otherwise images whose `src` has stray whitespace are missing from the PDF export. + """ + document = factories.DocumentFactory(link_reach="public") + + # Mock DNS resolution to return a public IP address + mock_getaddrinfo.return_value = [ + (socket.AF_INET, socket.SOCK_STREAM, 0, "", ("8.8.8.8", 0)) + ] + + client = APIClient() + url_to_fetch = "https://external-url.com/assets/logo-gouv.png" + responses.get(url_to_fetch, body=b"", status=200, content_type="image/png") + response = client.get( + f"/api/v1.0/documents/{document.id!s}/cors-proxy/?url= {url_to_fetch} " + ) + assert response.status_code == 200 + assert response.headers["Content-Type"] == "image/png" + assert response.streaming_content + + def test_api_docs_cors_proxy_without_url_query_string(): """Test the CORS proxy API for documents without a URL query string.""" document = factories.DocumentFactory(link_reach="public")