@@ -37,6 +37,82 @@ namespace network {
3737namespace http {
3838namespace impl {
3939
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+
40116template <class Tag ,unsigned version_major,unsigned version_minor>
41117struct async_connection_base ;
42118
@@ -72,8 +148,10 @@ struct http_async_connection
72148
73149http_async_connection (resolver_type& resolver, resolve_function resolve,
74150bool follow_redirect,int timeout,
151+ bool remove_chunk_markers,
75152 connection_delegate_ptr delegate)
76153 : timeout_(timeout),
154+ remove_chunk_markers_ (remove_chunk_markers),
77155 timer_(resolver.get_io_service()),
78156 is_timedout_(false ),
79157 follow_redirect_(follow_redirect),
@@ -348,8 +426,11 @@ struct http_async_connection
348426
349427// The invocation of the callback is synchronous to allow us to
350428// 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+ }
353434auto self =this ->shared_from_this ();
354435 delegate_->read_some (
355436boost::asio::mutable_buffers_1 (this ->part .data (),
@@ -388,14 +469,31 @@ struct http_async_connection
388469// We call the callback function synchronously passing the error
389470// condition (in this case, end of file) so that it can handle it
390471// 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+ }
392477 }else {
393478 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);
398493 }else {
494+ std::swap (body_string,this ->partial_parsed );
495+ body_string.append (this ->part .begin (),
496+ this ->part .begin () + bytes_transferred);
399497this ->body_promise .set_value (body_string);
400498 }
401499 }
@@ -417,7 +515,11 @@ struct http_async_connection
417515this ->part .begin ();
418516typename protocol_base::buffer_type::const_iterator end = begin;
419517std::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+ }
421523auto self =this ->shared_from_this ();
422524 delegate_->read_some (
423525boost::asio::mutable_buffers_1 (this ->part .data (),
@@ -476,38 +578,8 @@ struct http_async_connection
476578 }
477579 }
478580
479- string_typeparse_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_typeline (begin, iter);
490- if (line.empty ()) {
491- break ;
492- }
493- std::stringstreamstream (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-
510581int timeout_;
582+ bool remove_chunk_markers_;
511583 boost::asio::steady_timer timer_;
512584bool is_timedout_;
513585bool follow_redirect_;
@@ -517,6 +589,7 @@ struct http_async_connection
517589 connection_delegate_ptr delegate_;
518590 boost::asio::streambuf command_streambuf;
519591 string_type method;
592+ chunk_encoding_parser<Tag> parse_chunk_encoding;
520593};
521594
522595}// namespace impl