11
11
12
12
#include < iterator>
13
13
#include < cstdint>
14
+ #include < iostream>
14
15
#include < boost/algorithm/string/trim.hpp>
15
16
#include < boost/asio/steady_timer.hpp>
16
17
#include < boost/asio/placeholders.hpp>
@@ -37,6 +38,77 @@ namespace network {
37
38
namespace http {
38
39
namespace impl {
39
40
41
+ template <class Tag >
42
+ struct chunk_encoding_parser {
43
+
44
+ chunk_encoding_parser () : state(state_t ::header), chunk_size(0 ) {}
45
+
46
+ enum state_t { header, header_end, data, data_end };
47
+
48
+ state_t state;
49
+ size_t chunk_size;
50
+ std::array<typename char_<Tag>::type, 1024 > buffer;
51
+
52
+ void update_chunk_size (boost::iterator_range<typename std::array<typename char_<Tag>::type, 1024 >::const_iterator> const & range) {
53
+ if (range.empty ())
54
+ return ;
55
+ std::stringstream ss;
56
+ ss << std::hex << range;
57
+ size_t size;
58
+ ss >> size;
59
+ chunk_size = (chunk_size << (range.size ()*4 )) + size;
60
+ }
61
+
62
+ boost::iterator_range<typename std::array<typename char_<Tag>::type, 1024 >::const_iterator> operator ()(boost::iterator_range<typename std::array<typename char_<Tag>::type, 1024 >::const_iterator> const & range) {
63
+ auto iter = boost::begin (range);
64
+ auto begin = iter;
65
+ auto pos = boost::begin (buffer);
66
+
67
+ while (iter != boost::end (range))
68
+ switch (state) {
69
+ case state_t ::header:
70
+ iter = std::find (iter, boost::end (range), ' \r ' );
71
+ update_chunk_size (boost::make_iterator_range (begin, iter));
72
+ if (iter != boost::end (range)) {
73
+ state = state_t ::header_end;
74
+ ++iter;
75
+ }
76
+ break ;
77
+
78
+ case state_t ::header_end:
79
+ BOOST_ASSERT (*iter == ' \n ' );
80
+ ++iter;
81
+ state = state_t ::data;
82
+ break ;
83
+
84
+ case state_t ::data:
85
+ if (chunk_size == 0 ) {
86
+ BOOST_ASSERT (*iter == ' \r ' );
87
+ ++iter;
88
+ state = state_t ::data_end;
89
+ } else {
90
+ auto len = std::min (chunk_size, (size_t )std::distance (iter, boost::end (range)));
91
+ begin = iter;
92
+ iter = std::next (iter, len);
93
+ pos = std::copy (begin, iter, pos);
94
+ chunk_size -= len;
95
+ }
96
+ break ;
97
+
98
+ case state_t ::data_end:
99
+ BOOST_ASSERT (*iter == ' \n ' );
100
+ ++iter;
101
+ begin = iter;
102
+ state = state_t ::header;
103
+ break ;
104
+
105
+ default :
106
+ BOOST_ASSERT (false && " Bug, report this to the developers!" );
107
+ }
108
+ return boost::make_iterator_range (boost::begin (buffer), pos);
109
+ }
110
+ };
111
+
40
112
template <class Tag , unsigned version_major, unsigned version_minor>
41
113
struct async_connection_base ;
42
114
@@ -72,8 +144,10 @@ struct http_async_connection
72
144
73
145
http_async_connection (resolver_type& resolver, resolve_function resolve,
74
146
bool follow_redirect, int timeout,
147
+ bool remove_chunk_markers,
75
148
connection_delegate_ptr delegate)
76
149
: timeout_(timeout),
150
+ remove_chunk_markers_ (remove_chunk_markers),
77
151
timer_(resolver.get_io_service()),
78
152
is_timedout_(false ),
79
153
follow_redirect_(follow_redirect),
@@ -348,8 +422,11 @@ struct http_async_connection
348
422
349
423
// The invocation of the callback is synchronous to allow us to
350
424
// wait before scheduling another read.
351
- callback (make_iterator_range (begin, end), ec);
352
-
425
+ if (this ->is_chunk_encoding && remove_chunk_markers_) {
426
+ callback (parse_chunk_encoding (make_iterator_range (begin, end)), ec);
427
+ } else {
428
+ callback (make_iterator_range (begin, end), ec);
429
+ }
353
430
auto self = this ->shared_from_this ();
354
431
delegate_->read_some (
355
432
boost::asio::mutable_buffers_1 (this ->part .data (),
@@ -388,14 +465,28 @@ struct http_async_connection
388
465
// We call the callback function synchronously passing the error
389
466
// condition (in this case, end of file) so that it can handle it
390
467
// appropriately.
391
- callback (make_iterator_range (begin, end), ec);
468
+ if (this ->is_chunk_encoding && remove_chunk_markers_) {
469
+ callback (parse_chunk_encoding (make_iterator_range (begin, end)), ec);
470
+ } else {
471
+ callback (make_iterator_range (begin, end), ec);
472
+ }
392
473
} else {
393
474
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));
475
+ if (this ->is_chunk_encoding && remove_chunk_markers_) {
476
+ for (size_t i = 0 ; i < this ->partial_parsed .size (); i += 1024 ) {
477
+ auto range = parse_chunk_encoding (
478
+ boost::make_iterator_range (this ->partial_parsed .data () + i,
479
+ this ->partial_parsed .data () + std::min (i+1024 , this ->partial_parsed .size ())));
480
+ body_string.append (boost::begin (range), boost::end (range));
481
+ }
482
+ this ->partial_parsed .clear ();
483
+ auto range = parse_chunk_encoding (boost::make_iterator_range (this ->part .begin (),
484
+ this ->part .begin () + bytes_transferred));
485
+ body_string.append (boost::begin (range), boost::end (range));
486
+ this ->body_promise .set_value (body_string);
398
487
} else {
488
+ std::swap (body_string, this ->partial_parsed );
489
+ body_string.append (this ->part .begin (), this ->part .begin () + bytes_transferred);
399
490
this ->body_promise .set_value (body_string);
400
491
}
401
492
}
@@ -417,7 +508,11 @@ struct http_async_connection
417
508
this ->part .begin ();
418
509
typename protocol_base::buffer_type::const_iterator end = begin;
419
510
std::advance (end, bytes_transferred);
420
- callback (make_iterator_range (begin, end), ec);
511
+ if (this ->is_chunk_encoding && remove_chunk_markers_) {
512
+ callback (parse_chunk_encoding (make_iterator_range (begin, end)), ec);
513
+ } else {
514
+ callback (make_iterator_range (begin, end), ec);
515
+ }
421
516
auto self = this ->shared_from_this ();
422
517
delegate_->read_some (
423
518
boost::asio::mutable_buffers_1 (this ->part .data (),
@@ -476,38 +571,39 @@ struct http_async_connection
476
571
}
477
572
}
478
573
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
- }
574
+ // string_type parse_chunk_encoding(string_type& body_string) {
575
+ // string_type body;
576
+ // string_type crlf = "\r\n";
506
577
507
- return body;
508
- }
578
+ // typename string_type::iterator begin = body_string.begin();
579
+ // for (typename string_type::iterator iter =
580
+ // std::search(begin, body_string.end(), crlf.begin(), crlf.end());
581
+ // iter != body_string.end();
582
+ // iter =
583
+ // std::search(begin, body_string.end(), crlf.begin(), crlf.end())) {
584
+ // string_type line(begin, iter);
585
+ // if (line.empty()) {
586
+ // break;
587
+ // }
588
+ // std::stringstream stream(line);
589
+ // int len;
590
+ // stream >> std::hex >> len;
591
+ // std::advance(iter, 2);
592
+ // if (len == 0) {
593
+ // break;
594
+ // }
595
+ // if (len <= body_string.end() - iter) {
596
+ // body.insert(body.end(), iter, iter + len);
597
+ // std::advance(iter, len + 2);
598
+ // }
599
+ // begin = iter;
600
+ // }
601
+
602
+ // return body;
603
+ // }
509
604
510
605
int timeout_;
606
+ bool remove_chunk_markers_;
511
607
boost::asio::steady_timer timer_;
512
608
bool is_timedout_;
513
609
bool follow_redirect_;
@@ -517,6 +613,7 @@ struct http_async_connection
517
613
connection_delegate_ptr delegate_;
518
614
boost::asio::streambuf command_streambuf;
519
615
string_type method;
616
+ chunk_encoding_parser<Tag> parse_chunk_encoding;
520
617
};
521
618
522
619
} // namespace impl
0 commit comments