Mercurial > hg > orthanc
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; |