1111
1212#include < iterator>
1313#include < cstdint>
14+ #include < iostream>
1415#include < boost/algorithm/string/trim.hpp>
1516#include < boost/asio/steady_timer.hpp>
1617#include < boost/asio/placeholders.hpp>
@@ -37,6 +38,77 @@ namespace network {
3738namespace http {
3839namespace impl {
3940
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+
40112template <class Tag ,unsigned version_major,unsigned version_minor>
41113struct async_connection_base ;
42114
@@ -72,8 +144,10 @@ struct http_async_connection
72144
73145http_async_connection (resolver_type& resolver, resolve_function resolve,
74146bool follow_redirect,int timeout,
147+ bool remove_chunk_markers,
75148 connection_delegate_ptr delegate)
76149 : timeout_(timeout),
150+ remove_chunk_markers_ (remove_chunk_markers),
77151 timer_(resolver.get_io_service()),
78152 is_timedout_(false ),
79153 follow_redirect_(follow_redirect),
@@ -348,8 +422,11 @@ struct http_async_connection
348422
349423// The invocation of the callback is synchronous to allow us to
350424// 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+ }
353430auto self =this ->shared_from_this ();
354431 delegate_->read_some (
355432boost::asio::mutable_buffers_1 (this ->part .data (),
@@ -388,14 +465,28 @@ struct http_async_connection
388465// We call the callback function synchronously passing the error
389466// condition (in this case, end of file) so that it can handle it
390467// 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+ }
392473 }else {
393474 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);
398487 }else {
488+ std::swap (body_string,this ->partial_parsed );
489+ body_string.append (this ->part .begin (),this ->part .begin () + bytes_transferred);
399490this ->body_promise .set_value (body_string);
400491 }
401492 }
@@ -417,7 +508,11 @@ struct http_async_connection
417508this ->part .begin ();
418509typename protocol_base::buffer_type::const_iterator end = begin;
419510std::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+ }
421516auto self =this ->shared_from_this ();
422517 delegate_->read_some (
423518boost::asio::mutable_buffers_1 (this ->part .data (),
@@ -476,38 +571,39 @@ struct http_async_connection
476571 }
477572 }
478573
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- }
574+ // string_type parse_chunk_encoding(string_type& body_string) {
575+ // string_type body;
576+ // string_type crlf = "\r\n";
506577
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+ // }
509604
510605int timeout_;
606+ bool remove_chunk_markers_;
511607 boost::asio::steady_timer timer_;
512608bool is_timedout_;
513609bool follow_redirect_;
@@ -517,6 +613,7 @@ struct http_async_connection
517613 connection_delegate_ptr delegate_;
518614 boost::asio::streambuf command_streambuf;
519615 string_type method;
616+ chunk_encoding_parser<Tag> parse_chunk_encoding;
520617};
521618
522619}// namespace impl