Merge pull request #10864 from Icinga/fix-http-message-sendfile-failbit-handling
Some checks failed
Container Image / Container Image (push) Has been cancelled
Linux / alpine:bash (push) Has been cancelled
Linux / amazonlinux:2 (push) Has been cancelled
Linux / amazonlinux:2023 (push) Has been cancelled
Linux / debian:11 (linux/386) (push) Has been cancelled
Linux / debian:11 (push) Has been cancelled
Linux / debian:12 (linux/386) (push) Has been cancelled
Linux / debian:12 (push) Has been cancelled
Linux / debian:13 (push) Has been cancelled
Linux / fedora:41 (push) Has been cancelled
Linux / fedora:42 (push) Has been cancelled
Linux / fedora:43 (push) Has been cancelled
Linux / fedora:44 (push) Has been cancelled
Linux / opensuse/leap:15.6 (push) Has been cancelled
Linux / opensuse/leap:16.0 (push) Has been cancelled
Linux / registry.suse.com/bci/bci-base:16.0 (push) Has been cancelled
Linux / registry.suse.com/suse/sle15:15.6 (push) Has been cancelled
Linux / registry.suse.com/suse/sle15:15.7 (push) Has been cancelled
Linux / rockylinux/rockylinux:10 (push) Has been cancelled
Linux / rockylinux:8 (push) Has been cancelled
Linux / rockylinux:9 (push) Has been cancelled
Linux / ubuntu:22.04 (push) Has been cancelled
Linux / ubuntu:24.04 (push) Has been cancelled
Linux / ubuntu:25.04 (push) Has been cancelled
Linux / ubuntu:25.10 (push) Has been cancelled
Linux / ubuntu:26.04 (push) Has been cancelled
Windows / Windows (push) Has been cancelled

Fix handling the `std::ifstream::failbit` in `OutgoingHttpMessage`
This commit is contained in:
Julian Brost 2026-06-10 17:17:46 +02:00 committed by GitHub
commit 91eeb41ff1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 32 additions and 4 deletions

View file

@ -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;

View file

@ -226,7 +226,7 @@ void OutgoingHttpMessage<isRequest, Body, StreamVariant>::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);

View file

@ -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()) {

View file

@ -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()