Skip to content

Commit 0886fcc

Browse files
authored
Fix tcp::resolver data race in the asio backend and be defensive against empty results (#1339)
* Move TCP resolver to asio_context rather than asio_client, as that type is not safe to touch from multiple threads. * Defend against empty responses from async_resolve. Co-authored-by: Jinming Hu jinming.hu@microsoft.com
1 parent 43f6f34 commit 0886fcc

File tree

1 file changed

+18
-16
lines changed

1 file changed

+18
-16
lines changed

Release/src/http/client/http_client_asio.cpp

+18-16
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,6 @@ class asio_client final : public _http_client_communicator
474474
public:
475475
asio_client(http::uri&& address, http_client_config&& client_config)
476476
: _http_client_communicator(std::move(address), std::move(client_config))
477-
, m_resolver(crossplat::threadpool::shared_instance().service())
478477
, m_pool(std::make_shared<asio_connection_pool>())
479478
{
480479
}
@@ -502,8 +501,6 @@ class asio_client final : public _http_client_communicator
502501

503502
virtual pplx::task<http_response> propagate(http_request request) override;
504503

505-
tcp::resolver m_resolver;
506-
507504
private:
508505
const std::shared_ptr<asio_connection_pool> m_pool;
509506
};
@@ -520,6 +517,7 @@ class asio_context final : public request_context, public std::enable_shared_fro
520517
, m_content_length(0)
521518
, m_needChunked(false)
522519
, m_timer(client->client_config().timeout<std::chrono::microseconds>())
520+
, m_resolver(crossplat::threadpool::shared_instance().service())
523521
, m_connection(connection)
524522
#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE
525523
, m_openssl_failed(false)
@@ -585,11 +583,11 @@ class asio_context final : public request_context, public std::enable_shared_fro
585583
tcp::resolver::query query(utility::conversions::to_utf8string(proxy_host), to_string(proxy_port));
586584

587585
auto client = std::static_pointer_cast<asio_client>(m_context->m_http_client);
588-
client->m_resolver.async_resolve(query,
589-
boost::bind(&ssl_proxy_tunnel::handle_resolve,
590-
shared_from_this(),
591-
boost::asio::placeholders::error,
592-
boost::asio::placeholders::iterator));
586+
m_context->m_resolver.async_resolve(query,
587+
boost::bind(&ssl_proxy_tunnel::handle_resolve,
588+
shared_from_this(),
589+
boost::asio::placeholders::error,
590+
boost::asio::placeholders::iterator));
593591
}
594592

595593
private:
@@ -887,12 +885,11 @@ class asio_context final : public request_context, public std::enable_shared_fro
887885
auto tcp_port = proxy_type == http_proxy_type::http ? proxy_port : port;
888886

889887
tcp::resolver::query query(tcp_host, to_string(tcp_port));
890-
auto client = std::static_pointer_cast<asio_client>(ctx->m_http_client);
891-
client->m_resolver.async_resolve(query,
892-
boost::bind(&asio_context::handle_resolve,
893-
ctx,
894-
boost::asio::placeholders::error,
895-
boost::asio::placeholders::iterator));
888+
ctx->m_resolver.async_resolve(query,
889+
boost::bind(&asio_context::handle_resolve,
890+
ctx,
891+
boost::asio::placeholders::error,
892+
boost::asio::placeholders::iterator));
896893
}
897894

898895
// Register for notification on cancellation to abort this request.
@@ -1053,6 +1050,10 @@ class asio_context final : public request_context, public std::enable_shared_fro
10531050
{
10541051
report_error("Error resolving address", ec, httpclient_errorcode_context::connect);
10551052
}
1053+
else if (endpoints == tcp::resolver::iterator())
1054+
{
1055+
report_error("Failed to resolve address", ec, httpclient_errorcode_context::connect);
1056+
}
10561057
else
10571058
{
10581059
m_timer.reset();
@@ -1452,8 +1453,8 @@ class asio_context final : public request_context, public std::enable_shared_fro
14521453
}
14531454
}
14541455

1455-
m_content_length = (std::numeric_limits<size_t>::max)(); // Without Content-Length header, size should be same as
1456-
// TCP stream - set it size_t max.
1456+
m_content_length = (std::numeric_limits<size_t>::max)(); // Without Content-Length header, size should be same
1457+
// as TCP stream - set it size_t max.
14571458
m_response.headers().match(header_names::content_length, m_content_length);
14581459

14591460
if (!this->handle_compression())
@@ -1936,6 +1937,7 @@ class asio_context final : public request_context, public std::enable_shared_fro
19361937
uint64_t m_content_length;
19371938
bool m_needChunked;
19381939
timeout_timer m_timer;
1940+
tcp::resolver m_resolver;
19391941
boost::asio::streambuf m_body_buf;
19401942
std::shared_ptr<asio_connection> m_connection;
19411943

0 commit comments

Comments
 (0)