DICOMweb Tag.RetrieveURL behind reverse proxy

Hello! I originally asked this question in the Weasis GitHub repository (https://github.com/nroduit/Weasis/issues/264).

I am trying to setup Weasis to work via DICOMweb with 2 load-balanced Orthanc instances. They are served by NGINX under the URI $HOST/orthanc-nightly-reader

Inside Weasis, I created the configuration like this:

166563625-80eb1cb2-a802-4da6-8ad0-97fcbf627daa.png

And when I query the server, I have the list of studies. However, when I try to import them, nothing happens. Weasis log shows:

03.05.2022 21:39:29.500 DEBUG [Dicom Q/R task-pool-2-thread-1] org.weasis.dicom.qr.RetrieveTask: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies/1.2.392.200036.9125.2.1631116563610.64944063984.261631/series?includefield=0008103E,00080060,0020000E,00200011,00081190

Notice the URL in the first request: http://localhost/orthanc-nightly-reader/dicom-web

The second request, however, changes the URL and fails:

org.weasis.dicom.qr.RetrieveTask: QIDO-RS request: https://localhost/dicom-web/studies/1.2.392.200036.9125.2.1631116563610.64944063984.261631/series/1.2.392.200036.9125.3.1631116563610.64944063984.261633/instances?includefield=00080018,00200013,00081190

org.weasis.dicom.qr.RetrieveTask: QIDO-RS all instances with seriesUID 1.2.392.200036.9125.3.1631116563610.64944063984.261633 org.weasis.core.util.StreamIOException: java.net.ConnectException: Connection refused: no further information
at org.weasis.core.api.util.NetworkUtil.prepareConnection(NetworkUtil.java:162)
at org.weasis.core.api.util.NetworkUtil.getHttpResponse(NetworkUtil.java:80)
at org.weasis.core.api.util.NetworkUtil.getHttpResponse(NetworkUtil.java:73)

The original URL (http://localhost/orthanc-nightly-reader/dicom-web) becomes https://localhost/dicom-web

I got this response:

"I’m not very familiar with Orthanc but I think the difference in URL comes from the fact that it is the server that can give the retrieved URL for an instance (Tag.RetrieveURL).

The Nginx configuration has to respect the Orthanc configuration contexts. If Orthanc returns retrieve URLs, these must be accessible."

Is it possible to configure the Tag.RetrieveURL inside Orthanc to serve DICOMweb via reverse proxy?

Hi Diego,

Note that, in your reverse proxy, you should make sure to set the Forwarded header. Orthanc will reuse it to get the host and proto. But, unfortunately, it seems that host should just be a hostname and can not include a subpath.

So, in your case, it seems that you would just need a new ‘BaseRetrieveURL’ configuration right ? You would have this config:
“Root”: “/dicom-web/”
“BaseRetrieveURL”: “/orthanc-nightly-reader/dicom-web/”

Please confirm that my understanding is correct, and I’ll add it.

Best regards,

Alain.

166563625-80eb1cb2-a802-4da6-8ad0-97fcbf627daa.png

Hi Alain. How are you doing?

Yes, this is it! Just to be clear, I don’t know how the Root variable is taken into account in the URI construction, because if it is always appended to all DICOMweb URLs, I believe BaseRetrieveURL should be /orthanc-nightly-reader/

A quarta-feira, 4 de maio de 2022 à(s) 16:51:51 UTC+1, alain...@osimis.io escreveu:

Hi Diego,

I’ve implemented it here: https://hg.orthanc-server.com/orthanc-dicomweb/rev/05f2e83dc050. Could you give it a try ? (note that you’ll need the Orthanc mainline as well to test it).

Note that, to keep max flexibility, you’ll have to include “/dicom-web/” as well (you could decide to hide this part of the url in your reverse proxy as well). In your case:

“Root”: “/dicom-web/”
“PublicRoot”: “/orthanc-nightly-reader/dicom-web/”

HTH

Alain.

Hello Alain! It works!!!

For a preliminary test, here is what I did:

I changed the Orthanc readers version to latest in the Dockerfile

FROM jodogne/orthanc:latest

I changed VERSION_DICOM_WEB to mainline in the download-plugins.sh script

VERSION_DICOM_WEB=mainline

I have a 404 error for some URLs trying to render thumbnails, but I think it is because Orthanc does not implement it. I don’t know if it is possible to ask a server which parts of the DICOMweb specification it supports, so that Weasis could avoid the thumbnail requests (I will ask in the Weasis issue tracker).

I will do a proper test and share all details when I get home!

A quinta-feira, 5 de maio de 2022 à(s) 11:09:27 UTC+1, alain...@osimis.io escreveu:

FYI, here is what is happening between Orthanc and Weasis:

1 - Search request
Weasis log says
06.05.2022 04:26:02.673 DEBUG [QIDO-RS] org.weasis.dicom.qr.RsQuery: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies?&includefield=00080020,00080030,00080050,00080061,00080090,00081030,00100010,00100020,00100021,00100030,00100040,0020000D,00200010&limit=10&offset=0
06.05.2022 04:26:13.706 DEBUG [QIDO-RS] org.weasis.dicom.qr.RsQuery: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies/1.2.840.113564.100161.20210406151605296230/series?includefield=0008103E,00080060,0020000E,00200011,00081190
06.05.2022 04:26:13.943 DEBUG [QIDO-RS] org.weasis.dicom.qr.RsQuery: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies/1.2.392.200036.9125.2.1631116563610.64944063984.261631/series?includefield=0008103E,00080060,0020000E,00200011,00081190
06.05.2022 04:26:14.171 DEBUG [QIDO-RS] org.weasis.dicom.qr.RsQuery: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies/1.3.51.0.7.2878952877.24100.9283.41717.7152.19798.33951/series?includefield=0008103E,00080060,0020000E,00200011,00081190
06.05.2022 04:26:14.400 DEBUG [QIDO-RS] org.weasis.dicom.qr.RsQuery: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies/1.3.51.0.7.14244326474.23676.7233.41950.41962.15853.61026/series?includefield=0008103E,00080060,0020000E,00200011,00081190
06.05.2022 04:26:14.653 DEBUG [QIDO-RS] org.weasis.dicom.qr.RsQuery: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies/1.2.840.113619.6.408.238400482930226395819532980666425232388/series?includefield=0008103E,00080060,0020000E,00200011,00081190
06.05.2022 04:26:21.630 DEBUG [QIDO-RS] org.weasis.dicom.qr.RsQuery: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series?includefield=0008103E,00080060,0020000E,00200011,00081190
06.05.2022 04:26:21.855 DEBUG [QIDO-RS] org.weasis.dicom.qr.RsQuery: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies/1.2.392.200036.9116.2.6.1.3268.2054832338.1616857609.90261/series?includefield=0008103E,00080060,0020000E,00200011,00081190

Orthanc log says
infra-orthanc-reader-nightly-1-1 | E0506 03:26:02.283525 PluginsManager.cpp:186] Exception while invoking plugin service 26: Unknown DICOM tag (???)
infra-orthanc-reader-nightly-1-1 | W0506 03:26:02.453941 ServerContext.cpp:2403] W001: Accessing Dicom tags from storage when accessing study : 0008,0201;0010,0021
infra-orthanc-reader-nightly-1-1 | E0506 03:26:13.296876 PluginsManager.cpp:153] Unsupported return MIME type: text/html, image/gif, image/jpeg, *; q=.2, /; q=.2, will return DICOM+JSON (???)

