Mercurial > hg > orthanc
diff Plugins/Engine/OrthancPlugins.cpp @ 3528:f6fe095f7130
don't open a multipart stream if plugin only sends one part
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 26 Sep 2019 13:40:49 +0200 |
parents | 69e49fc044f8 |
children | 94f4a18a79cc |
line wrap: on
line diff
--- a/Plugins/Engine/OrthancPlugins.cpp Thu Sep 26 10:50:58 2019 +0200 +++ b/Plugins/Engine/OrthancPlugins.cpp Thu Sep 26 13:40:49 2019 +0200 @@ -422,25 +422,46 @@ boost::mutex contextMutex_; ServerContext* context_; - public: class PluginHttpOutput : public boost::noncopyable { private: + enum MultipartState + { + MultipartState_None, + MultipartState_FirstPart, + MultipartState_SecondPart, + MultipartState_NextParts + }; + HttpOutput& output_; std::auto_ptr<std::string> errorDetails_; bool logDetails_; + MultipartState multipartState_; + std::string multipartSubType_; + std::string multipartContentType_; + std::string multipartFirstPart_; + std::map<std::string, std::string> multipartFirstHeaders_; public: PluginHttpOutput(HttpOutput& output) : - output_(output), - logDetails_(false) + output_(output), + logDetails_(false), + multipartState_(MultipartState_None) { } HttpOutput& GetOutput() { - return output_; + if (multipartState_ == MultipartState_None) + { + return output_; + } + else + { + // Must use "SendMultipartItem()" on multipart streams + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } } void SetErrorDetails(const std::string& details, @@ -472,14 +493,100 @@ } } + void StartMultipart(const char* subType, + const char* contentType) + { + if (multipartState_ != MultipartState_None) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + multipartState_ = MultipartState_FirstPart; + multipartSubType_ = subType; + multipartContentType_ = contentType; + } + } + + void SendMultipartItem(const void* data, + size_t size, + const std::map<std::string, std::string>& headers) + { + if (size != 0 && data == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + + switch (multipartState_) + { + case MultipartState_None: + // Must call "StartMultipart()" before + throw OrthancException(ErrorCode_BadSequenceOfCalls); + + case MultipartState_FirstPart: + multipartFirstPart_.assign(reinterpret_cast<const char*>(data), size); + multipartFirstHeaders_ = headers; + multipartState_ = MultipartState_SecondPart; + break; + + case MultipartState_SecondPart: + // Start an actual stream for chunked transfer as soon as + // there are more than 2 elements in the multipart stream + output_.StartMultipart(multipartSubType_, multipartContentType_); + output_.SendMultipartItem(multipartFirstPart_.c_str(), multipartFirstPart_.size(), + multipartFirstHeaders_); + multipartFirstPart_.clear(); // Release memory + + output_.SendMultipartItem(data, size, headers); + multipartState_ = MultipartState_NextParts; + break; + + case MultipartState_NextParts: + output_.SendMultipartItem(data, size, headers); + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + void Close(OrthancPluginErrorCode error, PluginsErrorDictionary& dictionary) { if (error == OrthancPluginErrorCode_Success) { - if (GetOutput().IsWritingMultipart()) + switch (multipartState_) { - GetOutput().CloseMultipart(); + case MultipartState_None: + assert(!output_.IsWritingMultipart()); + break; + + case MultipartState_FirstPart: // Multipart started, but no part was sent + case MultipartState_SecondPart: // Multipart started, first part is pending + { + assert(!output_.IsWritingMultipart()); + std::vector<const void*> parts; + std::vector<size_t> sizes; + std::vector<const std::map<std::string, std::string>*> headers; + + if (multipartState_ == MultipartState_SecondPart) + { + parts.push_back(multipartFirstPart_.c_str()); + sizes.push_back(multipartFirstPart_.size()); + headers.push_back(&multipartFirstHeaders_); + } + + output_.AnswerMultipartWithoutChunkedTransfer(multipartSubType_, multipartContentType_, + parts, sizes, headers); + break; + } + + case MultipartState_NextParts: + assert(output_.IsWritingMultipart()); + output_.CloseMultipart(); + + default: + throw OrthancException(ErrorCode_InternalError); } } else @@ -2911,10 +3018,8 @@ const _OrthancPluginAnswerBuffer& p = *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters); - HttpOutput& output = reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->GetOutput(); - std::map<std::string, std::string> headers; // No custom headers - output.SendMultipartItem(p.answer, p.answerSize, headers); + reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->SendMultipartItem(p.answer, p.answerSize, headers); } @@ -2924,7 +3029,6 @@ // connection was closed by the HTTP client. const _OrthancPluginSendMultipartItem2& p = *reinterpret_cast<const _OrthancPluginSendMultipartItem2*>(parameters); - HttpOutput& output = reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->GetOutput(); std::map<std::string, std::string> headers; for (uint32_t i = 0; i < p.headersCount; i++) @@ -2932,7 +3036,7 @@ headers[p.headersKeys[i]] = p.headersValues[i]; } - output.SendMultipartItem(p.answer, p.answerSize, headers); + reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->SendMultipartItem(p.answer, p.answerSize, headers); } @@ -3207,8 +3311,7 @@ { const _OrthancPluginStartMultipartAnswer& p = *reinterpret_cast<const _OrthancPluginStartMultipartAnswer*>(parameters); - HttpOutput& output = reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->GetOutput(); - output.StartMultipart(p.subType, p.contentType); + reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->StartMultipart(p.subType, p.contentType); return true; }