@@ -33,12 +33,6 @@ namespace network {
33
33
boost::asio::streambuf request_buffer_;
34
34
boost::asio::streambuf response_buffer_;
35
35
36
- // TODO configure chunked transfer encoding
37
- bool chunked_;
38
-
39
- // TODO configure deadline timer for timeouts
40
- bool timedout_;
41
-
42
36
std::uint64_t total_bytes_written_, total_bytes_read_;
43
37
44
38
request_context (
@@ -47,8 +41,6 @@ namespace network {
47
41
: connection_(connection),
48
42
request_ (request),
49
43
options_(options),
50
- chunked_(false ),
51
- timedout_(false ),
52
44
total_bytes_written_(0 ),
53
45
total_bytes_read_(0 ) {}
54
46
};
@@ -63,8 +55,14 @@ namespace network {
63
55
64
56
~impl ();
65
57
58
+ void set_error (const boost::system::error_code &ec,
59
+ std::shared_ptr<request_context> context);
60
+
66
61
std::future<response> execute (std::shared_ptr<request_context> context);
67
62
63
+ void timeout (const boost::system::error_code &ec,
64
+ std::shared_ptr<request_context> context);
65
+
68
66
void connect (const boost::system::error_code &ec,
69
67
tcp::resolver::iterator endpoint_iterator,
70
68
std::shared_ptr<request_context> context);
@@ -101,7 +99,11 @@ namespace network {
101
99
boost::asio::io_service::strand strand_;
102
100
std::unique_ptr<client_connection::async_resolver> resolver_;
103
101
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_;
104
105
std::thread lifetime_thread_;
106
+
105
107
};
106
108
107
109
client::impl::impl (client_options options)
@@ -110,6 +112,8 @@ namespace network {
110
112
strand_(io_service_),
111
113
resolver_(new client_connection::tcp_resolver(
112
114
io_service_, options_.cache_resolved())),
115
+ timedout_(false ),
116
+ timer_(io_service_),
113
117
lifetime_thread_([=]() { io_service_.run (); }) {}
114
118
115
119
client::impl::impl (
@@ -120,13 +124,23 @@ namespace network {
120
124
sentinel_ (new boost::asio::io_service::work(io_service_)),
121
125
strand_(io_service_),
122
126
resolver_(std::move(mock_resolver)),
127
+ timedout_(false ),
128
+ timer_(io_service_),
123
129
lifetime_thread_([=]() { io_service_.run (); }) {}
124
130
125
131
client::impl::~impl () {
126
132
sentinel_.reset ();
127
133
lifetime_thread_.join ();
128
134
}
129
135
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
+
130
144
std::future<response> client::impl::execute (
131
145
std::shared_ptr<request_context> context) {
132
146
std::future<response> res = context->response_promise_ .get_future ();
@@ -153,15 +167,29 @@ namespace network {
153
167
connect (ec, endpoint_iterator, context);
154
168
}));
155
169
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
+
156
177
return res;
157
178
}
158
179
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
+
159
188
void client::impl::connect (const boost::system::error_code &ec,
160
189
tcp::resolver::iterator endpoint_iterator,
161
190
std::shared_ptr<request_context> context) {
162
191
if (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);
165
193
return ;
166
194
}
167
195
@@ -188,9 +216,13 @@ namespace network {
188
216
void client::impl::write_request (
189
217
const boost::system::error_code &ec,
190
218
std::shared_ptr<request_context> context) {
219
+ if (timedout_) {
220
+ set_error (boost::asio::error::timed_out, context);
221
+ return ;
222
+ }
223
+
191
224
if (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);
194
226
return ;
195
227
}
196
228
@@ -200,6 +232,7 @@ namespace network {
200
232
if (!request_stream) {
201
233
context->response_promise_ .set_exception (std::make_exception_ptr (
202
234
client_exception (client_error::invalid_request)));
235
+ timer_.cancel ();
203
236
}
204
237
205
238
context->connection_ ->async_write (
@@ -213,9 +246,13 @@ namespace network {
213
246
void client::impl::write_body (const boost::system::error_code &ec,
214
247
std::size_t bytes_written,
215
248
std::shared_ptr<request_context> context) {
249
+ if (timedout_) {
250
+ set_error (boost::asio::error::timed_out, context);
251
+ return ;
252
+ }
253
+
216
254
if (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);
219
256
return ;
220
257
}
221
258
@@ -245,9 +282,13 @@ namespace network {
245
282
void client::impl::read_response (
246
283
const boost::system::error_code &ec, std::size_t bytes_written,
247
284
std::shared_ptr<request_context> context) {
285
+ if (timedout_) {
286
+ set_error (boost::asio::error::timed_out, context);
287
+ return ;
288
+ }
289
+
248
290
if (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);
251
292
return ;
252
293
}
253
294
@@ -272,9 +313,13 @@ namespace network {
272
313
const boost::system::error_code &ec, std::size_t ,
273
314
std::shared_ptr<request_context> context,
274
315
std::shared_ptr<response> res) {
316
+ if (timedout_) {
317
+ set_error (boost::asio::error::timed_out, context);
318
+ return ;
319
+ }
320
+
275
321
if (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);
278
323
return ;
279
324
}
280
325
@@ -304,9 +349,13 @@ namespace network {
304
349
const boost::system::error_code &ec, std::size_t ,
305
350
std::shared_ptr<request_context> context,
306
351
std::shared_ptr<response> res) {
352
+ if (timedout_) {
353
+ set_error (boost::asio::error::timed_out, context);
354
+ return ;
355
+ }
356
+
307
357
if (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);
310
359
return ;
311
360
}
312
361
@@ -370,6 +419,7 @@ namespace network {
370
419
// If there's no data else to read, then set the response and exit.
371
420
if (bytes_read == 0 ) {
372
421
context->response_promise_ .set_value (*res);
422
+ timer_.cancel ();
373
423
return ;
374
424
}
375
425
0 commit comments