@@ -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,10 @@ struct http_async_protocol_handler {
266
270
}
267
271
trim (header_pair.second );
268
272
headers.insert (header_pair);
273
+ if (boost::iequals (header_pair.first , " Content-Length" )) {
274
+ is_content_length = true ;
275
+ content_length = std::stoi (header_pair.second );
276
+ }
269
277
}
270
278
// determine if the body parser will need to handle chunked encoding
271
279
typename headers_range<basic_response<Tag> >::type transfer_encoding_range =
@@ -325,14 +333,61 @@ struct http_async_protocol_handler {
325
333
parsed_ok, std::distance (std::end (result_range), part_end));
326
334
}
327
335
336
+ inline bool check_parse_body_complete () const {
337
+ if (this ->is_chunk_encoding ) {
338
+ return parse_chunk_encoding_complete ();
339
+ }
340
+ if (this ->is_content_length && this ->content_length >= 0 ) {
341
+ return parse_content_length_complete ();
342
+ }
343
+ return false ;
344
+ }
345
+
346
+ inline bool parse_content_length_complete () const {
347
+ return this ->partial_parsed .length () >= this -> content_length;
348
+ }
349
+
350
+ bool parse_chunk_encoding_complete () const {
351
+ string_type body;
352
+ string_type crlf = " \r\n " ;
353
+
354
+ typename string_type::const_iterator begin = partial_parsed.begin ();
355
+ for (typename string_type::const_iterator iter =
356
+ std::search (begin, partial_parsed.end (), crlf.begin (), crlf.end ());
357
+ iter != partial_parsed.end ();
358
+ iter =
359
+ std::search (begin, partial_parsed.end (), crlf.begin (), crlf.end ())) {
360
+ string_type line (begin, iter);
361
+ if (line.empty ()) {
362
+ std::advance (iter, 2 );
363
+ begin = iter;
364
+ continue ;
365
+ }
366
+ std::stringstream stream (line);
367
+ int len;
368
+ stream >> std::hex >> len;
369
+ std::advance (iter, 2 );
370
+ if (!len) return true ;
371
+ if (len <= partial_parsed.end () - iter) {
372
+ std::advance (iter, len + 2 );
373
+ }
374
+ begin = iter;
375
+ }
376
+ return false ;
377
+ }
378
+
328
379
template <class Delegate , class Callback >
329
380
void parse_body (Delegate& delegate_, Callback callback, size_t bytes) {
330
381
// TODO(dberris): we should really not use a string for the partial body
331
382
// buffer.
332
383
partial_parsed.append (part_begin, part_begin + bytes);
333
384
part_begin = part.begin ();
334
- delegate_->read_some (
335
- boost::asio::mutable_buffers_1 (part.data (), part.size ()), callback);
385
+ if (check_parse_body_complete ()) {
386
+ callback (boost::asio::error::eof, bytes);
387
+ } else {
388
+ delegate_->read_some (
389
+ boost::asio::mutable_buffers_1 (part.data (), part.size ()), callback);
390
+ }
336
391
}
337
392
338
393
typedef response_parser<Tag> response_parser_type;
@@ -351,6 +406,9 @@ struct http_async_protocol_handler {
351
406
typename buffer_type::const_iterator part_begin;
352
407
string_type partial_parsed;
353
408
bool is_chunk_encoding;
409
+ bool is_chunk_end;
410
+ bool is_content_length;
411
+ std::size_t content_length;
354
412
};
355
413
356
414
} // namespace impl
0 commit comments