changeset 3590:d5740d3b1d67

fix for issue #156: Chunked Dicom-web transfer uses 100% CPU
author Alain Mazy <alain@mazy.be>
date Mon, 23 Dec 2019 10:42:59 +0100
parents a648c2d67a65
children 19d88138c30f
files Core/HttpClient.cpp
diffstat 1 files changed, 35 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/Core/HttpClient.cpp	Thu Dec 19 22:17:24 2019 +0100
+++ b/Core/HttpClient.cpp	Mon Dec 23 10:42:59 2019 +0100
@@ -44,7 +44,7 @@
 #include <curl/curl.h>
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/thread/mutex.hpp>
-
+#include <list>
 
 // Default timeout = 60 seconds (in Orthanc <= 1.5.6, it was 10 seconds)
 static const unsigned int DEFAULT_HTTP_TIMEOUT = 60;
@@ -209,7 +209,8 @@
   {
   private:
     HttpClient::IRequestBody*  body_;
-    std::string                buffer_;
+    std::string                sourceBuffer_;
+    size_t                     sourceBufferTransmittedSize_;
 
     size_t CallbackInternal(char* curlBuffer,
                             size_t curlBufferSize)
@@ -225,43 +226,61 @@
       }
 
       // Read chunks from the body stream so as to fill the target buffer
-      std::string chunk;
+      size_t curlBufferFilledSize = 0;
+      size_t sourceRemainingSize = sourceBuffer_.size() - sourceBufferTransmittedSize_;
+      bool hasMore = true;
       
-      while (buffer_.size() < curlBufferSize &&
-             body_->ReadNextChunk(chunk))
+      while (sourceRemainingSize < curlBufferSize && hasMore)
       {
-        buffer_ += chunk;
+        if (sourceRemainingSize > 0)
+        {
+          // transmit the end of current source buffer
+          memcpy(curlBuffer + curlBufferFilledSize, sourceBuffer_.data() + sourceBufferTransmittedSize_, sourceRemainingSize);
+
+          curlBufferFilledSize += sourceRemainingSize;
+        }
+
+        // start filling a new source buffer
+        sourceBufferTransmittedSize_ = 0;
+        sourceBuffer_.clear();
+
+        hasMore = body_->ReadNextChunk(sourceBuffer_);
+
+        sourceRemainingSize = sourceBuffer_.size();
       }
 
-      size_t s = std::min(buffer_.size(), curlBufferSize);
-      
-      if (s != 0)
+      if (sourceRemainingSize > 0 && (curlBufferSize - curlBufferFilledSize) > 0)
       {
-        memcpy(curlBuffer, buffer_.c_str(), s);
+        size_t s = std::min(sourceRemainingSize, curlBufferSize - curlBufferFilledSize);
 
-        // Remove the bytes that were actually sent from the buffer
-        buffer_.erase(0, s);
+        memcpy(curlBuffer + curlBufferFilledSize, sourceBuffer_.data() + sourceBufferTransmittedSize_, s);
+
+        sourceBufferTransmittedSize_ += s;
+        curlBufferFilledSize += s;
       }
 
-      return s;
+      return curlBufferFilledSize;
     }
     
   public:
     CurlRequestBody() :
-      body_(NULL)
+      body_(NULL),
+      sourceBufferTransmittedSize_(0)
     {
     }
 
     void SetBody(HttpClient::IRequestBody& body)
     {
       body_ = &body;
-      buffer_.clear();
+      sourceBufferTransmittedSize_ = 0;
+      sourceBuffer_.clear();
     }
 
     void Clear()
     {
       body_ = NULL;
-      buffer_.clear();
+      sourceBufferTransmittedSize_ = 0;
+      sourceBuffer_.clear();
     }
 
     bool IsValid() const