Refactor to use format for http responses

This commit is contained in:
2025-09-03 22:45:59 -04:00
parent 978861c430
commit b2ffe3bfab
3 changed files with 81 additions and 58 deletions

View File

@@ -79,6 +79,8 @@
* - **Simple concatenation**: Basic string + number + string combinations
* - **Compile-time optimization**: When all types/values known at compile time
* - **Template contexts**: Where compile-time buffer sizing is beneficial
* - **IMPORTANT**: Only works with compile-time string literals, NOT runtime
* const char*
*
* ## Optimization Details:
* The function uses `ArenaAllocator::allocate_remaining_space()` to claim all
@@ -206,10 +208,12 @@ inline constexpr DoubleTerm term(double s) { return DoubleTerm(s); }
* optimized term writers for maximum speed.
*
* ## Supported Types:
* - **String literals**: C-style string literals and arrays
* - **String literals**: C-style string literals and arrays ("Hello", "World")
* - **Integers**: All integral types (int, int64_t, uint32_t, etc.)
* - **Floating point**: double (uses high-precision Grisu2 algorithm)
* - **Custom types**: Via specialization of `detail::term()`
* - **NOT supported**: const char* variables, std::string, std::string_view
* variables
*
* ## Performance Characteristics:
* - **Compile-time buffer sizing**: Buffer size calculated at compile time (no
@@ -245,16 +249,23 @@ inline constexpr DoubleTerm term(double s) { return DoubleTerm(s); }
*
* ## When to Use:
* - **Hot paths**: Performance-critical code where formatting speed matters
* - **Known types**: When argument types are known at compile time
* - **Compile-time string literals**: All string arguments must be string
* literals (e.g., "Hello")
* - **Simple formatting**: Concatenation and basic type conversion
* - **Template code**: Where compile-time optimization is beneficial
* - **CANNOT use runtime strings**: No const char*, std::string, or string_view
* variables
*
* ## When to Use format() Instead:
* - **Printf-style formatting**: When you need format specifiers like "%d",
* "%.2f"
* - **Runtime flexibility**: When format strings come from variables/config
* - **Complex formatting**: When you need padding, precision, etc.
* - **Convenience**: For quick debugging or non-critical paths
* - **Runtime strings**: When you have const char*, std::string, or string_view
* variables
* - **Dynamic content**: When format strings come from variables/config/user
* input
* - **Complex formatting**: When you need padding, precision, width specifiers
* - **Mixed literal/runtime**: When combining string literals with runtime
* string data
*
* @note All arguments are passed by forwarding reference for optimal
* performance

View File

@@ -195,8 +195,9 @@ void HttpHandler::handlePostCommit(Connection &conn,
const char *error = state.commit_parser
? state.commit_parser->get_parse_error()
: "No parser initialized";
std::string error_msg = "Parse failed: ";
error_msg += error ? error : "Unknown error";
ArenaAllocator &arena = conn.get_arena();
std::string_view error_msg =
format(arena, "Parse failed: %s", error ? error : "Unknown error");
send_error_response(conn, 400, error_msg, state.connection_close);
return;
}
@@ -319,57 +320,47 @@ void HttpHandler::handleNotFound(Connection &conn,
void HttpHandler::sendResponse(Connection &conn, int status_code,
std::string_view content_type,
std::string_view body, bool close_connection) {
[[maybe_unused]] ArenaAllocator &arena = conn.get_arena();
// Build HTTP response using arena
std::string response;
response.reserve(256 + body.size());
response += "HTTP/1.1 ";
response += std::to_string(status_code);
response += " ";
// Status text
switch (status_code) {
case 200:
response += "OK";
break;
case 400:
response += "Bad Request";
break;
case 404:
response += "Not Found";
break;
case 500:
response += "Internal Server Error";
break;
default:
response += "Unknown";
break;
}
ArenaAllocator &arena = conn.get_arena();
auto *state = static_cast<HttpConnectionState *>(conn.user_data);
response += "\r\n";
response += "Content-Type: ";
response += content_type;
response += "\r\n";
response += "Content-Length: ";
response += std::to_string(body.size());
response += "\r\n";
response += "X-Response-ID: ";
response += std::to_string(state->request_id);
response += "\r\n";
if (close_connection) {
response += "Connection: close\r\n";
conn.close_after_send(); // Signal connection should be closed after sending
} else {
response += "Connection: keep-alive\r\n";
// Status text
std::string_view status_text;
switch (status_code) {
case 200:
status_text = "OK";
break;
case 400:
status_text = "Bad Request";
break;
case 404:
status_text = "Not Found";
break;
case 500:
status_text = "Internal Server Error";
break;
default:
status_text = "Unknown";
break;
}
response += "\r\n";
response += body;
const char *connection_header = close_connection ? "close" : "keep-alive";
std::string_view response =
format(arena,
"HTTP/1.1 %d %.*s\r\n"
"Content-Type: %.*s\r\n"
"Content-Length: %zu\r\n"
"X-Response-ID: %ld\r\n"
"Connection: %s\r\n"
"\r\n%.*s",
status_code, static_cast<int>(status_text.size()),
status_text.data(), static_cast<int>(content_type.size()),
content_type.data(), body.size(), state->request_id,
connection_header, static_cast<int>(body.size()), body.data());
if (close_connection) {
conn.close_after_send();
}
conn.append_message(response);
}
@@ -383,11 +374,11 @@ void HttpHandler::send_json_response(Connection &conn, int status_code,
void HttpHandler::send_error_response(Connection &conn, int status_code,
std::string_view message,
bool close_connection) {
[[maybe_unused]] ArenaAllocator &arena = conn.get_arena();
ArenaAllocator &arena = conn.get_arena();
std::string json = R"({"error":")";
json += message;
json += R"("})";
std::string_view json =
format(arena, R"({"error":"%.*s"})", static_cast<int>(message.size()),
message.data());
send_json_response(conn, status_code, json, close_connection);
}