DicomWeb CORS Error Loading Image in OHIF

Context and full textual description of your issue: I have setup an orthanc server with an AWS S3 plugin using this repo(https://github.com/radpointhq/orthanc-s3-storage). In the repo I build the plugin, and then using the Osimis Orthanc Docker image, run Orthanc in a docker container. Then I use nginx as a reverse proxy with CORS headers as per the documentation(see the nginx config file below). This works as expected and stores the instances in S3.

The problem occurs when I attempt to integrate the OHIF Viewer with this Orthanc server. Before someone says “Go ask those guys”, the viewer works with other servers so I’m very confident the issue is on the server side or with my config for the viewer, which . OHIF uses the dicom-web protocol to receive the images from Orthanc so I built and included this plugin(https://book.orthanc-server.com/plugins/dicomweb.html).

The observed vs. expected results: The viewer receives study information from orthanc and successfully displays the studies we have. Once I click into a study, the images and thumbnails fail to load with the CORS error below:

CORSError.png

When I make the same request in the browser in isolation I get this:
{

“Details” : “expecting ‘Accept: multipart/related’ HTTP header”,
“HttpError” : “Bad Request”,
“HttpStatus” : 400,
“Message” : “Parameter out of range”,
“Method” : “GET”,
“OrthancError” : “Parameter out of range”,

“OrthancStatus” : 3,
“Uri” : “/dicom-web/studies/1.2.826.0.1.3680043.2.91.335327876259865898215262702885611091770/series/1.2.826.0.1.3680043.2.91.6938927763951427772746839458289770611/instances/1.2.826.0.1.3680043.2.91.19995590109728170343851175207279310896/frames/1”
}

When I make the same request in CURL it gives me the image:

curlWorks.png

I’ve tried many different configurations and different attempts at doing this, but none seem to work. Has anybody else experienced this with OHIF or with Orthanc? If you can offer any help at all I’d be very grateful!

A sequence of command lines that lead to your problem:

  1. Launch a medium EC2 instance in AWS, ssh into it and clone the radpointHQ S3 repo linked above into it.

  2. Download and configure your environment for use with Docker

  3. Implement the nginx reverse proxy detailed in the orthanc book with the provided nginx config below.

  4. Build the dicomWeb plugin(https://hg.orthanc-server.com/orthanc-dicomweb)

  5. Use the OHIF Viewer with the config listed below replacing serverIP with your own.

  6. Upload a dicom file to the server

  7. Navigate to your OHIF Viewer and click on the study shown

Orthanc Config File: {
“Name” : “Orthanc inside Docker”,
“StorageDirectory” : “/var/lib/orthanc/db”,
“IndexDirectory” : “/var/lib/orthanc/db”,
“StorageCompression” : false,
“MaximumStorageSize” : 0,
“MaximumPatientCount” : 0,
“LuaScripts” : [
],
“Plugins” : [ “/usr/local/share/orthanc/plugins” ],
“ConcurrentJobs” : 2,
“HttpServerEnabled” : true,
“HttpPort” : 8042,
“HttpDescribeErrors” : true,
“HttpCompressionEnabled” : true,
“DicomServerEnabled” : true,
“DicomAet” : “ORTHANC”,
“DicomCheckCalledAet” : false,
“DicomPort” : 4242,
“DicomWeb” : {
“Enable” : true, // Whether DICOMweb support is enabled
“Root” : “/dicom-web/”, // Root URI of the DICOMweb API (for QIDO-RS, STOW-RS and WADO-RS)
“EnableWado” : true, // Whether WADO-URI (previously known as WADO) support is enabled
“WadoRoot” : “/wado”, // Root URI of the WADO-URI (aka. WADO) API
“Ssl” : false, // Whether HTTPS should be used for subsequent WADO-RS requests
“QidoCaseSensitive” : true, // For QIDO-RS server, whether search is case sensitive (since release 0.5)
“StudiesMetadata” : “Full”, // How study-level metadata is retrieved (since release 1.1, cf. section below)
“SeriesMetadata” : “Full” // How series-level metadata is retrieved (since release 1.1, cf. section below)
},
“DefaultEncoding” : “Latin1”,
“DeflatedTransferSyntaxAccepted” : true,
“JpegTransferSyntaxAccepted” : true,
“Jpeg2000TransferSyntaxAccepted” : true,
“JpegLosslessTransferSyntaxAccepted” : true,
“JpipTransferSyntaxAccepted” : true,
“Mpeg2TransferSyntaxAccepted” : true,
“RleTransferSyntaxAccepted” : true,
“UnknownSopClassAccepted” : false,
“DicomScpTimeout” : 30,
“RemoteAccessAllowed” : true,
“SslEnabled” : false,
“SslCertificate” : “certificate.pem”,
“AuthenticationEnabled” : false,
“DicomModalitiesInDatabase” : false,
“DicomAlwaysAllowEcho” : true,
“DicomAlwaysAllowStore” : true,
“DicomCheckModalityHost” : false,
“DicomScuTimeout” : 10,
“OrthancPeers” : {},
“OrthancPeersInDatabase” : false,
“HttpProxy” : “”,
“HttpVerbose” : false,
“HttpTimeout” : 10,
“HttpsVerifyPeers” : true,
“HttpsCACertificates” : “”,
“UserMetadata” : {},
“UserContentType” : {},
“StableAge” : 60,
“StrictAetComparison” : false,
“StoreMD5ForAttachments” : true,
“LimitFindResults” : 0,
“LimitFindInstances” : 0,
“LimitJobs” : 10,
“LogExportedResources” : false,
“KeepAlive” : true,
“TcpNoDelay” : true,
“HttpThreadsCount” : 50,
“StoreDicom” : true,
“DicomAssociationCloseDelay” : 5,
“QueryRetrieveSize” : 10,
“CaseSensitivePN” : false,
“LoadPrivateDictionary” : true,
“Dictionary” : {},
“SynchronousCMove” : true,
“JobsHistorySize” : 10,
“SaveJobs” : true,
“OverwriteInstances” : false,
“MediaArchiveSize” : 1,
“StorageAccessOnFind” : “Always”,
“MetricsEnabled” : true,
}

OHIF Viewer Config:

servers: {
dicomWeb: [
{
name: ‘Orthanc Dev’,
wadoUriRoot: ‘http://serverIP/wado’,
qidoRoot: ‘http://serverIP/dicom-web’,
wadoRoot: ‘http://serverIP/dicom-web’,
qidoSupportsIncludeField: true,
imageRendering: ‘wadors’,
thumbnailRendering: ‘wadors’,
enableStudyLazyLoad: true,
},
],
},

Logs:

Startup command: Orthanc /etc/orthanc/orthanc.json
W0312 22:01:46.259500 main.cpp:1625] Orthanc version: mainline (20200820T134348)
W0312 22:01:46.259691 OrthancConfiguration.cpp:62] Reading the configuration from: “/etc/orthanc/orthanc.json”
W0312 22:01:46.284325 FromDcmtkBridge.cpp:298] Loading external DICOM dictionary: “/usr/share/libdcmtk14/dicom.dic”
W0312 22:01:46.294856 FromDcmtkBridge.cpp:298] Loading external DICOM dictionary: “/usr/share/libdcmtk14/private.dic”
W0312 22:01:46.313356 main.cpp:802] Loading plugin(s) from: /usr/local/share/orthanc/plugins
W0312 22:01:46.315066 PluginsManager.cpp:269] Registering plugin ‘dicom-web’ (version mainline)
W0312 22:01:46.315108 PluginsManager.cpp:168] Performance warning in DICOMweb: Non-release build, runtime debug assertions are turned on
W0312 22:01:46.316059 PluginsManager.cpp:168] URI to the DICOMweb REST API: /dicom-web/
W0312 22:01:46.316750 PluginsManager.cpp:168] URI to the WADO-URI API: /wado
W0312 22:01:46.316868 OrthancInitialization.cpp:293] SQLite index directory: “/var/lib/orthanc/db”
W0312 22:01:46.317104 OrthancInitialization.cpp:368] Storage directory: “/var/lib/orthanc/db”
W0312 22:01:46.317837 HttpClient.cpp:1053] HTTPS will use the CA certificates from this file: /etc/orthanc
W0312 22:01:46.318434 LuaContext.cpp:93] Lua says: Lua toolbox installed
W0312 22:01:46.318654 LuaContext.cpp:93] Lua says: Lua toolbox installed
W0312 22:01:46.318761 ServerContext.cpp:390] Disk compression is disabled
W0312 22:01:46.318784 ServerIndex.cpp:1636] No limit on the number of stored patients
W0312 22:01:46.318797 ServerIndex.cpp:1653] No limit on the size of the storage area
W0312 22:01:46.319027 ServerContext.cpp:191] Reloading the jobs from the last execution of Orthanc
W0312 22:01:46.319305 JobsEngine.cpp:272] The jobs engine has started with 2 threads
W0312 22:01:46.319828 main.cpp:1109] DICOM server listening with AET ORTHANC on port: 4242
W0312 22:01:46.319862 HttpServer.cpp:1298] HTTP compression is enabled
W0312 22:01:46.319873 main.cpp:938] ====> Remote access is enabled while user authentication is explicitly disabled, your setup is POSSIBLY INSECURE <====
W0312 22:01:46.319882 main.cpp:1011] Remote LUA script execution is disabled
W0312 22:01:46.321623 HttpServer.cpp:1205] HTTP server listening on port: 8042 (HTTPS encryption is disabled, remote access is allowed)
W0312 22:01:46.322036 main.cpp:814] Orthanc has started

Hi Evan,

Orthanc does not support CORS requests. In order to support CORS, you need to use a HTTP proxy such as Nginx like you done.

The error you get is because the Nginx CORS request is missing the required headers. In this case Access-Control-Allow-Origin.

I couldn’t find your Nginx conf file, but here is a great resource for enabling CORS using Nginx https://enable-cors.org/server_nginx.html. This snippet sets the required headers on the Preflight Options Requests and Actual Requests. Depending on your setup, you may need to adjust Access-Control-Allow-Headers or Access-Control-Allow-Methods to include any other headers or methods you require.

I think your situation is complicated because Orthanc is returning a non 400 (error) response and unless configured, Nginx doesn’t include the CORS headers for errors, which in a browser throws a CORS error and masks the real return. In order to include CORS headers for errors please see https://stackoverflow.com/a/53047154/251352

Re: the DICOM-Web error response you receive, I can’t help with that sorry.

HTH.

James

You can look here Cross-Origin Information for OHIF | OHIF