Skip to content

Commit 5cc4ea3

Browse files
author
Dean Michael Berris
committed
Fixing implementation ironing out bugs with parsing and use of Boost.Asio.
1 parent 4834464 commit 5cc4ea3

File tree

6 files changed

+66
-78
lines changed

6 files changed

+66
-78
lines changed

boost/network/protocol/http/client/async_impl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ namespace boost { namespace network { namespace http {
4848
)));
4949
}
5050

51-
~async_client()
51+
~async_client() throw ()
5252
{
5353
sentinel_.reset();
5454
lifetime_thread_->join();

boost/network/protocol/http/impl/http_async_connection.hpp

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <boost/logic/tribool.hpp>
2020
#include <boost/network/protocol/http/parser/incremental.hpp>
2121
#include <boost/network/protocol/http/message/wrappers/uri.hpp>
22+
#include <boost/array.hpp>
2223
#include <iterator>
2324

2425
namespace boost { namespace network { namespace http { namespace impl {
@@ -55,11 +56,13 @@ namespace boost { namespace network { namespace http { namespace impl {
5556
template <class U>
5657
string_type const operator() (U const & pair) const {
5758
typedef typename ostringstream<Tag>::type ostringstream_type;
59+
typedef constants<Tag> constants;
5860
ostringstream_type header_line;
5961
header_line << pair.first
60-
<< constants<Tag>::colon()
62+
<< constants::colon()
63+
<< constants::space()
6164
<< pair.second
62-
<< constants<Tag>::crlf();
65+
<< constants::crlf();
6366
return header_line.str();
6467
}
6568
};
@@ -84,12 +87,12 @@ namespace boost { namespace network { namespace http { namespace impl {
8487
if (!get_body) body_promise.set_value(string_type());
8588

8689
typename ostringstream<Tag>::type command_stream;
87-
string_type uri_str;
88-
uri_str = boost::network::http::uri(request);
90+
string_type path_str;
91+
path_str = path(request);
8992
typedef constants<Tag> constants;
9093
command_stream
9194
<< method << constants::space()
92-
<< uri_str << constants::space()
95+
<< path_str << constants::space()
9396
<< constants::http_slash() << version_major
9497
<< constants::dot() << version_minor
9598
<< constants::crlf();
@@ -122,18 +125,19 @@ namespace boost { namespace network { namespace http { namespace impl {
122125
<< constants::user_agent() << constants::colon() << constants::space() << constants::cpp_netlib_slash() << BOOST_NETLIB_VERSION << constants::crlf();
123126
}
124127

128+
command_stream << constants::crlf();
129+
125130
command_string_ = command_stream.str();
126131

127132
this->method = method;
128-
129-
resolve_(resolver_, host(request),
133+
134+
resolve_(resolver_, host(request), port(request),
130135
request_strand_->wrap(
131136
boost::bind(
132137
&http_async_connection<Tag,version_major,version_minor>::handle_resolved,
133138
http_async_connection<Tag,version_major,version_minor>::shared_from_this(),
134139
port(request),
135140
_1, _2)));
136-
137141
return temp;
138142
}
139143

@@ -217,7 +221,7 @@ namespace boost { namespace network { namespace http { namespace impl {
217221
if (!ec) {
218222
boost::asio::async_read(
219223
*socket_,
220-
response_buffer_,
224+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
221225
request_strand_->wrap(
222226
boost::bind(
223227
&http_async_connection<Tag,version_major,version_minor>::handle_received_version,
@@ -238,8 +242,10 @@ namespace boost { namespace network { namespace http { namespace impl {
238242
}
239243

240244
void parse_version() {
245+
std::cerr << '\n';
246+
241247
logic::tribool parsed_ok;
242-
typename response_parser_type::range_type result_range;
248+
typename boost::iterator_range<typename buffer_type::const_iterator> result_range;
243249
fusion::tie(parsed_ok, result_range) = response_parser_.parse_until(
244250
response_parser_type::http_version_done,
245251
part);
@@ -249,8 +255,8 @@ namespace boost { namespace network { namespace http { namespace impl {
249255
version.append(boost::begin(result_range), boost::end(result_range));
250256
algorithm::trim(version);
251257
version_promise.set_value(version);
252-
typename string_type::const_iterator end = part.end();
253-
part.assign(boost::end(result_range), end);
258+
typename buffer_type::const_iterator end = part.end();
259+
std::copy(boost::end(result_range), end, part.begin());
254260
this->parse_status();
255261
} else if (parsed_ok == false) {
256262
std::runtime_error error("Invalid Version Part.");
@@ -266,10 +272,9 @@ namespace boost { namespace network { namespace http { namespace impl {
266272
part.begin(),
267273
part.end()
268274
);
269-
string_type().swap(part);
270275
boost::asio::async_read(
271276
*socket_,
272-
response_buffer_,
277+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
273278
request_strand_->wrap(
274279
boost::bind(
275280
&http_async_connection<Tag,version_major,version_minor>::handle_received_version,
@@ -279,12 +284,8 @@ namespace boost { namespace network { namespace http { namespace impl {
279284
}
280285

281286
void handle_received_version(boost::system::error_code const & ec, std::size_t bytes_transferred) {
282-
if (!ec) {
283-
typename istream<Tag>::type input_stream(&response_buffer_);
284-
part.append(
285-
std::istream_iterator<typename char_<Tag>::type>(input_stream)
286-
, std::istream_iterator<typename char_<Tag>::type>()
287-
);
287+
if (!ec || ec == boost::asio::error::eof) {
288+
this->parse_version();
288289
} else {
289290
boost::system::system_error error(ec);
290291
version_promise.set_exception(boost::copy_exception(error));
@@ -299,7 +300,7 @@ namespace boost { namespace network { namespace http { namespace impl {
299300

300301
void parse_status() {
301302
logic::tribool parsed_ok;
302-
typename response_parser_type::range_type result_range;
303+
typename boost::iterator_range<typename buffer_type::const_iterator> result_range;
303304
fusion::tie(parsed_ok, result_range) = response_parser_.parse_until(
304305
response_parser_type::http_status_done,
305306
part);
@@ -310,8 +311,8 @@ namespace boost { namespace network { namespace http { namespace impl {
310311
trim(status);
311312
boost::uint16_t status_int = lexical_cast<boost::uint16_t>(status);
312313
status_promise.set_value(status_int);
313-
typename string_type::iterator end = part.end();
314-
part.assign(boost::end(result_range), end);
314+
typename buffer_type::const_iterator end = part.end();
315+
std::copy(boost::end(result_range), end, part.begin());
315316
this->parse_status_message();
316317
} else if (parsed_ok == false) {
317318
std::runtime_error error("Invalid status part.");
@@ -323,8 +324,8 @@ namespace boost { namespace network { namespace http { namespace impl {
323324
body_promise.set_exception(boost::copy_exception(error));
324325
} else {
325326
partial_parsed.append(part.begin(), part.end());
326-
string_type().swap(part);
327-
boost::asio::async_read(*socket_, response_buffer_,
327+
boost::asio::async_read(*socket_,
328+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
328329
request_strand_->wrap(
329330
boost::bind(
330331
&http_async_connection<Tag,version_major,version_minor>::handle_received_status,
@@ -335,11 +336,6 @@ namespace boost { namespace network { namespace http { namespace impl {
335336

336337
void handle_received_status(boost::system::error_code const & ec, size_t bytes_transferred) {
337338
if (!ec) {
338-
typename istream<Tag>::type input_stream(&response_buffer_);
339-
part.append(
340-
std::istream_iterator<typename char_<Tag>::type>(input_stream)
341-
, std::istream_iterator<typename char_<Tag>::type>()
342-
);
343339
this->parse_status();
344340
} else {
345341
boost::system::system_error error(ec);
@@ -354,7 +350,7 @@ namespace boost { namespace network { namespace http { namespace impl {
354350

355351
void parse_status_message() {
356352
logic::tribool parsed_ok;
357-
typename response_parser_type::range_type result_range;
353+
typename boost::iterator_range<typename buffer_type::const_iterator> result_range;
358354
fusion::tie(parsed_ok, result_range) = response_parser_.parse_until(
359355
response_parser_type::http_status_message_done,
360356
part);
@@ -364,8 +360,8 @@ namespace boost { namespace network { namespace http { namespace impl {
364360
status_message.append(boost::begin(result_range), boost::end(result_range));
365361
algorithm::trim(status_message);
366362
status_message_promise.set_value(status_message);
367-
typename string_type::iterator end = part.end();
368-
part.assign(boost::end(result_range), end);
363+
typename buffer_type::const_iterator end = part.end();
364+
std::copy(boost::end(result_range), end, part.c_array());
369365
this->parse_headers();
370366
} else if (parsed_ok == false) {
371367
std::runtime_error error("Invalid status message part.");
@@ -376,10 +372,9 @@ namespace boost { namespace network { namespace http { namespace impl {
376372
body_promise.set_exception(boost::copy_exception(error));
377373
} else {
378374
partial_parsed.append(part.begin(), part.end());
379-
string_type().swap(part);
380375
boost::asio::async_read(
381376
*socket_,
382-
response_buffer_,
377+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
383378
request_strand_->wrap(
384379
boost::bind(
385380
&http_async_connection<Tag,version_major,version_minor>::handle_received_status_message,
@@ -390,11 +385,6 @@ namespace boost { namespace network { namespace http { namespace impl {
390385

391386
void handle_received_status_message(boost::system::error_code const & ec, size_t bytes_transferred) {
392387
if (!ec) {
393-
typename istream<Tag>::type input_stream(&response_buffer_);
394-
part.append(
395-
std::istream_iterator<typename char_<Tag>::type>(input_stream)
396-
, std::istream_iterator<typename char_<Tag>::type>()
397-
);
398388
this->parse_status_message();
399389
} else {
400390
boost::system::system_error error(ec);
@@ -408,26 +398,24 @@ namespace boost { namespace network { namespace http { namespace impl {
408398

409399
void parse_headers() {
410400
logic::tribool parsed_ok;
411-
typename response_parser_type::range_type result_range;
401+
typename boost::iterator_range<typename buffer_type::const_iterator> result_range;
412402
fusion::tie(parsed_ok, result_range) = response_parser_.parse_until(
413403
response_parser_type::http_headers_done,
414404
part);
415405
if (parsed_ok == true) {
416406
string_type headers_string;
417407
std::swap(headers_string, partial_parsed);
418408
headers_string.append(boost::begin(result_range), boost::end(result_range));
419-
typename string_type::const_iterator end = part.end();
420-
part.assign(boost::end(result_range), end);
421-
// TODO implement the header line parsing here.
422-
this->parse_body();
409+
typename buffer_type::const_iterator end = part.end();
410+
std::copy(boost::end(result_range), end, part.begin());
411+
this->parse_body(std::distance(boost::end(result_range), end));
423412
} else if (parsed_ok == false) {
424413
std::runtime_error error("Invalid header part.");
425414
} else {
426415
partial_parsed.append(part.begin(), part.end());
427-
string_type().swap(part);
428416
boost::asio::async_read(
429417
*socket_,
430-
response_buffer_,
418+
boost::asio::mutable_buffers_1(part.c_array(), part.size()),
431419
request_strand_->wrap(
432420
boost::bind(
433421
&http_async_connection<Tag,version_major,version_minor>::handle_received_headers,
@@ -438,11 +426,6 @@ namespace boost { namespace network { namespace http { namespace impl {
438426

439427
void handle_received_headers(boost::system::error_code const & ec, size_t bytes_transferred) {
440428
if (!ec) {
441-
typename istream<Tag>::type input_stream(&response_buffer_);
442-
part.append(
443-
std::istream_iterator<typename char_<Tag>::type>(input_stream)
444-
, std::istream_iterator<typename char_<Tag>::type>()
445-
);
446429
this->parse_headers();
447430
} else {
448431
boost::system::system_error error(ec);
@@ -453,13 +436,12 @@ namespace boost { namespace network { namespace http { namespace impl {
453436
}
454437
}
455438

456-
void parse_body() {
457-
partial_parsed.append(part.begin(), part.end());
458-
string_type().swap(part);
459-
boost::asio::async_read(*socket_, response_buffer_,
439+
void parse_body(size_t bytes) {
440+
partial_parsed.append(part.begin(), bytes);
441+
boost::asio::async_read(*socket_, boost::asio::mutable_buffers_1(part.c_array(), part.size()),
460442
request_strand_->wrap(
461443
boost::bind(
462-
&http_async_connection<Tag,version_major,version_minor>::handle_received_body,
444+
&http_async_connection<Tag,version_major,version_minor>::handle_recieved_body,
463445
http_async_connection<Tag,version_major,version_minor>::shared_from_this(),
464446
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
465447
}
@@ -468,17 +450,18 @@ namespace boost { namespace network { namespace http { namespace impl {
468450
if (ec == boost::asio::error::eof) {
469451
string_type body;
470452
std::swap(body, partial_parsed);
471-
typename istream<Tag>::type input_stream(&response_buffer_);
472453
body.append(
473-
std::istream_iterator<typename char_<Tag>::type>(input_stream)
474-
, std::istream_iterator<typename char_<Tag>::type>()
454+
part.begin()
455+
, bytes_transferred
475456
);
476457
body_promise.set_value(body);
477458
// TODO set the destination value somewhere!
478459
destination_promise.set_value("");
479460
source_promise.set_value("");
480-
string_type().swap(part);
461+
part.assign('\0');
481462
response_parser_.reset();
463+
} else if (!ec) {
464+
this->parse_body(bytes_transferred);
482465
} else {
483466
boost::system::system_error error(ec);
484467
source_promise.set_exception(boost::copy_exception(error));
@@ -488,6 +471,7 @@ namespace boost { namespace network { namespace http { namespace impl {
488471
}
489472

490473
typedef response_parser<Tag> response_parser_type;
474+
typedef boost::array<typename char_<Tag>::type, 1024> buffer_type;
491475

492476
boost::shared_ptr<resolver_type> resolver_;
493477
resolve_function resolve_;
@@ -502,9 +486,8 @@ namespace boost { namespace network { namespace http { namespace impl {
502486
boost::promise<string_type> destination_promise;
503487
boost::promise<string_type> body_promise;
504488
string_type command_string_;
505-
boost::asio::streambuf response_buffer_;
506489
response_parser_type response_parser_;
507-
string_type part;
490+
buffer_type part;
508491
string_type partial_parsed;
509492
string_type method;
510493
};

boost/network/protocol/http/parser/incremental.hpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ namespace boost { namespace network { namespace http {
4444
http_headers_done
4545
};
4646

47-
typedef typename string<Tag>::type::const_iterator iterator_type;
48-
typedef iterator_range<iterator_type> range_type;
49-
5047
explicit response_parser (state_t state=http_response_begin)
5148
: state_(state) {}
5249

@@ -65,13 +62,14 @@ namespace boost { namespace network { namespace http {
6562
}
6663

6764
template <class Range>
68-
fusion::tuple<logic::tribool,range_type> parse_until(state_t stop_state, Range & range_) {
65+
fusion::tuple<logic::tribool,iterator_range<typename Range::const_iterator> > parse_until(state_t stop_state, Range & range_) {
6966
//FIXME -- find a way to make better use of the Boost.String_algorithm classifiers
7067
logic::tribool parsed_ok(logic::indeterminate);
71-
iterator_type start = boost::begin(range_),
68+
typename Range::const_iterator start = boost::begin(range_),
7269
current = start,
7370
end = boost::end(range_);
74-
range_type local_range = boost::make_iterator_range(start, end);
71+
boost::iterator_range<typename Range::const_iterator>
72+
local_range = boost::make_iterator_range(start, end);
7573
while (!boost::empty(local_range) && indeterminate(parsed_ok)) {
7674
current = boost::begin(local_range);
7775
if (state_ == stop_state) {

boost/network/protocol/http/policies/async_connection.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,14 @@ namespace boost { namespace network { namespace http {
5454
typedef boost::shared_ptr<connection_impl> connection_ptr;
5555
connection_ptr get_connection(boost::shared_ptr<resolver_type> resolver, basic_request<typename sync_only<Tag>::type> const & request_) {
5656
string_type protocol_ = protocol(request_);
57+
boost::uint16_t port_ = port(request_);
5758
connection_ptr connection_(
5859
new connection_impl(
5960
follow_redirect_
6061
, boost::bind(
6162
&async_connection_policy<Tag, version_major, version_minor>::resolve,
6263
this,
63-
_1, _2, _3
64+
_1, _2, _3, _4
6465
)
6566
, resolver
6667
, boost::iequals(protocol_, string_type("https"))

0 commit comments

Comments
 (0)