2121#include < boost/network/traits/istream.hpp>
2222#include < boost/logic/tribool.hpp>
2323#include < boost/network/protocol/http/parser/incremental.hpp>
24+ #include < boost/network/protocol/http/message.hpp>
2425#include < boost/network/protocol/http/message/wrappers/uri.hpp>
2526#include < boost/network/protocol/http/client/connection/async_protocol_handler.hpp>
2627#include < boost/network/protocol/http/algorithms/linearize.hpp>
@@ -68,11 +69,20 @@ struct http_async_connection
6869 connection_delegate_ptr;
6970
7071http_async_connection (resolver_type& resolver, resolve_function resolve,
71- bool follow_redirect,int timeout,
72+ bool follow_redirect,int timeout,bool remove_chunk_markers,
73+ optional<string_type> proxy_host,
74+ optional<string_type> proxy_port,
75+ optional<string_type> proxy_username,
76+ optional<string_type> proxy_password,
7277 connection_delegate_ptr delegate)
7378 : timeout_(timeout),
7479timer_ (resolver.get_io_service()),
7580 is_timedout_(false ),
81+ remove_chunk_markers_(remove_chunk_markers),
82+ proxy_host_(proxy_host),
83+ proxy_port_(proxy_port),
84+ proxy_username_(proxy_username),
85+ proxy_password_(proxy_password),
7686 follow_redirect_(follow_redirect),
7787 resolver_(resolver),
7888 resolve_(resolve),
@@ -89,15 +99,24 @@ struct http_async_connection
8999 body_generator_function_type generator) {
90100 response response_;
91101this ->init_response (response_, get_body);
102+
103+ boost::uint16_t port_ =port (request);
104+ string_type host_ =host (request);
105+ boost::uint16_t source_port = request.source_port ();
106+
107+ string_type tcp_host = host_;
108+
109+ if (connect_via_proxy ())
110+ {
111+ tcp_host = *proxy_host_;
112+ }
113+
92114linearize (request, method, version_major, version_minor,
93115 std::ostreambuf_iterator<typename char_<Tag>::type>(
94116 &command_streambuf));
95117this ->method = method;
96- boost::uint16_t port_ =port (request);
97- string_type host_ =host (request);
98- boost::uint16_t source_port = request.source_port ();
99118
100- resolve_ (resolver_,host_ , port_,
119+ resolve_ (resolver_,tcp_host , port_,
101120 request_strand_.wrap (boost::bind (
102121 &this_type::handle_resolved,this_type::shared_from_this (),
103122 host_, port_, source_port, get_body, callback,
@@ -140,15 +159,23 @@ struct http_async_connection
140159// Here we deal with the case that there was an error encountered
141160// and
142161// that there's still more endpoints to try connecting to.
162+
163+ boost::uint16_t tcp_port = port;
164+
165+ if (connect_via_proxy ()) {
166+ tcp_port = boost::lexical_cast<boost::uint16_t >(*proxy_port_);
167+ }
168+
143169 resolver_iterator iter =boost::begin (endpoint_range);
144- asio::ip::tcp::endpointendpoint (iter->endpoint ().address (),port );
170+ asio::ip::tcp::endpointendpoint (iter->endpoint ().address (),tcp_port );
145171 delegate_->connect (
146- endpoint, host, source_port,
172+ endpoint, host,port, source_port,
147173 request_strand_.wrap (boost::bind (
148174 &this_type::handle_connected,this_type::shared_from_this (), host,
149175 port, source_port, get_body, callback, generator,
150176std::make_pair (++iter,resolver_iterator ()),
151- placeholders::error)));
177+ placeholders::error)),
178+ connect_via_proxy (), proxy_username_, proxy_password_);
152179 }else {
153180set_errors (ec ? ec : boost::asio::error::host_not_found);
154181 boost::iterator_range<const char *> range;
@@ -176,12 +203,13 @@ struct http_async_connection
176203 resolver_iterator iter =boost::begin (endpoint_range);
177204 asio::ip::tcp::endpointendpoint (iter->endpoint ().address (), port);
178205 delegate_->connect (
179- endpoint, host, source_port,
206+ endpoint, host,port, source_port,
180207 request_strand_.wrap (boost::bind (
181208 &this_type::handle_connected,this_type::shared_from_this (),
182209 host, port, source_port, get_body, callback, generator,
183210std::make_pair (++iter,resolver_iterator ()),
184- placeholders::error)));
211+ placeholders::error)),
212+ connect_via_proxy (), proxy_username_, proxy_password_);
185213 }else {
186214set_errors (ec ? ec : boost::asio::error::host_not_found);
187215 boost::iterator_range<const char *> range;
@@ -322,10 +350,24 @@ struct http_async_connection
322350// has already been parsed appropriately and we're
323351// looking to treat everything that remains in the
324352// buffer.
325- typename protocol_base::buffer_type::const_iterator begin =
326- this ->part_begin ;
327- typename protocol_base::buffer_type::const_iterator end = begin;
328- std::advance (end, remainder);
353+
354+ this ->partial_parsed .append (this ->part_begin , remainder);
355+ this ->part_begin =this ->part .begin ();
356+ string_type body_string;
357+
358+ if (remove_chunk_markers_ &&this ->is_chunk_encoding )
359+ {
360+ body_string =parse_chunk_encoding (this ->partial_parsed ,true );
361+ }
362+ else
363+ {
364+ body_string.swap (this ->partial_parsed );
365+ }
366+
367+ typename protocol_base::buffer_type::const_iterator
368+ begin = body_string.c_str (),
369+ end = begin;
370+ std::advance (end, body_string.size ());
329371
330372// We're setting the body promise here to an empty string
331373// because
@@ -346,7 +388,7 @@ struct http_async_connection
346388 &this_type::handle_received_data,
347389this_type::shared_from_this (), body, get_body, callback,
348390 placeholders::error, placeholders::bytes_transferred)));
349- }else {
391+ }else {
350392// Here we handle the body data ourself and append to an
351393// ever-growing string buffer.
352394this ->parse_body (
@@ -367,10 +409,24 @@ struct http_async_connection
367409// the end
368410// of the body processing chain.
369411if (callback) {
412+
413+ this ->partial_parsed .append (this ->part_begin , bytes_transferred);
414+ this ->part_begin =this ->part .begin ();
415+ string_type body_string;
416+
417+ if (remove_chunk_markers_ &&this ->is_chunk_encoding )
418+ {
419+ body_string =parse_chunk_encoding (this ->partial_parsed ,true );
420+ }
421+ else
422+ {
423+ body_string.swap (this ->partial_parsed );
424+ }
425+
370426typename protocol_base::buffer_type::const_iterator
371- begin =this -> part . begin (),
427+ begin =body_string. c_str (),
372428 end = begin;
373- std::advance (end,bytes_transferred );
429+ std::advance (end,body_string. size () );
374430
375431// We call the callback function synchronously passing the
376432// error
@@ -383,9 +439,9 @@ struct http_async_connection
383439std::swap (body_string,this ->partial_parsed );
384440 body_string.append (this ->part .begin (), bytes_transferred);
385441if (this ->is_chunk_encoding )
386- this -> body_promise . set_value ( parse_chunk_encoding (body_string) );
387- else
388- this ->body_promise .set_value (body_string);
442+ body_string = parse_chunk_encoding (body_string);
443+
444+ this ->body_promise .set_value (body_string);
389445 }
390446// TODO set the destination value somewhere!
391447this ->destination_promise .set_value (" " );
@@ -403,10 +459,25 @@ struct http_async_connection
403459// callback from here and make sure we're getting more
404460// data
405461// right after.
406- typename protocol_base::buffer_type::const_iterator begin =
407- this ->part .begin ();
408- typename protocol_base::buffer_type::const_iterator end = begin;
409- std::advance (end, bytes_transferred);
462+
463+ this ->partial_parsed .append (this ->part_begin , bytes_transferred);
464+ this ->part_begin =this ->part .begin ();
465+ string_type body_string;
466+
467+ if (remove_chunk_markers_ &&this ->is_chunk_encoding )
468+ {
469+ body_string =parse_chunk_encoding (this ->partial_parsed ,true );
470+ }
471+ else
472+ {
473+ body_string.swap (this ->partial_parsed );
474+ }
475+
476+ typename protocol_base::buffer_type::const_iterator
477+ begin = body_string.c_str (),
478+ end = begin;
479+ std::advance (end, body_string.size ());
480+
410481callback (make_iterator_range (begin, end), ec);
411482 delegate_->read_some (
412483boost::asio::mutable_buffers_1 (this ->part .c_array (),
@@ -415,7 +486,7 @@ struct http_async_connection
415486 &this_type::handle_received_data,
416487this_type::shared_from_this (), body, get_body, callback,
417488 placeholders::error, placeholders::bytes_transferred)));
418- }else {
489+ }else {
419490// Here we don't have a body callback. Let's
420491// make sure that we deal with the remainder
421492// from the headers part in case we do have data
@@ -462,7 +533,7 @@ struct http_async_connection
462533 }
463534 }
464535
465- string_typeparse_chunk_encoding (string_type& body_string) {
536+ string_typeparse_chunk_encoding (string_type& body_string, bool update = false ) {
466537 string_type body;
467538 string_type crlf =" \r\n " ;
468539
@@ -482,16 +553,34 @@ struct http_async_connection
482553if (len <= body_string.end () - iter) {
483554 body.insert (body.end (), iter, iter + len);
484555std::advance (iter, len +2 );
556+ begin = iter;
557+ }
558+ else
559+ {
560+ break ;
485561 }
486- begin = iter;
487562 }
488563
564+ if (update)
565+ {
566+ body_string.erase (body_string.begin (), begin);
567+ }
489568return body;
490569 }
491570
571+ bool connect_via_proxy ()const
572+ {
573+ return (proxy_host_ && proxy_port_);
574+ }
575+
492576int timeout_;
493577 boost::asio::deadline_timer timer_;
494578bool is_timedout_;
579+ bool remove_chunk_markers_;
580+ optional<string_type> proxy_host_;
581+ optional<string_type> proxy_port_;
582+ optional<string_type> proxy_username_;
583+ optional<string_type> proxy_password_;
495584bool follow_redirect_;
496585 resolver_type& resolver_;
497586 resolve_function resolve_;