# HG changeset patch # User Benjamin Golinvaux # Date 1557227448 -7200 # Node ID ea07b29c6d0e0e2976090d2a7be8ffc9411dcf07 # Parent 815b81142ff70597504ad0733b61b3918c084685# Parent 7569d3dc1c2012cb31d7f7058d986d8659460f33 Merge fro default diff -r 815b81142ff7 -r ea07b29c6d0e Core/FileBuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/FileBuffer.cpp Tue May 07 13:10:48 2019 +0200 @@ -0,0 +1,122 @@ +/** + * 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 . + **/ + + +#include "PrecompiledHeaders.h" +#include "FileBuffer.h" + +#include "TemporaryFile.h" +#include "OrthancException.h" + +#include + + +namespace Orthanc +{ + class FileBuffer::PImpl + { + private: + TemporaryFile file_; + boost::filesystem::ofstream stream_; + bool isWriting_; + + public: + PImpl() : + isWriting_(true) + { + stream_.open(file_.GetPath(), std::ofstream::out | std::ofstream::binary); + if (!stream_.good()) + { + throw OrthancException(ErrorCode_CannotWriteFile); + } + } + + ~PImpl() + { + if (isWriting_) + { + stream_.close(); + } + } + + void Append(const char* buffer, + size_t size) + { + if (!isWriting_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + + if (size > 0) + { + stream_.write(buffer, size); + if (!stream_.good()) + { + stream_.close(); + throw OrthancException(ErrorCode_FileStorageCannotWrite); + } + } + } + + void Read(std::string& target) + { + if (isWriting_) + { + stream_.close(); + isWriting_ = false; + } + + file_.Read(target); + } + }; + + + FileBuffer::FileBuffer() : + pimpl_(new PImpl) + { + } + + + void FileBuffer::Append(const char* buffer, + size_t size) + { + assert(pimpl_.get() != NULL); + pimpl_->Append(buffer, size); + } + + + void FileBuffer::Read(std::string& target) + { + assert(pimpl_.get() != NULL); + pimpl_->Read(target); + } +} diff -r 815b81142ff7 -r ea07b29c6d0e Core/FileBuffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/FileBuffer.h Tue May 07 13:10:48 2019 +0200 @@ -0,0 +1,64 @@ +/** + * 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 . + **/ + + +#pragma once + +#if !defined(ORTHANC_SANDBOXED) +# error The macro ORTHANC_SANDBOXED must be defined +#endif + +#if ORTHANC_SANDBOXED == 1 +# error The namespace SystemToolbox cannot be used in sandboxed environments +#endif + +#include +#include + + +namespace Orthanc +{ + class FileBuffer : public boost::noncopyable + { + private: + class PImpl; + boost::shared_ptr pimpl_; + + public: + FileBuffer(); + + void Append(const char* buffer, + size_t size); + + void Read(std::string& target); + }; +} diff -r 815b81142ff7 -r ea07b29c6d0e Core/HttpClient.cpp --- a/Core/HttpClient.cpp Tue May 07 11:23:11 2019 +0200 +++ b/Core/HttpClient.cpp Tue May 07 13:10:48 2019 +0200 @@ -358,7 +358,7 @@ url_ = ""; method_ = HttpMethod_Get; - lastStatus_ = HttpStatus_200_Ok; + lastStatus_ = HttpStatus_None; SetVerbose(GlobalParameters::GetInstance().IsDefaultVerbose()); timeout_ = GlobalParameters::GetInstance().GetDefaultTimeout(); GlobalParameters::GetInstance().GetDefaultProxy(proxy_); diff -r 815b81142ff7 -r ea07b29c6d0e Core/HttpServer/HttpServer.cpp --- a/Core/HttpServer/HttpServer.cpp Tue May 07 11:23:11 2019 +0200 +++ b/Core/HttpServer/HttpServer.cpp Tue May 07 13:10:48 2019 +0200 @@ -36,9 +36,11 @@ #include "../PrecompiledHeaders.h" #include "HttpServer.h" +#include "../ChunkedBuffer.h" +#include "../FileBuffer.h" #include "../Logging.h" -#include "../ChunkedBuffer.h" #include "../OrthancException.h" +#include "../TemporaryFile.h" #include "HttpToolbox.h" #if ORTHANC_ENABLE_MONGOOSE == 1 @@ -308,41 +310,69 @@ IHttpHandler::Arguments::const_iterator cs = headers.find("content-length"); if (cs == headers.end()) { - return PostDataStatus_NoLength; - } - - int length; - try - { - length = boost::lexical_cast(cs->second); - } - catch (boost::bad_lexical_cast&) - { - return PostDataStatus_NoLength; - } + // Store all the individual chunks within a temporary file, then + // read it back into the memory buffer "postData" + FileBuffer buffer; - if (length < 0) - { - length = 0; - } - - postData.resize(length); - - size_t pos = 0; - while (length > 0) - { - int r = mg_read(connection, &postData[pos], length); - if (r <= 0) + std::string tmp(1024 * 1024, 0); + + for (;;) { - return PostDataStatus_Failure; + int r = mg_read(connection, &tmp[0], tmp.size()); + if (r < 0) + { + return PostDataStatus_Failure; + } + else if (r == 0) + { + break; + } + else + { + buffer.Append(tmp.c_str(), r); + } } - assert(r <= length); - length -= r; - pos += r; + buffer.Read(postData); + + return PostDataStatus_Success; } + else + { + // "Content-Length" is available + int length; + try + { + length = boost::lexical_cast(cs->second); + } + catch (boost::bad_lexical_cast&) + { + return PostDataStatus_NoLength; + } - return PostDataStatus_Success; + if (length < 0) + { + length = 0; + } + + postData.resize(length); + + size_t pos = 0; + while (length > 0) + { + int r = mg_read(connection, &postData[pos], length); + if (r <= 0) + { + return PostDataStatus_Failure; + } + + assert(r <= length); + length -= r; + pos += r; + } + + return PostDataStatus_Success; + } } diff -r 815b81142ff7 -r ea07b29c6d0e Core/Logging.cpp --- a/Core/Logging.cpp Tue May 07 11:23:11 2019 +0200 +++ b/Core/Logging.cpp Tue May 07 13:10:48 2019 +0200 @@ -274,6 +274,10 @@ } } + void Initialize() + { + } + void EnableInfoLevel(bool enabled) { globalVerbose_ = enabled; diff -r 815b81142ff7 -r ea07b29c6d0e NEWS --- a/NEWS Tue May 07 11:23:11 2019 +0200 +++ b/NEWS Tue May 07 13:10:48 2019 +0200 @@ -5,6 +5,7 @@ Maintenance ----------- +* Orthanc now accepts "-H 'Transfer-Encoding: chunked'" option from curl * Size of the Orthanc static binaries are reduced by compressing ICU data * Anonymization: Preserve hierarchical relationships in (0008,1115) [] (0020,000e) * Fix issue #136 (C-FIND request fails when found DICOM file does not have certain tags) diff -r 815b81142ff7 -r ea07b29c6d0e Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp --- a/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp Tue May 07 11:23:11 2019 +0200 +++ b/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp Tue May 07 13:10:48 2019 +0200 @@ -371,7 +371,10 @@ if (decoded.empty()) { decoded.resize(pimpl_->GetImage().GetBufferLength()); - pimpl_->GetImage().GetBuffer(&decoded[0]); + if (!pimpl_->GetImage().GetBuffer(&decoded[0])) + { + throw std::runtime_error("Image not properly decoded to a memory buffer"); + } } const void* sourceBuffer = &decoded[0]; diff -r 815b81142ff7 -r ea07b29c6d0e Resources/CMake/OrthancFrameworkConfiguration.cmake --- a/Resources/CMake/OrthancFrameworkConfiguration.cmake Tue May 07 11:23:11 2019 +0200 +++ b/Resources/CMake/OrthancFrameworkConfiguration.cmake Tue May 07 13:10:48 2019 +0200 @@ -541,6 +541,7 @@ list(APPEND ORTHANC_CORE_SOURCES_INTERNAL ${ORTHANC_ROOT}/Core/Cache/SharedArchive.cpp + ${ORTHANC_ROOT}/Core/FileBuffer.cpp ${ORTHANC_ROOT}/Core/FileStorage/FilesystemStorage.cpp ${ORTHANC_ROOT}/Core/MetricsRegistry.cpp ${ORTHANC_ROOT}/Core/MultiThreading/RunnableWorkersPool.cpp diff -r 815b81142ff7 -r ea07b29c6d0e Resources/EmbedResources.py --- a/Resources/EmbedResources.py Tue May 07 11:23:11 2019 +0200 +++ b/Resources/EmbedResources.py Tue May 07 13:10:48 2019 +0200 @@ -231,6 +231,12 @@ # http://stackoverflow.com/a/1035360 pos = 0 + buffer = [] # instead of appending a few bytes at a time to the cpp file, + # we first append each chunk to a list, join it and write it + # to the file. We've measured that it was 2-3 times faster in python3. + # Note that speed is important since if generation is too slow, + # cmake might try to compile the EmbeddedResources.cpp file while it is + # still being generated ! for b in content: if PYTHON_MAJOR_VERSION == 2: c = ord(b[0]) @@ -238,17 +244,18 @@ c = b if pos > 0: - cpp.write(', ') + buffer.append(",") if (pos % 16) == 0: - cpp.write('\n ') + buffer.append("\n") if c < 0: raise Exception("Internal error") - cpp.write("0x%02x" % c) + buffer.append("0x%02x" % c) pos += 1 + cpp.write("".join(buffer)) # Zero-size array are disallowed, so we put one single void character in it. if pos == 0: cpp.write(' 0') diff -r 815b81142ff7 -r ea07b29c6d0e UnitTestsSources/UnitTestsMain.cpp --- a/UnitTestsSources/UnitTestsMain.cpp Tue May 07 11:23:11 2019 +0200 +++ b/UnitTestsSources/UnitTestsMain.cpp Tue May 07 13:10:48 2019 +0200 @@ -39,6 +39,7 @@ #include #include "../Core/DicomFormat/DicomTag.h" +#include "../Core/FileBuffer.h" #include "../Core/HttpServer/HttpToolbox.h" #include "../Core/Logging.h" #include "../Core/MetricsRegistry.h" @@ -679,6 +680,21 @@ } +TEST(Toolbox, FileBuffer) +{ + FileBuffer f; + f.Append("a", 1); + f.Append("", 0); + f.Append("bc", 2); + + std::string s; + f.Read(s); + ASSERT_EQ("abc", s); + + ASSERT_THROW(f.Append("d", 1), OrthancException); // File is closed +} + + TEST(Toolbox, Wildcard) { ASSERT_EQ("abcd", Toolbox::WildcardToRegularExpression("abcd"));