Skip to content

Commit 01140d2

Browse files
committed
Fixing HTTP 1.1 pipelining support implementation, so it does not fail when it tries to re-use a connection when the server gives up.
1 parent 0aed5d1 commit 01140d2

File tree

3 files changed

+63
-44
lines changed

3 files changed

+63
-44
lines changed

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ namespace boost { namespace network { namespace http { namespace impl {
224224

225225
void close_socket() {
226226
if (is_open()) {
227+
socket_.lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
227228
socket_.lowest_layer().close();
228229
}
229230
}
@@ -275,7 +276,7 @@ namespace boost { namespace network { namespace http { namespace impl {
275276

276277
bool is_open() { return socket_.is_open(); }
277278

278-
void close_socket() { if (is_open()) { socket_.close(); } }
279+
void close_socket() { if (is_open()) { socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both); socket_.close(); } }
279280

280281
private:
281282

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

+59-42
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ namespace boost { namespace network { namespace http {
4040
, get_connection_(get_connection) {}
4141

4242
basic_response<Tag> send_request(string_type const & method, basic_request<Tag> request_, bool get_body) {
43-
return send_request_recursive(method, request_, get_body, 0);
43+
return send_request_impl(method, request_, get_body);
4444
}
4545

4646
~connection_impl () {
@@ -49,50 +49,67 @@ namespace boost { namespace network { namespace http {
4949

5050
private:
5151

52-
basic_response<Tag> send_request_recursive(string_type const & method, basic_request<Tag> request_, bool get_body, int count) {
53-
if (count >= BOOST_NETWORK_HTTP_MAXIMUM_REDIRECT_COUNT)
54-
throw std::runtime_error("Redirection exceeds maximum redirect count.");
55-
56-
basic_response<Tag> response_;
57-
// check if the socket is open first
58-
if (!pimpl->is_open()) {
59-
pimpl->init_socket(request_.host(), lexical_cast<string_type>(request_.port()));
60-
}
61-
pimpl->send_request_impl(method, request_);
62-
response_ = basic_response<Tag>();
63-
response_ << source(request_.host());
64-
65-
boost::asio::streambuf response_buffer;
66-
pimpl->read_status(response_, response_buffer);
67-
pimpl->read_headers(response_, response_buffer);
68-
if (
69-
get_body && response_.status() != 304
70-
&& (response_.status() != 204)
71-
&& not (response_.status() >= 100 && response_.status() <= 199)
72-
) {
73-
pimpl->read_body(response_, response_buffer);
74-
}
75-
76-
if (connection_follow_redirect_) {
77-
boost::uint16_t status = response_.status();
78-
if (status >= 300 && status <= 307) {
79-
typename headers_range<basic_response<Tag> >::type location_range = headers(response_)["Location"];
80-
typename range_iterator<typename headers_range<basic_request<Tag> >::type>::type location_header = begin(location_range);
81-
if (location_header != end(location_range)) {
82-
request_.uri(location_header->second);
83-
connection_ptr connection_;
84-
connection_ = get_connection_(resolver_, request_);
85-
return connection_->send_request_recursive(method, request_, get_body, ++count);
86-
} else throw std::runtime_error("Location header not defined in redirect response.");
52+
basic_response<Tag> send_request_impl(string_type const & method, basic_request<Tag> request_, bool get_body) {
53+
boost::uint8_t count = 0;
54+
bool retry = false;
55+
do {
56+
if (count >= BOOST_NETWORK_HTTP_MAXIMUM_REDIRECT_COUNT)
57+
throw std::runtime_error("Redirection exceeds maximum redirect count.");
58+
59+
basic_response<Tag> response_;
60+
// check if the socket is open first
61+
if (!pimpl->is_open()) {
62+
pimpl->init_socket(request_.host(), lexical_cast<string_type>(request_.port()));
63+
}
64+
response_ = basic_response<Tag>();
65+
response_ << source(request_.host());
66+
67+
pimpl->send_request_impl(method, request_);
68+
boost::asio::streambuf response_buffer;
69+
70+
try {
71+
pimpl->read_status(response_, response_buffer);
72+
} catch (boost::system::system_error & e) {
73+
if (!retry && e.code() == boost::asio::error::eof) {
74+
retry = true;
75+
pimpl->init_socket(request_.host(), lexical_cast<string_type>(request_.port()));
76+
continue;
77+
}
78+
throw; // it's a retry, and there's something wrong.
79+
}
80+
81+
pimpl->read_headers(response_, response_buffer);
82+
83+
if (
84+
get_body && response_.status() != 304
85+
&& (response_.status() != 204)
86+
&& not (response_.status() >= 100 && response_.status() <= 199)
87+
) {
88+
pimpl->read_body(response_, response_buffer);
8789
}
88-
}
8990

90-
typename headers_range<basic_response<Tag> >::type connection_range = headers(response_)["Connection"];
91-
if (!empty(connection_range) && begin(connection_range)->second == string_type("close")) {
92-
pimpl->close_socket();
93-
}
91+
if (connection_follow_redirect_) {
92+
boost::uint16_t status = response_.status();
93+
if (status >= 300 && status <= 307) {
94+
typename headers_range<basic_response<Tag> >::type location_range = headers(response_)["Location"];
95+
typename range_iterator<typename headers_range<basic_request<Tag> >::type>::type location_header = begin(location_range);
96+
if (location_header != end(location_range)) {
97+
request_.uri(location_header->second);
98+
connection_ptr connection_;
99+
connection_ = get_connection_(resolver_, request_);
100+
++count;
101+
continue;
102+
} else throw std::runtime_error("Location header not defined in redirect response.");
103+
}
104+
}
105+
106+
typename headers_range<basic_response<Tag> >::type connection_range = headers(response_)["Connection"];
107+
if (!empty(connection_range) && begin(connection_range)->second == string_type("close")) {
108+
pimpl->close_socket();
109+
}
94110

95-
return response_;
111+
return response_;
112+
} while(true);
96113
}
97114

98115
shared_ptr<http::impl::sync_connection_base<Tag,version_major,version_minor> > pimpl;

libs/network/test/http_1_1_test.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(http_cached_resolve, T, tag_types) {
5858
http::basic_client<T, 1, 1> client_(http::basic_client<T, 1, 1>::cache_resolved);
5959
http::basic_response<T> response_;
6060
BOOST_CHECK_NO_THROW ( response_ = client_.get(request) );
61-
BOOST_CHECK_NO_THROW ( response_ = client_.get(other_request) );
61+
//BOOST_CHECK_NO_THROW ( response_ = client_.get(other_request) );
62+
response_ = client_.get(other_request);
6263
}
6364

6465
BOOST_AUTO_TEST_CASE_TEMPLATE(http_redirection_test, T, tag_types) {

0 commit comments

Comments
 (0)