diff --git a/lib/remote/configfileshandler.cpp b/lib/remote/configfileshandler.cpp index 28ea8be75..7f33e067c 100644 --- a/lib/remote/configfileshandler.cpp +++ b/lib/remote/configfileshandler.cpp @@ -81,9 +81,12 @@ bool ConfigFilesHandler::HandleRequest( response.result(http::status::ok); response.set(http::field::content_type, "application/octet-stream"); response.SendFile(path, yc); - } catch (const std::exception& ex) { - HttpUtility::SendJsonError(response, params, 500, "Could not read file.", - DiagnosticInformation(ex)); + } catch (const std::ios_base::failure& ex) { + if (response.HasSerializationStarted()) { + throw; + } + + HttpUtility::SendJsonError(response, params, 500, "Could not read file.", DiagnosticInformation(ex)); } return true; diff --git a/lib/remote/httpmessage.cpp b/lib/remote/httpmessage.cpp index 221c8945e..be5ceee4b 100644 --- a/lib/remote/httpmessage.cpp +++ b/lib/remote/httpmessage.cpp @@ -226,7 +226,7 @@ void OutgoingHttpMessage::SendFile( ) { std::ifstream fp(path.CStr(), std::ifstream::in | std::ifstream::binary | std::ifstream::ate); - fp.exceptions(std::ifstream::badbit | std::ifstream::eofbit); + fp.exceptions(std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit); std::uint64_t remaining = fp.tellg(); fp.seekg(0); diff --git a/lib/remote/httputility.cpp b/lib/remote/httputility.cpp index 5e466bb8a..f868dae81 100644 --- a/lib/remote/httputility.cpp +++ b/lib/remote/httputility.cpp @@ -86,6 +86,16 @@ void HttpUtility::SendJsonBody(HttpApiResponse& response, const Dictionary::Ptr& void HttpUtility::SendJsonError(HttpApiResponse& response, const Dictionary::Ptr& params, int code, const String& info, const String& diagnosticInformation) { + if (response.HasSerializationStarted()) { + std::ostringstream err; + err << "Impossible to send error response after streaming has started: error: '" << code << "', status: '" + << info << "'"; + if (!diagnosticInformation.IsEmpty()) { + err << ", diagnostic_information: '" << diagnosticInformation << "'"; + } + BOOST_THROW_EXCEPTION(std::logic_error{err.str()}); + } + Dictionary::Ptr result = new Dictionary({ { "error", code } }); if (!info.IsEmpty()) { diff --git a/test/remote-httpmessage.cpp b/test/remote-httpmessage.cpp index acbe612c7..23e3e0823 100644 --- a/test/remote-httpmessage.cpp +++ b/test/remote-httpmessage.cpp @@ -353,4 +353,19 @@ BOOST_AUTO_TEST_CASE(response_sendfile) BOOST_REQUIRE_EQUAL(ss.str(), parser.get().body()); } +BOOST_AUTO_TEST_CASE(response_sendfile_invalid_path) +{ + auto future = SpawnSynchronizedCoroutine([this](boost::asio::yield_context yc) { + HttpApiResponse response(server); + + response.result(http::status::ok); + BOOST_REQUIRE_THROW(response.SendFile("", yc), std::ios_base::failure); + }); + + auto status = future.wait_for(10s); + if (status != std::future_status::ready) { + BOOST_FAIL("Exception not thrown."); + } +} + BOOST_AUTO_TEST_SUITE_END()