Skip to content

Commit 13e5dd5

Browse files
leecoderjellevdd
authored andcommitted
Added client timeout option
1 parent 800a7f5 commit 13e5dd5

19 files changed

+160
-29
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ struct async_client
3737
typedef function<bool(string_type&)> body_generator_function_type;
3838

3939
async_client(bool cache_resolved, bool follow_redirect,
40-
bool always_verify_peer,
40+
bool always_verify_peer, int timeout,
4141
boost::shared_ptr<boost::asio::io_service> service,
4242
optional<string_type> const& certificate_filename,
4343
optional<string_type> const& verify_path,
4444
optional<string_type> const& certificate_file,
4545
optional<string_type> const& private_key_file)
46-
: connection_base(cache_resolved, follow_redirect),
46+
: connection_base(cache_resolved, follow_redirect, timeout),
4747
service_ptr(service.get()
4848
? service
4949
: boost::make_shared<boost::asio::io_service>()),

boost/network/protocol/http/client/connection/async_base.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ namespace boost { namespace network { namespace http { namespace impl {
3939
bool follow_redirect,
4040
bool always_verify_peer,
4141
bool https,
42+
int timeout,
4243
optional<string_type> certificate_filename=optional<string_type>(),
4344
optional<string_type> const & verify_path=optional<string_type>(),
4445
optional<string_type> certificate_file=optional<string_type>(),
@@ -52,6 +53,7 @@ namespace boost { namespace network { namespace http { namespace impl {
5253
resolver,
5354
resolve,
5455
follow_redirect,
56+
timeout,
5557
delegate_factory_type::new_connection_delegate(
5658
resolver.get_io_service(),
5759
https,

boost/network/protocol/http/client/connection/async_normal.hpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,11 @@ struct http_async_connection
6868
connection_delegate_ptr;
6969

7070
http_async_connection(resolver_type& resolver, resolve_function resolve,
71-
bool follow_redirect, connection_delegate_ptr delegate)
72-
: follow_redirect_(follow_redirect),
71+
bool follow_redirect, int timeout,
72+
connection_delegate_ptr delegate)
73+
: timeout_(timeout),
74+
timer_(resolver.get_io_service()),
75+
follow_redirect_(follow_redirect),
7376
resolver_(resolver),
7477
resolve_(resolve),
7578
request_strand_(resolver.get_io_service()),
@@ -92,6 +95,13 @@ struct http_async_connection
9295
request_strand_.wrap(boost::bind(
9396
&this_type::handle_resolved, this_type::shared_from_this(),
9497
port_, get_body, callback, generator, _1, _2)));
98+
if (timeout_ > 0) {
99+
timer_.expires_from_now(boost::posix_time::seconds(timeout_));
100+
timer_.async_wait(request_strand_.wrap(
101+
boost::bind(&this_type::handle_timeout,
102+
this_type::shared_from_this(),
103+
_1)));
104+
}
95105
return response_;
96106
}
97107

@@ -107,6 +117,11 @@ struct http_async_connection
107117
this->source_promise.set_exception(boost::copy_exception(error));
108118
this->destination_promise.set_exception(boost::copy_exception(error));
109119
this->body_promise.set_exception(boost::copy_exception(error));
120+
this->timer_.cancel();
121+
}
122+
123+
void handle_timeout(boost::system::error_code const &ec) {
124+
if (!ec) delegate_->disconnect();
110125
}
111126

112127
void handle_resolved(boost::uint16_t port, bool get_body,
@@ -348,6 +363,7 @@ struct http_async_connection
348363
this->source_promise.set_value("");
349364
this->part.assign('\0');
350365
this->response_parser_.reset();
366+
this->timer_.cancel();
351367
} else {
352368
// This means the connection has not been closed yet and we want
353369
// to get more
@@ -436,6 +452,8 @@ struct http_async_connection
436452
return body;
437453
}
438454

455+
int timeout_;
456+
boost::asio::deadline_timer timer_;
439457
bool follow_redirect_;
440458
resolver_type& resolver_;
441459
resolve_function resolve_;

boost/network/protocol/http/client/connection/connection_delegate.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct connection_delegate {
1616
function<void(system::error_code const &, size_t)> handler) = 0;
1717
virtual void read_some(asio::mutable_buffers_1 const & read_buffer,
1818
function<void(system::error_code const &, size_t)> handler) = 0;
19+
virtual void disconnect() = 0;
1920
virtual ~connection_delegate() {}
2021
};
2122

boost/network/protocol/http/client/connection/normal_delegate.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct normal_delegate : connection_delegate {
2222
function<void(system::error_code const &, size_t)> handler);
2323
virtual void read_some(asio::mutable_buffers_1 const & read_buffer,
2424
function<void(system::error_code const &, size_t)> handler);
25+
virtual void disconnect();
2526
~normal_delegate();
2627

2728
private:

boost/network/protocol/http/client/connection/normal_delegate.ipp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ void boost::network::http::impl::normal_delegate::read_some(
3737
socket_->async_read_some(read_buffer, handler);
3838
}
3939

40+
void boost::network::http::impl::normal_delegate::disconnect() {
41+
if (socket_.get() && socket_->is_open()) {
42+
boost::system::error_code ignored;
43+
socket_->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored);
44+
if (!ignored) {
45+
socket_->close(ignored);
46+
}
47+
}
48+
}
49+
4050
boost::network::http::impl::normal_delegate::~normal_delegate() {}
4151

4252
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_NORMAL_DELEGATE_IPP_20110819 */

boost/network/protocol/http/client/connection/ssl_delegate.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct ssl_delegate : connection_delegate,
3636
virtual void read_some(
3737
asio::mutable_buffers_1 const &read_buffer,
3838
function<void(system::error_code const &, size_t)> handler);
39+
virtual void disconnect();
3940
~ssl_delegate();
4041

4142
private:

boost/network/protocol/http/client/connection/ssl_delegate.ipp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ void boost::network::http::impl::ssl_delegate::read_some(
7878
socket_->async_read_some(read_buffer, handler);
7979
}
8080

81+
void boost::network::http::impl::ssl_delegate::disconnect() {
82+
if (socket_.get() && socket_->lowest_layer().is_open()) {
83+
boost::system::error_code ignored;
84+
socket_->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored);
85+
if (!ignored) {
86+
socket_->lowest_layer().close(ignored);
87+
}
88+
}
89+
}
90+
8191
boost::network::http::impl::ssl_delegate::~ssl_delegate() {}
8292

8393
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_SSL_DELEGATE_IPP_20110819 \

boost/network/protocol/http/client/connection/sync_base.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ struct sync_connection_base {
239239
// ranges
240240
static sync_connection_base<Tag, version_major, version_minor>*
241241
new_connection(resolver_type& resolver, resolver_function_type resolve,
242-
bool https, bool always_verify_peer,
242+
bool https, bool always_verify_peer, int timeout,
243243
optional<string_type> const& certificate_filename =
244244
optional<string_type>(),
245245
optional<string_type> const& verify_path =
@@ -253,7 +253,7 @@ struct sync_connection_base {
253253
return dynamic_cast<
254254
sync_connection_base<Tag, version_major, version_minor>*>(
255255
new https_sync_connection<Tag, version_major, version_minor>(
256-
resolver, resolve,
256+
resolver, resolve, always_verify_peer, timeout,
257257
certificate_filename, verify_path,
258258
certificate_file, private_key_file));
259259
#else
@@ -263,7 +263,8 @@ struct sync_connection_base {
263263
return dynamic_cast<
264264
sync_connection_base<Tag, version_major, version_minor>*>(
265265
new http_sync_connection<Tag, version_major, version_minor>(resolver,
266-
resolve));
266+
resolve,
267+
timeout));
267268
}
268269

269270
virtual void init_socket(string_type const& hostname,

boost/network/protocol/http/client/connection/sync_normal.hpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,26 @@ struct sync_connection_base;
2525
template <class Tag, unsigned version_major, unsigned version_minor>
2626
struct http_sync_connection
2727
: public virtual sync_connection_base<Tag, version_major, version_minor>,
28-
sync_connection_base_impl<Tag, version_major, version_minor> {
28+
sync_connection_base_impl<Tag, version_major, version_minor>,
29+
boost::enable_shared_from_this<http_sync_connection<Tag, version_major, version_minor> > {
2930
typedef typename resolver_policy<Tag>::type resolver_base;
3031
typedef typename resolver_base::resolver_type resolver_type;
3132
typedef typename string<Tag>::type string_type;
3233
typedef function<typename resolver_base::resolver_iterator_pair(
3334
resolver_type&,
3435
string_type const&,
3536
string_type const&)> resolver_function_type;
37+
typedef http_sync_connection<Tag, version_major, version_minor> this_type;
3638
typedef sync_connection_base_impl<Tag, version_major, version_minor>
3739
connection_base;
3840
typedef function<bool(string_type&)> body_generator_function_type;
3941

40-
http_sync_connection(resolver_type& resolver, resolver_function_type resolve)
42+
http_sync_connection(resolver_type& resolver,
43+
resolver_function_type resolve,
44+
int timeout)
4145
: connection_base(),
46+
timeout_(timeout),
47+
timer_(resolver.get_io_service()),
4248
resolver_(resolver),
4349
resolve_(resolve),
4450
socket_(resolver.get_io_service()) {}
@@ -69,6 +75,12 @@ struct http_sync_connection
6975
connection_base::send_request_impl(socket_, method, request_buffer);
7076
}
7177
}
78+
if (timeout_ > 0) {
79+
timer_.expires_from_now(boost::posix_time::seconds(timeout_));
80+
timer_.async_wait(boost::bind(&this_type::handle_timeout,
81+
this_type::shared_from_this(),
82+
_1));
83+
}
7284
}
7385

7486
void read_status(basic_response<Tag>& response_,
@@ -97,6 +109,7 @@ struct http_sync_connection
97109
bool is_open() { return socket_.is_open(); }
98110

99111
void close_socket() {
112+
timer_.cancel();
100113
if (!is_open())
101114
return;
102115
boost::system::error_code ignored;
@@ -107,7 +120,12 @@ struct http_sync_connection
107120
}
108121

109122
private:
123+
void handle_timeout(boost::system::error_code const &ec) {
124+
if (!ec) close_socket();
125+
}
110126

127+
int timeout_;
128+
boost::asio::deadline_timer timer_;
111129
resolver_type& resolver_;
112130
resolver_function_type resolve_;
113131
boost::asio::ip::tcp::socket socket_;

0 commit comments

Comments
 (0)