diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index ead627be92..54d27dadc2 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -792,6 +792,10 @@ class asio_context : public request_context, public std::enable_shared_from_this { write_request(); } + else if (ec.value() == boost::system::errc::operation_canceled) + { + request_context::report_error(ec.value(), "Request canceled by user."); + } else if (endpoints == tcp::resolver::iterator()) { report_error("Failed to connect to any resolved endpoint", ec, httpclient_errorcode_context::connect); diff --git a/Release/tests/functional/http/client/connections_and_errors.cpp b/Release/tests/functional/http/client/connections_and_errors.cpp index bd57390f3a..99a689ea20 100644 --- a/Release/tests/functional/http/client/connections_and_errors.cpp +++ b/Release/tests/functional/http/client/connections_and_errors.cpp @@ -27,6 +27,9 @@ #include "cpprest/http_listener.h" #endif +#include +#include + using namespace web; using namespace utility; using namespace concurrency; @@ -400,6 +403,36 @@ TEST_FIXTURE(uri_address, cancel_while_downloading_data) } #endif +// Try to connect to a server on a closed port and cancel the operation. +TEST_FIXTURE(uri_address, cancel_bad_port) +{ + // http_client_asio had a bug where, when canceled, it would cancel only the + // current connection but then go and try the next address from the list of + // resolved addresses, i.e., it wouldn't actually cancel as long as there + // are more addresses to try. Consequently, it would not report the task as + // being canceled. This was easiest to observe when trying to connect to a + // server that does not respond on a certain port, otherwise the timing + // might be tricky. + + // We need to connect to a URI for which there are multiple addresses + // associated (i.e., multiple A records). + web::http::uri uri(U("https://microsoft.com:442/")); + + // Send request. + http_client c(uri); + web::http::http_request r; + auto cts = pplx::cancellation_token_source(); + auto ct = cts.get_token(); + auto t = c.request(r, ct); + + // Make sure that the client already finished resolving before canceling, + // otherwise the bug might not be triggered. + std::this_thread::sleep_for(std::chrono::seconds(1)); + cts.cancel(); + + VERIFY_THROWS_HTTP_ERROR_CODE(t.get(), std::errc::operation_canceled); +} + } // SUITE(connections_and_errors) }}}}