From 99764b8e3e5f4d1cc991ea45d30cc7b3aa8a8af8 Mon Sep 17 00:00:00 2001 From: Mohamed El Amine BOUKERFA Date: Tue, 28 Apr 2026 14:47:16 +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 7d19f7c03..6d053d18f 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -2268,7 +2268,7 @@ class DocumentViewSet( 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 a5753c37b..4a06e976e 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")