Updated header configuration.
This commit is contained in:
parent
59d075d8e0
commit
ce81738292
130
rproxy.c
130
rproxy.c
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a request to be forwarded to upstream
|
buffer_consume(buf, total_request_len); // Consume the processed request
|
||||||
log_info("[ROUTING-FORWARD] >>> FORWARDING TO UPSTREAM <<< fd=%d: %s %s",
|
|
||||||
conn->fd, conn->request.method, conn->request.uri);
|
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.
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not an internal route, forward the request to the upstream server.
|
||||||
|
log_info("[ROUTING-FORWARD] Forwarding request for fd=%d: %s %s", 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user