feat: process buffered client data after upstream connection closes to prevent data loss
Add logic in connection_close to detect remaining buffered data on client read buffer when an upstream connection is closed, and invoke handle_client_read to process it. Also add a forward declaration for handle_client_read and include debug logging for routing decisions. A new test validates that pipelined requests buffered before upstream close are correctly handled.
This commit is contained in:
+20
-1
@@ -36,6 +36,8 @@ connection_t connections[MAX_FDS];
|
||||
int epoll_fd = -1;
|
||||
time_t cached_time = 0;
|
||||
|
||||
static void handle_client_read(connection_t *conn);
|
||||
|
||||
void connection_update_cached_time(void) {
|
||||
cached_time = time(NULL);
|
||||
}
|
||||
@@ -246,6 +248,13 @@ void connection_close(int fd) {
|
||||
pair->splice_pipe[0] = -1;
|
||||
pair->splice_pipe[1] = -1;
|
||||
pair->can_splice = 0;
|
||||
|
||||
memset(&pair->request, 0, sizeof(http_request_t));
|
||||
|
||||
if (buffer_available_read(&pair->read_buf) > 0) {
|
||||
log_debug("Processing buffered data on client fd %d after upstream close", pair->fd);
|
||||
handle_client_read(pair);
|
||||
}
|
||||
} else if (conn->type == CONN_TYPE_CLIENT && pair->type == CONN_TYPE_UPSTREAM) {
|
||||
log_debug("Client fd %d is closing. Closing orphaned upstream pair fd %d.", fd, pair->fd);
|
||||
pair->pair = NULL;
|
||||
@@ -776,7 +785,13 @@ static void handle_client_read(connection_t *conn) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
conn->request_start_time = ts.tv_sec + ts.tv_nsec / 1e9;
|
||||
|
||||
if (http_uri_is_internal_route(conn->request.uri)) {
|
||||
log_debug("[ROUTING-DEBUG] fd=%d state=%d method=%s uri=%s host=%s",
|
||||
conn->fd, conn->state, conn->request.method, conn->request.uri, conn->request.host);
|
||||
|
||||
int is_internal = http_uri_is_internal_route(conn->request.uri);
|
||||
log_debug("[ROUTING-DEBUG] fd=%d is_internal=%d for uri=%s", conn->fd, is_internal, conn->request.uri);
|
||||
|
||||
if (is_internal) {
|
||||
char normalized_uri[2048];
|
||||
http_normalize_uri_path(conn->request.uri, normalized_uri, sizeof(normalized_uri));
|
||||
|
||||
@@ -805,6 +820,9 @@ static void handle_client_read(connection_t *conn) {
|
||||
conn->state = CLIENT_STATE_CLOSING;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
log_debug("[ROUTING-DEBUG] fd=%d NOT internal route, will forward to vhost. uri=%s host=%s",
|
||||
conn->fd, conn->request.uri, conn->request.host);
|
||||
}
|
||||
|
||||
route_config_t *route = config_find_route(conn->request.host);
|
||||
@@ -899,6 +917,7 @@ static void handle_forwarding(connection_t *conn) {
|
||||
log_info("ROUTING-ORPHAN: Client fd=%d lost upstream, resetting to READING_HEADERS", conn->fd);
|
||||
conn->state = CLIENT_STATE_READING_HEADERS;
|
||||
conn->pair = NULL;
|
||||
memset(&conn->request, 0, sizeof(http_request_t));
|
||||
if (buffer_available_read(&conn->read_buf) > 0) {
|
||||
handle_client_read(conn);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user