Mercurial > hg > orthanc
changeset 3357:c0aa5f1cf2f5
new class: FileBuffer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 02 May 2019 09:22:36 +0200 |
parents | f744730c294b |
children | 849c651c1381 |
files | Core/FileBuffer.cpp Core/FileBuffer.h Core/HttpServer/HttpServer.cpp Resources/CMake/OrthancFrameworkConfiguration.cmake UnitTestsSources/UnitTestsMain.cpp |
diffstat | 5 files changed, 213 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/FileBuffer.cpp Thu May 02 09:22:36 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 <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeaders.h" +#include "FileBuffer.h" + +#include "TemporaryFile.h" +#include "OrthancException.h" + +#include <boost/filesystem/fstream.hpp> + + +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); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/FileBuffer.h Thu May 02 09:22:36 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 <http://www.gnu.org/licenses/>. + **/ + + +#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 <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> + + +namespace Orthanc +{ + class FileBuffer : public boost::noncopyable + { + private: + class PImpl; + boost::shared_ptr<PImpl> pimpl_; + + public: + FileBuffer(); + + void Append(const char* buffer, + size_t size); + + void Read(std::string& target); + }; +}
--- a/Core/HttpServer/HttpServer.cpp Mon Apr 29 17:24:30 2019 +0200 +++ b/Core/HttpServer/HttpServer.cpp Thu May 02 09:22:36 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,17 +310,12 @@ IHttpHandler::Arguments::const_iterator cs = headers.find("content-length"); if (cs == headers.end()) { - // TODO - Avoid storing this entirely in RAM, use temporary - // files instead. The amount of RAM needed to receive one body - // of "N" bytes is currently "2*N" bytes (one copy in "buffer", - // one copy in "postData"). With a - // "ChunkedBufferInTemporaryFiles", one would need "N" bytes (in - // "postData" only). - + // Store all the individual chunks within a temporary file, then + // read it back into the memory buffer "postData" + FileBuffer buffer; + std::string tmp(1024 * 1024, 0); - ChunkedBuffer buffer; - for (;;) { int r = mg_read(connection, &tmp[0], tmp.size()); @@ -332,16 +329,17 @@ } else { - buffer.AddChunk(tmp.c_str(), r); + buffer.Append(tmp.c_str(), r); } } - buffer.Flatten(postData); + buffer.Read(postData); return PostDataStatus_Success; } else { + // "Content-Length" is available int length; try {
--- a/Resources/CMake/OrthancFrameworkConfiguration.cmake Mon Apr 29 17:24:30 2019 +0200 +++ b/Resources/CMake/OrthancFrameworkConfiguration.cmake Thu May 02 09:22:36 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
--- a/UnitTestsSources/UnitTestsMain.cpp Mon Apr 29 17:24:30 2019 +0200 +++ b/UnitTestsSources/UnitTestsMain.cpp Thu May 02 09:22:36 2019 +0200 @@ -39,6 +39,7 @@ #include <ctype.h> #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"));