77// (See accompanying file LICENSE_1_0.txt or copy at
88// http://www.boost.org/LICENSE_1_0.txt)
99
10- #include < boost/network/protocol/http/traits/resolver_policy.hpp>
11-
1210#include < boost/algorithm/string/predicate.hpp>
1311#include < boost/network/protocol/http/client/connection/sync_base.hpp>
1412#include < boost/network/protocol/http/response.hpp>
13+ #include < boost/network/protocol/http/traits/resolver_policy.hpp>
1514#include < boost/shared_ptr.hpp>
15+ #include < boost/thread/mutex.hpp>
1616#include < boost/unordered_map.hpp>
1717#include < utility>
1818
@@ -37,7 +37,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
3737 system::error_codeconst &)> body_callback_function_type;
3838typedef function<bool (string_type&)> body_generator_function_type;
3939
40- void cleanup () {host_connection_map ().swap (host_connections ); }
40+ void cleanup () {host_connection_map ().swap (host_connections_ ); }
4141
4242struct connection_impl {
4343typedef function<shared_ptr<connection_impl>(
@@ -47,10 +47,10 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
4747 get_connection_function;
4848
4949connection_impl (
50- resolver_type& resolver,bool follow_redirect, string_type /* unused */ const & host,
51- string_typeconst &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,
5454 optional<string_type>const & certificate_filename =
5555 optional<string_type>(),
5656 optional<string_type>const & verify_path = optional<string_type>(),
@@ -77,7 +77,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
7777 (void )port;
7878 }
7979
80- basic_response<Tag>send_request (string_type/* unused */ const & method,
80+ basic_response<Tag>send_request (string_typeconst & method,
8181 basic_request<Tag> request_,bool get_body,
8282 body_callback_function_type callback,
8383 body_generator_function_type generator) {
@@ -86,7 +86,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
8686
8787private:
8888 basic_response<Tag>send_request_impl (
89- string_type/* unused */ const & method, basic_request<Tag> request_,bool get_body,
89+ string_typeconst & method, basic_request<Tag> request_,bool get_body,
9090 body_callback_function_type callback,
9191 body_generator_function_type generator) {
9292// TODO(dberris): review parameter necessity.
@@ -113,8 +113,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
113113
114114try {
115115 pimpl->read_status (response_, response_buffer);
116- }
117- catch (boost::system::system_error& e) {
116+ }catch (boost::system::system_error& e) {
118117if (!retry && e.code () == boost::asio::error::eof) {
119118 retry =true ;
120119 pimpl->init_socket (request_.host (),
@@ -182,49 +181,57 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
182181
183182typedef shared_ptr<connection_impl> connection_ptr;
184183
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_;
187187bool follow_redirect_;
188188int timeout_;
189189
190190 connection_ptrget_connection (
191191 resolver_type& resolver, basic_request<Tag>const & request_,
192192bool always_verify_peer,
193- optional<string_type>/* unused */ const & certificate_filename =
193+ optional<string_type>const & certificate_filename =
194194 optional<string_type>(),
195195 optional<string_type>const & verify_path = optional<string_type>(),
196196 optional<string_type>const & certificate_file = optional<string_type>(),
197197 optional<string_type>const & private_key_file = optional<string_type>(),
198198 optional<string_type>const & ciphers = optional<string_type>()) {
199199 string_type index =
200200 (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_locklock (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;
220208 }
221- return it->second ;
209+
210+ connection_ptrconnection (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;
222228 }
223229
224230pooled_connection_policy (bool cache_resolved,bool follow_redirect,
225231int timeout)
226232 : resolver_base(cache_resolved),
227- host_connections(),
233+ host_mutex_(),
234+ host_connections_(),
228235 follow_redirect_(follow_redirect),
229236 timeout_(timeout) {}
230237};