Despite Orthanc exception and warnings, the search works fine and returns a list of studies.

2 - Retrieve request (Weasis import)
Weasis log
06.05.2022 04:30:30.133 DEBUG [Dicom Q/R task-pool-2-thread-1] org.weasis.dicom.qr.RetrieveTask: QIDO-RS request: http://localhost/orthanc-nightly-reader/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series?includefield=0008103E,00080060,0020000E,00200011,00081190
06.05.2022 04:30:30.476 DEBUG [Dicom Q/R task-pool-2-thread-1] org.weasis.dicom.qr.RetrieveTask: QIDO-RS request: http://localhost:80/orthanc-nightly-reader/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series/1.2.840.113564.100020.20220430091234311830/instances?includefield=00080018,00200013,00081190
06.05.2022 04:30:30.598 WARN [Dicom Q/R task-pool-2-thread-1] org.weasis.core.api.util.NetworkUtil: http Status 404 - Not Found
06.05.2022 04:30:30.598 TRACE [Dicom Q/R task-pool-2-thread-1] org.weasis.core.api.util.NetworkUtil: HttpURLConnection ERROR, server response: { “HttpError” : “Not Found”, “HttpStatus” : 404, “Message” : “Unknown resource”, “Method” : “GET”, “OrthancError” : “Unknown resource”, “OrthancStatus” : 17, “Uri” : “/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series/1.2.840.113564.100020.20220430091234279810/thumbnail”}
06.05.2022 04:30:30.598 ERROR [Dicom Q/R task-pool-2-thread-1] org.weasis.dicom.explorer.wado.LoadSeries: Downloading thumbnail with http://localhost:80/orthanc-nightly-reader/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series/1.2.840.113564.100020.20220430091234279810/thumbnail?viewport=256%2C256 org.weasis.core.util.StreamIOException: Not Found
at org.weasis.core.api.util.NetworkUtil.readResponse(NetworkUtil.java:184)
at org.weasis.core.api.util.NetworkUtil.prepareConnection(NetworkUtil.java:157)
at org.weasis.core.api.util.NetworkUtil.getHttpResponse(NetworkUtil.java:80)
06.05.2022 04:30:30.612 WARN [Dicom Q/R task-pool-2-thread-1] org.weasis.core.api.util.NetworkUtil: http Status 404 - Not Found
06.05.2022 04:30:30.612 TRACE [Dicom Q/R task-pool-2-thread-1] org.weasis.core.api.util.NetworkUtil: HttpURLConnection ERROR, server response: { “HttpError” : “Not Found”, “HttpStatus” : 404, “Message” : “Unknown resource”, “Method” : “GET”, “OrthancError” : “Unknown resource”, “OrthancStatus” : 17, “Uri” : “/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series/1.2.840.113564.100020.20220430091234311830/thumbnail”}
06.05.2022 04:30:30.612 ERROR [Dicom Q/R task-pool-2-thread-1] org.weasis.dicom.explorer.wado.LoadSeries: Downloading thumbnail with http://localhost:80/orthanc-nightly-reader/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series/1.2.840.113564.100020.20220430091234311830/thumbnail?viewport=256%2C256 org.weasis.core.util.StreamIOException: Not Found
at org.weasis.core.api.util.NetworkUtil.readResponse(NetworkUtil.java:184)
at org.weasis.core.api.util.NetworkUtil.prepareConnection(NetworkUtil.java:157)
at org.weasis.core.api.util.NetworkUtil.getHttpResponse(NetworkUtil.java:80)
06.05.2022 04:30:30.622 INFO [AWT-EventQueue-0] org.weasis.dicom.explorer.DicomExplorer: Add series: AP
06.05.2022 04:30:30.630 INFO [AWT-EventQueue-0] org.weasis.dicom.explorer.DicomExplorer: Add series: Lateral
06.05.2022 04:31:06.705 INFO [AWT-EventQueue-0] org.weasis.dicom.explorer.wado.LoadSeries: PERF type:DICOMDIR seriesUID:1.2.840.113564.100020.20220430091234279810 modality:CR nbImages:1 size:5786510 time:1258 rate:4599.77 errors:0
06.05.2022 04:31:06.705 INFO [AWT-EventQueue-0] org.weasis.dicom.explorer.wado.LoadSeries: PERF type:DICOMDIR seriesUID:1.2.840.113564.100020.20220430091234311830 modality:CR nbImages:1 size:7245626 time:1258 rate:5759.64 errors:0
06.05.2022 04:31:06.762 DEBUG [Thumbnail Loader-pool-10-thread-1] org.weasis.core.api.media.data.ImageElement: Asking for reading image: 1.2.840.113564.100020.20220430091242173900.3203801020003
06.05.2022 04:31:06.763 DEBUG [Image Loader-pool-9-thread-1] org.weasis.dicom.codec.DicomMediaIO: Start reading dicom image frame: 0 sopUID: 1.2.840.113564.100020.20220430091242173900.3203801020003

