diff --git a/ChangeLog b/ChangeLog index e887bea0..05eea630 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ Changes in 1.4.9-stable: o Clear the timer cache when leaving the event loop; reported by Robin Haberkorn o Fix a typo in setting the global event base; reported by lance. o Fix a memory leak when reading multi-line headers + o Fix a memory leak by not running explicit close detection for server connections Changes in 1.4.8-stable: o Match the query in DNS replies to the query in the request; from Vsevolod Stakhov. diff --git a/http.c b/http.c index 0dfed985..3e3f621c 100644 --- a/http.c +++ b/http.c @@ -1907,8 +1907,6 @@ void evhttp_send_reply(struct evhttp_request *req, int code, const char *reason, struct evbuffer *databuf) { - /* set up to watch for client close */ - evhttp_connection_start_detectclose(req->evcon); evhttp_response_code(req, code, reason); evhttp_send(req, databuf); @@ -1918,8 +1916,6 @@ void evhttp_send_reply_start(struct evhttp_request *req, int code, const char *reason) { - /* set up to watch for client close */ - evhttp_connection_start_detectclose(req->evcon); evhttp_response_code(req, code, reason); if (req->major == 1 && req->minor == 1) { /* use chunked encoding for HTTP/1.1 */ diff --git a/test/regress.c b/test/regress.c index e939d1d1..b5fab7e6 100644 --- a/test/regress.c +++ b/test/regress.c @@ -1515,6 +1515,10 @@ main (int argc, char **argv) err = WSAStartup( wVersionRequested, &wsaData ); #endif +#ifndef WIN32 + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + return (1); +#endif setvbuf(stdout, NULL, _IONBF, 0); /* Initalize the event library */ diff --git a/test/regress_http.c b/test/regress_http.c index 7dc763cf..11189c54 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -70,6 +70,7 @@ void http_basic_cb(struct evhttp_request *req, void *arg); static void http_chunked_cb(struct evhttp_request *req, void *arg); void http_post_cb(struct evhttp_request *req, void *arg); void http_dispatcher_cb(struct evhttp_request *req, void *arg); +static void http_large_delay_cb(struct evhttp_request *req, void *arg); static struct evhttp * http_setup(short *pport, struct event_base *base) @@ -94,6 +95,7 @@ http_setup(short *pport, struct event_base *base) evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL); evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, NULL); evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL); + evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, NULL); evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL); *pport = port; @@ -375,6 +377,31 @@ http_basic_test(void) fprintf(stdout, "OK\n"); } +static struct evhttp_connection *delayed_client; + +static void +http_delay_reply(int fd, short what, void *arg) +{ + struct evhttp_request *req = arg; + + evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL); + + ++test_ok; +} + +static void +http_large_delay_cb(struct evhttp_request *req, void *arg) +{ + struct timeval tv; + timerclear(&tv); + tv.tv_sec = 3; + + event_once(-1, EV_TIMEOUT, http_delay_reply, req, &tv); + + /* here we close the client connection which will cause an EOF */ + evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF); +} + void http_request_done(struct evhttp_request *, void *); void http_request_empty_done(struct evhttp_request *, void *); @@ -819,6 +846,7 @@ http_failure_test(void) static void close_detect_done(struct evhttp_request *req, void *arg) { + struct timeval tv; if (req == NULL || req->response_code != HTTP_OK) { fprintf(stderr, "FAILED\n"); @@ -826,7 +854,11 @@ close_detect_done(struct evhttp_request *req, void *arg) } test_ok = 1; - event_loopexit(NULL); + + timerclear(&tv); + tv.tv_sec = 3; /* longer than the http time out */ + + event_loopexit(&tv); } static void @@ -853,7 +885,7 @@ close_detect_cb(struct evhttp_request *req, void *arg) struct evhttp_connection *evcon = arg; struct timeval tv; - if (req->response_code != HTTP_OK) { + if (req != NULL && req->response_code != HTTP_OK) { fprintf(stderr, "FAILED\n"); exit(1); @@ -868,14 +900,15 @@ close_detect_cb(struct evhttp_request *req, void *arg) static void -http_close_detection(void) +http_close_detection(int with_delay) { short port = -1; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; test_ok = 0; - fprintf(stdout, "Testing Connection Close Detection: "); + fprintf(stdout, "Testing Connection Close Detection%s: ", + with_delay ? " (with delay)" : ""); http = http_setup(&port, NULL); @@ -888,6 +921,8 @@ http_close_detection(void) exit(1); } + delayed_client = evcon; + /* * At this point, we want to schedule a request to the HTTP * server using our make request method. @@ -899,7 +934,8 @@ http_close_detection(void) evhttp_add_header(req->output_headers, "Host", "somehost"); /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { + if (evhttp_make_request(evcon, + req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) { fprintf(stdout, "FAILED\n"); exit(1); } @@ -911,6 +947,12 @@ http_close_detection(void) exit(1); } + /* at this point, the http server should have no connection */ + if (TAILQ_FIRST(&http->connections) != NULL) { + fprintf(stdout, "FAILED (left connections)\n"); + exit(1); + } + evhttp_connection_free(evcon); evhttp_free(http); @@ -1361,7 +1403,8 @@ http_suite(void) http_basic_test(); http_connection_test(0 /* not-persistent */); http_connection_test(1 /* persistent */); - http_close_detection(); + http_close_detection(0 /* with delay */); + http_close_detection(1 /* with delay */); http_post_test(); http_failure_test(); http_highport_test();