@@ -33,12 +33,6 @@ namespace network {
3333 boost::asio::streambuf request_buffer_;
3434 boost::asio::streambuf response_buffer_;
3535
36- // TODO configure chunked transfer encoding
37- bool chunked_;
38-
39- // TODO configure deadline timer for timeouts
40- bool timedout_;
41-
4236 std::uint64_t total_bytes_written_, total_bytes_read_;
4337
4438request_context (
@@ -47,8 +41,6 @@ namespace network {
4741 : connection_(connection),
4842request_ (request),
4943 options_(options),
50- chunked_(false ),
51- timedout_(false ),
5244 total_bytes_written_(0 ),
5345 total_bytes_read_(0 ) {}
5446 };
@@ -63,8 +55,14 @@ namespace network {
6355
6456~impl ();
6557
58+ void set_error (const boost::system::error_code &ec,
59+ std::shared_ptr<request_context> context);
60+
6661 std::future<response>execute (std::shared_ptr<request_context> context);
6762
63+ void timeout (const boost::system::error_code &ec,
64+ std::shared_ptr<request_context> context);
65+
6866void connect (const boost::system::error_code &ec,
6967 tcp::resolver::iterator endpoint_iterator,
7068 std::shared_ptr<request_context> context);
@@ -101,7 +99,11 @@ namespace network {
10199 boost::asio::io_service::strand strand_;
102100 std::unique_ptr<client_connection::async_resolver> resolver_;
103101 std::shared_ptr<client_connection::async_connection> mock_connection_;
102+ // TODO configure deadline timer for timeouts
103+ bool timedout_;
104+ boost::asio::deadline_timer timer_;
104105 std::thread lifetime_thread_;
106+
105107 };
106108
107109client::impl::impl (client_options options)
@@ -110,6 +112,8 @@ namespace network {
110112 strand_(io_service_),
111113 resolver_(new client_connection::tcp_resolver(
112114 io_service_, options_.cache_resolved())),
115+ timedout_(false ),
116+ timer_(io_service_),
113117 lifetime_thread_([=]() { io_service_.run (); }) {}
114118
115119client::impl::impl (
@@ -120,13 +124,23 @@ namespace network {
120124sentinel_ (new boost::asio::io_service::work(io_service_)),
121125 strand_(io_service_),
122126 resolver_(std::move(mock_resolver)),
127+ timedout_(false ),
128+ timer_(io_service_),
123129 lifetime_thread_([=]() { io_service_.run (); }) {}
124130
125131client::impl::~impl () {
126132 sentinel_.reset ();
127133 lifetime_thread_.join ();
128134 }
129135
136+
137+ void client::impl::set_error (const boost::system::error_code &ec,
138+ std::shared_ptr<request_context> context) {
139+ context->response_promise_ .set_exception (std::make_exception_ptr (
140+ std::system_error (ec.value (),std::system_category ())));
141+ timer_.cancel ();
142+ }
143+
130144 std::future<response>client::impl::execute (
131145 std::shared_ptr<request_context> context) {
132146 std::future<response> res = context->response_promise_ .get_future ();
@@ -153,15 +167,29 @@ namespace network {
153167connect (ec, endpoint_iterator, context);
154168 }));
155169
170+ if (options_.timeout () >std::chrono::milliseconds (0 )) {
171+ timer_.expires_from_now (boost::posix_time::milliseconds (options_.timeout ().count ()));
172+ timer_.async_wait (strand_.wrap ([=](const boost::system::error_code &ec) {
173+ timeout (ec, context);
174+ }));
175+ }
176+
156177return res;
157178 }
158179
180+ void client::impl::timeout (const boost::system::error_code &ec,
181+ std::shared_ptr<request_context> context) {
182+ if (!ec) {
183+ context->connection_ ->disconnect ();
184+ }
185+ timedout_ =true ;
186+ }
187+
159188void client::impl::connect (const boost::system::error_code &ec,
160189 tcp::resolver::iterator endpoint_iterator,
161190 std::shared_ptr<request_context> context) {
162191if (ec) {
163- context->response_promise_ .set_exception (std::make_exception_ptr (
164- std::system_error (ec.value (),std::system_category ())));
192+ set_error (ec, context);
165193return ;
166194 }
167195
@@ -188,9 +216,13 @@ namespace network {
188216void client::impl::write_request (
189217const boost::system::error_code &ec,
190218 std::shared_ptr<request_context> context) {
219+ if (timedout_) {
220+ set_error (boost::asio::error::timed_out, context);
221+ return ;
222+ }
223+
191224if (ec) {
192- context->response_promise_ .set_exception (std::make_exception_ptr (
193- std::system_error (ec.value (),std::system_category ())));
225+ set_error (ec, context);
194226return ;
195227 }
196228
@@ -200,6 +232,7 @@ namespace network {
200232if (!request_stream) {
201233 context->response_promise_ .set_exception (std::make_exception_ptr (
202234client_exception (client_error::invalid_request)));
235+ timer_.cancel ();
203236 }
204237
205238 context->connection_ ->async_write (
@@ -213,9 +246,13 @@ namespace network {
213246void client::impl::write_body (const boost::system::error_code &ec,
214247 std::size_t bytes_written,
215248 std::shared_ptr<request_context> context) {
249+ if (timedout_) {
250+ set_error (boost::asio::error::timed_out, context);
251+ return ;
252+ }
253+
216254if (ec) {
217- context->response_promise_ .set_exception (std::make_exception_ptr (
218- std::system_error (ec.value (),std::system_category ())));
255+ set_error (ec, context);
219256return ;
220257 }
221258
@@ -245,9 +282,13 @@ namespace network {
245282void client::impl::read_response (
246283const boost::system::error_code &ec, std::size_t bytes_written,
247284 std::shared_ptr<request_context> context) {
285+ if (timedout_) {
286+ set_error (boost::asio::error::timed_out, context);
287+ return ;
288+ }
289+
248290if (ec) {
249- context->response_promise_ .set_exception (std::make_exception_ptr (
250- std::system_error (ec.value (),std::system_category ())));
291+ set_error (ec, context);
251292return ;
252293 }
253294
@@ -272,9 +313,13 @@ namespace network {
272313const boost::system::error_code &ec, std::size_t ,
273314 std::shared_ptr<request_context> context,
274315 std::shared_ptr<response> res) {
316+ if (timedout_) {
317+ set_error (boost::asio::error::timed_out, context);
318+ return ;
319+ }
320+
275321if (ec) {
276- context->response_promise_ .set_exception (std::make_exception_ptr (
277- std::system_error (ec.value (),std::system_category ())));
322+ set_error (ec, context);
278323return ;
279324 }
280325
@@ -304,9 +349,13 @@ namespace network {
304349const boost::system::error_code &ec, std::size_t ,
305350 std::shared_ptr<request_context> context,
306351 std::shared_ptr<response> res) {
352+ if (timedout_) {
353+ set_error (boost::asio::error::timed_out, context);
354+ return ;
355+ }
356+
307357if (ec) {
308- context->response_promise_ .set_exception (std::make_exception_ptr (
309- std::system_error (ec.value (),std::system_category ())));
358+ set_error (ec, context);
310359return ;
311360 }
312361
@@ -370,6 +419,7 @@ namespace network {
370419// If there's no data else to read, then set the response and exit.
371420if (bytes_read ==0 ) {
372421 context->response_promise_ .set_value (*res);
422+ timer_.cancel ();
373423return ;
374424 }
375425