Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix http_client_asio "https" with a proxy #1051

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Release/include/cpprest/http_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,28 @@ class http_exception : public std::exception
m_msg = m_errorCode.message();
}

/// <summary>
/// Creates an <c>http_exception</c> with from a error code with a category, and a string message.
/// </summary>
/// <param name="errorCode">Error code value.</param>
/// <param name="whatArg">Error message string.</param>
http_exception(std::error_code errorCode, const utility::string_t& whatArg)
: m_errorCode(std::move(errorCode)), m_msg(utility::conversions::to_utf8string(whatArg))
{
}

#ifdef _WIN32
/// <summary>
/// Creates an <c>http_exception</c> with from a error code with a category, and a string message.
/// </summary>
/// <param name="errorCode">Error code value.</param>
/// <param name="whatArg">Error message string.</param>
http_exception(std::error_code errorCode, std::string whatArg)
: m_errorCode(std::move(errorCode)), m_msg(std::move(whatArg))
{
}
#endif

/// <summary>
/// Gets a string identifying the cause of the exception.
/// </summary>
Expand Down
66 changes: 51 additions & 15 deletions Release/src/http/client/http_client_asio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,11 @@ namespace
{
const std::string CRLF("\r\n");

std::string calc_cn_host(const bool secure,
const web::http::uri& baseUri,
std::string calc_cn_host(const web::http::uri& baseUri,
const web::http::http_headers& requestHeaders)
{
std::string result;
if (secure)
if (baseUri.scheme() == U("https"))
{
const utility::string_t* encResult;
const auto hostHeader = requestHeaders.find(_XPLATSTR("Host"));
Expand Down Expand Up @@ -472,7 +471,6 @@ class asio_client final : public _http_client_communicator
: _http_client_communicator(std::move(address), std::move(client_config))
, m_resolver(crossplat::threadpool::shared_instance().service())
, m_pool(std::make_shared<asio_connection_pool>())
, m_start_with_ssl(base_uri().scheme() == U("https") && !this->client_config().proxy().is_specified())
{
}

Expand All @@ -482,13 +480,13 @@ class asio_client final : public _http_client_communicator

std::shared_ptr<asio_connection> obtain_connection(const http_request& req)
{
std::string cn_host = calc_cn_host(m_start_with_ssl, base_uri(), req.headers());
std::string cn_host = calc_cn_host(base_uri(), req.headers());
std::shared_ptr<asio_connection> conn = m_pool->try_acquire(cn_host);
if (conn == nullptr)
{
// Pool was empty. Create a new connection
conn = std::make_shared<asio_connection>(crossplat::threadpool::shared_instance().service());
if (m_start_with_ssl)
if (base_uri().scheme() == U("https") && !this->client_config().proxy().is_specified())
{
conn->upgrade_to_ssl(std::move(cn_host), this->client_config().get_ssl_context_callback());
}
Expand All @@ -499,13 +497,10 @@ class asio_client final : public _http_client_communicator

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

bool start_with_ssl() const CPPREST_NOEXCEPT { return m_start_with_ssl; }

tcp::resolver m_resolver;

private:
const std::shared_ptr<asio_connection_pool> m_pool;
const bool m_start_with_ssl;
};

class asio_context final : public request_context, public std::enable_shared_from_this<asio_context>
Expand Down Expand Up @@ -631,7 +626,15 @@ class asio_context final : public request_context, public std::enable_shared_fro
m_context->m_timer.reset();
//// Replace the connection. This causes old connection object to go out of scope.
auto client = std::static_pointer_cast<asio_client>(m_context->m_http_client);
m_context->m_connection = client->obtain_connection(m_context->m_request);
try
{
m_context->m_connection = client->obtain_connection(m_context->m_request);
}
catch (...)
{
m_context->report_exception(std::current_exception());
return;
}

auto endpoint = *endpoints;
m_context->m_connection->async_connect(endpoint,
Expand Down Expand Up @@ -688,7 +691,15 @@ class asio_context final : public request_context, public std::enable_shared_fro
return;
}

m_context->upgrade_to_ssl();
try
{
m_context->upgrade_to_ssl();
}
catch (...)
{
m_context->report_exception(std::current_exception());
return;
}

m_ssl_tunnel_established(m_context);
}
Expand Down Expand Up @@ -925,7 +936,7 @@ class asio_context final : public request_context, public std::enable_shared_fro
void upgrade_to_ssl()
{
auto& client = static_cast<asio_client&>(*m_http_client);
m_connection->upgrade_to_ssl(calc_cn_host(client.start_with_ssl(), client.base_uri(), m_request.headers()),
m_connection->upgrade_to_ssl(calc_cn_host(client.base_uri(), m_request.headers()),
client.client_config().get_ssl_context_callback());
}

Expand Down Expand Up @@ -1009,7 +1020,15 @@ class asio_context final : public request_context, public std::enable_shared_fro
{
// Replace the connection. This causes old connection object to go out of scope.
auto client = std::static_pointer_cast<asio_client>(m_http_client);
m_connection = client->obtain_connection(m_request);
try
{
m_connection = client->obtain_connection(m_request);
}
catch (...)
{
request_context::report_exception(std::current_exception());
return;
}

auto endpoint = *endpoints;
m_connection->async_connect(
Expand Down Expand Up @@ -1330,7 +1349,16 @@ class asio_context final : public request_context, public std::enable_shared_fro
// Create a new context and copy the request object, completion event and
// cancellation registration to maintain the old state.
// This also obtains a new connection from pool.
auto new_ctx = create_request_context(m_http_client, m_request);
std::shared_ptr<request_context> new_ctx;
try
{
new_ctx = create_request_context(m_http_client, m_request);
}
catch (...)
{
report_exception(std::current_exception());
return;
}

// If the request contains a valid instream, we try to rewind it to
// replay the just-failed request. Otherwise we assume that no data
Expand Down Expand Up @@ -1940,7 +1968,15 @@ void asio_client::send_request(const std::shared_ptr<request_context>& request_c
pplx::task<http_response> asio_client::propagate(http_request request)
{
auto self = std::static_pointer_cast<_http_client_communicator>(shared_from_this());
auto context = details::asio_context::create_request_context(self, request);
std::shared_ptr<request_context> context;
try
{
context = details::asio_context::create_request_context(self, request);
}
catch (...)
{
return pplx::task_from_exception<http_response>(std::current_exception());
}

// Use a task to externally signal the final result and completion of the task.
auto result_task = pplx::create_task(context->m_request_completion);
Expand Down