Thu, 26 Feb 2026 21:35:53 +0100
fix proxy event handling
--- a/src/server/proxy/httpclient.c Wed Feb 25 23:14:47 2026 +0100 +++ b/src/server/proxy/httpclient.c Thu Feb 26 21:35:53 2026 +0100 @@ -39,6 +39,7 @@ static int client_connected(EventHandler *ev, Event *event); static int client_io(EventHandler *ev, Event *event); +static int client_process(HttpClient *client, Event *event); static int client_finished(EventHandler *ev, Event *event); static int client_send_buf(HttpClient *client); @@ -239,11 +240,14 @@ return ret; } -int http_client_process(HttpClient *client) { - if(client->stage < 0) { - return 0; +int http_client_process(HttpClient *client, Event *event) { + int ret = client_process(client, event); + if(ret && client->error == 0 && client->event.fn == NULL) { + if(client_start_poll(client)) { + client->error = 1; + } } - return client_io(client->ev, &client->event); + return ret; } size_t http_client_message_buf_size_available(HttpClient *client) { @@ -296,6 +300,7 @@ static int client_connected(EventHandler *ev, Event *event) { HttpClient *client = event->cookie; + client->last_event = event; if(client->stage < 0) { return 0; } @@ -310,6 +315,11 @@ static int client_io(EventHandler *ev, Event *event) { HttpClient *client = event->cookie; + return client_process(client, event); +} + +static int client_process(HttpClient *client, Event *event) { + client->last_event = event; if(client->stage < 0) { return 0; } @@ -330,7 +340,23 @@ } // writing complete, switch to read events - event->events = EVENT_POLLIN; + + if(client->event.events != EVENT_POLLIN) { + if(&client->event != event) { + // The current event, that invoked client_process, is not the + // actual HttpClient event. + // Remove the current HttpClient poll event and re-add it later + // if needed + if(ev_remove_poll(client->ev, client->socketfd)) { + client->error = 1; + return 1; + } + client->event.fn = NULL; + } + client->event.events = EVENT_POLLIN; + + } + client->stage = 1; if(client_read_response_header(client)) { @@ -357,6 +383,7 @@ close(client->socketfd); client->socketfd = -1; + client->stage = -1; // request finished if(client->response_finished) { @@ -381,7 +408,7 @@ if(w <= 0) { if(errno != EAGAIN) { // TODO: log correct host - log_ereport(LOG_VERBOSE, "http-client %s - %s: write failed: %s", "localhost", client->uri, strerror(errno)); + log_ereport(LOG_FAILURE, "http-client %s - %s: write failed: %s", "localhost", client->uri, strerror(errno)); client->error = 1; } return 1;
--- a/src/server/proxy/httpclient.h Wed Feb 25 23:14:47 2026 +0100 +++ b/src/server/proxy/httpclient.h Thu Feb 26 21:35:53 2026 +0100 @@ -141,6 +141,10 @@ void (*response_finished)(HttpClient *, void *); void *response_finished_userdata; + /* + * The last event handler, that processed the http client + */ + Event *last_event; // internals HttpParser *parser; @@ -219,7 +223,7 @@ /* * Handle HttpClient IO and process the request/response */ -int http_client_process(HttpClient *client); +int http_client_process(HttpClient *client, Event *event); /* * Adds message data, that will be sent to client->socketfd. This function
--- a/src/server/safs/proxy.c Wed Feb 25 23:14:47 2026 +0100 +++ b/src/server/safs/proxy.c Thu Feb 26 21:35:53 2026 +0100 @@ -130,6 +130,17 @@ ret = REQ_ABORTED; } + if(client->last_event != &proxy->event && proxy->event.fn != NULL) { + if(!ev_remove_poll(client->ev, proxy->event.object)) { + proxy_unref(proxy); + } else { + log_ereport(LOG_FAILURE, "proxy_response_finished: cannot remove poll"); + } + proxy->event.finish = NULL; + } + + // return to nsapi threadpool + net_setnonblock(proxy->sn->csd, 0); nsapi_function_return(proxy->sn, proxy->rq, ret); proxy_unref(proxy); @@ -137,7 +148,7 @@ static int proxy_request_read_event(EventHandler *eh, Event *event) { ProxyRequest *proxy = event->cookie; - if(http_client_process(proxy->client)) { + if(http_client_process(proxy->client, event)) { if(proxy->client->error == 0) { return 1; } @@ -161,7 +172,7 @@ if(st->io_errno == EWOULDBLOCK) { ret = HTTP_CLIENT_CALLBACK_WOULD_BLOCK; // is there already an poll event for csd? - if(!proxy->event.cookie) { + if(!proxy->event.fn) { proxy->ref++; proxy->event.cookie = proxy; proxy->event.fn = proxy_request_read_event; @@ -181,16 +192,41 @@ static ssize_t proxy_response_write(HttpClient *client, void *buf, size_t nbytes, void *userdata) { ProxyRequest *proxy = userdata; ssize_t ret = net_write(proxy->sn->csd, buf, nbytes); - // TODO: handle errors + if(ret == NETBUF_EOF) { + ret = HTTP_CLIENT_CALLBACK_ERROR; + } else if(ret < 0) { + IOStream *st = proxy->sn->csd; + if(st->io_errno == EWOULDBLOCK) { + // Is there already an poll event for csd? + if(client->last_event == &proxy->event) { + // Yes, there is already an event, and it even is the event that triggert this call. + // Make sure it is a write event + proxy->event.events = EVENT_POLLOUT; + return HTTP_CLIENT_CALLBACK_WOULD_BLOCK; + } else if(proxy->event.fn != NULL) { + // There is an inactive event, probably a read event + // Remove the old event before we add a write event + if(ev_remove_poll(client->ev, proxy->event.object)) { + log_ereport(LOG_FAILURE, "proxy_response_write: cannot remove poll"); + return HTTP_CLIENT_CALLBACK_ERROR; + } + } else { + proxy->ref++; + proxy->event.cookie = proxy; + proxy->event.fn = proxy_request_read_event; + proxy->event.finish = proxy_request_read_finished; + } + // Add write event + if(event_pollout(client->ev, proxy->sn->csd, &proxy->event)) { + proxy_unref(proxy); + log_ereport(LOG_FAILURE, "proxy_response_write: cannot add write poll"); + } + return HTTP_CLIENT_CALLBACK_ERROR; + } + } return ret; } -static void proxy_request_finished(HttpClient *client, void *userdata) { - ProxyRequest *proxy = userdata; - net_setnonblock(proxy->sn->csd, 0); - nsapi_saf_return(proxy->sn, proxy->rq, REQ_PROCEED); -} - int http_reverse_proxy_service(pblock *param, Session *sn, Request *rq) { EventHandler *ev = sn->ev; const char *method = pblock_findkeyval(pb_key_method, rq->reqpb); @@ -396,7 +432,7 @@ client->response_start_userdata = proxy; client->response_body_write = proxy_response_write; client->response_body_write_userdata = proxy; - client->response_finished = proxy_request_finished; + client->response_finished = proxy_response_finished; client->response_finished_userdata = proxy; net_setnonblock(sn->csd, 1);
--- a/src/server/util/io.c Wed Feb 25 23:14:47 2026 +0100 +++ b/src/server/util/io.c Thu Feb 26 21:35:53 2026 +0100 @@ -360,7 +360,7 @@ WSBool httpstream_eof(IOStream *st) { HttpStream *http = (HttpStream*)st; - return http->read_eof; + return http->read_eof || http->read == http->max_read; } int64_t httpstream_written(IOStream *st) {