From: Stephan Bosch Date: Sun, 22 May 2016 10:48:37 +0000 (+0200) Subject: lib-http: client: Prevent useless and unexpected request callbacks during http_client... X-Git-Tag: 2.3.0.rc1~3658 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6ab81c81be13f33486746deeffe02a1ef2bcc821;p=thirdparty%2Fdovecot%2Fcore.git lib-http: client: Prevent useless and unexpected request callbacks during http_client_deinit(). Requests are now destroyed before queues, hosts, peers and connections. As a side-effect, requests are now removed from the client request list at http_client_request_destroy(), so that requests with lingering references will no longer make http_client_wait() hang. --- diff --git a/src/lib-http/http-client-private.h b/src/lib-http/http-client-private.h index 565170ae50..4976889702 100644 --- a/src/lib-http/http-client-private.h +++ b/src/lib-http/http-client-private.h @@ -131,6 +131,7 @@ struct http_client_request { unsigned int payload_wait:1; unsigned int urgent:1; unsigned int submitted:1; + unsigned int listed:1; unsigned int connect_tunnel:1; unsigned int connect_direct:1; unsigned int ssl_tunnel:1; diff --git a/src/lib-http/http-client-request.c b/src/lib-http/http-client-request.c index 5d78a4bf69..2eff143987 100644 --- a/src/lib-http/http-client-request.c +++ b/src/lib-http/http-client-request.c @@ -151,6 +151,32 @@ http_client_request_connect_ip(struct http_client *client, return req; } +static void +http_client_request_add(struct http_client_request *req) +{ + struct http_client *client = req->client; + + DLLIST_PREPEND(&client->requests_list, req); + client->requests_count++; + req->listed = TRUE; +} + +static void +http_client_request_remove(struct http_client_request *req) +{ + struct http_client *client = req->client; + + if (req->listed) { + /* only decrease pending request counter if this request was submitted */ + DLLIST_REMOVE(&client->requests_list, req); + client->requests_count--; + } + req->listed = FALSE; + + if (client->requests_count == 0 && client->ioloop != NULL) + io_loop_stop(client->ioloop); +} + void http_client_request_ref(struct http_client_request *req) { i_assert(req->refcount > 0); @@ -183,11 +209,7 @@ bool http_client_request_unref(struct http_client_request **_req) req->destroy_callback = NULL; } - /* only decrease pending request counter if this request was submitted */ - if (req->submitted) { - DLLIST_REMOVE(&client->requests_list, req); - client->requests_count--; - } + http_client_request_remove(req); if (client->requests_count == 0 && client->ioloop != NULL) io_loop_stop(client->ioloop); @@ -214,6 +236,10 @@ void http_client_request_destroy(struct http_client_request **_req) http_client_request_debug(req, "Destroy (requests left=%d)", client->requests_count); + if (req->state < HTTP_REQUEST_STATE_FINISHED) + req->state = HTTP_REQUEST_STATE_ABORTED; + req->callback = NULL; + if (req->queue != NULL) http_client_queue_drop_request(req->queue, req); @@ -223,6 +249,7 @@ void http_client_request_destroy(struct http_client_request **_req) req->destroy_callback = NULL; callback(req->destroy_context); } + http_client_request_remove(req); http_client_request_unref(&req); } @@ -589,16 +616,13 @@ static void http_client_request_do_submit(struct http_client_request *req) void http_client_request_submit(struct http_client_request *req) { - struct http_client *client = req->client; - req->submit_time = ioloop_timeval; http_client_request_do_submit(req); http_client_request_debug(req, "Submitted"); req->submitted = TRUE; - DLLIST_PREPEND(&client->requests_list, req); - client->requests_count++; + http_client_request_add(req); } void diff --git a/src/lib-http/http-client.c b/src/lib-http/http-client.c index ec1cba878e..dad3b56070 100644 --- a/src/lib-http/http-client.c +++ b/src/lib-http/http-client.c @@ -163,24 +163,20 @@ struct http_client *http_client_init(const struct http_client_settings *set) void http_client_deinit(struct http_client **_client) { struct http_client *client = *_client; - struct http_client_request *req, *const *req_idx; + struct http_client_request *req; struct http_client_host *host; struct http_client_peer *peer; *_client = NULL; - /* drop delayed failing requests */ - while (array_count(&client->delayed_failing_requests) > 0) { - req_idx = array_idx(&client->delayed_failing_requests, 0); - req = *req_idx; - - i_assert(req->refcount == 1); - http_client_request_error_delayed(&req); + /* destroy requests without calling callbacks */ + req = client->requests_list; + while (req != NULL) { + struct http_client_request *next_req = req->next; + http_client_request_destroy(&req); + req = next_req; } - array_free(&client->delayed_failing_requests); - - if (client->to_failing_requests != NULL) - timeout_remove(&client->to_failing_requests); + i_assert(client->requests_count == 0); /* free peers */ while (client->peers_list != NULL) { @@ -196,6 +192,10 @@ void http_client_deinit(struct http_client **_client) } hash_table_destroy(&client->hosts); + array_free(&client->delayed_failing_requests); + if (client->to_failing_requests != NULL) + timeout_remove(&client->to_failing_requests); + connection_list_deinit(&client->conn_list); if (client->ssl_ctx != NULL)