diff OrthancFramework/Sources/HttpClient.cpp @ 4151:8c559dd5034b

Fix possible crash in HttpClient if sending multipart body (can occur in STOW-RS)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 19 Aug 2020 11:59:02 +0200
parents bf7b9edf6b81
children db38b2ad4c4a
line wrap: on
line diff
--- a/OrthancFramework/Sources/HttpClient.cpp	Wed Aug 19 11:18:55 2020 +0200
+++ b/OrthancFramework/Sources/HttpClient.cpp	Wed Aug 19 11:59:02 2020 +0200
@@ -197,8 +197,8 @@
   {
   private:
     HttpClient::IRequestBody*  body_;
-    std::string                sourceBuffer_;
-    size_t                     sourceBufferTransmittedSize_;
+    std::string                pending_;
+    size_t                     pendingPos_;
 
     size_t CallbackInternal(char* curlBuffer,
                             size_t curlBufferSize)
@@ -213,65 +213,63 @@
         throw OrthancException(ErrorCode_InternalError);
       }
 
-      // Read chunks from the body stream so as to fill the target buffer
-      size_t curlBufferFilledSize = 0;
-      size_t sourceRemainingSize = sourceBuffer_.size() - sourceBufferTransmittedSize_;
-      bool hasMore = true;
-      
-      while (sourceRemainingSize < curlBufferSize && hasMore)
+      if (pendingPos_ + curlBufferSize <= pending_.size())
+      {
+        assert(sizeof(char) == 1);
+        memcpy(curlBuffer, &pending_[pendingPos_], curlBufferSize);
+        pendingPos_ += curlBufferSize;
+        return curlBufferSize;
+      }
+      else
       {
-        if (sourceRemainingSize > 0)
+        ChunkedBuffer buffer;
+        buffer.SetPendingBufferSize(curlBufferSize);
+
+        if (pendingPos_ < pending_.size())
         {
-          // transmit the end of current source buffer
-          memcpy(curlBuffer + curlBufferFilledSize,
-                 sourceBuffer_.data() + sourceBufferTransmittedSize_, sourceRemainingSize);
-
-          curlBufferFilledSize += sourceRemainingSize;
+          buffer.AddChunk(&pending_[pendingPos_], pending_.size() - pendingPos_);
+        }
+        
+        // Read chunks from the body stream so as to fill the target buffer
+        std::string chunk;
+        
+        while (buffer.GetNumBytes() < curlBufferSize &&
+               body_->ReadNextChunk(chunk))
+        {
+          buffer.AddChunk(chunk);
         }
 
-        // start filling a new source buffer
-        sourceBufferTransmittedSize_ = 0;
-        sourceBuffer_.clear();
-
-        hasMore = body_->ReadNextChunk(sourceBuffer_);
-
-        sourceRemainingSize = sourceBuffer_.size();
-      }
+        buffer.Flatten(pending_);
+        pendingPos_ = std::min(pending_.size(), curlBufferSize);
 
-      if (sourceRemainingSize > 0 &&
-          curlBufferSize > curlBufferFilledSize)
-      {
-        size_t s = std::min(sourceRemainingSize, curlBufferSize - curlBufferFilledSize);
+        if (pendingPos_ != 0)
+        {
+          memcpy(curlBuffer, pending_.c_str(), pendingPos_);
+        }
 
-        memcpy(curlBuffer + curlBufferFilledSize,
-               sourceBuffer_.data() + sourceBufferTransmittedSize_, s);
-
-        sourceBufferTransmittedSize_ += s;
-        curlBufferFilledSize += s;
+        return pendingPos_;
       }
-
-      return curlBufferFilledSize;
     }
     
   public:
     CurlRequestBody() :
       body_(NULL),
-      sourceBufferTransmittedSize_(0)
+      pendingPos_(0)
     {
     }
 
     void SetBody(HttpClient::IRequestBody& body)
     {
       body_ = &body;
-      sourceBufferTransmittedSize_ = 0;
-      sourceBuffer_.clear();
+      pending_.clear();
+      pendingPos_ = 0;
     }
 
     void Clear()
     {
       body_ = NULL;
-      sourceBufferTransmittedSize_ = 0;
-      sourceBuffer_.clear();
+      pending_.clear();
+      pendingPos_ = 0;
     }
 
     bool IsValid() const