Mercurial > hg > orthanc
changeset 3375:73d60d80a74a
merge
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 14 May 2019 16:38:20 +0200 |
parents | d0d6bd633e4c (current diff) 4a8e8a96b233 (diff) |
children | 56ea9c476dba |
files | |
diffstat | 8 files changed, 826 insertions(+), 819 deletions(-) [+] |
line wrap: on
line diff
--- a/Core/Images/ImageProcessing.h Tue May 14 16:38:02 2019 +0200 +++ b/Core/Images/ImageProcessing.h Tue May 14 16:38:20 2019 +0200 @@ -37,6 +37,7 @@ #include <vector> #include <stdint.h> +#include <algorithm> namespace Orthanc { @@ -64,6 +65,12 @@ y_ = y; } + void ClipTo(int32_t minX, int32_t maxX, int32_t minY, int32_t maxY) + { + x_ = std::max(minX, std::min(maxX, x_)); + y_ = std::max(minY, std::min(maxY, y_)); + } + double GetDistanceTo(const ImagePoint& other) const; };
--- a/INSTALL Tue May 14 16:38:02 2019 +0200 +++ b/INSTALL Tue May 14 16:38:20 2019 +0200 @@ -1,162 +1,162 @@ -Orthanc - A Lightweight, RESTful DICOM Server -============================================= - - -Dependencies ------------- - -1) CMake: Orthanc uses CMake (http://www.cmake.org/) to automate its - building process. - -2) Python: Some code is autogenerated through Python - (http://www.python.org/). - -3) Mercurial: To use the cutting edge code, a Mercurial client must be - installed (http://mercurial.selenic.com/). We recommend TortoiseHg. - -W) 7-Zip: For the native build under Windows, the 7-Zip tool is used - to uncompress the third-party packages (http://www.7-zip.org/). - -You thus have to download and install CMake, Python, Mercurial and -possibly 7-Zip first. The path to their executable must be in the -"PATH" environment variable. - -The other third party dependencies are automatically downloaded by the -CMake scripts. The downloaded packages are stored in the -"ThirdPartyDownloads" directory. - - -Building Orthanc at a glance ----------------------------- - -To build Orthanc, you must: - -1) Download the source code (either using Mercurial, or through the - official releases). For the examples below, we assume the source - directory is "~/Orthanc". - -2) Create a build directory. For the examples below, we assume the - build directory is "~/OrthancBuild". - -3) Depending on your platform, follow the build instructions below. - - -WARNING 1: If you do not create a fresh "~/OrthancBuild" directory -after upgrading the source code (i.e. if you reuse the build directory -that was used to build a different version of Orthanc), the build -might fail because of changes in the compilation/linking flags. Always -prefer to force a re-build in a new directory. - -WARNING 2: If cmake complains about not being able to uncompress -third-party dependencies, delete the "~/Orthanc/ThirdPartyDownloads/" -folder, then restart cmake. - -WARNING 3: If performance is important to you, make sure to add the -option "-DCMAKE_BUILD_TYPE=Release" when invoking cmake. Indeed, by -default, run-time debug assertions are enabled, which can seriously -impact performance, especially if your Orthanc server stores a lot of -DICOM instances. - - -Native GNU/Linux Compilation ----------------------------- - -See the file "LinuxCompilation.txt". - - -Native OS X Compilation ------------------------ - -See the file "DarwinCompilation.txt". - - - -Native Windows build with Microsoft Visual Studio 2008 ------------------------------------------------------- - -# cd [...]\OrthancBuild -# cmake -DSTANDALONE_BUILD=ON -DSTATIC_BUILD=ON -DALLOW_DOWNLOADS=ON \ - -DUSE_LEGACY_JSONCPP=ON -G "Visual Studio 9 2008" [...]\Orthanc - -Then open the "[...]/OrthancBuild/Orthanc.sln" with Visual Studio. - -NOTES: -* More recent versions of Visual Studio than 2008 should also - work. Type "cmake" without arguments to have the list of generators - that are available on your computer. -* You will have to install the Platform SDK (version 6 or above) for - Visual Studio 2005: - http://en.wikipedia.org/wiki/Microsoft_Windows_SDK. - Read the CMake FAQ: http://goo.gl/By90B -* The "-DUSE_LEGACY_JSONCPP=ON" must be set for versions of - Visual Studio that do not support C++11 - - -Orthanc as compiled above will not work properly with some Asian -encodings (unit tests will fail). In international setups, you can -compile Orthanc together with ICU as follows: - -# cmake -DSTANDALONE_BUILD=ON -DSTATIC_BUILD=ON -DALLOW_DOWNLOADS=ON \ - -DBOOST_LOCALE_BACKEND=icu -DUSE_LEGACY_JSONCPP=ON -DUSE_LEGACY_LIBICU=ON \ - -G "Visual Studio 9 2008" [...]\Orthanc - - - -Native Windows build with Microsoft Visual Studio 2015, Ninja and QtCreator ---------------------------------------------------------------------------- - -Open a Visual Studio 2015 x64 Command Prompt. - -# cd [...]\OrthancBuild -# cmake -G Ninja -DSTATIC_BUILD=ON [...]\Orthanc -# ninja - -Then, you can open an existing project in QtCreator: -* Select the CMakeLists.txt in [...]\Orthanc -* Import build from [...]\OrthancBuild - - -Instructions to include support for Asian encodings: - -# cmake -G Ninja -T host=x64 -DSTATIC_BUILD=ON -DBOOST_LOCALE_BACKEND=icu [...]\Orthanc - -The option "-T host=x64" is necessary to prevent error "C1060: -compiler is out of heap space" when compiling Orthanc with ICU. - - - -Cross-Compilation for Windows under GNU/Linux ---------------------------------------------- - -Some versions of MinGW-W64 might have problems with C++11 (notably -those shipped in Ubuntu 16.04 LTS, in the "mingw-w64" package). Use -the following command to disable C++11: - -# cd ~/OrthancBuild -# cmake ~/Orthanc \ - -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_TOOLCHAIN_FILE=~/Orthanc/Resources/MinGW-W64-Toolchain32.cmake \ - -DSTANDALONE_BUILD=ON \ - -DSTATIC_BUILD=ON \ - -DUSE_LEGACY_JSONCPP=ON -# make - -NB: Use the toolchain "MinGW-W64-Toolchain64.cmake" to produce 64bit -Windows binaries. - - - -Legacy MinGW32 compilers (notably those shipped in Ubuntu 14.04 LTS, -in the "mingw32" package) are incompatible with DCMTK 3.6.2 and -C++11. Use the following command to force using DCMTK 3.6.0 and -disable C++11: - -# cd ~/OrthancBuild -# cmake ~/Orthanc \ - -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_TOOLCHAIN_FILE=~/Orthanc/Resources/MinGWToolchain.cmake \ - -DSTANDALONE_BUILD=ON \ - -DSTATIC_BUILD=ON \ - -DDCMTK_STATIC_VERSION=3.6.0 \ - -DUSE_LEGACY_JSONCPP=ON -# make +Orthanc - A Lightweight, RESTful DICOM Server +============================================= + + +Dependencies +------------ + +1) CMake: Orthanc uses CMake (http://www.cmake.org/) to automate its + building process. + +2) Python: Some code is autogenerated through Python + (http://www.python.org/). + +3) Mercurial: To use the cutting edge code, a Mercurial client must be + installed (http://mercurial.selenic.com/). We recommend TortoiseHg. + +W) 7-Zip: For the native build under Windows, the 7-Zip tool is used + to uncompress the third-party packages (http://www.7-zip.org/). + +You thus have to download and install CMake, Python, Mercurial and +possibly 7-Zip first. The path to their executable must be in the +"PATH" environment variable. + +The other third party dependencies are automatically downloaded by the +CMake scripts. The downloaded packages are stored in the +"ThirdPartyDownloads" directory. + + +Building Orthanc at a glance +---------------------------- + +To build Orthanc, you must: + +1) Download the source code (either using Mercurial, or through the + official releases). For the examples below, we assume the source + directory is "~/Orthanc". + +2) Create a build directory. For the examples below, we assume the + build directory is "~/OrthancBuild". + +3) Depending on your platform, follow the build instructions below. + + +WARNING 1: If you do not create a fresh "~/OrthancBuild" directory +after upgrading the source code (i.e. if you reuse the build directory +that was used to build a different version of Orthanc), the build +might fail because of changes in the compilation/linking flags. Always +prefer to force a re-build in a new directory. + +WARNING 2: If cmake complains about not being able to uncompress +third-party dependencies, delete the "~/Orthanc/ThirdPartyDownloads/" +folder, then restart cmake. + +WARNING 3: If performance is important to you, make sure to add the +option "-DCMAKE_BUILD_TYPE=Release" when invoking cmake. Indeed, by +default, run-time debug assertions are enabled, which can seriously +impact performance, especially if your Orthanc server stores a lot of +DICOM instances. + + +Native GNU/Linux Compilation +---------------------------- + +See the file "LinuxCompilation.txt". + + +Native OS X Compilation +----------------------- + +See the file "DarwinCompilation.txt". + + + +Native Windows build with Microsoft Visual Studio 2008 +------------------------------------------------------ + +# cd [...]\OrthancBuild +# cmake -DSTANDALONE_BUILD=ON -DSTATIC_BUILD=ON -DALLOW_DOWNLOADS=ON \ + -DUSE_LEGACY_JSONCPP=ON -G "Visual Studio 9 2008" [...]\Orthanc + +Then open the "[...]/OrthancBuild/Orthanc.sln" with Visual Studio. + +NOTES: +* More recent versions of Visual Studio than 2008 should also + work. Type "cmake" without arguments to have the list of generators + that are available on your computer. +* You will have to install the Platform SDK (version 6 or above) for + Visual Studio 2005: + http://en.wikipedia.org/wiki/Microsoft_Windows_SDK. + Read the CMake FAQ: http://goo.gl/By90B +* The "-DUSE_LEGACY_JSONCPP=ON" must be set for versions of + Visual Studio that do not support C++11 + + +Orthanc as compiled above will not work properly with some Asian +encodings (unit tests will fail). In international setups, you can +compile Orthanc together with ICU as follows: + +# cmake -DSTANDALONE_BUILD=ON -DSTATIC_BUILD=ON -DALLOW_DOWNLOADS=ON \ + -DBOOST_LOCALE_BACKEND=icu -DUSE_LEGACY_JSONCPP=ON -DUSE_LEGACY_LIBICU=ON \ + -G "Visual Studio 9 2008" [...]\Orthanc + + + +Native Windows build with Microsoft Visual Studio 2015, Ninja and QtCreator +--------------------------------------------------------------------------- + +Open a Visual Studio 2015 x64 Command Prompt. + +# cd [...]\OrthancBuild +# cmake -G Ninja -DSTATIC_BUILD=ON [...]\Orthanc +# ninja + +Then, you can open an existing project in QtCreator: +* Select the CMakeLists.txt in [...]\Orthanc +* Import build from [...]\OrthancBuild + + +Instructions to include support for Asian encodings: + +# cmake -G Ninja -T host=x64 -DSTATIC_BUILD=ON -DBOOST_LOCALE_BACKEND=icu [...]\Orthanc + +The option "-T host=x64" is necessary to prevent error "C1060: +compiler is out of heap space" when compiling Orthanc with ICU. + + + +Cross-Compilation for Windows under GNU/Linux +--------------------------------------------- + +Some versions of MinGW-W64 might have problems with C++11 (notably +those shipped in Ubuntu 16.04 LTS, in the "mingw-w64" package). Use +the following command to disable C++11: + +# cd ~/OrthancBuild +# cmake ~/Orthanc \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_TOOLCHAIN_FILE=~/Orthanc/Resources/MinGW-W64-Toolchain32.cmake \ + -DSTANDALONE_BUILD=ON \ + -DSTATIC_BUILD=ON \ + -DUSE_LEGACY_JSONCPP=ON +# make + +NB: Use the toolchain "MinGW-W64-Toolchain64.cmake" to produce 64bit +Windows binaries. + + + +Legacy MinGW32 compilers (notably those shipped in Ubuntu 14.04 LTS, +in the "mingw32" package) are incompatible with DCMTK 3.6.2 and +C++11. Use the following command to force using DCMTK 3.6.0 and +disable C++11: + +# cd ~/OrthancBuild +# cmake ~/Orthanc \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_TOOLCHAIN_FILE=~/Orthanc/Resources/MinGWToolchain.cmake \ + -DSTANDALONE_BUILD=ON \ + -DSTATIC_BUILD=ON \ + -DDCMTK_STATIC_VERSION=3.6.0 \ + -DUSE_LEGACY_JSONCPP=ON +# make
--- a/OrthancExplorer/libs/date.js Tue May 14 16:38:02 2019 +0200 +++ b/OrthancExplorer/libs/date.js Tue May 14 16:38:20 2019 +0200 @@ -1,10 +1,10 @@ -/** - * Version: 1.0 Alpha-1 - * Build Date: 13-Nov-2007 - * Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved. - * License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. - * Website: http://www.datejs.com/ or http://www.coolite.com/datejs/ - */ +/** + * Version: 1.0 Alpha-1 + * Build Date: 13-Nov-2007 + * Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved. + * License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. + * Website: http://www.datejs.com/ or http://www.coolite.com/datejs/ + */ Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}}; Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}} return-1;};Date.getDayNumberFromName=function(name){var n=Date.CultureInfo.dayNames,m=Date.CultureInfo.abbreviatedDayNames,o=Date.CultureInfo.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}} @@ -101,4 +101,4 @@ return g._start.call({},s);};}());Date._parse=Date.parse;Date.parse=function(s){var r=null;if(!s){return null;} try{r=Date.Grammar.start.call({},s);}catch(e){return null;} return((r[1].length===0)?r[0]:null);};Date.getParseFunction=function(fx){var fn=Date.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;} -return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);}; +return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};
--- a/OrthancExplorer/query-retrieve.js Tue May 14 16:38:02 2019 +0200 +++ b/OrthancExplorer/query-retrieve.js Tue May 14 16:38:20 2019 +0200 @@ -1,337 +1,337 @@ -function JavascriptDateToDicom(date) -{ - var s = date.toISOString(); - return s.substring(0, 4) + s.substring(5, 7) + s.substring(8, 10); -} - -function GenerateDicomDate(days) -{ - var today = new Date(); - var other = new Date(today); - other.setDate(today.getDate() + days); - return JavascriptDateToDicom(other); -} - - -$('#query-retrieve').live('pagebeforeshow', function() { - var targetDate; - - $.ajax({ - url: '../modalities', - dataType: 'json', - async: false, - cache: false, - success: function(modalities) { - var targetServer = $('#qr-server'); - var option; - - $('option', targetServer).remove(); - - for (var i = 0; i < modalities.length; i++) { - option = $('<option>').text(modalities[i]); - targetServer.append(option); - } - - targetServer.selectmenu('refresh'); - } - }); - - targetDate = $('#qr-date'); - $('option', targetDate).remove(); - targetDate.append($('<option>').attr('value', '*').text('Any date')); - targetDate.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today')); - targetDate.append($('<option>').attr('value', GenerateDicomDate(-1)).text('Yesterday')); - targetDate.append($('<option>').attr('value', GenerateDicomDate(-7) + '-').text('Last 7 days')); - targetDate.append($('<option>').attr('value', GenerateDicomDate(-31) + '-').text('Last 31 days')); - targetDate.append($('<option>').attr('value', GenerateDicomDate(-31 * 3) + '-').text('Last 3 months')); - targetDate.append($('<option>').attr('value', GenerateDicomDate(-365) + '-').text('Last year')); - targetDate.selectmenu('refresh'); -}); - - -$('#qr-echo').live('click', function() { - var server = $('#qr-server').val(); - var message = 'Error: The C-Echo has failed!'; - - $.ajax({ - url: '../modalities/' + server + '/echo', - type: 'POST', - cache: false, - async: false, - success: function() { - message = 'The C-Echo has succeeded!'; - } - }); - - $('<div>').simpledialog2({ - mode: 'button', - headerText: 'Echo result', - headerClose: true, - buttonPrompt: message, - animate: false, - buttons : { - 'OK': { click: function () { } } - } - }); - - return false; -}); - - -$('#qr-submit').live('click', function() { - var query, server, modalities, field; - - query = { - 'Level' : 'Study', - 'Query' : { - 'AccessionNumber' : '', - 'PatientBirthDate' : '', - 'PatientID' : '', - 'PatientName' : '', - 'PatientSex' : '', - 'StudyDate' : $('#qr-date').val(), - 'StudyDescription' : '*' - } - }; - - modalities = ''; - - field = $('#qr-fields input:checked').val(); - query['Query'][field] = $('#qr-value').val().toUpperCase(); - - $('#qr-modalities input:checked').each(function() { - var s = $(this).attr('name'); - if (modalities == '') - modalities = s; - else - modalities += '\\' + s; - }); - - if (modalities.length > 0) { - query['Query']['ModalitiesInStudy'] = modalities; - } - - - server = $('#qr-server').val(); - $.ajax({ - url: '../modalities/' + server + '/query', - type: 'POST', - data: JSON.stringify(query), - dataType: 'json', - async: false, - error: function() { - alert('Error during query (C-Find)'); - }, - success: function(result) { - ChangePage('query-retrieve-2', { - 'server' : server, - 'uuid' : result['ID'] - }); - } - }); - - return false; -}); - - - -$('#query-retrieve-2').live('pagebeforeshow', function() { - var pageData, uri; - - if ($.mobile.pageData) { - pageData = DeepCopy($.mobile.pageData); - - uri = '../queries/' + pageData.uuid + '/answers'; - - $.ajax({ - url: uri, - dataType: 'json', - async: false, - success: function(answers) { - var target = $('#query-retrieve-2 ul'); - $('li', target).remove(); - - for (var i = 0; i < answers.length; i++) { - $.ajax({ - url: uri + '/' + answers[i] + '/content?simplify', - dataType: 'json', - async: false, - success: function(study) { - var series = '#query-retrieve-3?server=' + pageData.server + '&uuid=' + study['StudyInstanceUID']; - - var content = ($('<div>') - .append($('<h3>').text(study['PatientID'] + ' - ' + study['PatientName'])) - .append($('<p>').text('Accession number: ') - .append($('<b>').text(study['AccessionNumber']))) - .append($('<p>').text('Birth date: ') - .append($('<b>').text(study['PatientBirthDate']))) - .append($('<p>').text('Patient sex: ') - .append($('<b>').text(study['PatientSex']))) - .append($('<p>').text('Study description: ') - .append($('<b>').text(study['StudyDescription']))) - .append($('<p>').text('Study date: ') - .append($('<b>').text(FormatDicomDate(study['StudyDate']))))); - - var info = $('<a>').attr('href', series).html(content); - - var answerId = answers[i]; - var retrieve = $('<a>').text('Retrieve all study').click(function() { - ChangePage('query-retrieve-4', { - 'query' : pageData.uuid, - 'answer' : answerId, - 'server' : pageData.server - }); - }); - - target.append($('<li>').append(info).append(retrieve)); - } - }); - } - - target.listview('refresh'); - } - }); - } -}); - - -$('#query-retrieve-3').live('pagebeforeshow', function() { - var pageData, query; - - if ($.mobile.pageData) { - pageData = DeepCopy($.mobile.pageData); - - query = { - 'Level' : 'Series', - 'Query' : { - 'Modality' : '*', - 'ProtocolName' : '*', - 'SeriesDescription' : '*', - 'SeriesInstanceUID' : '*', - 'StudyInstanceUID' : pageData.uuid - } - }; - - $.ajax({ - url: '../modalities/' + pageData.server + '/query', - type: 'POST', - data: JSON.stringify(query), - dataType: 'json', - async: false, - error: function() { - alert('Error during query (C-Find)'); - }, - success: function(answer) { - var queryUuid = answer['ID']; - var uri = '../queries/' + answer['ID'] + '/answers'; - - $.ajax({ - url: uri, - dataType: 'json', - async: false, - success: function(answers) { - - var target = $('#query-retrieve-3 ul'); - $('li', target).remove(); - - for (var i = 0; i < answers.length; i++) { - $.ajax({ - url: uri + '/' + answers[i] + '/content?simplify', - dataType: 'json', - async: false, - success: function(series) { - var content = ($('<div>') - .append($('<h3>').text(series['SeriesDescription'])) - .append($('<p>').text('Modality: ') - .append($('<b>').text(series['Modality']))) - .append($('<p>').text('ProtocolName: ') - .append($('<b>').text(series['ProtocolName'])))); - - var info = $('<a>').html(content); - - var answerId = answers[i]; - info.click(function() { - ChangePage('query-retrieve-4', { - 'query' : queryUuid, - 'study' : pageData.uuid, - 'answer' : answerId, - 'server' : pageData.server - }); - }); - - target.append($('<li>').attr('data-icon', 'arrow-d').append(info)); - } - }); - } - - target.listview('refresh'); - } - }); - } - }); - } -}); - - - -$('#query-retrieve-4').live('pagebeforeshow', function() { - var pageData, uri; - - if ($.mobile.pageData) { - var pageData = DeepCopy($.mobile.pageData); - var uri = '../queries/' + pageData.query + '/answers/' + pageData.answer + '/retrieve'; - - $.ajax({ - url: '../system', - dataType: 'json', - async: false, - cache: false, - success: function(system) { - $('#retrieve-target').val(system['DicomAet']); - - $('#retrieve-form').submit(function(event) { - var aet; - - event.preventDefault(); - - aet = $('#retrieve-target').val(); - if (aet.length == 0) { - aet = system['DicomAet']; - } - - $.ajax({ - url: uri, - type: 'POST', - async: true, // Necessary to block UI - dataType: 'text', - data: aet, - beforeSend: function() { - $.blockUI({ message: $('#info-retrieve') }); - }, - complete: function(s) { - $.unblockUI(); - }, - success: function() { - if (pageData.study) { - // Go back to the list of series - ChangePage('query-retrieve-3', { - 'server' : pageData.server, - 'uuid' : pageData.study - }); - } else { - // Go back to the list of studies - ChangePage('query-retrieve-2', { - 'server' : pageData.server, - 'uuid' : pageData.query - }); - } - }, - error: function() { - alert('Error during retrieve'); - } - }); - }); - } - }); - } -}); +function JavascriptDateToDicom(date) +{ + var s = date.toISOString(); + return s.substring(0, 4) + s.substring(5, 7) + s.substring(8, 10); +} + +function GenerateDicomDate(days) +{ + var today = new Date(); + var other = new Date(today); + other.setDate(today.getDate() + days); + return JavascriptDateToDicom(other); +} + + +$('#query-retrieve').live('pagebeforeshow', function() { + var targetDate; + + $.ajax({ + url: '../modalities', + dataType: 'json', + async: false, + cache: false, + success: function(modalities) { + var targetServer = $('#qr-server'); + var option; + + $('option', targetServer).remove(); + + for (var i = 0; i < modalities.length; i++) { + option = $('<option>').text(modalities[i]); + targetServer.append(option); + } + + targetServer.selectmenu('refresh'); + } + }); + + targetDate = $('#qr-date'); + $('option', targetDate).remove(); + targetDate.append($('<option>').attr('value', '*').text('Any date')); + targetDate.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today')); + targetDate.append($('<option>').attr('value', GenerateDicomDate(-1)).text('Yesterday')); + targetDate.append($('<option>').attr('value', GenerateDicomDate(-7) + '-').text('Last 7 days')); + targetDate.append($('<option>').attr('value', GenerateDicomDate(-31) + '-').text('Last 31 days')); + targetDate.append($('<option>').attr('value', GenerateDicomDate(-31 * 3) + '-').text('Last 3 months')); + targetDate.append($('<option>').attr('value', GenerateDicomDate(-365) + '-').text('Last year')); + targetDate.selectmenu('refresh'); +}); + + +$('#qr-echo').live('click', function() { + var server = $('#qr-server').val(); + var message = 'Error: The C-Echo has failed!'; + + $.ajax({ + url: '../modalities/' + server + '/echo', + type: 'POST', + cache: false, + async: false, + success: function() { + message = 'The C-Echo has succeeded!'; + } + }); + + $('<div>').simpledialog2({ + mode: 'button', + headerText: 'Echo result', + headerClose: true, + buttonPrompt: message, + animate: false, + buttons : { + 'OK': { click: function () { } } + } + }); + + return false; +}); + + +$('#qr-submit').live('click', function() { + var query, server, modalities, field; + + query = { + 'Level' : 'Study', + 'Query' : { + 'AccessionNumber' : '', + 'PatientBirthDate' : '', + 'PatientID' : '', + 'PatientName' : '', + 'PatientSex' : '', + 'StudyDate' : $('#qr-date').val(), + 'StudyDescription' : '*' + } + }; + + modalities = ''; + + field = $('#qr-fields input:checked').val(); + query['Query'][field] = $('#qr-value').val().toUpperCase(); + + $('#qr-modalities input:checked').each(function() { + var s = $(this).attr('name'); + if (modalities == '') + modalities = s; + else + modalities += '\\' + s; + }); + + if (modalities.length > 0) { + query['Query']['ModalitiesInStudy'] = modalities; + } + + + server = $('#qr-server').val(); + $.ajax({ + url: '../modalities/' + server + '/query', + type: 'POST', + data: JSON.stringify(query), + dataType: 'json', + async: false, + error: function() { + alert('Error during query (C-Find)'); + }, + success: function(result) { + ChangePage('query-retrieve-2', { + 'server' : server, + 'uuid' : result['ID'] + }); + } + }); + + return false; +}); + + + +$('#query-retrieve-2').live('pagebeforeshow', function() { + var pageData, uri; + + if ($.mobile.pageData) { + pageData = DeepCopy($.mobile.pageData); + + uri = '../queries/' + pageData.uuid + '/answers'; + + $.ajax({ + url: uri, + dataType: 'json', + async: false, + success: function(answers) { + var target = $('#query-retrieve-2 ul'); + $('li', target).remove(); + + for (var i = 0; i < answers.length; i++) { + $.ajax({ + url: uri + '/' + answers[i] + '/content?simplify', + dataType: 'json', + async: false, + success: function(study) { + var series = '#query-retrieve-3?server=' + pageData.server + '&uuid=' + study['StudyInstanceUID']; + + var content = ($('<div>') + .append($('<h3>').text(study['PatientID'] + ' - ' + study['PatientName'])) + .append($('<p>').text('Accession number: ') + .append($('<b>').text(study['AccessionNumber']))) + .append($('<p>').text('Birth date: ') + .append($('<b>').text(study['PatientBirthDate']))) + .append($('<p>').text('Patient sex: ') + .append($('<b>').text(study['PatientSex']))) + .append($('<p>').text('Study description: ') + .append($('<b>').text(study['StudyDescription']))) + .append($('<p>').text('Study date: ') + .append($('<b>').text(FormatDicomDate(study['StudyDate']))))); + + var info = $('<a>').attr('href', series).html(content); + + var answerId = answers[i]; + var retrieve = $('<a>').text('Retrieve all study').click(function() { + ChangePage('query-retrieve-4', { + 'query' : pageData.uuid, + 'answer' : answerId, + 'server' : pageData.server + }); + }); + + target.append($('<li>').append(info).append(retrieve)); + } + }); + } + + target.listview('refresh'); + } + }); + } +}); + + +$('#query-retrieve-3').live('pagebeforeshow', function() { + var pageData, query; + + if ($.mobile.pageData) { + pageData = DeepCopy($.mobile.pageData); + + query = { + 'Level' : 'Series', + 'Query' : { + 'Modality' : '*', + 'ProtocolName' : '*', + 'SeriesDescription' : '*', + 'SeriesInstanceUID' : '*', + 'StudyInstanceUID' : pageData.uuid + } + }; + + $.ajax({ + url: '../modalities/' + pageData.server + '/query', + type: 'POST', + data: JSON.stringify(query), + dataType: 'json', + async: false, + error: function() { + alert('Error during query (C-Find)'); + }, + success: function(answer) { + var queryUuid = answer['ID']; + var uri = '../queries/' + answer['ID'] + '/answers'; + + $.ajax({ + url: uri, + dataType: 'json', + async: false, + success: function(answers) { + + var target = $('#query-retrieve-3 ul'); + $('li', target).remove(); + + for (var i = 0; i < answers.length; i++) { + $.ajax({ + url: uri + '/' + answers[i] + '/content?simplify', + dataType: 'json', + async: false, + success: function(series) { + var content = ($('<div>') + .append($('<h3>').text(series['SeriesDescription'])) + .append($('<p>').text('Modality: ') + .append($('<b>').text(series['Modality']))) + .append($('<p>').text('ProtocolName: ') + .append($('<b>').text(series['ProtocolName'])))); + + var info = $('<a>').html(content); + + var answerId = answers[i]; + info.click(function() { + ChangePage('query-retrieve-4', { + 'query' : queryUuid, + 'study' : pageData.uuid, + 'answer' : answerId, + 'server' : pageData.server + }); + }); + + target.append($('<li>').attr('data-icon', 'arrow-d').append(info)); + } + }); + } + + target.listview('refresh'); + } + }); + } + }); + } +}); + + + +$('#query-retrieve-4').live('pagebeforeshow', function() { + var pageData, uri; + + if ($.mobile.pageData) { + var pageData = DeepCopy($.mobile.pageData); + var uri = '../queries/' + pageData.query + '/answers/' + pageData.answer + '/retrieve'; + + $.ajax({ + url: '../system', + dataType: 'json', + async: false, + cache: false, + success: function(system) { + $('#retrieve-target').val(system['DicomAet']); + + $('#retrieve-form').submit(function(event) { + var aet; + + event.preventDefault(); + + aet = $('#retrieve-target').val(); + if (aet.length == 0) { + aet = system['DicomAet']; + } + + $.ajax({ + url: uri, + type: 'POST', + async: true, // Necessary to block UI + dataType: 'text', + data: aet, + beforeSend: function() { + $.blockUI({ message: $('#info-retrieve') }); + }, + complete: function(s) { + $.unblockUI(); + }, + success: function() { + if (pageData.study) { + // Go back to the list of series + ChangePage('query-retrieve-3', { + 'server' : pageData.server, + 'uuid' : pageData.study + }); + } else { + // Go back to the list of studies + ChangePage('query-retrieve-2', { + 'server' : pageData.server, + 'uuid' : pageData.query + }); + } + }, + error: function() { + alert('Error during retrieve'); + } + }); + }); + } + }); + } +});
--- a/Plugins/Samples/Common/OrthancPlugins.cmake Tue May 14 16:38:02 2019 +0200 +++ b/Plugins/Samples/Common/OrthancPlugins.cmake Tue May 14 16:38:20 2019 +0200 @@ -1,32 +1,32 @@ -set(ORTHANC_ROOT ${SAMPLES_ROOT}/../..) -include(CheckIncludeFiles) -include(CheckIncludeFileCXX) -include(CheckLibraryExists) -include(FindPythonInterp) -include(${ORTHANC_ROOT}/Resources/CMake/AutoGeneratedCode.cmake) -include(${ORTHANC_ROOT}/Resources/CMake/DownloadPackage.cmake) -include(${ORTHANC_ROOT}/Resources/CMake/Compiler.cmake) - - -if (CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic") -endif() - - -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - # Linking with "pthread" is necessary, otherwise the software crashes - # http://sourceware.org/bugzilla/show_bug.cgi?id=10652#c17 - link_libraries(dl rt pthread) -endif() - - -include_directories(${SAMPLES_ROOT}/../Include/) - - -if (MSVC) - include_directories(${SAMPLES_ROOT}/../../Resources/ThirdParty/VisualStudio/) -endif() - - -add_definitions(-DHAS_ORTHANC_EXCEPTION=0) +set(ORTHANC_ROOT ${SAMPLES_ROOT}/../..) +include(CheckIncludeFiles) +include(CheckIncludeFileCXX) +include(CheckLibraryExists) +include(FindPythonInterp) +include(${ORTHANC_ROOT}/Resources/CMake/AutoGeneratedCode.cmake) +include(${ORTHANC_ROOT}/Resources/CMake/DownloadPackage.cmake) +include(${ORTHANC_ROOT}/Resources/CMake/Compiler.cmake) + + +if (CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic") +endif() + + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + # Linking with "pthread" is necessary, otherwise the software crashes + # http://sourceware.org/bugzilla/show_bug.cgi?id=10652#c17 + link_libraries(dl rt pthread) +endif() + + +include_directories(${SAMPLES_ROOT}/../Include/) + + +if (MSVC) + include_directories(${SAMPLES_ROOT}/../../Resources/ThirdParty/VisualStudio/) +endif() + + +add_definitions(-DHAS_ORTHANC_EXCEPTION=0)
--- a/Resources/Patches/mongoose-3.1-patch.diff Tue May 14 16:38:02 2019 +0200 +++ b/Resources/Patches/mongoose-3.1-patch.diff Tue May 14 16:38:20 2019 +0200 @@ -1,54 +1,54 @@ --- /home/jodogne/Subversion/Orthanc/ThirdPartyDownloads/mongoose/mongoose.c 2012-03-11 23:41:35.000000000 +0100 +++ mongoose.c 2013-03-07 10:07:00.566266153 +0100 @@ -92,8 +92,9 @@ - #define strtoll(x, y, z) strtol(x, y, z) - #else - #define __func__ __FUNCTION__ --#define strtoull(x, y, z) _strtoui64(x, y, z) --#define strtoll(x, y, z) _strtoi64(x, y, z) -+#include <stdlib.h> -+//#define strtoull(x, y, z) _strtoui64(x, y, z) -+//#define strtoll(x, y, z) _strtoi64(x, y, z) - #endif // _MSC_VER - - #define ERRNO GetLastError() + #define strtoll(x, y, z) strtol(x, y, z) + #else + #define __func__ __FUNCTION__ +-#define strtoull(x, y, z) _strtoui64(x, y, z) +-#define strtoll(x, y, z) _strtoi64(x, y, z) ++#include <stdlib.h> ++//#define strtoull(x, y, z) _strtoui64(x, y, z) ++//#define strtoll(x, y, z) _strtoi64(x, y, z) + #endif // _MSC_VER + + #define ERRNO GetLastError() @@ -253,6 +254,14 @@ - #define MSG_NOSIGNAL 0 - #endif - -+#if __gnu_hurd__ == 1 -+/** -+ * There is no limit on the length on a path under GNU Hurd, so we set -+ * it to an arbitrary constant. -+ **/ -+#define PATH_MAX 4096 -+#endif -+ - typedef void * (*mg_thread_func_t)(void *); - - static const char *http_500_error = "Internal Server Error"; + #define MSG_NOSIGNAL 0 + #endif + ++#if __gnu_hurd__ == 1 ++/** ++ * There is no limit on the length on a path under GNU Hurd, so we set ++ * it to an arbitrary constant. ++ **/ ++#define PATH_MAX 4096 ++#endif ++ + typedef void * (*mg_thread_func_t)(void *); + + static const char *http_500_error = "Internal Server Error"; @@ -3844,10 +3853,8 @@ - } - - static void discard_current_request_from_buffer(struct mg_connection *conn) { -- char *buffered; - int buffered_len, body_len; - -- buffered = conn->buf + conn->request_len; - buffered_len = conn->data_len - conn->request_len; - assert(buffered_len >= 0); - + } + + static void discard_current_request_from_buffer(struct mg_connection *conn) { +- char *buffered; + int buffered_len, body_len; + +- buffered = conn->buf + conn->request_len; + buffered_len = conn->data_len - conn->request_len; + assert(buffered_len >= 0); + @@ -4148,7 +4155,13 @@ - - // Wait until mg_fini() stops - while (ctx->stop_flag != 2) { -+#if defined(__linux__) -+ usleep(100000); -+#elif defined(_WIN32) -+ Sleep(100); -+#else - (void) sleep(0); -+#endif - } - free_context(ctx); - + + // Wait until mg_fini() stops + while (ctx->stop_flag != 2) { ++#if defined(__linux__) ++ usleep(100000); ++#elif defined(_WIN32) ++ Sleep(100); ++#else + (void) sleep(0); ++#endif + } + free_context(ctx); +
--- a/Resources/Patches/mongoose-3.8-patch.diff Tue May 14 16:38:02 2019 +0200 +++ b/Resources/Patches/mongoose-3.8-patch.diff Tue May 14 16:38:20 2019 +0200 @@ -1,106 +1,106 @@ --- mongoose.c.orig 2019-01-14 13:06:27.147098524 +0100 +++ mongoose.c 2019-01-14 12:44:35.331361929 +0100 @@ -50,6 +50,14 @@ - #define PATH_MAX FILENAME_MAX - #endif // __SYMBIAN32__ - -+#if __gnu_hurd__ == 1 -+/** -+ * There is no limit on the length on a path under GNU Hurd, so we set -+ * it to an arbitrary constant. -+ **/ -+#define PATH_MAX 4096 -+#endif -+ - #ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE - #include <sys/types.h> - #include <sys/stat.h> + #define PATH_MAX FILENAME_MAX + #endif // __SYMBIAN32__ + ++#if __gnu_hurd__ == 1 ++/** ++ * There is no limit on the length on a path under GNU Hurd, so we set ++ * it to an arbitrary constant. ++ **/ ++#define PATH_MAX 4096 ++#endif ++ + #ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE + #include <sys/types.h> + #include <sys/stat.h> @@ -108,8 +116,9 @@ - #define strtoll(x, y, z) _atoi64(x) - #else - #define __func__ __FUNCTION__ --#define strtoull(x, y, z) _strtoui64(x, y, z) --#define strtoll(x, y, z) _strtoi64(x, y, z) -+#include <stdlib.h> -+//#define strtoull(x, y, z) _strtoui64(x, y, z) -+//#define strtoll(x, y, z) _strtoi64(x, y, z) - #endif // _MSC_VER - - #define ERRNO GetLastError() + #define strtoll(x, y, z) _atoi64(x) + #else + #define __func__ __FUNCTION__ +-#define strtoull(x, y, z) _strtoui64(x, y, z) +-#define strtoll(x, y, z) _strtoi64(x, y, z) ++#include <stdlib.h> ++//#define strtoull(x, y, z) _strtoui64(x, y, z) ++//#define strtoll(x, y, z) _strtoi64(x, y, z) + #endif // _MSC_VER + + #define ERRNO GetLastError() @@ -2997,19 +3006,19 @@ - } - } - --static int is_valid_http_method(const char *method) { -- return !strcmp(method, "GET") || !strcmp(method, "POST") || -+static int is_valid_http_method(const char *method, int *isValidHttpMethod) { -+ *isValidHttpMethod = !strcmp(method, "GET") || !strcmp(method, "POST") || - !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") || - !strcmp(method, "PUT") || !strcmp(method, "DELETE") || - !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND") -- || !strcmp(method, "MKCOL") -- ; -+ || !strcmp(method, "MKCOL"); -+ return *isValidHttpMethod; - } - - // Parse HTTP request, fill in mg_request_info structure. - // This function modifies the buffer by NUL-terminating - // HTTP request components, header names and header values. --static int parse_http_message(char *buf, int len, struct mg_request_info *ri) { -+static int parse_http_message(char *buf, int len, struct mg_request_info *ri, int *isValidHttpMethod) { - int is_request, request_length = get_request_len(buf, len); - if (request_length > 0) { - // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port + } + } + +-static int is_valid_http_method(const char *method) { +- return !strcmp(method, "GET") || !strcmp(method, "POST") || ++static int is_valid_http_method(const char *method, int *isValidHttpMethod) { ++ *isValidHttpMethod = !strcmp(method, "GET") || !strcmp(method, "POST") || + !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") || + !strcmp(method, "PUT") || !strcmp(method, "DELETE") || + !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND") +- || !strcmp(method, "MKCOL") +- ; ++ || !strcmp(method, "MKCOL"); ++ return *isValidHttpMethod; + } + + // Parse HTTP request, fill in mg_request_info structure. + // This function modifies the buffer by NUL-terminating + // HTTP request components, header names and header values. +-static int parse_http_message(char *buf, int len, struct mg_request_info *ri) { ++static int parse_http_message(char *buf, int len, struct mg_request_info *ri, int *isValidHttpMethod) { + int is_request, request_length = get_request_len(buf, len); + if (request_length > 0) { + // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port @@ -3025,7 +3034,7 @@ - ri->request_method = skip(&buf, " "); - ri->uri = skip(&buf, " "); - ri->http_version = skip(&buf, "\r\n"); -- if (((is_request = is_valid_http_method(ri->request_method)) && -+ if (((is_request = is_valid_http_method(ri->request_method, isValidHttpMethod)) && - memcmp(ri->http_version, "HTTP/", 5) != 0) || - (!is_request && memcmp(ri->request_method, "HTTP/", 5)) != 0) { - request_length = -1; + ri->request_method = skip(&buf, " "); + ri->uri = skip(&buf, " "); + ri->http_version = skip(&buf, "\r\n"); +- if (((is_request = is_valid_http_method(ri->request_method)) && ++ if (((is_request = is_valid_http_method(ri->request_method, isValidHttpMethod)) && + memcmp(ri->http_version, "HTTP/", 5) != 0) || + (!is_request && memcmp(ri->request_method, "HTTP/", 5)) != 0) { + request_length = -1; @@ -4930,7 +4939,7 @@ - return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0'); - } - --static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) { -+static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *isValidHttpMethod) { - const char *cl; - - ebuf[0] = '\0'; + return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0'); + } + +-static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) { ++static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *isValidHttpMethod) { + const char *cl; + + ebuf[0] = '\0'; @@ -4944,7 +4953,7 @@ - } else if (conn->request_len <= 0) { - snprintf(ebuf, ebuf_len, "%s", "Client closed connection"); - } else if (parse_http_message(conn->buf, conn->buf_size, -- &conn->request_info) <= 0) { -+ &conn->request_info, isValidHttpMethod) <= 0) { - snprintf(ebuf, ebuf_len, "Bad request: [%.*s]", conn->data_len, conn->buf); - } else { - // Request is valid + } else if (conn->request_len <= 0) { + snprintf(ebuf, ebuf_len, "%s", "Client closed connection"); + } else if (parse_http_message(conn->buf, conn->buf_size, +- &conn->request_info) <= 0) { ++ &conn->request_info, isValidHttpMethod) <= 0) { + snprintf(ebuf, ebuf_len, "Bad request: [%.*s]", conn->data_len, conn->buf); + } else { + // Request is valid @@ -4973,7 +4982,8 @@ - } else if (mg_vprintf(conn, fmt, ap) <= 0) { - snprintf(ebuf, ebuf_len, "%s", "Error sending request"); - } else { -- getreq(conn, ebuf, ebuf_len); -+ int isValidHttpMethod = 1; /* unused in this case */ -+ getreq(conn, ebuf, ebuf_len, &isValidHttpMethod); - } - if (ebuf[0] != '\0' && conn != NULL) { - mg_close_connection(conn); + } else if (mg_vprintf(conn, fmt, ap) <= 0) { + snprintf(ebuf, ebuf_len, "%s", "Error sending request"); + } else { +- getreq(conn, ebuf, ebuf_len); ++ int isValidHttpMethod = 1; /* unused in this case */ ++ getreq(conn, ebuf, ebuf_len, &isValidHttpMethod); + } + if (ebuf[0] != '\0' && conn != NULL) { + mg_close_connection(conn); @@ -4995,8 +5005,13 @@ - // to crule42. - conn->data_len = 0; - do { -- if (!getreq(conn, ebuf, sizeof(ebuf))) { -+ int isValidHttpMethod = 1; -+ if (!getreq(conn, ebuf, sizeof(ebuf), &isValidHttpMethod)) { -+ if (isValidHttpMethod) { - send_http_error(conn, 500, "Server Error", "%s", ebuf); -+ } else { -+ send_http_error(conn, 400, "Bad Request", "%s", ebuf); -+ } - conn->must_close = 1; - } else if (!is_valid_uri(conn->request_info.uri)) { - snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri); + // to crule42. + conn->data_len = 0; + do { +- if (!getreq(conn, ebuf, sizeof(ebuf))) { ++ int isValidHttpMethod = 1; ++ if (!getreq(conn, ebuf, sizeof(ebuf), &isValidHttpMethod)) { ++ if (isValidHttpMethod) { + send_http_error(conn, 500, "Server Error", "%s", ebuf); ++ } else { ++ send_http_error(conn, 400, "Bad Request", "%s", ebuf); ++ } + conn->must_close = 1; + } else if (!is_valid_uri(conn->request_info.uri)) { + snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);
--- a/UnitTestsSources/ToolboxTests.cpp Tue May 14 16:38:02 2019 +0200 +++ b/UnitTestsSources/ToolboxTests.cpp Tue May 14 16:38:20 2019 +0200 @@ -1,136 +1,136 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "PrecompiledHeadersUnitTests.h" -#include "gtest/gtest.h" -#include "../Core/OrthancException.h" -#include "../Core/Toolbox.h" - -using namespace Orthanc; - -TEST(Toolbox, Base64_allByteValues) -{ - std::string toEncode; - std::string base64Result; - std::string decodedResult; - - size_t size = 2*256; - toEncode.reserve(size); - for (size_t i = 0; i < size; i++) - toEncode.push_back(i % 256); - - Toolbox::EncodeBase64(base64Result, toEncode); - Toolbox::DecodeBase64(decodedResult, base64Result); - - ASSERT_EQ(toEncode, decodedResult); -} - -TEST(Toolbox, Base64_multipleSizes) -{ - std::string toEncode; - std::string base64Result; - std::string decodedResult; - - for (size_t size = 0; size <= 5; size++) - { - printf("base64, testing size %zu\n", size); - toEncode.clear(); - toEncode.reserve(size); - for (size_t i = 0; i < size; i++) - toEncode.push_back(i % 256); - - Toolbox::EncodeBase64(base64Result, toEncode); - Toolbox::DecodeBase64(decodedResult, base64Result); - - ASSERT_EQ(toEncode, decodedResult); - } -} - -static std::string EncodeBase64Bis(const std::string& s) -{ - std::string result; - Toolbox::EncodeBase64(result, s); - return result; -} - - -TEST(Toolbox, Base64) -{ - ASSERT_EQ("", EncodeBase64Bis("")); - ASSERT_EQ("YQ==", EncodeBase64Bis("a")); - - const std::string hello = "SGVsbG8gd29ybGQ="; - ASSERT_EQ(hello, EncodeBase64Bis("Hello world")); - - std::string decoded; - Toolbox::DecodeBase64(decoded, hello); - ASSERT_EQ("Hello world", decoded); - - // Invalid character - ASSERT_THROW(Toolbox::DecodeBase64(decoded, "?"), OrthancException); - - // All the allowed characters - Toolbox::DecodeBase64(decoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); -} - - -#if 0 // enable only when compiling in Release with a C++ 11 compiler -#include <chrono> // I had troubles to link with boost::chrono ... - -TEST(Toolbox, Base64_largeString) -{ - std::string toEncode; - std::string base64Result; - std::string decodedResult; - - size_t size = 10 * 1024 * 1024; - toEncode.reserve(size); - for (size_t i = 0; i < size; i++) - toEncode.push_back(i % 256); - - std::chrono::high_resolution_clock::time_point start; - std::chrono::high_resolution_clock::time_point afterEncoding; - std::chrono::high_resolution_clock::time_point afterDecoding; - - start = std::chrono::high_resolution_clock::now(); - Orthanc::Toolbox::EncodeBase64(base64Result, toEncode); - afterEncoding = std::chrono::high_resolution_clock::now(); - Orthanc::Toolbox::DecodeBase64(decodedResult, base64Result); - afterDecoding = std::chrono::high_resolution_clock::now(); - - ASSERT_EQ(toEncode, decodedResult); - - printf("encoding took %zu ms\n", (std::chrono::duration_cast<std::chrono::milliseconds>(afterEncoding - start))); - printf("decoding took %zu ms\n", (std::chrono::duration_cast<std::chrono::milliseconds>(afterDecoding - afterEncoding))); -} -#endif +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeadersUnitTests.h" +#include "gtest/gtest.h" +#include "../Core/OrthancException.h" +#include "../Core/Toolbox.h" + +using namespace Orthanc; + +TEST(Toolbox, Base64_allByteValues) +{ + std::string toEncode; + std::string base64Result; + std::string decodedResult; + + size_t size = 2*256; + toEncode.reserve(size); + for (size_t i = 0; i < size; i++) + toEncode.push_back(i % 256); + + Toolbox::EncodeBase64(base64Result, toEncode); + Toolbox::DecodeBase64(decodedResult, base64Result); + + ASSERT_EQ(toEncode, decodedResult); +} + +TEST(Toolbox, Base64_multipleSizes) +{ + std::string toEncode; + std::string base64Result; + std::string decodedResult; + + for (size_t size = 0; size <= 5; size++) + { + printf("base64, testing size %zu\n", size); + toEncode.clear(); + toEncode.reserve(size); + for (size_t i = 0; i < size; i++) + toEncode.push_back(i % 256); + + Toolbox::EncodeBase64(base64Result, toEncode); + Toolbox::DecodeBase64(decodedResult, base64Result); + + ASSERT_EQ(toEncode, decodedResult); + } +} + +static std::string EncodeBase64Bis(const std::string& s) +{ + std::string result; + Toolbox::EncodeBase64(result, s); + return result; +} + + +TEST(Toolbox, Base64) +{ + ASSERT_EQ("", EncodeBase64Bis("")); + ASSERT_EQ("YQ==", EncodeBase64Bis("a")); + + const std::string hello = "SGVsbG8gd29ybGQ="; + ASSERT_EQ(hello, EncodeBase64Bis("Hello world")); + + std::string decoded; + Toolbox::DecodeBase64(decoded, hello); + ASSERT_EQ("Hello world", decoded); + + // Invalid character + ASSERT_THROW(Toolbox::DecodeBase64(decoded, "?"), OrthancException); + + // All the allowed characters + Toolbox::DecodeBase64(decoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); +} + + +#if 0 // enable only when compiling in Release with a C++ 11 compiler +#include <chrono> // I had troubles to link with boost::chrono ... + +TEST(Toolbox, Base64_largeString) +{ + std::string toEncode; + std::string base64Result; + std::string decodedResult; + + size_t size = 10 * 1024 * 1024; + toEncode.reserve(size); + for (size_t i = 0; i < size; i++) + toEncode.push_back(i % 256); + + std::chrono::high_resolution_clock::time_point start; + std::chrono::high_resolution_clock::time_point afterEncoding; + std::chrono::high_resolution_clock::time_point afterDecoding; + + start = std::chrono::high_resolution_clock::now(); + Orthanc::Toolbox::EncodeBase64(base64Result, toEncode); + afterEncoding = std::chrono::high_resolution_clock::now(); + Orthanc::Toolbox::DecodeBase64(decodedResult, base64Result); + afterDecoding = std::chrono::high_resolution_clock::now(); + + ASSERT_EQ(toEncode, decodedResult); + + printf("encoding took %zu ms\n", (std::chrono::duration_cast<std::chrono::milliseconds>(afterEncoding - start))); + printf("decoding took %zu ms\n", (std::chrono::duration_cast<std::chrono::milliseconds>(afterDecoding - afterEncoding))); +} +#endif