@@ -246,6 +246,10 @@ struct http_async_protocol_handler {
246
246
response_parser_type::http_header_line_done);
247
247
typename headers_container<Tag>::type headers;
248
248
std::pair<string_type, string_type> header_pair;
249
+ // init params
250
+ is_content_length = false ;
251
+ content_length = -1 ;
252
+ is_chunk_end = false ;
249
253
while (!boost::empty (input_range)) {
250
254
std::tie (parsed_ok, result_range) = headers_parser.parse_until (
251
255
response_parser_type::http_header_colon, input_range);
@@ -266,6 +270,16 @@ struct http_async_protocol_handler {
266
270
}
267
271
trim (header_pair.second );
268
272
headers.insert (header_pair);
273
+ if (!is_content_length &&
274
+ boost::iequals (header_pair.first , " Content-Length" )) {
275
+ try {
276
+ content_length = std::stoll (header_pair.second );
277
+ is_content_length = true ;
278
+ }
279
+ catch (std::exception &) {
280
+ // is_content_length = false;
281
+ }
282
+ }
269
283
}
270
284
// determine if the body parser will need to handle chunked encoding
271
285
typename headers_range<basic_response<Tag> >::type transfer_encoding_range =
@@ -325,6 +339,49 @@ struct http_async_protocol_handler {
325
339
parsed_ok, std::distance (std::end (result_range), part_end));
326
340
}
327
341
342
+ inline bool check_parse_body_complete () const {
343
+ if (this ->is_chunk_encoding ) {
344
+ return parse_chunk_encoding_complete ();
345
+ }
346
+ if (this ->is_content_length && this ->content_length >= 0 ) {
347
+ return parse_content_length_complete ();
348
+ }
349
+ return false ;
350
+ }
351
+
352
+ inline bool parse_content_length_complete () const {
353
+ return this ->partial_parsed .length () >= this -> content_length;
354
+ }
355
+
356
+ bool parse_chunk_encoding_complete () const {
357
+ string_type body;
358
+ string_type crlf = " \r\n " ;
359
+
360
+ typename string_type::const_iterator begin = partial_parsed.begin ();
361
+ for (typename string_type::const_iterator iter =
362
+ std::search (begin, partial_parsed.end (), crlf.begin (), crlf.end ());
363
+ iter != partial_parsed.end ();
364
+ iter =
365
+ std::search (begin, partial_parsed.end (), crlf.begin (), crlf.end ())) {
366
+ string_type line (begin, iter);
367
+ if (line.empty ()) {
368
+ std::advance (iter, 2 );
369
+ begin = iter;
370
+ continue ;
371
+ }
372
+ std::stringstream stream (line);
373
+ int len;
374
+ stream >> std::hex >> len;
375
+ std::advance (iter, 2 );
376
+ if (!len) return true ;
377
+ if (len <= partial_parsed.end () - iter) {
378
+ std::advance (iter, len + 2 );
379
+ }
380
+ begin = iter;
381
+ }
382
+ return false ;
383
+ }
384
+
328
385
template <class Delegate , class Callback >
329
386
void parse_body (Delegate& delegate_, Callback callback, size_t bytes) {
330
387
// TODO(dberris): we should really not use a string for the partial body
@@ -333,8 +390,12 @@ struct http_async_protocol_handler {
333
390
std::advance (it, bytes);
334
391
partial_parsed.append (part_begin, it);
335
392
part_begin = part.begin ();
336
- delegate_->read_some (
337
- boost::asio::mutable_buffers_1 (part.data (), part.size ()), callback);
393
+ if (check_parse_body_complete ()) {
394
+ callback (boost::asio::error::eof, bytes);
395
+ } else {
396
+ delegate_->read_some (
397
+ boost::asio::mutable_buffers_1 (part.data (), part.size ()), callback);
398
+ }
338
399
}
339
400
340
401
typedef response_parser<Tag> response_parser_type;
@@ -353,6 +414,9 @@ struct http_async_protocol_handler {
353
414
typename buffer_type::const_iterator part_begin;
354
415
string_type partial_parsed;
355
416
bool is_chunk_encoding;
417
+ bool is_chunk_end;
418
+ bool is_content_length;
419
+ long long content_length;
356
420
};
357
421
358
422
} // namespace impl
0 commit comments