Orthanc log
infra-orthanc-reader-nightly-1-1 | W0506 03:30:29.909515 ServerContext.cpp:2403] W001: Accessing Dicom tags from storage when accessing series : 0008,0201;0040,0244;0040,0245;0040,0275
infra-orthanc-reader-nightly-1-1 | E0506 03:30:29.960149 PluginsManager.cpp:153] Unsupported return MIME type: text/html, image/gif, image/jpeg, *; q=.2, /; q=.2, will return DICOM+JSON
infra-nginx-1 | 172.18.0.1 - sismed [06/May/2022:03:30:29 +0000] “GET /orthanc-nightly-reader/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series?includefield=0008103E,00080060,0020000E,00200011,00081190 HTTP/1.1” 200 3342 “-” “Weasis/4.0.0-RC (Windows 11; 10.0; amd64; default; NATIVE) Java/18”
infra-orthanc-reader-nightly-1-1 | W0506 03:30:30.045084 ServerContext.cpp:2403] W001: Accessing Dicom tags from storage when accessing instance : 0008,0016;0008,0201;0028,0010;0028,0011;0028,0100;0040,0244;0040,0245;0040,0275
infra-orthanc-reader-nightly-1-1 | E0506 03:30:30.068652 PluginsManager.cpp:153] Unsupported return MIME type: text/html, image/gif, image/jpeg, *; q=.2, /; q=.2, will return DICOM+JSON
infra-nginx-1 | 172.18.0.1 - sismed [06/May/2022:03:30:30 +0000] “GET /orthanc-nightly-reader/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series/1.2.840.113564.100020.20220430091234279810/instances?includefield=00080018,00200013,00081190 HTTP/1.1” 200 2223 “-” “Weasis/4.0.0-RC (Windows 11; 10.0; amd64; default; NATIVE) Java/18”
infra-orthanc-reader-nightly-2-1 | W0506 03:30:30.153432 ServerContext.cpp:2403] W001: Accessing Dicom tags from storage when accessing instance : 0008,0016;0008,0201;0028,0010;0028,0011;0028,0100;0040,0244;0040,0245;0040,0275
infra-orthanc-reader-nightly-2-1 | E0506 03:30:30.183662 PluginsManager.cpp:153] Unsupported return MIME type: text/html, image/gif, image/jpeg, *; q=.2, /; q=.2, will return DICOM+JSON
infra-nginx-1 | 172.18.0.1 - sismed [06/May/2022:03:30:30 +0000] “GET /orthanc-nightly-reader/dicom-web/studies/1.2.840.113564.100020.20220430091139648790/series/1.2.840.113564.100020.20220430091234311830/instances?includefield=00080018,00200013,00081190 HTTP/1.1” 200 2228 “-” “Weasis/4.0.0-RC (Windows 11; 10.0; amd64; default; NATIVE) Java/18”

