7
7
// (See accompanying file LICENSE_1_0.txt or copy at
8
8
// http://www.boost.org/LICENSE_1_0.txt)
9
9
10
- #include < boost/network/protocol/http/traits/resolver_policy.hpp>
11
-
12
10
#include < boost/algorithm/string/predicate.hpp>
13
11
#include < boost/network/protocol/http/client/connection/sync_base.hpp>
14
12
#include < boost/network/protocol/http/response.hpp>
13
+ #include < boost/network/protocol/http/traits/resolver_policy.hpp>
15
14
#include < boost/shared_ptr.hpp>
15
+ #include < boost/thread/mutex.hpp>
16
16
#include < boost/unordered_map.hpp>
17
17
#include < utility>
18
18
@@ -37,7 +37,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
37
37
system::error_code const &)> body_callback_function_type;
38
38
typedef function<bool (string_type&)> body_generator_function_type;
39
39
40
- void cleanup () { host_connection_map ().swap (host_connections ); }
40
+ void cleanup () { host_connection_map ().swap (host_connections_ ); }
41
41
42
42
struct connection_impl {
43
43
typedef function<shared_ptr<connection_impl>(
@@ -47,10 +47,10 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
47
47
get_connection_function;
48
48
49
49
connection_impl (
50
- resolver_type& resolver, bool follow_redirect, string_type /* unused */ const & host,
51
- string_type const & port, resolver_function_type resolve ,
52
- get_connection_function get_connection, bool https ,
53
- bool always_verify_peer, int timeout,
50
+ resolver_type& resolver, bool follow_redirect,
51
+ string_type /* unused */ const & host, string_type const & port ,
52
+ resolver_function_type resolve, get_connection_function get_connection ,
53
+ bool https, bool always_verify_peer, int timeout,
54
54
optional<string_type> const & certificate_filename =
55
55
optional<string_type>(),
56
56
optional<string_type> const & verify_path = optional<string_type>(),
@@ -77,7 +77,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
77
77
(void )port;
78
78
}
79
79
80
- basic_response<Tag> send_request (string_type /* unused */ const & method,
80
+ basic_response<Tag> send_request (string_type const & method,
81
81
basic_request<Tag> request_, bool get_body,
82
82
body_callback_function_type callback,
83
83
body_generator_function_type generator) {
@@ -86,7 +86,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
86
86
87
87
private:
88
88
basic_response<Tag> send_request_impl (
89
- string_type /* unused */ const & method, basic_request<Tag> request_, bool get_body,
89
+ string_type const & method, basic_request<Tag> request_, bool get_body,
90
90
body_callback_function_type callback,
91
91
body_generator_function_type generator) {
92
92
// TODO(dberris): review parameter necessity.
@@ -113,8 +113,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
113
113
114
114
try {
115
115
pimpl->read_status (response_, response_buffer);
116
- }
117
- catch (boost::system ::system_error& e) {
116
+ } catch (boost::system ::system_error& e) {
118
117
if (!retry && e.code () == boost::asio::error::eof) {
119
118
retry = true ;
120
119
pimpl->init_socket (request_.host (),
@@ -182,49 +181,57 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
182
181
183
182
typedef shared_ptr<connection_impl> connection_ptr;
184
183
185
- typedef unordered_map<string_type, connection_ptr> host_connection_map;
186
- host_connection_map host_connections;
184
+ typedef unordered_map<string_type, weak_ptr<connection_impl>> host_connection_map;
185
+ boost::mutex host_mutex_;
186
+ host_connection_map host_connections_;
187
187
bool follow_redirect_;
188
188
int timeout_;
189
189
190
190
connection_ptr get_connection (
191
191
resolver_type& resolver, basic_request<Tag> const & request_,
192
192
bool always_verify_peer,
193
- optional<string_type> /* unused */ const & certificate_filename =
193
+ optional<string_type> const & certificate_filename =
194
194
optional<string_type>(),
195
195
optional<string_type> const & verify_path = optional<string_type>(),
196
196
optional<string_type> const & certificate_file = optional<string_type>(),
197
197
optional<string_type> const & private_key_file = optional<string_type>(),
198
198
optional<string_type> const & ciphers = optional<string_type>()) {
199
199
string_type index =
200
200
(request_.host () + ' :' ) + lexical_cast<string_type>(request_.port ());
201
- connection_ptr connection_;
202
- typename host_connection_map::iterator it = host_connections.find (index );
203
- if (it == host_connections.end ()) {
204
- connection_.reset (new connection_impl (
205
- resolver, follow_redirect_, request_.host (),
206
- lexical_cast<string_type>(request_.port ()),
207
- boost::bind (&pooled_connection_policy<Tag, version_major,
208
- version_minor>::resolve,
209
- this , boost::arg<1 >(), boost::arg<2 >(), boost::arg<3 >()),
210
- boost::bind (&pooled_connection_policy<Tag, version_major,
211
- version_minor>::get_connection,
212
- this , boost::arg<1 >(), boost::arg<2 >(),
213
- always_verify_peer, boost::arg<3 >(), boost::arg<4 >(),
214
- boost::arg<5 >(), boost::arg<6 >(), boost::arg<7 >()),
215
- boost::iequals (request_.protocol (), string_type (" https" )),
216
- always_verify_peer, timeout_, certificate_filename, verify_path,
217
- certificate_file, private_key_file, ciphers, 0 ));
218
- host_connections.insert (std::make_pair (index , connection_));
219
- return connection_;
201
+ boost::mutex::scoped_lock lock (host_mutex_);
202
+ auto it = host_connections_.find (index );
203
+ if (it != host_connections_.end ()) {
204
+ // We've found an existing connection; but we should check if that
205
+ // connection hasn't been deleted yet.
206
+ auto result = it->second .lock ();
207
+ if (!result) return result;
220
208
}
221
- return it->second ;
209
+
210
+ connection_ptr connection (new connection_impl (
211
+ resolver, follow_redirect_, request_.host (),
212
+ lexical_cast<string_type>(request_.port ()),
213
+ // resolver function
214
+ boost::bind (&pooled_connection_policy<Tag, version_major,
215
+ version_minor>::resolve,
216
+ this , boost::arg<1 >(), boost::arg<2 >(), boost::arg<3 >()),
217
+ // connection factory
218
+ boost::bind (&pooled_connection_policy<Tag, version_major,
219
+ version_minor>::get_connection,
220
+ this , boost::arg<1 >(), boost::arg<2 >(), always_verify_peer,
221
+ boost::arg<3 >(), boost::arg<4 >(), boost::arg<5 >(),
222
+ boost::arg<6 >(), boost::arg<7 >()),
223
+ boost::iequals (request_.protocol (), string_type (" https" )),
224
+ always_verify_peer, timeout_, certificate_filename, verify_path,
225
+ certificate_file, private_key_file, ciphers, 0 ));
226
+ host_connections_.insert (std::make_pair (index , connection));
227
+ return connection;
222
228
}
223
229
224
230
pooled_connection_policy (bool cache_resolved, bool follow_redirect,
225
231
int timeout)
226
232
: resolver_base(cache_resolved),
227
- host_connections(),
233
+ host_mutex_(),
234
+ host_connections_(),
228
235
follow_redirect_(follow_redirect),
229
236
timeout_(timeout) {}
230
237
};
0 commit comments