What changed, and why it matters
This commit adds a new helper class for formatting HTTP response headers in Bitcoin Core's internal web server. It does not change any existing behavior or fix any known problem; it is purely new infrastructure code with accompanying tests.
No security action required. Review as normal code-quality/refactoring change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces HTTPResponse, HTTPVersion, and HTTPStatusReasonString to centralize serialization of HTTP status lines and headers. It adds a StringifyHeaders() method that builds ‘HTTP/major.minor status reason\r\nheaders\r\n’. The change is additive only (+76 lines, no deletions) and includes a unit test. No existing call sites are modified, and no security-sensitive logic (e.g., input parsing, authentication, memory handling) is altered.
Changed components
src/httpserver.cppsrc/httpserver.hsrc/rpc/protocol.hsrc/test/httpserver_tests.cppInspect captured patch +76 / −0
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 45824b7a..a1b3e7a2 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -808,4 +808,14 @@ std::string HTTPHeaders::Stringify() const
return out;
}
+
+std::string HTTPResponse::StringifyHeaders() const
+{
+ return strprintf("HTTP/%d.%d %d %s\r\n%s",
+ m_version.major,
+ m_version.minor,
+ m_status,
+ HTTPStatusReasonString(m_status),
+ m_headers.Stringify());
+}
} // namespace http_bitcoin
diff --git a/src/httpserver.h b/src/httpserver.h
index a888979f..245abb75 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -10,6 +10,7 @@
#include <span>
#include <string>
+#include <rpc/protocol.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -234,6 +235,29 @@ private:
*/
std::vector<std::pair<std::string, std::string>> m_headers;
};
+
+struct HTTPVersion {
+ /**
+ * Default HTTP protocol version 1.1 is used by error responses
+ * when a request is unreadable.
+ */
+ /// @{
+ uint8_t major{1};
+ uint8_t minor{1};
+ /// @}
+};
+
+
+class HTTPResponse
+{
+public:
+ HTTPVersion m_version;
+
+ HTTPStatusCode m_status{HTTP_INTERNAL_SERVER_ERROR};
+ HTTPHeaders m_headers;
+
+ std::string StringifyHeaders() const;
+};
} // namespace http_bitcoin
#endif // BITCOIN_HTTPSERVER_H
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 40e685d5..0ba17ae0 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -20,6 +20,27 @@ enum HTTPStatusCode : int
HTTP_SERVICE_UNAVAILABLE = 503,
};
+//! Mapping of HTTP status codes to short string explanation.
+//! Copied from libevent http.c success_phrases[] and client_error_phrases[]
+inline std::string_view HTTPStatusReasonString(HTTPStatusCode code)
+{
+ switch (code) {
+ case HTTP_OK: return "OK";
+ case HTTP_NO_CONTENT: return "No Content";
+ case HTTP_BAD_REQUEST: return "Bad Request";
+ case HTTP_UNAUTHORIZED: return "Unauthorized";
+ case HTTP_FORBIDDEN: return "Forbidden";
+ case HTTP_NOT_FOUND: return "Not Found";
+ case HTTP_BAD_METHOD: return "Method Not Allowed";
+ case HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
+ case HTTP_SERVICE_UNAVAILABLE: return "Service Unavailable";
+ }
+
+ // Reason phrases are optional and may be replaced by local variants.
+ // https://httpwg.org/specs/rfc9110.html#rfc.section.15.1
+ return "";
+}
+
//! Bitcoin RPC error codes
enum RPCErrorCode
{
diff --git a/src/test/httpserver_tests.cpp b/src/test/httpserver_tests.cpp
index d2d03f8a..baf0ae40 100644
--- a/src/test/httpserver_tests.cpp
+++ b/src/test/httpserver_tests.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <httpserver.h>
+#include <rpc/protocol.h>
#include <test/util/common.h>
#include <test/util/setup_common.h>
#include <util/string.h>
@@ -10,6 +11,7 @@
#include <boost/test/unit_test.hpp>
using http_bitcoin::HTTPHeaders;
+using http_bitcoin::HTTPResponse;
using http_bitcoin::MAX_HEADERS_SIZE;
BOOST_FIXTURE_TEST_SUITE(httpserver_tests, BasicTestingSetup)
@@ -144,4 +146,23 @@ BOOST_AUTO_TEST_CASE(http_headers_tests)
BOOST_CHECK_EQUAL(headers.FindFirst("key"), "value");
}
}
+
+BOOST_AUTO_TEST_CASE(http_response_tests)
+{
+ // Typical HTTP 1.1 response headers
+ HTTPHeaders headers{};
+ headers.Write("Content-Length", "41");
+
+ // Response points to headers which already exist because some of them
+ // are set before we even know what the response will be.
+ HTTPResponse res;
+ res.m_version = {.major = 1, .minor = 1};
+ res.m_status = HTTP_OK;
+ res.m_headers = std::move(headers);
+ BOOST_CHECK_EQUAL(
+ res.StringifyHeaders(),
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Length: 41\r\n"
+ "\r\n");
+}
BOOST_AUTO_TEST_SUITE_END()
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.