diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 0dc78ed38f..845ecd85c0 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -53,3 +53,4 @@ Christian Deneke (chris0x44) leetal Benjamin Lee (mobileben) +René Meusel (reneme) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 3292447061..ec4edd6995 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -1322,7 +1322,39 @@ class asio_context final : public request_context, public std::enable_shared_fro // 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); - new_ctx->m_request._get_impl()->instream().seek(0); + + // If the request contains a valid instream, we try to rewind it to + // replay the just-failed request. Otherwise we assume that no data + // was sent in the first place. + const auto& instream = new_ctx->m_request._get_impl()->instream(); + if (instream) + { + // As stated in the commit message of f4f2348, we might encounter + // streams that are not capable of rewinding and hence resending the + // request is not possible. We cannot recover from this condition and + // need to escalate it to the using code. + if (!instream.can_seek()) + { + report_error("cannot rewind input stream for connection re-establishment", + ec, + httpclient_errorcode_context::readheader); + return; + } + + try + { + // Rewinding the stream might throw, in which case we cannot do the + // connection re-establishment transparently. I.e. report the exception + // to the calling code. + instream.seek(0); + } + catch (...) + { + report_exception(std::current_exception()); + return; + } + } + new_ctx->m_request_completion = m_request_completion; new_ctx->m_cancellationRegistration = m_cancellationRegistration;