From be5d43f2746486c5b717e8b1c9b3c7ac7c25c410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Meusel?= Date: Wed, 16 Jan 2019 21:12:22 +0100 Subject: [PATCH] FIX: crash with std::logic_error when reusing a connection that timed out on the server (#1019) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FIX: check whether instream() is valid before trying to rewind * add .can_seek() as a second line of defense * apply clang-format * improve error reporting for unrewindable streams * Add René Meusel (reneme) to CONTRIBUTORS.txt. --- CONTRIBUTORS.txt | 1 + Release/src/http/client/http_client_asio.cpp | 34 +++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) 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;