# HG changeset patch # User Olaf Wintermann # Date 1772054180 -3600 # Node ID 778dcf4ad63c48352064709bba3fe4ddb006e765 # Parent 395c62fac7e5fb6207be74dfe76ab3cde7b3b527 fix multiple reads could corrupt the httpclient buffer content diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/daemon/event.h --- a/src/server/daemon/event.h Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/daemon/event.h Wed Feb 25 22:16:20 2026 +0100 @@ -120,6 +120,7 @@ int ev_pollin(EventHandler *h, int fd, Event *event); int ev_pollout(EventHandler *h, int fd, Event *event); +int ev_poll(EventHandler *h, int fd, Event *event); int ev_remove_poll(EventHandler *h, int fd); int ev_send(EventHandler *h, Event *event); diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/daemon/event_bsd.c --- a/src/server/daemon/event_bsd.c Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/daemon/event_bsd.c Wed Feb 25 22:16:20 2026 +0100 @@ -199,6 +199,20 @@ return kevent(h->kqueue, &kev, 1, NULL, 0, NULL); } +int ev_poll(EventHandler *h, int fd, Event *event) { + event->events = EVENT_POLLOUT; + int filter = 0; + if(event->events & EVENT_POLLOUT) { + filter |= EVFILT_WRITE; + } + if(event->events & EVENT_POLIN) { + filter |= EVFILT_READ; + } + struct kevent kev; + EV_SET(&kev, fd, filter, EV_ADD, 0, 0, event); + return kevent(h->kqueue, &kev, 1, NULL, 0, NULL); +} + int ev_remove_poll(EventHandler *h, int fd) { struct kevent kev; EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/daemon/event_linux.c --- a/src/server/daemon/event_linux.c Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/daemon/event_linux.c Wed Feb 25 22:16:20 2026 +0100 @@ -278,8 +278,8 @@ } } -int ev_convert2sys_events(int events) { - int e = EPOLLET; +uint32_t ev_convert2sys_events(int events) { + uint32_t e = EPOLLET | EPOLLRDHUP; if((events & EVENT_POLLIN) == EVENT_POLLIN) { e |= EPOLLIN; } @@ -309,6 +309,15 @@ return epoll_ctl(ev->ep, EPOLL_CTL_ADD, fd, &epev); } +int ev_poll(EventHandler *h, int fd, Event *event) { + EventHandlerLinux *ev = (EventHandlerLinux*)h; + event->object = (intptr_t)fd; + struct epoll_event epev; + epev.events = ev_convert2sys_events(event->events); + epev.data.ptr = event; + return epoll_ctl(ev->ep, EPOLL_CTL_ADD, fd, &epev); +} + int ev_remove_poll(EventHandler *h, int fd) { EventHandlerLinux *ev = (EventHandlerLinux*)h; return epoll_ctl(ev->ep, EPOLL_CTL_DEL, fd, NULL); diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/daemon/event_linux.h --- a/src/server/daemon/event_linux.h Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/daemon/event_linux.h Wed Feb 25 22:16:20 2026 +0100 @@ -111,7 +111,7 @@ void ev_handle_events(EventHandlerLinux *ev); -int ev_convert2sys_events(int events); +uint32_t ev_convert2sys_events(int events); void ev_queue_free(EventQueue *queue); diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/daemon/event_solaris.c --- a/src/server/daemon/event_solaris.c Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/daemon/event_solaris.c Wed Feb 25 22:16:20 2026 +0100 @@ -202,6 +202,17 @@ event); } +int ev_poll(EventHandler *h, int fd, Event *event) { + EventHandlerSolaris *ev = (EventHandlerSolaris*)h; + event->object = (intptr_t)fd; + return port_associate( + ev->port, + PORT_SOURCE_FD, + (uintptr_t)fd, + ev_convert2sys_events(event->events), + event); +} + int ev_remove_poll(EventHandler *h, int fd) { EventHandlerSolaris *ev = (EventHandlerSolaris*)h; return port_dissociate(ev->port, PORT_SOURCE_FD, (uintptr_t)fd); diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/proxy/httpclient.c --- a/src/server/proxy/httpclient.c Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/proxy/httpclient.c Wed Feb 25 22:16:20 2026 +0100 @@ -194,22 +194,19 @@ return http_client_add_request_header(client, cx_mutstr("transfer-encoding"), cx_mutstr("chunked")); } -static int client_start_poll(HttpClient *client, int in) { +static int client_start_poll(HttpClient *client) { client->event.fn = client_connected; client->event.finish = client_finished; - if(in) { - return ev_pollin(client->ev, client->socketfd, &client->event); - } else { - return ev_pollout(client->ev, client->socketfd, &client->event); - } + return ev_poll(client->ev, client->socketfd, &client->event); } int http_client_start(HttpClient *client) { + client->event.events = EVENT_POLLOUT; client->event.cookie = client; if(client->socketfd != -1) { int ret = client_connected(client->ev, &client->event); if(ret != 0) { - return client_start_poll(client, 1); // TODO: check event type + return client_start_poll(client); } return 0; } @@ -222,12 +219,12 @@ return 1; } client->socketfd = socketfd; - + int ret = 1; if(connect(socketfd, client->addr, client->addrlen)) { int err = errno; if(err == EINPROGRESS) { - ret = client_start_poll(client, 1); + ret = client_start_poll(client); } else { log_ereport(LOG_FAILURE, "http-client-start: connect failed: %s", strerror(err)); } @@ -326,7 +323,7 @@ event->events = EVENT_POLLIN; client->stage = 1; - if(client_read_response_header(client)) { + if(client_read_response_header(client)) { return client->error == 0; } int ret = 0; @@ -472,9 +469,9 @@ unsigned char *buffer = client->buffer.inbuf + client->buffer.cursize; size_t nbytes = client->buffer.maxsize - client->buffer.cursize; - + ssize_t r; - while((r = read(client->socketfd, buffer, nbytes)) > 0) { + while((r = read(client->socketfd, client->buffer.inbuf + client->buffer.cursize, client->buffer.maxsize - client->buffer.cursize)) > 0) { client->buffer.cursize += r; if(!client->response_header_complete) { switch(http_parser_process(client->parser)) { diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/proxy/httpclient.h --- a/src/server/proxy/httpclient.h Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/proxy/httpclient.h Wed Feb 25 22:16:20 2026 +0100 @@ -62,7 +62,7 @@ int socketfd; HttpStream *stream; - + HeaderArray *request_headers; HeaderArray *response_headers; diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/test/httpclient.c --- a/src/server/test/httpclient.c Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/test/httpclient.c Wed Feb 25 22:16:20 2026 +0100 @@ -43,6 +43,21 @@ static pthread_cond_t test_cond; static volatile int test_finished; +void http_client_tests_init(void) { + pthread_mutex_init(&test_mutex, NULL); + pthread_cond_init(&test_cond, NULL); + + EventHandlerConfig config; + config.isdefault = 0; + config.name = cx_str(NULL); + config.nthreads = 1; + test_eventhandler = evhandler_create(&config); +} + +void http_client_tests_cleanup(void) { + ev_instance_shutdown(test_eventhandler->instances[0]); +} + static void test_response_finished(HttpClient *client, void *userdata) { pthread_mutex_lock(&test_mutex); pthread_cond_signal(&test_cond); @@ -53,21 +68,10 @@ static ssize_t test_response_body_write(HttpClient *client, void *buf, size_t nbytes, void *userdata) { char *str = buf; - return cxBufferWrite(buf, 1, nbytes, userdata); + return cxBufferWrite(str, 1, nbytes, userdata); } CX_TEST_SUBROUTINE(test_httpclient, cxstring *response_blocks, size_t num_blocks, CxBuffer *out, int error_interval) { - pthread_mutex_init(&test_mutex, NULL); - pthread_cond_init(&test_cond, NULL); - - if(!test_eventhandler) { - EventHandlerConfig config; - config.isdefault = 0; - config.name = cx_str(NULL); - config.nthreads = 1; - test_eventhandler = evhandler_create(&config); - } - HttpClient *client = http_client_new(test_eventhandler->instances[0]); client->response_body_write = test_response_body_write; client->response_body_write_userdata = out; @@ -80,7 +84,7 @@ http_client_set_socket(client, fds[0]); http_client_set_method(client, "GET"); http_client_set_uri(client, "/testx01"); - + test_finished = 0; int ret = http_client_start(client); CX_TEST_ASSERT(ret == 0); @@ -97,13 +101,13 @@ } } - close(fds[1]); - pthread_mutex_lock(&test_mutex); if(test_finished == 0) { pthread_cond_wait(&test_cond, &test_mutex); } pthread_mutex_unlock(&test_mutex); + + close(fds[1]); } CX_TEST(test_http_client_simple_get1) { diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/test/httpclient.h --- a/src/server/test/httpclient.h Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/test/httpclient.h Wed Feb 25 22:16:20 2026 +0100 @@ -35,6 +35,9 @@ extern "C" { #endif +void http_client_tests_init(void); +void http_client_tests_cleanup(void); + CX_TEST(test_http_client_simple_get1); CX_TEST(test_http_client_simple_get_line_io); CX_TEST(test_http_client_simple_get_small_blocksize); diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/test/main.c --- a/src/server/test/main.c Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/test/main.c Wed Feb 25 22:16:20 2026 +0100 @@ -75,6 +75,8 @@ pblock_init_default_keys(); vfs_init(); + http_client_tests_init(); + //test(); //printf("%s", "Webserver Test Suite\n====================\n\n"); @@ -222,6 +224,8 @@ cx_test_run_stdout(suite); fflush(stdout); + http_client_tests_cleanup(); + return EXIT_SUCCESS; } diff -r 395c62fac7e5 -r 778dcf4ad63c src/server/util/socket.c --- a/src/server/util/socket.c Tue Feb 24 21:28:06 2026 +0100 +++ b/src/server/util/socket.c Wed Feb 25 22:16:20 2026 +0100 @@ -65,7 +65,7 @@ if(port) { *port = ntohs(addr.sin_port); } - + return socket_fd; }