Again, despite thumbnail errors and other warnings, the DICOMweb retrieve works fine.

As Alain said, the headers are playing a really important role here! Make sure you got them right. My NGINX configuration (updated after the production errors I found!):

location /orthanc-nightly-reader {
proxy_pass http://readerOrthancsNightly;
proxy_set_header HOST $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
rewrite /orthanc-nightly-reader(.) $1 break;
add_header ‘Access-Control-Allow-Credentials’ ‘true’;
add_header ‘Access-Control-Allow-Headers’ ‘DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type’;
add_header ‘Access-Control-Allow-Methods’ ‘GET, POST, OPTIONS’;
add_header ‘Access-Control-Allow-Origin’ '
';
}

Regarding the thumbnail issue, I think that a possible improvement for Orthanc is implementing the DICOMweb capabilities endpoint. Quoting DICOMweb spec (https://www.dicomstandard.org/using/dicomweb/capabilities/):

“The Capabilities service enables you to discover the supported services of a particular DICOMweb end-point. Make the HTTP OPTIONS query against an end-point, and a WADL response will be returned explaining the various options and what it supports. The specification can be found in PS3.18 8.9.”

By implementing the DICOMweb capabilities endpoint, Orthanc would be able to tell Weasis, during an initial handshake, it is not able to serve thumbnails to avoid receiving those requests.

To have some control over the dicom-web requests, I’ve created additional checks in the orthanc.RegisterIncomingHttpRequestFilter event. The DICOMweb “search” request has limit/offset parameters. I wonder if there is a way for Orthanc to restrain or change the limit value on the fly and forward the request.

The only significant problem I encountered is that big studies (namely MR/CT) are not entirely retrieved from Orthanc. I will need to investigate this. But small studies like MG, DX, CR are working great!

A quinta-feira, 5 de maio de 2022 à(s) 16:25:23 UTC+1, Diego Victor de Jesus escreveu: