]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: client: Prevent useless and unexpected request callbacks during http_client...
authorStephan Bosch <stephan@dovecot.fi>
Sun, 22 May 2016 10:48:37 +0000 (12:48 +0200)
committerStephan Bosch <stephan@dovecot.fi>
Thu, 26 May 2016 01:05:44 +0000 (03:05 +0200)
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.

src/lib-http/http-client-private.h
src/lib-http/http-client-request.c
src/lib-http/http-client.c

index 565170ae5063a77ce1fc25de1feb425ab0409c4a..497688970282fe2a284f68db47c4afdb4820c7a4 100644 (file)
@@ -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;
index 5d78a4bf69900c62cabbc755d6429301ec879303..2eff143987b7b59537cea4b640873c71c3c89b47 100644 (file)
@@ -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
index ec1cba878ecaef0aaa7619f0e4c919ed026ea190..dad3b560708f1fba75363b498f97e009491a1dd7 100644 (file)
@@ -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)