From: Stephan Bosch Date: Wed, 9 Aug 2017 18:06:00 +0000 (+0200) Subject: lib-http: client: Made http_client record the current ioloop it is switched to. X-Git-Tag: 2.3.0.rc1~63 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e8a1b62fe4a81b211dcccd1a58b44f254074eab6;p=thirdparty%2Fdovecot%2Fcore.git lib-http: client: Made http_client record the current ioloop it is switched to. This prevents http_client_wait() from switching the client to an ioloop it was never explicitly switched to. --- diff --git a/src/lib-http/http-client-private.h b/src/lib-http/http-client-private.h index e6e8bae240..425ce3c1ed 100644 --- a/src/lib-http/http-client-private.h +++ b/src/lib-http/http-client-private.h @@ -377,6 +377,8 @@ struct http_client { struct http_client_request *requests_list; unsigned int requests_count; + + bool waiting:1; }; struct http_client_context { diff --git a/src/lib-http/http-client-request.c b/src/lib-http/http-client-request.c index 42360a4b91..2418d04487 100644 --- a/src/lib-http/http-client-request.c +++ b/src/lib-http/http-client-request.c @@ -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); } diff --git a/src/lib-http/http-client.c b/src/lib-http/http-client.c index dea7966b0f..3503b6120c 100644 --- a/src/lib-http/http-client.c +++ b/src/lib-http/http-client.c @@ -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) diff --git a/src/lib-http/http-client.h b/src/lib-http/http-client.h index df3555efdf..f339a544f1 100644 --- a/src/lib-http/http-client.h +++ b/src/lib-http/http-client.h @@ -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);