@@ -37,6 +37,82 @@ namespace network {
37
37
namespace http {
38
38
namespace impl {
39
39
40
+ template <class Tag >
41
+ struct chunk_encoding_parser {
42
+ chunk_encoding_parser () : state(state_t ::header), chunk_size(0 ) {}
43
+
44
+ enum class state_t { header, header_end, data, data_end };
45
+
46
+ state_t state;
47
+ size_t chunk_size;
48
+ std::array<typename char_<Tag>::type, 1024 > buffer;
49
+
50
+ void update_chunk_size (
51
+ boost::iterator_range<typename std::array<
52
+ typename char_<Tag>::type, 1024 >::const_iterator> const &range) {
53
+ if (range.empty ()) return ;
54
+ std::stringstream ss;
55
+ ss << std::hex << range;
56
+ size_t size;
57
+ ss >> size;
58
+ // New digits are appended as LSBs
59
+ chunk_size = (chunk_size << (range.size () * 4 )) | size;
60
+ }
61
+
62
+ boost::iterator_range<
63
+ typename std::array<typename char_<Tag>::type, 1024 >::const_iterator>
64
+ operator ()(
65
+ boost::iterator_range<typename std::array<
66
+ typename char_<Tag>::type, 1024 >::const_iterator> const &range) {
67
+ auto iter = boost::begin (range);
68
+ auto begin = iter;
69
+ auto pos = boost::begin (buffer);
70
+
71
+ while (iter != boost::end (range)) switch (state) {
72
+ case state_t ::header:
73
+ iter = std::find (iter, boost::end (range), ' \r ' );
74
+ update_chunk_size (boost::make_iterator_range (begin, iter));
75
+ if (iter != boost::end (range)) {
76
+ state = state_t ::header_end;
77
+ ++iter;
78
+ }
79
+ break ;
80
+
81
+ case state_t ::header_end:
82
+ BOOST_ASSERT (*iter == ' \n ' );
83
+ ++iter;
84
+ state = state_t ::data;
85
+ break ;
86
+
87
+ case state_t ::data:
88
+ if (chunk_size == 0 ) {
89
+ BOOST_ASSERT (*iter == ' \r ' );
90
+ ++iter;
91
+ state = state_t ::data_end;
92
+ } else {
93
+ auto len = std::min (chunk_size,
94
+ (size_t )std::distance (iter, boost::end (range)));
95
+ begin = iter;
96
+ iter = std::next (iter, len);
97
+ pos = std::copy (begin, iter, pos);
98
+ chunk_size -= len;
99
+ }
100
+ break ;
101
+
102
+ case state_t ::data_end:
103
+ BOOST_ASSERT (*iter == ' \n ' );
104
+ ++iter;
105
+ begin = iter;
106
+ state = state_t ::header;
107
+ break ;
108
+
109
+ default :
110
+ BOOST_ASSERT (false && " Bug, report this to the developers!" );
111
+ }
112
+ return boost::make_iterator_range (boost::begin (buffer), pos);
113
+ }
114
+ };
115
+
40
116
template <class Tag , unsigned version_major, unsigned version_minor>
41
117
struct async_connection_base ;
42
118
@@ -72,8 +148,10 @@ struct http_async_connection
72
148
73
149
http_async_connection (resolver_type& resolver, resolve_function resolve,
74
150
bool follow_redirect, int timeout,
151
+ bool remove_chunk_markers,
75
152
connection_delegate_ptr delegate)
76
153
: timeout_(timeout),
154
+ remove_chunk_markers_ (remove_chunk_markers),
77
155
timer_(resolver.get_io_service()),
78
156
is_timedout_(false ),
79
157
follow_redirect_(follow_redirect),
@@ -348,8 +426,11 @@ struct http_async_connection
348
426
349
427
// The invocation of the callback is synchronous to allow us to
350
428
// wait before scheduling another read.
351
- callback (make_iterator_range (begin, end), ec);
352
-
429
+ if (this ->is_chunk_encoding && remove_chunk_markers_) {
430
+ callback (parse_chunk_encoding (make_iterator_range (begin, end)), ec);
431
+ } else {
432
+ callback (make_iterator_range (begin, end), ec);
433
+ }
353
434
auto self = this ->shared_from_this ();
354
435
delegate_->read_some (
355
436
boost::asio::mutable_buffers_1 (this ->part .data (),
@@ -388,14 +469,31 @@ struct http_async_connection
388
469
// We call the callback function synchronously passing the error
389
470
// condition (in this case, end of file) so that it can handle it
390
471
// appropriately.
391
- callback (make_iterator_range (begin, end), ec);
472
+ if (this ->is_chunk_encoding && remove_chunk_markers_) {
473
+ callback (parse_chunk_encoding (make_iterator_range (begin, end)), ec);
474
+ } else {
475
+ callback (make_iterator_range (begin, end), ec);
476
+ }
392
477
} else {
393
478
string_type body_string;
394
- std::swap (body_string, this ->partial_parsed );
395
- body_string.append (this ->part .begin (), this ->part .begin () + bytes_transferred);
396
- if (this ->is_chunk_encoding ) {
397
- this ->body_promise .set_value (parse_chunk_encoding (body_string));
479
+ if (this ->is_chunk_encoding && remove_chunk_markers_) {
480
+ for (size_t i = 0 ; i < this ->partial_parsed .size (); i += 1024 ) {
481
+ auto range = parse_chunk_encoding (boost::make_iterator_range (
482
+ this ->partial_parsed .data () + i,
483
+ this ->partial_parsed .data () +
484
+ std::min (i + 1024 , this ->partial_parsed .size ())));
485
+ body_string.append (boost::begin (range), boost::end (range));
486
+ }
487
+ this ->partial_parsed .clear ();
488
+ auto range = parse_chunk_encoding (boost::make_iterator_range (
489
+ this ->part .begin (),
490
+ this ->part .begin () + bytes_transferred));
491
+ body_string.append (boost::begin (range), boost::end (range));
492
+ this ->body_promise .set_value (body_string);
398
493
} else {
494
+ std::swap (body_string, this ->partial_parsed );
495
+ body_string.append (this ->part .begin (),
496
+ this ->part .begin () + bytes_transferred);
399
497
this ->body_promise .set_value (body_string);
400
498
}
401
499
}
@@ -417,7 +515,11 @@ struct http_async_connection
417
515
this ->part .begin ();
418
516
typename protocol_base::buffer_type::const_iterator end = begin;
419
517
std::advance (end, bytes_transferred);
420
- callback (make_iterator_range (begin, end), ec);
518
+ if (this ->is_chunk_encoding && remove_chunk_markers_) {
519
+ callback (parse_chunk_encoding (make_iterator_range (begin, end)), ec);
520
+ } else {
521
+ callback (make_iterator_range (begin, end), ec);
522
+ }
421
523
auto self = this ->shared_from_this ();
422
524
delegate_->read_some (
423
525
boost::asio::mutable_buffers_1 (this ->part .data (),
@@ -476,38 +578,8 @@ struct http_async_connection
476
578
}
477
579
}
478
580
479
- string_type parse_chunk_encoding (string_type& body_string) {
480
- string_type body;
481
- string_type crlf = " \r\n " ;
482
-
483
- typename string_type::iterator begin = body_string.begin ();
484
- for (typename string_type::iterator iter =
485
- std::search (begin, body_string.end (), crlf.begin (), crlf.end ());
486
- iter != body_string.end ();
487
- iter =
488
- std::search (begin, body_string.end (), crlf.begin (), crlf.end ())) {
489
- string_type line (begin, iter);
490
- if (line.empty ()) {
491
- break ;
492
- }
493
- std::stringstream stream (line);
494
- int len;
495
- stream >> std::hex >> len;
496
- std::advance (iter, 2 );
497
- if (len == 0 ) {
498
- break ;
499
- }
500
- if (len <= body_string.end () - iter) {
501
- body.insert (body.end (), iter, iter + len);
502
- std::advance (iter, len + 2 );
503
- }
504
- begin = iter;
505
- }
506
-
507
- return body;
508
- }
509
-
510
581
int timeout_;
582
+ bool remove_chunk_markers_;
511
583
boost::asio::steady_timer timer_;
512
584
bool is_timedout_;
513
585
bool follow_redirect_;
@@ -517,6 +589,7 @@ struct http_async_connection
517
589
connection_delegate_ptr delegate_;
518
590
boost::asio::streambuf command_streambuf;
519
591
string_type method;
592
+ chunk_encoding_parser<Tag> parse_chunk_encoding;
520
593
};
521
594
522
595
} // namespace impl
0 commit comments