From 2f63a9db80b59aaa07d134ba83b19342a5d51eda Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Thu, 18 May 2023 19:06:26 +0200 Subject: [PATCH 01/16] init commit making TS customizable in OHIF settings --- .../cornerstone/src/initWADOImageLoader.js | 48 ++++++++++++++++--- platform/viewer/public/config/default.js | 1 + 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/extensions/cornerstone/src/initWADOImageLoader.js b/extensions/cornerstone/src/initWADOImageLoader.js index fbbf3b95d9d..3bee57efffe 100644 --- a/extensions/cornerstone/src/initWADOImageLoader.js +++ b/extensions/cornerstone/src/initWADOImageLoader.js @@ -54,7 +54,7 @@ export default function initWADOImageLoader( // we should set this flag to false. convertFloatPixelDataToInt: false, }, - beforeSend: function(xhr) { + beforeSend: function (xhr) { const headers = userAuthenticationService.getAuthorizationHeader(); // Request: @@ -62,12 +62,31 @@ export default function initWADOImageLoader( // whatever transfer-syntax the origin server provides. // For now we use image/jls and image/x-jls because some servers still use the old type // http://dicom.nema.org/medical/dicom/current/output/html/part18.html + + //Initialize the accept header content + const acceptHeader = ['multipart/related'] + //Storing the requesting transfer syntax specified in OHIF config + const requestTransferSyntaxUID = appConfig.requestTransferSyntaxUID + + if (requestTransferSyntaxUID) { + //Check TS is valid + if (!Object.keys(typeForTS).includes(requestTransferSyntaxUID)) { + console.warn(requestTransferSyntaxUID + 'is unexpected') + } else { + //Fetch type header according to requesting TS + let type = typeForTS[requestTransferSyntaxUID] + if (type === 'application/octet-stream' && !appConfig.omitQuotationForMultipartRequest) { + type = '"application/octet-stream"' + } + acceptHeader.push('type=' + type) + acceptHeader.push('transfer-syntax=' + requestTransferSyntaxUID) + } + + } const xhrRequestHeaders = { - Accept: appConfig.omitQuotationForMultipartRequest - ? 'multipart/related; type=application/octet-stream' - : 'multipart/related; type="application/octet-stream"', - // 'multipart/related; type="image/x-jls", multipart/related; type="image/jls"; transfer-syntax="1.2.840.10008.1.2.4.80", multipart/related; type="image/x-jls", multipart/related; type="application/octet-stream"; transfer-syntax=*', - }; + //Serialize Accept header + Accept: acceptHeader.join('; ') + } if (headers && headers.Authorization) { xhrRequestHeaders.Authorization = headers.Authorization; @@ -82,6 +101,23 @@ export default function initWADOImageLoader( initWebWorkers(appConfig); } +const typeForTS = { + "*": "application/octet-stream", + "1.2.840.10008.1.2.1": "application/octet-stream", + "1.2.840.10008.1.2": "application/octet-stream", + "1.2.840.10008.1.2.2": "application/octet-stream", + "1.2.840.10008.1.2.4.70": "image/jpeg", + "1.2.840.10008.1.2.4.50": "image/jpeg", + "1.2.840.10008.1.2.4.51": "image/dicom+jpeg", + "1.2.840.10008.1.2.4.57": "image/jpeg", + "1.2.840.10008.1.2.5": "image/dicom-rle", + "1.2.840.10008.1.2.4.80": "image/jls", + "1.2.840.10008.1.2.4.81": "image/jls", + "1.2.840.10008.1.2.4.90": "image/jp2", + "1.2.840.10008.1.2.4.91": "image/jp2", + "1.2.840.10008.1.2.4.92": "image/jpx", + "1.2.840.10008.1.2.4.93": "image/jpx", +} export function destroy() { // Note: we don't want to call .terminate on the webWorkerManager since diff --git a/platform/viewer/public/config/default.js b/platform/viewer/public/config/default.js index ff93f31a13e..8a9bf99d552 100644 --- a/platform/viewer/public/config/default.js +++ b/platform/viewer/public/config/default.js @@ -16,6 +16,7 @@ window.config = { showCPUFallbackMessage: true, showLoadingIndicator: true, strictZSpacingForVolumeViewport: true, + requestTransferSyntaxUID: '1.2.840.10008.1.2.4.80', maxNumRequests: { interaction: 100, thumbnail: 75, From 0e991d6bde32ccfaae510519b61ee9ae4e629720 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Thu, 18 May 2023 19:13:36 +0200 Subject: [PATCH 02/16] config documentation --- platform/docs/docs/configuration/configurationFiles.md | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index 141b2c00554..5a6f16e5573 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -112,6 +112,7 @@ Here are a list of some options available: - `maxNumberOfWebWorkers`: The maximum number of web workers to use for decoding. Defaults to minimum of `navigator.hardwareConcurrency` and what is specified by `maxNumberOfWebWorkers`. Some windows machines require smaller values. +- `requestTransferSyntaxUID` : Request for a specific TS to the DICOM archive ex : 1.2.840.10008.1.2.4.80 - `omitQuotationForMultipartRequest`: Some servers (e.g., .NET) require the `multipart/related` request to be sent without quotation marks. Defaults to `false`. If your server doesn't require this, then setting this flag to `true` might improve performance (by removing the need for preflight requests). Also note that if auth headers are used, a preflight request is required. - `maxNumRequests`: The maximum number of requests to allow in parallel. It is an object with keys of `interaction`, `thumbnail`, and `prefetch`. You can specify a specific number for each type. From 5e4043d99ca7e65b7973b9d688a6336a8c4ae265 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Thu, 18 May 2023 19:21:46 +0200 Subject: [PATCH 03/16] add source of type correspondancies --- extensions/cornerstone/src/initWADOImageLoader.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/extensions/cornerstone/src/initWADOImageLoader.js b/extensions/cornerstone/src/initWADOImageLoader.js index 3bee57efffe..c6d19f5c5bf 100644 --- a/extensions/cornerstone/src/initWADOImageLoader.js +++ b/extensions/cornerstone/src/initWADOImageLoader.js @@ -101,6 +101,11 @@ export default function initWADOImageLoader( initWebWorkers(appConfig); } + +/* +taken from +https://hg.orthanc-server.com/orthanc-dicomweb/file/tip/Plugin/WadoRsRetrieveFrames.cpp +*/ const typeForTS = { "*": "application/octet-stream", "1.2.840.10008.1.2.1": "application/octet-stream", From 5ae6e9caf4fed9cef6f9803621a1f715ba772902 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Thu, 18 May 2023 20:05:28 +0200 Subject: [PATCH 04/16] restaure config --- platform/viewer/public/config/default.js | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/viewer/public/config/default.js b/platform/viewer/public/config/default.js index 8a9bf99d552..ff93f31a13e 100644 --- a/platform/viewer/public/config/default.js +++ b/platform/viewer/public/config/default.js @@ -16,7 +16,6 @@ window.config = { showCPUFallbackMessage: true, showLoadingIndicator: true, strictZSpacingForVolumeViewport: true, - requestTransferSyntaxUID: '1.2.840.10008.1.2.4.80', maxNumRequests: { interaction: 100, thumbnail: 75, From 6da1734b6eda4a61b9cb959d1e9017e6a2db4366 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Mon, 29 May 2023 10:38:04 +0200 Subject: [PATCH 05/16] Moving requested ts in createDicomWebApi (WIP) --- .../cornerstone/src/initWADOImageLoader.js | 56 +-------- .../default/src/DicomWebDataSource/index.js | 111 ++++++++++++++---- platform/viewer/public/config/default.js | 1 + 3 files changed, 90 insertions(+), 78 deletions(-) diff --git a/extensions/cornerstone/src/initWADOImageLoader.js b/extensions/cornerstone/src/initWADOImageLoader.js index c6d19f5c5bf..2862aabb4c8 100644 --- a/extensions/cornerstone/src/initWADOImageLoader.js +++ b/extensions/cornerstone/src/initWADOImageLoader.js @@ -54,39 +54,12 @@ export default function initWADOImageLoader( // we should set this flag to false. convertFloatPixelDataToInt: false, }, + /* + TODO (Salim) : Seems to be implemented in createDicomWebApi, check if safe to remove beforeSend: function (xhr) { const headers = userAuthenticationService.getAuthorizationHeader(); - // Request: - // JPEG-LS Lossless (1.2.840.10008.1.2.4.80) if available, otherwise accept - // whatever transfer-syntax the origin server provides. - // For now we use image/jls and image/x-jls because some servers still use the old type - // http://dicom.nema.org/medical/dicom/current/output/html/part18.html - - //Initialize the accept header content - const acceptHeader = ['multipart/related'] - //Storing the requesting transfer syntax specified in OHIF config - const requestTransferSyntaxUID = appConfig.requestTransferSyntaxUID - - if (requestTransferSyntaxUID) { - //Check TS is valid - if (!Object.keys(typeForTS).includes(requestTransferSyntaxUID)) { - console.warn(requestTransferSyntaxUID + 'is unexpected') - } else { - //Fetch type header according to requesting TS - let type = typeForTS[requestTransferSyntaxUID] - if (type === 'application/octet-stream' && !appConfig.omitQuotationForMultipartRequest) { - type = '"application/octet-stream"' - } - acceptHeader.push('type=' + type) - acceptHeader.push('transfer-syntax=' + requestTransferSyntaxUID) - } - - } - const xhrRequestHeaders = { - //Serialize Accept header - Accept: acceptHeader.join('; ') - } + const xhrRequestHeaders = {} if (headers && headers.Authorization) { xhrRequestHeaders.Authorization = headers.Authorization; @@ -94,6 +67,7 @@ export default function initWADOImageLoader( return xhrRequestHeaders; }, + */ errorInterceptor: error => { errorHandler.getHTTPErrorHandler(error); }, @@ -102,28 +76,6 @@ export default function initWADOImageLoader( initWebWorkers(appConfig); } -/* -taken from -https://hg.orthanc-server.com/orthanc-dicomweb/file/tip/Plugin/WadoRsRetrieveFrames.cpp -*/ -const typeForTS = { - "*": "application/octet-stream", - "1.2.840.10008.1.2.1": "application/octet-stream", - "1.2.840.10008.1.2": "application/octet-stream", - "1.2.840.10008.1.2.2": "application/octet-stream", - "1.2.840.10008.1.2.4.70": "image/jpeg", - "1.2.840.10008.1.2.4.50": "image/jpeg", - "1.2.840.10008.1.2.4.51": "image/dicom+jpeg", - "1.2.840.10008.1.2.4.57": "image/jpeg", - "1.2.840.10008.1.2.5": "image/dicom-rle", - "1.2.840.10008.1.2.4.80": "image/jls", - "1.2.840.10008.1.2.4.81": "image/jls", - "1.2.840.10008.1.2.4.90": "image/jp2", - "1.2.840.10008.1.2.4.91": "image/jp2", - "1.2.840.10008.1.2.4.92": "image/jpx", - "1.2.840.10008.1.2.4.93": "image/jpx", -} - export function destroy() { // Note: we don't want to call .terminate on the webWorkerManager since // that resets the config diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index 01943417e7a..e68e9bc500b 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -59,15 +59,92 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { supportsReject, staticWado, singlepart, + requestTransferSyntaxUID, + omitQuotationForMultipartRequest } = dicomWebConfig; const dicomWebConfigCopy = JSON.parse(JSON.stringify(dicomWebConfig)); + const acceptHeader = ['multipart/related'] + + if (requestTransferSyntaxUID) { + + // Request: + // JPEG-LS Lossless (1.2.840.10008.1.2.4.80) if available, otherwise accept + // whatever transfer-syntax the origin server provides. + // For now we use image/jls and image/x-jls because some servers still use the old type + // http://dicom.nema.org/medical/dicom/current/output/html/part18.html + /* + taken from + https://hg.orthanc-server.com/orthanc-dicomweb/file/tip/Plugin/WadoRsRetrieveFrames.cpp + */ + + /* + Hard coding this prevents adding custom types here such as the single part, or adding priority. + Suggest dropping this table. + */ + + const typeForTS = { + "*": "application/octet-stream", + "1.2.840.10008.1.2.1": "application/octet-stream", + "1.2.840.10008.1.2": "application/octet-stream", + "1.2.840.10008.1.2.2": "application/octet-stream", + "1.2.840.10008.1.2.4.70": "image/jpeg", + "1.2.840.10008.1.2.4.50": "image/jpeg", + "1.2.840.10008.1.2.4.51": "image/dicom+jpeg", + "1.2.840.10008.1.2.4.57": "image/jpeg", + "1.2.840.10008.1.2.5": "image/dicom-rle", + "1.2.840.10008.1.2.4.80": "image/jls", + "1.2.840.10008.1.2.4.81": "image/jls", + "1.2.840.10008.1.2.4.90": "image/jp2", + "1.2.840.10008.1.2.4.91": "image/jp2", + "1.2.840.10008.1.2.4.92": "image/jpx", + "1.2.840.10008.1.2.4.93": "image/jpx", + } + + + /* + This should be the default TSUID, + but the actual request should be able to over-ride the requested TSUID. + Why not just allow configuring the default accept header - INCLUDING making it empty? + If it were set as an array of strings, then an empty array wouldn't set it, and would allow the default response to be sent. + Also, it is permissable to request single part types directly, + and it would be nice to allow that to be configured using the same mechanism - + for example: dataSource....defaultImageAccept: [] would not pass any accept header + (this is required to work on all DICOMweb servers) + dataSource...defaultImageAccept: ['multipart/related; type="image/jphc"', 'multipart/related; type="image/jpeg"] + would allow for either HTJ2K or JPEG responses - something that can be very important when fetching existing lossy encoded images. + Then, dataSource...defaultImageAccept: ['image/jpeg', 'image/jp2'] would return JPEG or JPEG2000 responses. + */ + //Check TS is valid + if (!typeForTS[requestTransferSyntaxUID]) { + console.warn(requestTransferSyntaxUID + 'is unexpected') + } else { + //Fetch type header according to requesting TS + let type = typeForTS[requestTransferSyntaxUID] + acceptHeader.push('type=' + type) + acceptHeader.push('transfer-syntax=' + requestTransferSyntaxUID) + } + + } + + if (!omitQuotationForMultipartRequest) { + acceptHeader.forEach((header) => '"' + header + '"') + } + + const authHeaders = userAuthenticationService.getAuthorizationHeader() + + const xhrRequestHeaders = {} + + if (authHeaders && authHeaders.Authorization) { + xhrRequestHeaders.Authorization = authHeaders.Authorization; + } + const qidoConfig = { url: qidoRoot, staticWado, singlepart, - headers: userAuthenticationService.getAuthorizationHeader(), + headers: xhrRequestHeaders, errorInterceptor: errorHandler.getHTTPErrorHandler(), }; @@ -75,7 +152,11 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { url: wadoRoot, staticWado, singlepart, - headers: userAuthenticationService.getAuthorizationHeader(), + headers: { + ...xhrRequestHeaders, + //Serialize Accept header + Accept: acceptHeader.join('; ') + }, errorInterceptor: errorHandler.getHTTPErrorHandler(), }; @@ -108,11 +189,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { query: { studies: { mapParams: mapParams.bind(), - search: async function(origParams) { - const headers = userAuthenticationService.getAuthorizationHeader(); - if (headers) { - qidoDicomWebClient.headers = headers; - } + search: async function (origParams) { const { studyInstanceUid, seriesInstanceUid, ...mappedParams } = mapParams(origParams, { @@ -133,12 +210,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { }, series: { // mapParams: mapParams.bind(), - search: async function(studyInstanceUid) { - const headers = userAuthenticationService.getAuthorizationHeader(); - if (headers) { - qidoDicomWebClient.headers = headers; - } - + search: async function (studyInstanceUid) { const results = await seriesInStudy( qidoDicomWebClient, studyInstanceUid @@ -150,11 +222,6 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { }, instances: { search: (studyInstanceUid, queryParameters) => { - const headers = userAuthenticationService.getAuthorizationHeader(); - if (headers) { - qidoDicomWebClient.headers = headers; - } - qidoSearch.call( undefined, qidoDicomWebClient, @@ -199,10 +266,6 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { sortFunction, madeInClient = false, } = {}) => { - const headers = userAuthenticationService.getAuthorizationHeader(); - if (headers) { - wadoDicomWebClient.headers = headers; - } if (!StudyInstanceUID) { throw new Error( @@ -233,10 +296,6 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { store: { dicom: async (dataset, request) => { - const headers = userAuthenticationService.getAuthorizationHeader(); - if (headers) { - wadoDicomWebClient.headers = headers; - } if (dataset instanceof ArrayBuffer) { const options = { diff --git a/platform/viewer/public/config/default.js b/platform/viewer/public/config/default.js index ff93f31a13e..8abf45f67b7 100644 --- a/platform/viewer/public/config/default.js +++ b/platform/viewer/public/config/default.js @@ -62,6 +62,7 @@ window.config = { staticWado: true, singlepart: 'bulkdata,video,pdf', useBulkDataURI: false, + requestTransferSyntaxUID: '1.2.840.10008.1.2.4.80' }, }, { From 8e2535a3087d70c2a0ea1bf25272197ad57be662 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Mon, 29 May 2023 10:38:27 +0200 Subject: [PATCH 06/16] temp disabled of requested ts --- platform/viewer/public/config/default.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/viewer/public/config/default.js b/platform/viewer/public/config/default.js index 8abf45f67b7..44570e3f15f 100644 --- a/platform/viewer/public/config/default.js +++ b/platform/viewer/public/config/default.js @@ -62,7 +62,7 @@ window.config = { staticWado: true, singlepart: 'bulkdata,video,pdf', useBulkDataURI: false, - requestTransferSyntaxUID: '1.2.840.10008.1.2.4.80' + //requestTransferSyntaxUID: '1.2.840.10008.1.2.4.80' }, }, { From f670678cf0886ba01429a368a1a166ddc5256258 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Mon, 29 May 2023 23:24:06 +0200 Subject: [PATCH 07/16] WIP accept header --- .../cornerstone/src/initWADOImageLoader.js | 14 ---- .../default/src/DicomWebDataSource/index.js | 69 ++----------------- 2 files changed, 6 insertions(+), 77 deletions(-) diff --git a/extensions/cornerstone/src/initWADOImageLoader.js b/extensions/cornerstone/src/initWADOImageLoader.js index 5727b16d302..c21326b5fac 100644 --- a/extensions/cornerstone/src/initWADOImageLoader.js +++ b/extensions/cornerstone/src/initWADOImageLoader.js @@ -54,20 +54,6 @@ export default function initWADOImageLoader( // we should set this flag to false. convertFloatPixelDataToInt: false, }, - /* - TODO (Salim) : Seems to be implemented in createDicomWebApi, check if safe to remove - beforeSend: function (xhr) { - const headers = userAuthenticationService.getAuthorizationHeader(); - - const xhrRequestHeaders = {} - - if (headers) { - Object.assign(xhrRequestHeaders, headers); - } - - return xhrRequestHeaders; - }, - */ errorInterceptor: error => { errorHandler.getHTTPErrorHandler(error); }, diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index ca3482e7d50..5c8a18880f3 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -60,73 +60,16 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { supportsReject, staticWado, singlepart, - requestTransferSyntaxUID, - omitQuotationForMultipartRequest + omitQuotationForMultipartRequest, + acceptHeader } = dicomWebConfig; const dicomWebConfigCopy = JSON.parse(JSON.stringify(dicomWebConfig)); - const acceptHeader = ['multipart/related'] - - if (requestTransferSyntaxUID) { - - // Request: - // JPEG-LS Lossless (1.2.840.10008.1.2.4.80) if available, otherwise accept - // whatever transfer-syntax the origin server provides. - // For now we use image/jls and image/x-jls because some servers still use the old type - // http://dicom.nema.org/medical/dicom/current/output/html/part18.html - /* - taken from - https://hg.orthanc-server.com/orthanc-dicomweb/file/tip/Plugin/WadoRsRetrieveFrames.cpp - */ - - /* - Hard coding this prevents adding custom types here such as the single part, or adding priority. - Suggest dropping this table. - */ - - const typeForTS = { - "*": "application/octet-stream", - "1.2.840.10008.1.2.1": "application/octet-stream", - "1.2.840.10008.1.2": "application/octet-stream", - "1.2.840.10008.1.2.2": "application/octet-stream", - "1.2.840.10008.1.2.4.70": "image/jpeg", - "1.2.840.10008.1.2.4.50": "image/jpeg", - "1.2.840.10008.1.2.4.51": "image/dicom+jpeg", - "1.2.840.10008.1.2.4.57": "image/jpeg", - "1.2.840.10008.1.2.5": "image/dicom-rle", - "1.2.840.10008.1.2.4.80": "image/jls", - "1.2.840.10008.1.2.4.81": "image/jls", - "1.2.840.10008.1.2.4.90": "image/jp2", - "1.2.840.10008.1.2.4.91": "image/jp2", - "1.2.840.10008.1.2.4.92": "image/jpx", - "1.2.840.10008.1.2.4.93": "image/jpx", - } - - - /* - This should be the default TSUID, - but the actual request should be able to over-ride the requested TSUID. - Why not just allow configuring the default accept header - INCLUDING making it empty? - If it were set as an array of strings, then an empty array wouldn't set it, and would allow the default response to be sent. - Also, it is permissable to request single part types directly, - and it would be nice to allow that to be configured using the same mechanism - - for example: dataSource....defaultImageAccept: [] would not pass any accept header - (this is required to work on all DICOMweb servers) - dataSource...defaultImageAccept: ['multipart/related; type="image/jphc"', 'multipart/related; type="image/jpeg"] - would allow for either HTJ2K or JPEG responses - something that can be very important when fetching existing lossy encoded images. - Then, dataSource...defaultImageAccept: ['image/jpeg', 'image/jp2'] would return JPEG or JPEG2000 responses. - */ - //Check TS is valid - if (!typeForTS[requestTransferSyntaxUID]) { - console.warn(requestTransferSyntaxUID + 'is unexpected') - } else { - //Fetch type header according to requesting TS - let type = typeForTS[requestTransferSyntaxUID] - acceptHeader.push('type=' + type) - acceptHeader.push('transfer-syntax=' + requestTransferSyntaxUID) - } - + //If accept header is not specified, set as multipart + let formattedAcceptHeader = acceptHeader ?? [] + if (acceptHeader.length === 0) { + formattedAcceptHeader = ['multipart/related'] } if (!omitQuotationForMultipartRequest) { From de60586b71a577ddec145d62d01a26cac7fe31b3 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Mon, 29 May 2023 23:39:06 +0200 Subject: [PATCH 08/16] fixes --- extensions/default/src/DicomWebDataSource/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index 5c8a18880f3..d1e5ef47270 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -68,12 +68,12 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { //If accept header is not specified, set as multipart let formattedAcceptHeader = acceptHeader ?? [] - if (acceptHeader.length === 0) { + if (formattedAcceptHeader.length === 0) { formattedAcceptHeader = ['multipart/related'] } if (!omitQuotationForMultipartRequest) { - acceptHeader.forEach((header) => '"' + header + '"') + formattedAcceptHeader.forEach((header) => '"' + header + '"') } const authHeaders = userAuthenticationService.getAuthorizationHeader() @@ -99,7 +99,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { headers: { ...xhrRequestHeaders, //Serialize Accept header - Accept: acceptHeader.join('; ') + Accept: formattedAcceptHeader.join('; ') }, errorInterceptor: errorHandler.getHTTPErrorHandler(), }; From c3654b7ddf1fab5d7c44baa8f295b7d8faa22d45 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Thu, 1 Jun 2023 23:18:54 +0200 Subject: [PATCH 09/16] rework TS --- extensions/cornerstone/src/init.tsx | 2 +- .../cornerstone/src/initWADOImageLoader.js | 57 ++++++++++++++++++- .../default/src/DicomWebDataSource/index.js | 42 ++++++++++---- .../docs/configuration/configurationFiles.md | 2 +- 4 files changed, 89 insertions(+), 14 deletions(-) diff --git a/extensions/cornerstone/src/init.tsx b/extensions/cornerstone/src/init.tsx index 4a07f4e635a..98f905ab900 100644 --- a/extensions/cornerstone/src/init.tsx +++ b/extensions/cornerstone/src/init.tsx @@ -166,7 +166,7 @@ export default async function init({ prefetch: appConfig?.maxNumRequests?.prefetch || 10, }; - initWADOImageLoader(userAuthenticationService, appConfig); + initWADOImageLoader(userAuthenticationService, appConfig, extensionManager); /* Measurement Service */ this.measurementServiceSource = connectToolsToMeasurementService( diff --git a/extensions/cornerstone/src/initWADOImageLoader.js b/extensions/cornerstone/src/initWADOImageLoader.js index c21326b5fac..f5ac1a8ab5e 100644 --- a/extensions/cornerstone/src/initWADOImageLoader.js +++ b/extensions/cornerstone/src/initWADOImageLoader.js @@ -35,7 +35,8 @@ function initWebWorkers(appConfig) { export default function initWADOImageLoader( userAuthenticationService, - appConfig + appConfig, + extensionManager ) { dicomImageLoader.external.cornerstone = cornerstone; dicomImageLoader.external.dicomParser = dicomParser; @@ -54,6 +55,32 @@ export default function initWADOImageLoader( // we should set this flag to false. convertFloatPixelDataToInt: false, }, + beforeSend: function (xhr) { + const headers = userAuthenticationService.getAuthorizationHeader(); + const sourceConfig = extensionManager.getActiveDataSource()[0].getConfig() + const acceptHeader = generateAcceptHeader(sourceConfig.acceptHeader, sourceConfig.omitQuotationForMultipartRequest) + + // Request: + // JPEG-LS Lossless (1.2.840.10008.1.2.4.80) if available, otherwise accept + // whatever transfer-syntax the origin server provides. + // For now we use image/jls and image/x-jls because some servers still use the old type + // http://dicom.nema.org/medical/dicom/current/output/html/part18.html + const xhrRequestHeaders = { + Accept: acceptHeader + /* + appConfig.omitQuotationForMultipartRequest + ? 'multipart/related; type=application/octet-stream' + : 'multipart/related; type="application/octet-stream"', + // 'multipart/related; type="image/x-jls", multipart/related; type="image/jls"; transfer-syntax="1.2.840.10008.1.2.4.80", multipart/related; type="image/x-jls", multipart/related; type="application/octet-stream"; transfer-syntax=*', + */ + }; + + if (headers) { + Object.assign(xhrRequestHeaders, headers); + } + + return xhrRequestHeaders; + }, errorInterceptor: error => { errorHandler.getHTTPErrorHandler(error); }, @@ -62,6 +89,34 @@ export default function initWADOImageLoader( initWebWorkers(appConfig); } +const generateAcceptHeader = (configAcceptHeader = [], omitQuotationForMultipartRequest = false) => { + let acceptHeader = [] + if (configAcceptHeader.length === 0) { + acceptHeader.push('multipart/related; type=application/octet-stream') + } else { + acceptHeader = configAcceptHeader + } + + if (!omitQuotationForMultipartRequest) { + //need to add quotation for each mime type of each accept entry + acceptHeader = acceptHeader.map(accept => { + let mimes = accept.split("; ") + let newMimes = mimes.map(mime => { + if (mime.startsWith('type=')) { + const quotedParam = 'type=' + '"' + mime.substring(5, mime.length) + '"' + return quotedParam + } else { + return mime + } + }) + return newMimes.join(';') + }) + } + + return acceptHeader + +} + export function destroy() { // Note: we don't want to call .terminate on the webWorkerManager since // that resets the config diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index d1e5ef47270..5c31ec0420d 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -66,15 +66,8 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { const dicomWebConfigCopy = JSON.parse(JSON.stringify(dicomWebConfig)); - //If accept header is not specified, set as multipart - let formattedAcceptHeader = acceptHeader ?? [] - if (formattedAcceptHeader.length === 0) { - formattedAcceptHeader = ['multipart/related'] - } - - if (!omitQuotationForMultipartRequest) { - formattedAcceptHeader.forEach((header) => '"' + header + '"') - } + //Generate accept header depending on config params + let formattedAcceptHeader = generateAcceptHeader(acceptHeader, omitQuotationForMultipartRequest) const authHeaders = userAuthenticationService.getAuthorizationHeader() @@ -98,8 +91,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { singlepart, headers: { ...xhrRequestHeaders, - //Serialize Accept header - Accept: formattedAcceptHeader.join('; ') + Accept: formattedAcceptHeader }, errorInterceptor: errorHandler.getHTTPErrorHandler(), }; @@ -526,4 +518,32 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { return IWebApiDataSource.create(implementation); } +const generateAcceptHeader = (configAcceptHeader = [], omitQuotationForMultipartRequest = false) => { + let acceptHeader = [] + if (configAcceptHeader.length === 0) { + acceptHeader.push('multipart/related; type=application/octet-stream') + } else { + acceptHeader = configAcceptHeader + } + + if (!omitQuotationForMultipartRequest) { + //need to add quotation for each mime type of each accept entry + acceptHeader = acceptHeader.map(accept => { + let mimes = accept.split("; ") + let newMimes = mimes.map(mime => { + if (mime.startsWith('type=')) { + const quotedParam = 'type=' + '"' + mime.substring(5, mime.length) + '"' + return quotedParam + } else { + return mime + } + }) + return newMimes.join(';') + }) + } + + return acceptHeader + +} + export { createDicomWebApi }; diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index 5a6f16e5573..21239030cda 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -112,7 +112,7 @@ Here are a list of some options available: - `maxNumberOfWebWorkers`: The maximum number of web workers to use for decoding. Defaults to minimum of `navigator.hardwareConcurrency` and what is specified by `maxNumberOfWebWorkers`. Some windows machines require smaller values. -- `requestTransferSyntaxUID` : Request for a specific TS to the DICOM archive ex : 1.2.840.10008.1.2.4.80 +- `acceptHeader` : accept header to request specific dicom transfer syntax ex : [ 'multipart/related; type=image/jls; q=1', 'multipart/related; type=application/octet-stream; q=0.1' ] - `omitQuotationForMultipartRequest`: Some servers (e.g., .NET) require the `multipart/related` request to be sent without quotation marks. Defaults to `false`. If your server doesn't require this, then setting this flag to `true` might improve performance (by removing the need for preflight requests). Also note that if auth headers are used, a preflight request is required. - `maxNumRequests`: The maximum number of requests to allow in parallel. It is an object with keys of `interaction`, `thumbnail`, and `prefetch`. You can specify a specific number for each type. From 62dd2e78bdbe4155dbb70cbf2fd3316ae0ca49c5 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Thu, 1 Jun 2023 23:32:16 +0200 Subject: [PATCH 10/16] null safe --- extensions/cornerstone/src/initWADOImageLoader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/cornerstone/src/initWADOImageLoader.js b/extensions/cornerstone/src/initWADOImageLoader.js index f5ac1a8ab5e..193209b0378 100644 --- a/extensions/cornerstone/src/initWADOImageLoader.js +++ b/extensions/cornerstone/src/initWADOImageLoader.js @@ -57,7 +57,7 @@ export default function initWADOImageLoader( }, beforeSend: function (xhr) { const headers = userAuthenticationService.getAuthorizationHeader(); - const sourceConfig = extensionManager.getActiveDataSource()[0].getConfig() + const sourceConfig = extensionManager.getActiveDataSource()?.[0].getConfig() ?? {} const acceptHeader = generateAcceptHeader(sourceConfig.acceptHeader, sourceConfig.omitQuotationForMultipartRequest) // Request: From e4937e7473e34b61c9836b047add2323489e33df Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Thu, 1 Jun 2023 23:35:13 +0200 Subject: [PATCH 11/16] update comments --- extensions/cornerstone/src/initWADOImageLoader.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/extensions/cornerstone/src/initWADOImageLoader.js b/extensions/cornerstone/src/initWADOImageLoader.js index 193209b0378..89f5e2c037b 100644 --- a/extensions/cornerstone/src/initWADOImageLoader.js +++ b/extensions/cornerstone/src/initWADOImageLoader.js @@ -56,23 +56,13 @@ export default function initWADOImageLoader( convertFloatPixelDataToInt: false, }, beforeSend: function (xhr) { - const headers = userAuthenticationService.getAuthorizationHeader(); + //TODO should be removed in the future and request emitted by DicomWebDataSource const sourceConfig = extensionManager.getActiveDataSource()?.[0].getConfig() ?? {} + const headers = userAuthenticationService.getAuthorizationHeader(); const acceptHeader = generateAcceptHeader(sourceConfig.acceptHeader, sourceConfig.omitQuotationForMultipartRequest) - // Request: - // JPEG-LS Lossless (1.2.840.10008.1.2.4.80) if available, otherwise accept - // whatever transfer-syntax the origin server provides. - // For now we use image/jls and image/x-jls because some servers still use the old type - // http://dicom.nema.org/medical/dicom/current/output/html/part18.html const xhrRequestHeaders = { Accept: acceptHeader - /* - appConfig.omitQuotationForMultipartRequest - ? 'multipart/related; type=application/octet-stream' - : 'multipart/related; type="application/octet-stream"', - // 'multipart/related; type="image/x-jls", multipart/related; type="image/jls"; transfer-syntax="1.2.840.10008.1.2.4.80", multipart/related; type="image/x-jls", multipart/related; type="application/octet-stream"; transfer-syntax=*', - */ }; if (headers) { From 50d264087628f158b06d974bbacc368f51578613 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Mon, 5 Jun 2023 22:32:29 +0200 Subject: [PATCH 12/16] accept both accept header and transfer syntax uid --- .../cornerstone/src/initWADOImageLoader.js | 43 ++++---------- .../default/src/DicomWebDataSource/index.js | 50 ++++------------ .../core/src/utils/generateAcceptHeader.ts | 58 +++++++++++++++++++ platform/core/src/utils/index.js | 3 + .../docs/configuration/configurationFiles.md | 1 + 5 files changed, 84 insertions(+), 71 deletions(-) create mode 100644 platform/core/src/utils/generateAcceptHeader.ts diff --git a/extensions/cornerstone/src/initWADOImageLoader.js b/extensions/cornerstone/src/initWADOImageLoader.js index 89f5e2c037b..8b2aec1cc2c 100644 --- a/extensions/cornerstone/src/initWADOImageLoader.js +++ b/extensions/cornerstone/src/initWADOImageLoader.js @@ -5,7 +5,7 @@ import dicomImageLoader, { webWorkerManager, } from '@cornerstonejs/dicom-image-loader'; import dicomParser from 'dicom-parser'; -import { errorHandler } from '@ohif/core'; +import { errorHandler, utils } from '@ohif/core'; const { registerVolumeLoader } = volumeLoader; @@ -55,14 +55,19 @@ export default function initWADOImageLoader( // we should set this flag to false. convertFloatPixelDataToInt: false, }, - beforeSend: function (xhr) { + beforeSend: function(xhr) { //TODO should be removed in the future and request emitted by DicomWebDataSource - const sourceConfig = extensionManager.getActiveDataSource()?.[0].getConfig() ?? {} + const sourceConfig = + extensionManager.getActiveDataSource()?.[0].getConfig() ?? {}; const headers = userAuthenticationService.getAuthorizationHeader(); - const acceptHeader = generateAcceptHeader(sourceConfig.acceptHeader, sourceConfig.omitQuotationForMultipartRequest) + const acceptHeader = utils.generateAcceptHeader( + sourceConfig.acceptHeader, + sourceConfig.requestTransferSyntaxUID, + sourceConfig.omitQuotationForMultipartRequest + ); const xhrRequestHeaders = { - Accept: acceptHeader + Accept: acceptHeader, }; if (headers) { @@ -79,34 +84,6 @@ export default function initWADOImageLoader( initWebWorkers(appConfig); } -const generateAcceptHeader = (configAcceptHeader = [], omitQuotationForMultipartRequest = false) => { - let acceptHeader = [] - if (configAcceptHeader.length === 0) { - acceptHeader.push('multipart/related; type=application/octet-stream') - } else { - acceptHeader = configAcceptHeader - } - - if (!omitQuotationForMultipartRequest) { - //need to add quotation for each mime type of each accept entry - acceptHeader = acceptHeader.map(accept => { - let mimes = accept.split("; ") - let newMimes = mimes.map(mime => { - if (mime.startsWith('type=')) { - const quotedParam = 'type=' + '"' + mime.substring(5, mime.length) + '"' - return quotedParam - } else { - return mime - } - }) - return newMimes.join(';') - }) - } - - return acceptHeader - -} - export function destroy() { // Note: we don't want to call .terminate on the webWorkerManager since // that resets the config diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index 5c31ec0420d..c0f05b4d2bc 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -61,17 +61,22 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { staticWado, singlepart, omitQuotationForMultipartRequest, - acceptHeader + acceptHeader, + requestTransferSyntaxUID, } = dicomWebConfig; const dicomWebConfigCopy = JSON.parse(JSON.stringify(dicomWebConfig)); //Generate accept header depending on config params - let formattedAcceptHeader = generateAcceptHeader(acceptHeader, omitQuotationForMultipartRequest) + let formattedAcceptHeader = utils.generateAcceptHeader( + acceptHeader, + requestTransferSyntaxUID, + omitQuotationForMultipartRequest + ); - const authHeaders = userAuthenticationService.getAuthorizationHeader() + const authHeaders = userAuthenticationService.getAuthorizationHeader(); - const xhrRequestHeaders = {} + const xhrRequestHeaders = {}; if (authHeaders && authHeaders.Authorization) { xhrRequestHeaders.Authorization = authHeaders.Authorization; @@ -91,7 +96,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { singlepart, headers: { ...xhrRequestHeaders, - Accept: formattedAcceptHeader + Accept: formattedAcceptHeader, }, errorInterceptor: errorHandler.getHTTPErrorHandler(), }; @@ -125,8 +130,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { query: { studies: { mapParams: mapParams.bind(), - search: async function (origParams) { - + search: async function(origParams) { const { studyInstanceUid, seriesInstanceUid, ...mappedParams } = mapParams(origParams, { supportsFuzzyMatching, @@ -146,7 +150,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { }, series: { // mapParams: mapParams.bind(), - search: async function (studyInstanceUid) { + search: async function(studyInstanceUid) { const results = await seriesInStudy( qidoDicomWebClient, studyInstanceUid @@ -202,7 +206,6 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { sortFunction, madeInClient = false, } = {}) => { - if (!StudyInstanceUID) { throw new Error( 'Unable to query for SeriesMetadata without StudyInstanceUID' @@ -232,7 +235,6 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { store: { dicom: async (dataset, request) => { - if (dataset instanceof ArrayBuffer) { const options = { datasets: [dataset], @@ -518,32 +520,4 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { return IWebApiDataSource.create(implementation); } -const generateAcceptHeader = (configAcceptHeader = [], omitQuotationForMultipartRequest = false) => { - let acceptHeader = [] - if (configAcceptHeader.length === 0) { - acceptHeader.push('multipart/related; type=application/octet-stream') - } else { - acceptHeader = configAcceptHeader - } - - if (!omitQuotationForMultipartRequest) { - //need to add quotation for each mime type of each accept entry - acceptHeader = acceptHeader.map(accept => { - let mimes = accept.split("; ") - let newMimes = mimes.map(mime => { - if (mime.startsWith('type=')) { - const quotedParam = 'type=' + '"' + mime.substring(5, mime.length) + '"' - return quotedParam - } else { - return mime - } - }) - return newMimes.join(';') - }) - } - - return acceptHeader - -} - export { createDicomWebApi }; diff --git a/platform/core/src/utils/generateAcceptHeader.ts b/platform/core/src/utils/generateAcceptHeader.ts new file mode 100644 index 00000000000..7de0607261f --- /dev/null +++ b/platform/core/src/utils/generateAcceptHeader.ts @@ -0,0 +1,58 @@ +const generateAcceptHeader = ( + configAcceptHeader = [], + requestTransferSyntaxUID = null, + omitQuotationForMultipartRequest = false +): string[] => { + //if acceptedHeader is passed by config use it as it. + if (configAcceptHeader.length > 0) { + return configAcceptHeader; + } + + let acceptHeader = ['multipart/related']; + if (requestTransferSyntaxUID && typeForTS[requestTransferSyntaxUID]) { + const type = typeForTS[requestTransferSyntaxUID]; + acceptHeader.push('type=' + type); + acceptHeader.push('transfer-syntax=' + requestTransferSyntaxUID); + } else { + acceptHeader.push('type=application/octet-stream'); + } + + if (!omitQuotationForMultipartRequest) { + //need to add quotation for each mime type of each accept entry + acceptHeader = acceptHeader.map(mime => { + if (mime.startsWith('type=')) { + const quotedParam = 'type="' + mime.substring(5, mime.length) + '"'; + return quotedParam; + } + if (mime.startsWith('transfer-syntax=')) { + const quotedParam = + 'transfer-syntax="' + mime.substring(16, mime.length) + '"'; + return quotedParam; + } else { + return mime; + } + }); + } + + return [acceptHeader.join('; ')]; +}; + +const typeForTS = { + '*': 'application/octet-stream', + '1.2.840.10008.1.2.1': 'application/octet-stream', + '1.2.840.10008.1.2': 'application/octet-stream', + '1.2.840.10008.1.2.2': 'application/octet-stream', + '1.2.840.10008.1.2.4.70': 'image/jpeg', + '1.2.840.10008.1.2.4.50': 'image/jpeg', + '1.2.840.10008.1.2.4.51': 'image/dicom+jpeg', + '1.2.840.10008.1.2.4.57': 'image/jpeg', + '1.2.840.10008.1.2.5': 'image/dicom-rle', + '1.2.840.10008.1.2.4.80': 'image/jls', + '1.2.840.10008.1.2.4.81': 'image/jls', + '1.2.840.10008.1.2.4.90': 'image/jp2', + '1.2.840.10008.1.2.4.91': 'image/jp2', + '1.2.840.10008.1.2.4.92': 'image/jpx', + '1.2.840.10008.1.2.4.93': 'image/jpx', +}; + +export default generateAcceptHeader; diff --git a/platform/core/src/utils/index.js b/platform/core/src/utils/index.js index 06e7537f3b1..4b801d05427 100644 --- a/platform/core/src/utils/index.js +++ b/platform/core/src/utils/index.js @@ -13,6 +13,7 @@ import Queue from './Queue'; import isDicomUid from './isDicomUid'; import formatDate from './formatDate'; import formatPN from './formatPN'; +import generateAcceptHeader from './generateAcceptHeader'; import resolveObjectPath from './resolveObjectPath'; import hierarchicalListUtils from './hierarchicalListUtils'; import progressTrackingUtils from './progressTrackingUtils'; @@ -74,6 +75,7 @@ const utils = { subscribeToNextViewportGridChange, splitComma, getSplitParam, + generateAcceptHeader, }; export { @@ -105,6 +107,7 @@ export { downloadCSVReport, splitComma, getSplitParam, + generateAcceptHeader, }; export default utils; diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index 21239030cda..5ce871583ab 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -113,6 +113,7 @@ Here are a list of some options available: decoding. Defaults to minimum of `navigator.hardwareConcurrency` and what is specified by `maxNumberOfWebWorkers`. Some windows machines require smaller values. - `acceptHeader` : accept header to request specific dicom transfer syntax ex : [ 'multipart/related; type=image/jls; q=1', 'multipart/related; type=application/octet-stream; q=0.1' ] +- `requestTransferSyntaxUID` : Request a specific Tansfer syntax from dicom web server ex: 1.2.840.10008.1.2.4.80 (applyed only if acceptHeader is not set) - `omitQuotationForMultipartRequest`: Some servers (e.g., .NET) require the `multipart/related` request to be sent without quotation marks. Defaults to `false`. If your server doesn't require this, then setting this flag to `true` might improve performance (by removing the need for preflight requests). Also note that if auth headers are used, a preflight request is required. - `maxNumRequests`: The maximum number of requests to allow in parallel. It is an object with keys of `interaction`, `thumbnail`, and `prefetch`. You can specify a specific number for each type. From 93f30f06c283aa193f203813f040c18b21d3de23 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Tue, 6 Jun 2023 16:57:19 +0200 Subject: [PATCH 13/16] Fix tests --- platform/core/src/utils/index.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/core/src/utils/index.test.js b/platform/core/src/utils/index.test.js index b3c3e1e26e8..5620a0fa2fd 100644 --- a/platform/core/src/utils/index.test.js +++ b/platform/core/src/utils/index.test.js @@ -24,6 +24,7 @@ describe('Top level exports', () => { 'b64toBlob', 'formatDate', 'formatPN', + 'generateAcceptHeader', 'isEqualWithin', //'loadAndCacheDerivedDisplaySets', 'isDisplaySetReconstructable', From fa73a458bd0e053d26818c32f4a4de92c86f7499 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Tue, 20 Jun 2023 09:34:20 +0000 Subject: [PATCH 14/16] WIP (not tested yet) --- .../default/src/DicomWebDataSource/index.js | 51 +++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index c0f05b4d2bc..a75781b6cc5 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -67,26 +67,35 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { const dicomWebConfigCopy = JSON.parse(JSON.stringify(dicomWebConfig)); - //Generate accept header depending on config params - let formattedAcceptHeader = utils.generateAcceptHeader( - acceptHeader, - requestTransferSyntaxUID, - omitQuotationForMultipartRequest - ); - - const authHeaders = userAuthenticationService.getAuthorizationHeader(); - - const xhrRequestHeaders = {}; + const getAuthrorizationHeader = () => { + const xhrRequestHeaders = {}; + const authHeaders = userAuthenticationService.getAuthorizationHeader(); + if (authHeaders && authHeaders.Authorization) { + xhrRequestHeaders.Authorization = authHeaders.Authorization; + } + return xhrRequestHeaders; + }; - if (authHeaders && authHeaders.Authorization) { - xhrRequestHeaders.Authorization = authHeaders.Authorization; - } + const generateWadoHeader = () => { + let baseHeader = getAuthrorizationHeader(); + //Generate accept header depending on config params + let formattedAcceptHeader = utils.generateAcceptHeader( + acceptHeader, + requestTransferSyntaxUID, + omitQuotationForMultipartRequest + ); + + return { + ...baseHeader, + Accept: formattedAcceptHeader, + }; + }; const qidoConfig = { url: qidoRoot, staticWado, singlepart, - headers: xhrRequestHeaders, + headers: getAuthrorizationHeader(), errorInterceptor: errorHandler.getHTTPErrorHandler(), }; @@ -94,10 +103,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { url: wadoRoot, staticWado, singlepart, - headers: { - ...xhrRequestHeaders, - Accept: formattedAcceptHeader, - }, + headers: generateWadoHeader(), errorInterceptor: errorHandler.getHTTPErrorHandler(), }; @@ -131,6 +137,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { studies: { mapParams: mapParams.bind(), search: async function(origParams) { + qidoDicomWebClient.headers = getAuthrorizationHeader(); const { studyInstanceUid, seriesInstanceUid, ...mappedParams } = mapParams(origParams, { supportsFuzzyMatching, @@ -151,6 +158,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { series: { // mapParams: mapParams.bind(), search: async function(studyInstanceUid) { + qidoDicomWebClient.headers = getAuthrorizationHeader(); const results = await seriesInStudy( qidoDicomWebClient, studyInstanceUid @@ -162,6 +170,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { }, instances: { search: (studyInstanceUid, queryParameters) => { + qidoDicomWebClient.headers = getAuthrorizationHeader(); qidoSearch.call( undefined, qidoDicomWebClient, @@ -188,6 +197,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { return getDirectURL({ wadoRoot, singlepart }, params); }, bulkDataURI: async ({ StudyInstanceUID, BulkDataURI }) => { + qidoDicomWebClient.headers = getAuthrorizationHeader(); const options = { multipart: false, BulkDataURI, @@ -235,12 +245,12 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { store: { dicom: async (dataset, request) => { + wadoDicomWebClient.headers = generateWadoHeader(); if (dataset instanceof ArrayBuffer) { const options = { datasets: [dataset], request, }; - await wadoDicomWebClient.storeInstances(options); } else { const meta = { @@ -278,7 +288,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { madeInClient ) => { const enableStudyLazyLoad = false; - + wadoDicomWebClient.headers = generateWadoHeader(); // data is all SOPInstanceUIDs const data = await retrieveStudyMetadata( wadoDicomWebClient, @@ -349,6 +359,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { madeInClient = false ) => { const enableStudyLazyLoad = true; + wadoDicomWebClient.headers = generateWadoHeader(); // Get Series const { preLoadData: seriesSummaryMetadata, From 1a91f210ab83789af040e43555143bd8b5de191d Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Tue, 20 Jun 2023 22:18:14 +0200 Subject: [PATCH 15/16] rename --- extensions/default/src/DicomWebDataSource/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index a75781b6cc5..cc4fe162e0e 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -77,7 +77,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { }; const generateWadoHeader = () => { - let baseHeader = getAuthrorizationHeader(); + let authorizationHeader = getAuthrorizationHeader(); //Generate accept header depending on config params let formattedAcceptHeader = utils.generateAcceptHeader( acceptHeader, @@ -86,7 +86,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { ); return { - ...baseHeader, + ...authorizationHeader, Accept: formattedAcceptHeader, }; }; From ca3a0b56f7a4c5bfddc034cee517bb5d543a7645 Mon Sep 17 00:00:00 2001 From: Salim Kanoun Date: Thu, 22 Jun 2023 21:26:26 +0200 Subject: [PATCH 16/16] update old configs --- platform/app/public/config/aws.js | 3 ++- platform/app/public/config/default.js | 3 +-- platform/app/public/config/demo.js | 2 +- platform/app/public/config/dicomweb-server.js | 2 +- platform/app/public/config/dicomweb_relative.js | 2 +- platform/app/public/config/docker_nginx-orthanc.js | 2 +- .../app/public/config/docker_openresty-orthanc-keycloak.js | 2 +- platform/app/public/config/docker_openresty-orthanc.js | 3 ++- platform/app/public/config/e2e.js | 2 +- platform/app/public/config/google.js | 2 +- platform/app/public/config/idc.js | 1 - platform/app/public/config/local_dcm4chee.js | 2 +- platform/app/public/config/local_static.js | 2 +- platform/app/public/config/multiple.js | 2 +- platform/app/public/config/netlify.js | 2 +- platform/app/public/config/public_dicomweb.js | 2 +- platform/docs/docs/configuration/configurationFiles.md | 2 ++ 17 files changed, 19 insertions(+), 17 deletions(-) diff --git a/platform/app/public/config/aws.js b/platform/app/public/config/aws.js index 35ffbde5ca6..cfd097d8aac 100644 --- a/platform/app/public/config/aws.js +++ b/platform/app/public/config/aws.js @@ -4,7 +4,7 @@ window.config = { modes: [], showStudyList: true, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, + showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -30,6 +30,7 @@ window.config = { supportsFuzzyMatching: false, supportsWildcard: false, staticWado: true, + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/default.js b/platform/app/public/config/default.js index 8ff91875b8d..11de5018ae6 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -11,7 +11,6 @@ window.config = { // some windows systems have issues with more than 3 web workers maxNumberOfWebWorkers: 3, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -51,7 +50,6 @@ window.config = { wadoUriRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb', qidoRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb', wadoRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb', - qidoSupportsIncludeField: false, supportsReject: false, imageRendering: 'wadors', @@ -68,6 +66,7 @@ window.config = { enabled: true, relativeResolution: 'studies', }, + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/demo.js b/platform/app/public/config/demo.js index b4d43b86195..5c10b63d8db 100644 --- a/platform/app/public/config/demo.js +++ b/platform/app/public/config/demo.js @@ -4,7 +4,6 @@ window.config = { extensions: [], showStudyList: true, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, strictZSpacingForVolumeViewport: true, showCPUFallbackMessage: true, @@ -25,6 +24,7 @@ window.config = { bulkDataURI: { enabled: false, }, + omitQuotationForMultipartRequest: true, }, }, ], diff --git a/platform/app/public/config/dicomweb-server.js b/platform/app/public/config/dicomweb-server.js index 4db99041765..0716e3da150 100644 --- a/platform/app/public/config/dicomweb-server.js +++ b/platform/app/public/config/dicomweb-server.js @@ -4,7 +4,6 @@ window.config = { modes: [], showStudyList: true, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -28,6 +27,7 @@ window.config = { enableStudyLazyLoad: true, supportsFuzzyMatching: false, supportsWildcard: false, + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/dicomweb_relative.js b/platform/app/public/config/dicomweb_relative.js index af024abd70f..ce4d1724d0a 100644 --- a/platform/app/public/config/dicomweb_relative.js +++ b/platform/app/public/config/dicomweb_relative.js @@ -5,7 +5,6 @@ window.config = { showStudyList: true, maxNumberOfWebWorkers: 3, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -31,6 +30,7 @@ window.config = { supportsWildcard: true, staticWado: true, singlepart: 'bulkdata,video,pdf', + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/docker_nginx-orthanc.js b/platform/app/public/config/docker_nginx-orthanc.js index 60d7f083ce4..a9fc8e4d747 100644 --- a/platform/app/public/config/docker_nginx-orthanc.js +++ b/platform/app/public/config/docker_nginx-orthanc.js @@ -4,7 +4,6 @@ window.config = { extensions: [], modes: [], // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -23,6 +22,7 @@ window.config = { qidoSupportsIncludeField: false, imageRendering: 'wadors', thumbnailRendering: 'wadors', + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/docker_openresty-orthanc-keycloak.js b/platform/app/public/config/docker_openresty-orthanc-keycloak.js index 07709a7ebef..31786e2626a 100644 --- a/platform/app/public/config/docker_openresty-orthanc-keycloak.js +++ b/platform/app/public/config/docker_openresty-orthanc-keycloak.js @@ -2,7 +2,6 @@ window.config = { routerBasename: '/', showStudyList: true, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -18,6 +17,7 @@ window.config = { qidoSupportsIncludeField: false, imageRendering: 'wadors', thumbnailRendering: 'wadors', + omitQuotationForMultipartRequest: true, // REQUIRED TAG: // TODO: Remove tag after https://github.com/OHIF/ohif-core/pull/19 is merged and we bump version // requestOptions: { diff --git a/platform/app/public/config/docker_openresty-orthanc.js b/platform/app/public/config/docker_openresty-orthanc.js index 33e41387792..08d61f00e15 100644 --- a/platform/app/public/config/docker_openresty-orthanc.js +++ b/platform/app/public/config/docker_openresty-orthanc.js @@ -4,7 +4,7 @@ window.config = { extensions: [], modes: [], // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, + showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -23,6 +23,7 @@ window.config = { qidoSupportsIncludeField: false, imageRendering: 'wadors', thumbnailRendering: 'wadors', + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/e2e.js b/platform/app/public/config/e2e.js index 47903374cb2..88d64b439af 100644 --- a/platform/app/public/config/e2e.js +++ b/platform/app/public/config/e2e.js @@ -4,7 +4,6 @@ window.config = { modes: ['@ohif/mode-test'], showStudyList: true, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, maxNumberOfWebWorkers: 3, showWarningMessageForCrossOrigin: false, showCPUFallbackMessage: false, @@ -31,6 +30,7 @@ window.config = { supportsFuzzyMatching: false, supportsWildcard: true, singlepart: 'video,thumbnail,pdf', + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/google.js b/platform/app/public/config/google.js index 847e08ebbd0..86ec59daac6 100644 --- a/platform/app/public/config/google.js +++ b/platform/app/public/config/google.js @@ -6,7 +6,6 @@ window.config = { }, enableGoogleCloudAdapter: false, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -55,6 +54,7 @@ window.config = { supportsFuzzyMatching: true, supportsWildcard: false, dicomUploadEnabled: true, + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/idc.js b/platform/app/public/config/idc.js index 6056962bd75..2760b60df01 100644 --- a/platform/app/public/config/idc.js +++ b/platform/app/public/config/idc.js @@ -2,7 +2,6 @@ window.config = { routerBasename: '/', enableGoogleCloudAdapter: true, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, diff --git a/platform/app/public/config/local_dcm4chee.js b/platform/app/public/config/local_dcm4chee.js index 763604ffdfd..45145000e6c 100644 --- a/platform/app/public/config/local_dcm4chee.js +++ b/platform/app/public/config/local_dcm4chee.js @@ -8,7 +8,6 @@ window.config = { extensions: [], modes: [], // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -39,6 +38,7 @@ window.config = { bulkDataURI: { enabled: true, }, + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/local_static.js b/platform/app/public/config/local_static.js index 6774e1b9a08..7b52732d212 100644 --- a/platform/app/public/config/local_static.js +++ b/platform/app/public/config/local_static.js @@ -8,7 +8,6 @@ window.config = { showStudyList: true, maxNumberOfWebWorkers: 4, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -33,6 +32,7 @@ window.config = { supportsWildcard: true, staticWado: true, singlepart: 'bulkdata,video,pdf', + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/multiple.js b/platform/app/public/config/multiple.js index 07a28426444..552ba47bba9 100644 --- a/platform/app/public/config/multiple.js +++ b/platform/app/public/config/multiple.js @@ -16,7 +16,6 @@ window.config = { showStudyList: true, maxNumberOfWebWorkers: 4, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -42,6 +41,7 @@ window.config = { supportsWildcard: true, staticWado: true, singlepart: 'bulkdata,video,pdf', + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/netlify.js b/platform/app/public/config/netlify.js index 1bc23c049d9..ec386500b98 100644 --- a/platform/app/public/config/netlify.js +++ b/platform/app/public/config/netlify.js @@ -4,7 +4,6 @@ window.config = { modes: [], showStudyList: true, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -38,6 +37,7 @@ window.config = { enabled: true, relativeResolution: 'studies', }, + omitQuotationForMultipartRequest: true, }, }, { diff --git a/platform/app/public/config/public_dicomweb.js b/platform/app/public/config/public_dicomweb.js index 322d8968465..2dc7503744f 100644 --- a/platform/app/public/config/public_dicomweb.js +++ b/platform/app/public/config/public_dicomweb.js @@ -2,7 +2,6 @@ window.config = { routerBasename: '/', showStudyList: true, // below flag is for performance reasons, but it might not work for all servers - omitQuotationForMultipartRequest: true, showWarningMessageForCrossOrigin: true, showCPUFallbackMessage: true, showLoadingIndicator: true, @@ -18,6 +17,7 @@ window.config = { imageRendering: 'wadors', thumbnailRendering: 'wadors', supportsFuzzyMatching: true, + omitQuotationForMultipartRequest: true, }, ], }, diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index be062c48ef2..5b581553295 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -48,6 +48,7 @@ window.config = { enableStudyLazyLoad: true, supportsFuzzyMatching: true, supportsWildcard: true, + omitQuotationForMultipartRequest: true, }, }, ], @@ -97,6 +98,7 @@ window.config = ({ servicesManager } = {}) => { enableStudyLazyLoad: true, supportsFuzzyMatching: true, supportsWildcard: true, + omitQuotationForMultipartRequest: true, }, }, ],