Updated header configuration.

This commit is contained in:
retoor 2025-09-25 19:16:07 +02:00
parent 59d075d8e0
commit ce81738292

128
rproxy.c
View File

@ -1983,128 +1983,110 @@ void handle_client_read(connection_t *conn) {
buffer_t *buf = &conn->read_buf; buffer_t *buf = &conn->read_buf;
log_info("[ROUTING-DEBUG] handle_client_read fd=%d, state=%d, has_pair=%d, bytes_available=%zu, bytes_read=%d", // This function can be re-entered for keep-alive connections.
conn->fd, conn->state, conn->pair ? 1 : 0, buffer_available_read(buf), bytes_read); // Ensure state is correct if a connection was forwarding but lost its pair.
// CRITICAL FIX: Always reset to reading headers if we're not actively forwarding
// This ensures internal routes are always checked first
if (conn->state == CLIENT_STATE_FORWARDING && conn->pair == NULL) { if (conn->state == CLIENT_STATE_FORWARDING && conn->pair == NULL) {
log_info("[ROUTING-FIX] Resetting orphaned forwarding state to READING_HEADERS for fd=%d", conn->fd);
conn->state = CLIENT_STATE_READING_HEADERS; conn->state = CLIENT_STATE_READING_HEADERS;
} }
// Don't process new requests while actively forwarding // Do not attempt to parse new requests if the connection is already actively forwarding.
if (conn->state == CLIENT_STATE_FORWARDING && conn->pair != NULL) { if (conn->state == CLIENT_STATE_FORWARDING) {
log_info("[ROUTING-DEBUG] Skipping request processing - actively forwarding for fd=%d", conn->fd);
return; return;
} }
// Process all complete requests in the buffer (for pipelining) // Process all complete HTTP requests currently in the read buffer (handles pipelining).
while (buffer_available_read(buf) > 0) { while (buffer_available_read(buf) > 0) {
char *data_start = buf->data + buf->head; char *data_start = buf->data + buf->head;
size_t data_len = buffer_available_read(buf); size_t data_len = buffer_available_read(buf);
// Look for end of headers // --- MODIFICATION START: Read until \r\n\r\n before parsing ---
// Step 1: Find the end-of-headers marker ("\r\n\r\n").
char *headers_end = memmem(data_start, data_len, "\r\n\r\n", 4); char *headers_end = memmem(data_start, data_len, "\r\n\r\n", 4);
// If the marker is not found, the full headers have not been received yet.
if (!headers_end) { if (!headers_end) {
if (data_len >= MAX_HEADER_SIZE) { if (data_len >= MAX_HEADER_SIZE) {
send_error_response(conn, 413, "Request Header Too Large", "Header too large"); send_error_response(conn, 413, "Request Header Too Large", "Header is too large.");
return; return;
} }
break; // Incomplete headers, wait for more data // Wait for more data to arrive from the client.
log_debug("fd %d: Incomplete headers, waiting for more data.", conn->fd);
break;
} }
// Step 2: The complete header block is now in the buffer. Proceed to parsing.
size_t headers_len = (headers_end - data_start) + 4; size_t headers_len = (headers_end - data_start) + 4;
// Parse the request
int parse_result = parse_http_request(data_start, headers_len, &conn->request); int parse_result = parse_http_request(data_start, headers_len, &conn->request);
if (parse_result < 0) {
break; // Incomplete, need more data if (parse_result == 0) {
} else if (parse_result == 0) { send_error_response(conn, 400, "Bad Request", "Malformed HTTP request.");
send_error_response(conn, 400, "Bad Request", "Malformed HTTP request");
return; return;
} }
// This case should be rare, but indicates the parser needs more data than just the headers.
if (parse_result < 0) {
break;
}
log_info("[ROUTING-DEBUG] Parsed request fd=%d: %s %s, Host: %s, Content-Length: %ld", // Step 3: Check if the entire request body (if any) has been received.
conn->fd, conn->request.method, conn->request.uri, conn->request.host,
conn->request.content_length);
// Calculate total request size including body
long long body_len = (conn->request.content_length > 0) ? conn->request.content_length : 0; long long body_len = (conn->request.content_length > 0) ? conn->request.content_length : 0;
size_t total_request_len = headers_len + body_len; size_t total_request_len = headers_len + body_len;
if (data_len < total_request_len) { if (data_len < total_request_len) {
break; // Incomplete body, wait for more data // Body is not fully received yet, wait for more data.
log_debug("fd %d: Incomplete body, waiting for more data.", conn->fd);
break;
} }
// --- MODIFICATION END: A full request is now ready for processing ---
// Start timing the request // Start timing the request
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
conn->request_start_time = ts.tv_sec + ts.tv_nsec / 1e9; conn->request_start_time = ts.tv_sec + ts.tv_nsec / 1e9;
// CRITICAL: Always check internal routes first, regardless of connection state // Check for internal routes like /dashboard or /api/stats
log_info("[ROUTING-CHECK] Checking if request is internal: method=%s, uri=%s", if (strcmp(conn->request.method, "GET") == 0 &&
conn->request.method, conn->request.uri); (strncmp(conn->request.uri, "/dashboard", 10) == 0 || strncmp(conn->request.uri, "/api/stats", 10) == 0)) {
if (strcmp(conn->request.method, "GET") == 0) { log_info("[ROUTING-INTERNAL] Serving internal route %s for fd=%d", conn->request.uri, conn->fd);
// If there was a previous upstream connection, close it.
if (conn->pair) {
close_connection(conn->pair->fd);
conn->pair = NULL;
}
conn->state = CLIENT_STATE_SERVING_INTERNAL;
if (strncmp(conn->request.uri, "/dashboard", 10) == 0) { if (strncmp(conn->request.uri, "/dashboard", 10) == 0) {
log_info("[ROUTING-INTERNAL] *** DASHBOARD REQUEST DETECTED *** fd=%d", conn->fd);
// Clean up any existing upstream connection
if (conn->pair) {
log_debug("[ROUTING] Closing existing upstream fd=%d before serving internal", conn->pair->fd);
close_connection(conn->pair->fd);
conn->pair = NULL;
}
conn->state = CLIENT_STATE_SERVING_INTERNAL;
serve_dashboard(conn); serve_dashboard(conn);
buffer_consume(buf, total_request_len); } else {
if (!conn->request.keep_alive) {
conn->state = CLIENT_STATE_CLOSING;
return;
}
conn->state = CLIENT_STATE_READING_HEADERS;
continue;
}
if (strncmp(conn->request.uri, "/api/stats", 10) == 0) {
log_info("[ROUTING-INTERNAL] *** API STATS REQUEST DETECTED *** fd=%d", conn->fd);
// Clean up any existing upstream connection
if (conn->pair) {
log_debug("[ROUTING] Closing existing upstream fd=%d before serving internal", conn->pair->fd);
close_connection(conn->pair->fd);
conn->pair = NULL;
}
conn->state = CLIENT_STATE_SERVING_INTERNAL;
serve_stats_api(conn); serve_stats_api(conn);
buffer_consume(buf, total_request_len);
if (!conn->request.keep_alive) {
conn->state = CLIENT_STATE_CLOSING;
return;
}
conn->state = CLIENT_STATE_READING_HEADERS;
continue;
} }
buffer_consume(buf, total_request_len); // Consume the processed request
if (!conn->request.keep_alive) {
conn->state = CLIENT_STATE_CLOSING;
return; // Exit function, connection will be closed on write complete.
}
conn->state = CLIENT_STATE_READING_HEADERS; // Ready for next keep-alive request.
continue; // Continue loop to process next pipelined request.
} }
// This is a request to be forwarded to upstream // If not an internal route, forward the request to the upstream server.
log_info("[ROUTING-FORWARD] >>> FORWARDING TO UPSTREAM <<< fd=%d: %s %s", log_info("[ROUTING-FORWARD] Forwarding request for fd=%d: %s %s", conn->fd, conn->request.method, conn->request.uri);
conn->fd, conn->request.method, conn->request.uri);
conn->vhost_stats = monitor_get_or_create_vhost_stats(conn->request.host); conn->vhost_stats = monitor_get_or_create_vhost_stats(conn->request.host);
monitor_record_request_start(conn->vhost_stats, conn->request.is_websocket); monitor_record_request_start(conn->vhost_stats, conn->request.is_websocket);
conn->state = CLIENT_STATE_FORWARDING; conn->state = CLIENT_STATE_FORWARDING;
// Create upstream connection and forward the complete request
connect_to_upstream(conn, data_start, total_request_len); connect_to_upstream(conn, data_start, total_request_len);
// Consume the forwarded request from buffer buffer_consume(buf, total_request_len); // Consume the forwarded request
buffer_consume(buf, total_request_len);
// After forwarding, exit the loop - the connection is now in forwarding mode // After starting to forward, stop processing further pipelined requests from this client
// until the current forwarding is complete. The state is now CLIENT_STATE_FORWARDING.
return; return;
} }
} }