Skip to content

Commit 47c76bf

Browse files
committed
feat: validate file length in zgw document download view
If the ZGW document backend is misbehaving, for instance because an intermediate service gateway is broken and returns some kind of XML message, the user will see a broken download message, because the announced content-length will not in fact match the content. In those cases, it's better UX to log and display an error message.
1 parent 6cc449f commit 47c76bf

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/open_inwoner/cms/cases/views/status.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,34 @@ def get(self, request, *args, **kwargs):
848848
if not content_stream:
849849
raise Http404
850850

851+
# Validate the actual content length matches the expected size
852+
actual_content_length = content_stream.headers.get("Content-Length")
853+
if (
854+
actual_content_length
855+
and int(actual_content_length) != info_object.bestandsomvang
856+
):
857+
logger.warning(
858+
"Document size mismatch",
859+
info_object_uuid=info_object_uuid,
860+
expected_size=info_object.bestandsomvang,
861+
actual_size=actual_content_length,
862+
)
863+
messages.error(
864+
request,
865+
_(
866+
"Het document kon niet worden gedownload vanwege een fout in de gegevens."
867+
),
868+
)
869+
return HttpResponseRedirect(
870+
reverse(
871+
"cases:case_detail",
872+
kwargs={
873+
"api_group_id": self.kwargs["api_group_id"],
874+
"object_id": self.zaak.uuid,
875+
},
876+
)
877+
)
878+
851879
self.log_case_document_downloaded(self.zaak, info_object.bestandsnaam)
852880

853881
headers = {

src/open_inwoner/openzaak/tests/test_documents.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,29 @@ def test_no_data_is_retrieved_when_document_download_data_http_500(self, m):
518518

519519
self.app.get(self.informatie_object_file.url, user=self.user, status=404)
520520

521+
def test_document_download_with_size_mismatch_shows_error(self, m):
522+
self._setUpAccessMocks(m)
523+
m.get(self.informatie_object["url"], json=self.informatie_object)
524+
# Mock the download endpoint with mismatched content length
525+
wrong_content = b"wrong content"
526+
m.get(
527+
self.informatie_object["inhoud"],
528+
content=wrong_content,
529+
headers={"Content-Length": str(len(wrong_content))},
530+
)
531+
532+
# Expect a redirect - auto_follow=False prevents following the redirect
533+
response = self.app.get(
534+
self.informatie_object_file.url,
535+
user=self.user,
536+
status=302,
537+
auto_follow=False,
538+
)
539+
540+
# Verify redirect location
541+
expected_redirect = f"/cases/{self.api_group.id}/{self.zaak['uuid']}/status/"
542+
self.assertEqual(response.location, expected_redirect)
543+
521544
def test_document_download_request_uses_service_credentials(self, m):
522545
server = CertificateFactory(label="server", cert_only=True)
523546
client = CertificateFactory(label="client", key_pair=True)

0 commit comments

Comments
 (0)