comparison 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
comparison
equal deleted inserted replaced
4150:b56f3a37a4a1 4151:8c559dd5034b
195 195
196 class HttpClient::CurlRequestBody : public boost::noncopyable 196 class HttpClient::CurlRequestBody : public boost::noncopyable
197 { 197 {
198 private: 198 private:
199 HttpClient::IRequestBody* body_; 199 HttpClient::IRequestBody* body_;
200 std::string sourceBuffer_; 200 std::string pending_;
201 size_t sourceBufferTransmittedSize_; 201 size_t pendingPos_;
202 202
203 size_t CallbackInternal(char* curlBuffer, 203 size_t CallbackInternal(char* curlBuffer,
204 size_t curlBufferSize) 204 size_t curlBufferSize)
205 { 205 {
206 if (body_ == NULL) 206 if (body_ == NULL)
211 if (curlBufferSize == 0) 211 if (curlBufferSize == 0)
212 { 212 {
213 throw OrthancException(ErrorCode_InternalError); 213 throw OrthancException(ErrorCode_InternalError);
214 } 214 }
215 215
216 // Read chunks from the body stream so as to fill the target buffer 216 if (pendingPos_ + curlBufferSize <= pending_.size())
217 size_t curlBufferFilledSize = 0; 217 {
218 size_t sourceRemainingSize = sourceBuffer_.size() - sourceBufferTransmittedSize_; 218 assert(sizeof(char) == 1);
219 bool hasMore = true; 219 memcpy(curlBuffer, &pending_[pendingPos_], curlBufferSize);
220 220 pendingPos_ += curlBufferSize;
221 while (sourceRemainingSize < curlBufferSize && hasMore) 221 return curlBufferSize;
222 { 222 }
223 if (sourceRemainingSize > 0) 223 else
224 {
225 ChunkedBuffer buffer;
226 buffer.SetPendingBufferSize(curlBufferSize);
227
228 if (pendingPos_ < pending_.size())
224 { 229 {
225 // transmit the end of current source buffer 230 buffer.AddChunk(&pending_[pendingPos_], pending_.size() - pendingPos_);
226 memcpy(curlBuffer + curlBufferFilledSize,
227 sourceBuffer_.data() + sourceBufferTransmittedSize_, sourceRemainingSize);
228
229 curlBufferFilledSize += sourceRemainingSize;
230 } 231 }
231 232
232 // start filling a new source buffer 233 // Read chunks from the body stream so as to fill the target buffer
233 sourceBufferTransmittedSize_ = 0; 234 std::string chunk;
234 sourceBuffer_.clear(); 235
235 236 while (buffer.GetNumBytes() < curlBufferSize &&
236 hasMore = body_->ReadNextChunk(sourceBuffer_); 237 body_->ReadNextChunk(chunk))
237 238 {
238 sourceRemainingSize = sourceBuffer_.size(); 239 buffer.AddChunk(chunk);
239 } 240 }
240 241
241 if (sourceRemainingSize > 0 && 242 buffer.Flatten(pending_);
242 curlBufferSize > curlBufferFilledSize) 243 pendingPos_ = std::min(pending_.size(), curlBufferSize);
243 { 244
244 size_t s = std::min(sourceRemainingSize, curlBufferSize - curlBufferFilledSize); 245 if (pendingPos_ != 0)
245 246 {
246 memcpy(curlBuffer + curlBufferFilledSize, 247 memcpy(curlBuffer, pending_.c_str(), pendingPos_);
247 sourceBuffer_.data() + sourceBufferTransmittedSize_, s); 248 }
248 249
249 sourceBufferTransmittedSize_ += s; 250 return pendingPos_;
250 curlBufferFilledSize += s; 251 }
251 }
252
253 return curlBufferFilledSize;
254 } 252 }
255 253
256 public: 254 public:
257 CurlRequestBody() : 255 CurlRequestBody() :
258 body_(NULL), 256 body_(NULL),
259 sourceBufferTransmittedSize_(0) 257 pendingPos_(0)
260 { 258 {
261 } 259 }
262 260
263 void SetBody(HttpClient::IRequestBody& body) 261 void SetBody(HttpClient::IRequestBody& body)
264 { 262 {
265 body_ = &body; 263 body_ = &body;
266 sourceBufferTransmittedSize_ = 0; 264 pending_.clear();
267 sourceBuffer_.clear(); 265 pendingPos_ = 0;
268 } 266 }
269 267
270 void Clear() 268 void Clear()
271 { 269 {
272 body_ = NULL; 270 body_ = NULL;
273 sourceBufferTransmittedSize_ = 0; 271 pending_.clear();
274 sourceBuffer_.clear(); 272 pendingPos_ = 0;
275 } 273 }
276 274
277 bool IsValid() const 275 bool IsValid() const
278 { 276 {
279 return body_ != NULL; 277 return body_ != NULL;