comparison Core/HttpClient.cpp @ 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 96780208dbd7
children 19d88138c30f
comparison
equal deleted inserted replaced
3589:a648c2d67a65 3590:d5740d3b1d67
42 42
43 #include <string.h> 43 #include <string.h>
44 #include <curl/curl.h> 44 #include <curl/curl.h>
45 #include <boost/algorithm/string/predicate.hpp> 45 #include <boost/algorithm/string/predicate.hpp>
46 #include <boost/thread/mutex.hpp> 46 #include <boost/thread/mutex.hpp>
47 47 #include <list>
48 48
49 // Default timeout = 60 seconds (in Orthanc <= 1.5.6, it was 10 seconds) 49 // Default timeout = 60 seconds (in Orthanc <= 1.5.6, it was 10 seconds)
50 static const unsigned int DEFAULT_HTTP_TIMEOUT = 60; 50 static const unsigned int DEFAULT_HTTP_TIMEOUT = 60;
51 51
52 52
207 207
208 class HttpClient::CurlRequestBody : public boost::noncopyable 208 class HttpClient::CurlRequestBody : public boost::noncopyable
209 { 209 {
210 private: 210 private:
211 HttpClient::IRequestBody* body_; 211 HttpClient::IRequestBody* body_;
212 std::string buffer_; 212 std::string sourceBuffer_;
213 size_t sourceBufferTransmittedSize_;
213 214
214 size_t CallbackInternal(char* curlBuffer, 215 size_t CallbackInternal(char* curlBuffer,
215 size_t curlBufferSize) 216 size_t curlBufferSize)
216 { 217 {
217 if (body_ == NULL) 218 if (body_ == NULL)
223 { 224 {
224 throw OrthancException(ErrorCode_InternalError); 225 throw OrthancException(ErrorCode_InternalError);
225 } 226 }
226 227
227 // Read chunks from the body stream so as to fill the target buffer 228 // Read chunks from the body stream so as to fill the target buffer
228 std::string chunk; 229 size_t curlBufferFilledSize = 0;
230 size_t sourceRemainingSize = sourceBuffer_.size() - sourceBufferTransmittedSize_;
231 bool hasMore = true;
229 232
230 while (buffer_.size() < curlBufferSize && 233 while (sourceRemainingSize < curlBufferSize && hasMore)
231 body_->ReadNextChunk(chunk)) 234 {
232 { 235 if (sourceRemainingSize > 0)
233 buffer_ += chunk; 236 {
234 } 237 // transmit the end of current source buffer
235 238 memcpy(curlBuffer + curlBufferFilledSize, sourceBuffer_.data() + sourceBufferTransmittedSize_, sourceRemainingSize);
236 size_t s = std::min(buffer_.size(), curlBufferSize); 239
237 240 curlBufferFilledSize += sourceRemainingSize;
238 if (s != 0) 241 }
239 { 242
240 memcpy(curlBuffer, buffer_.c_str(), s); 243 // start filling a new source buffer
241 244 sourceBufferTransmittedSize_ = 0;
242 // Remove the bytes that were actually sent from the buffer 245 sourceBuffer_.clear();
243 buffer_.erase(0, s); 246
244 } 247 hasMore = body_->ReadNextChunk(sourceBuffer_);
245 248
246 return s; 249 sourceRemainingSize = sourceBuffer_.size();
250 }
251
252 if (sourceRemainingSize > 0 && (curlBufferSize - curlBufferFilledSize) > 0)
253 {
254 size_t s = std::min(sourceRemainingSize, curlBufferSize - curlBufferFilledSize);
255
256 memcpy(curlBuffer + curlBufferFilledSize, sourceBuffer_.data() + sourceBufferTransmittedSize_, s);
257
258 sourceBufferTransmittedSize_ += s;
259 curlBufferFilledSize += s;
260 }
261
262 return curlBufferFilledSize;
247 } 263 }
248 264
249 public: 265 public:
250 CurlRequestBody() : 266 CurlRequestBody() :
251 body_(NULL) 267 body_(NULL),
268 sourceBufferTransmittedSize_(0)
252 { 269 {
253 } 270 }
254 271
255 void SetBody(HttpClient::IRequestBody& body) 272 void SetBody(HttpClient::IRequestBody& body)
256 { 273 {
257 body_ = &body; 274 body_ = &body;
258 buffer_.clear(); 275 sourceBufferTransmittedSize_ = 0;
276 sourceBuffer_.clear();
259 } 277 }
260 278
261 void Clear() 279 void Clear()
262 { 280 {
263 body_ = NULL; 281 body_ = NULL;
264 buffer_.clear(); 282 sourceBufferTransmittedSize_ = 0;
283 sourceBuffer_.clear();
265 } 284 }
266 285
267 bool IsValid() const 286 bool IsValid() const
268 { 287 {
269 return body_ != NULL; 288 return body_ != NULL;