]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: client: Made http_client record the current ioloop it is switched to.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Wed, 9 Aug 2017 18:06:00 +0000 (20:06 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 13 Dec 2017 16:04:29 +0000 (18:04 +0200)
This prevents http_client_wait() from switching the client to an ioloop it was never explicitly switched to.

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

index e6e8bae2406fa65249465848cb3900358cd20d3c..425ce3c1eda393fd77e563ad8dc9593888534681 100644 (file)
@@ -377,6 +377,8 @@ struct http_client {
 
        struct http_client_request *requests_list;
        unsigned int requests_count;
+
+       bool waiting:1;
 };
 
 struct http_client_context {
index 42360a4b91d2c3b54bed7f385816941bec35076b..2418d04487670536a3bbae60971c1331296408fe 100644 (file)
@@ -226,7 +226,7 @@ http_client_request_remove(struct http_client_request *req)
        }
        req->listed = FALSE;
 
-       if (client->requests_count == 0 && client->ioloop != NULL)
+       if (client->requests_count == 0 && client->waiting)
                io_loop_stop(client->ioloop);
 }
 
@@ -264,7 +264,7 @@ bool http_client_request_unref(struct http_client_request **_req)
 
        http_client_request_remove(req);
 
-       if (client->requests_count == 0 && client->ioloop != NULL)
+       if (client->requests_count == 0 && client->waiting)
                io_loop_stop(client->ioloop);
 
        if (req->delayed_error != NULL)
@@ -878,7 +878,7 @@ static int
 http_client_request_continue_payload(struct http_client_request **_req,
        const unsigned char *data, size_t size)
 {
-       struct ioloop *prev_ioloop = current_ioloop;
+       struct ioloop *prev_ioloop, *client_ioloop, *prev_client_ioloop;
        struct http_client_request *req = *_req;
        struct http_client_connection *conn = req->conn;
        struct http_client *client = req->client;
@@ -923,18 +923,20 @@ http_client_request_continue_payload(struct http_client_request **_req,
        } else {
                /* Wait for payload data to be written */
 
-               i_assert(client->ioloop == NULL);
-               client->ioloop = io_loop_create();
-               http_client_switch_ioloop(client);
+               prev_ioloop = current_ioloop;
+               client_ioloop = io_loop_create();
+               prev_client_ioloop = http_client_switch_ioloop(client);
                if (client->set.dns_client != NULL)
                        dns_client_switch_ioloop(client->set.dns_client);
 
+               client->waiting = TRUE;
                while (req->state < HTTP_REQUEST_STATE_PAYLOAD_IN) {
                        e_debug(req->event, "Waiting for request to finish");
                
                        if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT)
                                o_stream_set_flush_pending(req->payload_output, TRUE);
-                       io_loop_run(client->ioloop);
+
+                       io_loop_run(client_ioloop);
 
                        if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT &&
                                req->payload_input->eof) {
@@ -942,14 +944,18 @@ http_client_request_continue_payload(struct http_client_request **_req,
                                req->payload_input = NULL;
                                break;
                        }
-               }
+               }       
+               client->waiting = FALSE;
 
-               io_loop_set_current(prev_ioloop);
-               http_client_switch_ioloop(client);
+               if (prev_client_ioloop != NULL)
+                       io_loop_set_current(prev_client_ioloop);
+               else
+                       io_loop_set_current(prev_ioloop);
+               (void)http_client_switch_ioloop(client);
                if (client->set.dns_client != NULL)
                        dns_client_switch_ioloop(client->set.dns_client);
-               io_loop_set_current(client->ioloop);
-               io_loop_destroy(&client->ioloop);
+               io_loop_set_current(client_ioloop);
+               io_loop_destroy(&client_ioloop);
        }
 
        switch (req->state) {
@@ -1059,7 +1065,7 @@ int http_client_request_send_more(struct http_client_request *req,
                        i_assert(!pipelined);
                        conn->output_locked = TRUE;
                        http_client_connection_stop_request_timeout(conn);
-                       if (req->client->ioloop != NULL)
+                       if (req->client->waiting)
                                io_loop_stop(req->client->ioloop);
                } else {
                        /* finished sending payload */
@@ -1337,7 +1343,7 @@ http_client_request_send_error(struct http_client_request *req,
                                i_stream_unref(&req->payload_input);
                }
        }
-       if (req->payload_wait && req->client->ioloop != NULL)
+       if (req->payload_wait)
                io_loop_stop(req->client->ioloop);
        return TRUE;
 }
