Problem
The WADO-RS retrieve endpoints do not perform media type negotiation. The Accept header is only mined for the transfer-syntax parameter (service.rs extractor); the response media type is fixed (routes.rs). There is no 406 path anywhere in the codebase (grep -rn 406 src is empty).
DICOM PS3.18 Section 8.7.5 requires for the Retrieve transaction:
- the
Accept header field shall be present; a request without one shall be answered with 406 (Not Acceptable);
- if the origin server cannot produce any acceptable media type, the response shall be 406;
- an
Accept mixing DICOM and Rendered media types shall be answered with 400 (Bad Request).
Instead, every request gets 200 with multipart/related; type="application/dicom", whatever it asked for. Clients cannot detect that their requested representation (e.g. single-part application/dicom, or application/dicom+json) is unsupported, but they get a multipart body their parser may not expect.
Reproduction
Using examples/simple-setup (verified against DICOM-RST/0.3.0-beta.5). Requires only curl and jq; the test instance is synthesized via Orthanc's API, no DICOM files needed.
cd examples/simple-setup && docker compose up -d
# Create a synthetic instance in Orthanc and build the WADO-RS URL from its UIDs:
ID=$(curl -s http://localhost:8042/tools/create-dicom \
-d '{"Tags":{"PatientName":"ACCEPT^TEST","SOPClassUID":"1.2.840.10008.5.1.4.1.1.7"}}' | jq -r .ID)
URL=$(curl -s "http://localhost:8042/instances/$ID/tags?simplify" | jq -r \
'"http://localhost:8080/aets/ORTHANC/studies/\(.StudyInstanceUID)/series/\(.SeriesInstanceUID)/instances/\(.SOPInstanceUID)"')
# 1) Unsupported media type (expected 406):
curl -sD- -o /dev/null -H 'Accept: application/dicom+json' "$URL"
# 2) No Accept header at all (expected 406):
curl -sD- -o /dev/null -H 'Accept:' "$URL"
# 3) DICOM and Rendered media types mixed (expected 400):
curl -sD- -o /dev/null -H 'Accept: multipart/related; type="application/dicom", image/jpeg' "$URL"
All three return the identical response:
HTTP/1.1 200 OK
content-disposition: attachment; filename="1.2.276.0.7230010.3.1.2.447480576.1.1786095984.672056"
content-type: multipart/related; type="application/dicom"; boundary=boundary
vary: origin, access-control-request-method, access-control-request-headers
access-control-allow-origin: *
access-control-expose-headers: *
server: DICOM-RST/0.3.0-beta.5
transfer-encoding: chunked
The body is a real, successful multipart response (first part is a valid Part-10 instance), so this is not a downstream failure, negotiation simply never happens.
| Request |
Expected (PS3.18 §8.7.5) |
Actual |
Accept: application/dicom+json |
406 |
200, multipart/related |
no Accept header |
406 |
200, multipart/related |
| DICOM + Rendered mix |
400 |
200, multipart/related |
See also: #59
Problem
The WADO-RS retrieve endpoints do not perform media type negotiation. The
Acceptheader is only mined for thetransfer-syntaxparameter (service.rsextractor); the response media type is fixed (routes.rs). There is no 406 path anywhere in the codebase (grep -rn 406 srcis empty).DICOM PS3.18 Section 8.7.5 requires for the Retrieve transaction:
Acceptheader field shall be present; a request without one shall be answered with 406 (Not Acceptable);Acceptmixing DICOM and Rendered media types shall be answered with 400 (Bad Request).Instead, every request gets
200withmultipart/related; type="application/dicom", whatever it asked for. Clients cannot detect that their requested representation (e.g. single-partapplication/dicom, orapplication/dicom+json) is unsupported, but they get a multipart body their parser may not expect.Reproduction
Using
examples/simple-setup(verified againstDICOM-RST/0.3.0-beta.5). Requires onlycurlandjq; the test instance is synthesized via Orthanc's API, no DICOM files needed.All three return the identical response:
The body is a real, successful multipart response (first part is a valid Part-10 instance), so this is not a downstream failure, negotiation simply never happens.
Accept: application/dicom+jsonAcceptheaderSee also: #59