Accumulate headers properly
This commit is contained in:
@@ -6,14 +6,17 @@
|
||||
#include <strings.h>
|
||||
|
||||
// HttpConnectionState implementation
|
||||
HttpConnectionState::HttpConnectionState(
|
||||
[[maybe_unused]] ArenaAllocator &arena) {
|
||||
HttpConnectionState::HttpConnectionState(ArenaAllocator &arena)
|
||||
: current_header_field_buf(ArenaStlAllocator<char>(&arena)),
|
||||
current_header_value_buf(ArenaStlAllocator<char>(&arena)) {
|
||||
llhttp_settings_init(&settings);
|
||||
|
||||
// Set up llhttp callbacks
|
||||
settings.on_url = HttpHandler::onUrl;
|
||||
settings.on_header_field = HttpHandler::onHeaderField;
|
||||
settings.on_header_field_complete = HttpHandler::onHeaderFieldComplete;
|
||||
settings.on_header_value = HttpHandler::onHeaderValue;
|
||||
settings.on_header_value_complete = HttpHandler::onHeaderValueComplete;
|
||||
settings.on_headers_complete = HttpHandler::onHeadersComplete;
|
||||
settings.on_body = HttpHandler::onBody;
|
||||
settings.on_message_complete = HttpHandler::onMessageComplete;
|
||||
@@ -26,18 +29,23 @@ HttpConnectionState::HttpConnectionState(
|
||||
void HttpHandler::on_connection_established(Connection &conn) {
|
||||
// Allocate HTTP state in connection's arena
|
||||
ArenaAllocator &arena = conn.getArena();
|
||||
auto *state = arena.construct<HttpConnectionState>(arena);
|
||||
void *mem = arena.allocate_raw(sizeof(HttpConnectionState),
|
||||
alignof(HttpConnectionState));
|
||||
auto *state = new (mem) HttpConnectionState(arena);
|
||||
conn.user_data = state;
|
||||
}
|
||||
|
||||
void HttpHandler::on_connection_closed(Connection &conn) {
|
||||
// Arena cleanup happens automatically when connection is destroyed
|
||||
auto *state = static_cast<HttpConnectionState *>(conn.user_data);
|
||||
state->~HttpConnectionState();
|
||||
conn.user_data = nullptr;
|
||||
}
|
||||
|
||||
void HttpHandler::on_write_progress(std::unique_ptr<Connection> &conn_ptr) {
|
||||
// Reset arena after all messages have been written for the next request
|
||||
if (conn_ptr->outgoingBytesQueued() == 0) {
|
||||
on_connection_closed(*conn_ptr);
|
||||
conn_ptr->reset();
|
||||
on_connection_established(*conn_ptr);
|
||||
}
|
||||
@@ -312,31 +320,49 @@ int HttpHandler::onUrl(llhttp_t *parser, const char *at, size_t length) {
|
||||
int HttpHandler::onHeaderField(llhttp_t *parser, const char *at,
|
||||
size_t length) {
|
||||
auto *state = static_cast<HttpConnectionState *>(parser->data);
|
||||
// Store current header field name for processing in onHeaderValue
|
||||
state->current_header_field = std::string_view(at, length);
|
||||
// Accumulate header field data
|
||||
state->current_header_field_buf.append(at, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HttpHandler::onHeaderFieldComplete(llhttp_t *parser) {
|
||||
auto *state = static_cast<HttpConnectionState *>(parser->data);
|
||||
state->header_field_complete = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HttpHandler::onHeaderValue(llhttp_t *parser, const char *at,
|
||||
size_t length) {
|
||||
auto *state = static_cast<HttpConnectionState *>(parser->data);
|
||||
std::string_view value(at, length);
|
||||
// Accumulate header value data
|
||||
state->current_header_value_buf.append(at, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HttpHandler::onHeaderValueComplete(llhttp_t *parser) {
|
||||
auto *state = static_cast<HttpConnectionState *>(parser->data);
|
||||
|
||||
if (!state->header_field_complete) {
|
||||
// Field is not complete yet, wait
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Now we have complete header field and value
|
||||
const auto &field = state->current_header_field_buf;
|
||||
const auto &value = state->current_header_value_buf;
|
||||
|
||||
// Check for Connection header
|
||||
if (state->current_header_field.size() == 10 &&
|
||||
strncasecmp(state->current_header_field.data(), "connection", 10) == 0) {
|
||||
if (field.size() == 10 && strncasecmp(field.data(), "connection", 10) == 0) {
|
||||
if (value.size() == 5 && strncasecmp(value.data(), "close", 5) == 0) {
|
||||
state->connection_close = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for X-Request-Id header
|
||||
if (state->current_header_field.size() == 12 &&
|
||||
strncasecmp(state->current_header_field.data(), "x-request-id", 12) ==
|
||||
0) {
|
||||
if (field.size() == 12 &&
|
||||
strncasecmp(field.data(), "x-request-id", 12) == 0) {
|
||||
uint64_t id = 0;
|
||||
for (int i = 0; i < int(length); ++i) {
|
||||
auto c = at[i];
|
||||
for (char c : value) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
id = id * 10 + (c - '0');
|
||||
}
|
||||
@@ -344,6 +370,11 @@ int HttpHandler::onHeaderValue(llhttp_t *parser, const char *at,
|
||||
state->request_id = id;
|
||||
}
|
||||
|
||||
// Clear buffers for next header
|
||||
state->current_header_field_buf.clear();
|
||||
state->current_header_value_buf.clear();
|
||||
state->header_field_complete = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user