@@ -1411,8 +1417,10 @@ void http_client_request_abort(struct http_client_request **_req)
 
        if (req->queue != NULL)
                http_client_queue_drop_request(req->queue, req);
-       if (req->payload_wait && req->client->ioloop != NULL)
+       if (req->payload_wait) {
+               i_assert(req->client->ioloop != NULL);
                io_loop_stop(req->client->ioloop);
+       }
        http_client_request_destroy(&req);
 }
 
@@ -1432,8 +1440,10 @@ void http_client_request_finish(struct http_client_request *req)
 
        if (req->queue != NULL)
                http_client_queue_drop_request(req->queue, req);
-       if (req->payload_wait && req->client->ioloop != NULL)
+       if (req->payload_wait) {
+               i_assert(req->client->ioloop != NULL);
                io_loop_stop(req->client->ioloop);
+       }
        http_client_request_unref(&req);
 }
 
index dea7966b0ffec0cf54fb49161e1738f3d88f051a..3503b6120c00a7c8eb0c067b204941dd23dff56d 100644 (file)
@@ -250,8 +250,9 @@ void http_client_deinit(struct http_client **_client)
        pool_unref(&client->pool);
 }
 
-void http_client_switch_ioloop(struct http_client *client)
+struct ioloop *http_client_switch_ioloop(struct http_client *client)
 {
+       struct ioloop *prev_ioloop = client->ioloop;
        struct http_client_peer *peer;
        struct http_client_host *host;
 
@@ -272,40 +273,49 @@ void http_client_switch_ioloop(struct http_client *client)
        }
 
        http_client_context_switch_ioloop(client->cctx);
+
+       client->ioloop = current_ioloop;
+       return prev_ioloop;
 }
 
 void http_client_wait(struct http_client *client)
 {
-       struct ioloop *prev_ioloop = current_ioloop;
+       struct ioloop *prev_ioloop, *client_ioloop, *prev_client_ioloop;
 
        i_assert(client->ioloop == NULL);
 
        if (client->requests_count == 0)
                return;
 
-       client->ioloop = io_loop_create();
-       http_client_switch_ioloop(client);
+       prev_ioloop = current_ioloop;
+       client_ioloop = io_loop_create();
+       prev_client_ioloop = http_client_switch_ioloop(client);
        if (client->set.dns_client != NULL)
                dns_client_switch_ioloop(client->set.dns_client);
        /* either we're waiting for network I/O or we're getting out of a
           callback using timeout_add_short(0) */
-       i_assert(io_loop_have_ios(client->ioloop) ||
-                io_loop_have_immediate_timeouts(client->ioloop));
+       i_assert(io_loop_have_ios(client_ioloop) ||
+                io_loop_have_immediate_timeouts(client_ioloop));
 
+       client->waiting = TRUE;
        do {
                e_debug(client->event,
                        "Waiting for %d requests to finish", client->requests_count);
-               io_loop_run(client->ioloop);
+               io_loop_run(client_ioloop);
        } while (client->requests_count > 0);
+       client->waiting = FALSE;
 
        e_debug(client->event, "All requests finished");
 
-       io_loop_set_current(prev_ioloop);
-       http_client_switch_ioloop(client);
+       if (prev_client_ioloop != NULL)
+               io_loop_set_current(prev_client_ioloop);
+       else
+               io_loop_set_current(prev_ioloop);
+       (void)http_client_switch_ioloop(client);
        if (client->set.dns_client != NULL)
                dns_client_switch_ioloop(client->set.dns_client);
-       io_loop_set_current(client->ioloop);
-       io_loop_destroy(&client->ioloop);
+       io_loop_set_current(client_ioloop);
+       io_loop_destroy(&client_ioloop);
 }
 
 unsigned int http_client_get_pending_request_count(struct http_client *client)
index df3555efdf14cab273621674a6f6a1c3c8a458e4..f339a544f129ceca15e813ed8cec3d7cf55deddc 100644 (file)
@@ -430,7 +430,7 @@ http_client_init_shared(struct http_client_context *cctx,
 void http_client_deinit(struct http_client **_client);
 
 /* switch this client to the current ioloop */
-void http_client_switch_ioloop(struct http_client *client);
+struct ioloop *http_client_switch_ioloop(struct http_client *client);
 
 /* blocks until all currently submitted requests are handled */
 void http_client_wait(struct http_client *client);