diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 07bb4885bf..4eac430543 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -219,7 +219,7 @@ class asio_connection // These errors tell if connection was closed. if ((boost::asio::error::eof == ec) || (boost::asio::error::connection_reset == ec) || - (boost::asio::error::connection_aborted == ec)) + (boost::asio::error::connection_aborted == ec) || (boost::asio::error::broken_pipe == ec)) { return true; } @@ -710,7 +710,7 @@ class asio_context final : public request_context, public std::enable_shared_fro } else { - m_context->handle_failed_read_status_line(ec, "Failed to read HTTP status line from proxy"); + m_context->restore_closed_connection(ec, "Failed to read HTTP status line from proxy", httpclient_errorcode_context::readheader); } } @@ -1300,7 +1300,7 @@ class asio_context final : public request_context, public std::enable_shared_fro } else { - report_error("Failed to write request body", ec, httpclient_errorcode_context::writebody); + restore_closed_connection(ec, "Failed to write request body", httpclient_errorcode_context::writebody); } } @@ -1344,11 +1344,12 @@ class asio_context final : public request_context, public std::enable_shared_fro } else { - handle_failed_read_status_line(ec, "Failed to read HTTP status line"); + restore_closed_connection(ec, "Failed to read HTTP status line", httpclient_errorcode_context::readheader); } } - void handle_failed_read_status_line(const boost::system::error_code& ec, const char* generic_error_message) + void restore_closed_connection( + const boost::system::error_code& ec, const char* generic_error_message, httpclient_errorcode_context error_context) { if (m_connection->was_reused_and_closed_by_server(ec)) { @@ -1385,7 +1386,7 @@ class asio_context final : public request_context, public std::enable_shared_fro { report_error("cannot rewind input stream for connection re-establishment", ec, - httpclient_errorcode_context::readheader); + error_context); return; } @@ -1402,7 +1403,6 @@ class asio_context final : public request_context, public std::enable_shared_fro return; } } - new_ctx->m_request_completion = m_request_completion; new_ctx->m_cancellationRegistration = m_cancellationRegistration; @@ -1412,7 +1412,7 @@ class asio_context final : public request_context, public std::enable_shared_fro } else { - report_error(generic_error_message, ec, httpclient_errorcode_context::readheader); + report_error(generic_error_message, ec, error_context); } } diff --git a/Release/tests/functional/http/client/connections_and_errors.cpp b/Release/tests/functional/http/client/connections_and_errors.cpp index 847755d80a..d4e53a0fd4 100644 --- a/Release/tests/functional/http/client/connections_and_errors.cpp +++ b/Release/tests/functional/http/client/connections_and_errors.cpp @@ -130,6 +130,58 @@ SUITE(connections_and_errors) VERIFY_THROWS(client.request(methods::GET).wait(), web::http::http_exception); } + TEST_FIXTURE(uri_address, send_request_to_reopened_connection) + { + http_client_config config; + config.set_timeout(utility::seconds(1)); + + http_client client(m_uri, config); + { + // 1st request. + test_http_server::scoped_server server(m_uri); + auto t = server.server()->next_request().then([](test_request* p_request) { + p_request->reply(200); + }); + + // Send request. + auto response = client.request(methods::PUT); + + // Wait for request + VERIFY_NO_THROWS(t.get()); + + // Wait for reply. + VERIFY_NO_THROWS(response.wait()); + + // Close server connection. For example, keep-alive timeout reason. + server.server()->close(); + } + + { + // 2nd. Send request to connection has been closed. + + utility::string_t str_body(U("Hi, I'm reused connection")); + std::vector raw_body(str_body.size() * sizeof(utility::char_t)); + memcpy(&raw_body[0], &str_body[0], str_body.size() * sizeof(utility::char_t)); + + // Reopen connection. + test_http_server::scoped_server server(m_uri); + auto t = server.server()->next_request().then([&](test_request* p_request) { + VERIFY_ARE_EQUAL(p_request->m_body, raw_body); + p_request->reply(200); + }); + + // Try to send request with payload. + auto msg = http_request(methods::POST); + msg.set_body(str_body); + auto response = client.request(msg); + + // Wait for request + VERIFY_NO_THROWS(t.get()); + + http_asserts::assert_response_equals(response.get(), status_codes::OK); + } + } + TEST_FIXTURE(uri_address, request_timeout) { test_http_server::scoped_server scoped(m_uri);