From: Stephan Bosch Date: Wed, 10 Sep 2014 10:39:37 +0000 (+0300) Subject: lib-http: server: Fixed segfault occurring in connection input handler. X-Git-Tag: 2.2.14.rc1~103 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0998d8af979005bf094a3cebea2b9feb692575fb;p=thirdparty%2Fdovecot%2Fcore.git lib-http: server: Fixed segfault occurring in connection input handler. Request handlers could close and destroy the connection early. Fixed by holding a reference in the input handler. --- diff --git a/src/lib-http/http-server-connection.c b/src/lib-http/http-server-connection.c index fcce9d5a68..79b1687e3a 100644 --- a/src/lib-http/http-server-connection.c +++ b/src/lib-http/http-server-connection.c @@ -426,12 +426,15 @@ static void http_server_connection_input(struct connection *_conn) /* parse requests */ ret = 1; while (!conn->close_indicated && ret != 0) { + http_server_connection_ref(conn); while ((ret = http_request_parse_next (conn->http_parser, req->pool, &req->req, &error_code, &error)) > 0) { if (pending_request != NULL) { /* previous request is now fully read and ready to respond */ http_server_request_ready_to_respond(pending_request); + if (conn->closed) + break; } http_server_connection_debug(conn, @@ -452,6 +455,7 @@ static void http_server_connection_input(struct connection *_conn) http_server_request_destroy(&req); else http_server_request_unref(&req); + http_server_connection_unref(&conn); return; } if (req->req.connection_close) @@ -460,15 +464,16 @@ static void http_server_connection_input(struct connection *_conn) http_server_request_destroy(&req); else http_server_request_unref(&req); - + /* client indicated it will close after this request; stop trying - to read more. */ - if (conn->close_indicated) + to read more. */ + if (conn->close_indicated) break; if (conn->request_queue_count >= conn->server->set.max_pipelined_requests) { http_server_connection_input_halt(conn); + http_server_connection_unref(&conn); return; } @@ -476,6 +481,10 @@ static void http_server_connection_input(struct connection *_conn) req = http_server_request_new(conn); } + http_server_connection_unref(&conn); + if (conn == NULL || conn->closed) + return; + if (ret <= 0 && (conn->conn.input->eof || conn->conn.input->stream_errno != 0)) { int stream_errno = conn->conn.input->stream_errno; @@ -545,7 +554,11 @@ static void http_server_connection_input(struct connection *_conn) if (ret == 0 && pending_request != NULL && !http_request_parser_pending_payload(conn->http_parser)) { /* previous request is now fully read and ready to respond */ + http_server_connection_ref(conn); http_server_request_ready_to_respond(pending_request); + http_server_connection_unref(&conn); + if (conn == NULL || conn->closed) + return; } } }