]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: client: Fixed problem occuring when a nested ioloop was run inside a reques...
authorStephan Bosch <stephan@rename-it.nl>
Sat, 4 Oct 2014 14:30:54 +0000 (17:30 +0300)
committerStephan Bosch <stephan@rename-it.nl>
Sat, 4 Oct 2014 14:30:54 +0000 (17:30 +0300)
If requests in the nested ioloop would use the same connection as the one
that called the callback, the requests would (in the best scenario) all be
doomed to time out.

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

index 4a0d37de6666c014c1df93f39a97904cd5142ecb..6ea1e3d98dedfd15960d017737b9e17e785e71d6 100644 (file)
@@ -53,13 +53,22 @@ http_client_connection_count_pending(struct http_client_connection *conn)
 {
        unsigned int pending_count = array_count(&conn->request_wait_list);
 
-       if (conn->pending_request != NULL)
+       if (conn->in_req_callback || conn->pending_request != NULL)
                pending_count++;
        return pending_count;
 }
 
 bool http_client_connection_is_ready(struct http_client_connection *conn)
 {
+       if (conn->in_req_callback) {
+               /* this can happen when a nested ioloop is created inside request
+                  callback. we currently don't reuse connections that are occupied
+                  this way, but theoretically we could, although that would add
+                  quite a bit of complexity.
+                */
+               return FALSE;
+       }
+
        return (conn->connected && !conn->output_locked &&
                !conn->close_indicated && !conn->tunneling &&
                http_client_connection_count_pending(conn) <
@@ -184,6 +193,7 @@ void http_client_connection_check_idle(struct http_client_connection *conn)
        if (conn->connected &&
                array_is_created(&conn->request_wait_list) &&
                array_count(&conn->request_wait_list) == 0 &&
+               !conn->in_req_callback &&
                conn->incoming_payload == NULL &&
                conn->client->set.max_idle_time_msecs > 0) {
 
@@ -437,6 +447,7 @@ http_client_connection_return_response(struct http_client_connection *conn,
        struct istream *payload;
        bool retrying;
 
+       i_assert(!conn->in_req_callback);
        i_assert(conn->incoming_payload == NULL);
        i_assert(conn->pending_request == NULL);
 
@@ -459,10 +470,12 @@ http_client_connection_return_response(struct http_client_connection *conn,
                if (conn->to_requests != NULL)
                        timeout_remove(&conn->to_requests);
        }
-
+       
+       conn->in_req_callback = TRUE;
        http_client_connection_ref(conn);
        retrying = !http_client_request_callback(req, response);
        http_client_connection_unref(&conn);
+       conn->in_req_callback = FALSE;
        if (conn == NULL) {
                /* the callback managed to get this connection destroyed */
                if (!retrying)
index f16b332a01a7696e5d8fb4ced4d0811b236b8ce9..6fe7cf785174e9076879bfc4688bbc730ba30512 100644 (file)
@@ -142,6 +142,7 @@ struct http_client_connection {
        unsigned int output_locked:1;       /* output is locked; no pipelining */
        unsigned int payload_continue:1;    /* received 100-continue for current
                                                request */
+       unsigned int in_req_callback:1;  /* performin request callback (busy) */
 };
 
 struct http_client_peer {