Permalink
Browse files

Fix a memory leak by not running explicit close detection for server …

…connections.

svn:r967
  • Loading branch information...
1 parent f383ee2 commit cad8703a2a76c981082e807813e5bb584fc8482f @provos provos committed Dec 19, 2008
Showing with 54 additions and 10 deletions.
  1. +1 −0 ChangeLog
  2. +0 −4 http.c
  3. +4 −0 test/regress.c
  4. +49 −6 test/regress_http.c
View
@@ -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.
View
4 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 */
View
@@ -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 */
View
@@ -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,14 +846,19 @@ 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");
exit(1);
}
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();

0 comments on commit cad8703

Please sign in to comment.