]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: Callback can now request a retry with http_client_request_try_retry()
authorTimo Sirainen <tss@iki.fi>
Sun, 10 Mar 2013 18:37:41 +0000 (20:37 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 10 Mar 2013 18:37:41 +0000 (20:37 +0200)
This can be useful for handling "try again" errors from HTTP servers.

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

index 949af799f0411d018ad0a45321449afb2d3544b2..d4bc06590c5c4641ea854e1a92fe7846093fae43 100644 (file)
@@ -392,7 +392,17 @@ http_client_connection_return_response(struct http_client_connection *conn,
                io_remove(&conn->conn.io);
        }
 
-       http_client_request_callback(req, response);
+       if (!http_client_request_callback(req, response)) {
+               /* retrying, don't destroy the request */
+               if (response->payload != NULL) {
+                       i_stream_unset_destroy_callback(conn->incoming_payload);
+                       i_stream_unref(&conn->incoming_payload);
+                       conn->conn.io = io_add(conn->conn.fd_in, IO_READ,
+                                              http_client_connection_input,
+                                              &conn->conn);
+               }
+               return TRUE;
+       }
 
        // FIXME: conn may be freed at this point..
 
@@ -506,6 +516,7 @@ static void http_client_connection_input(struct connection *_conn)
                /* remove request from queue */
                array_delete(&conn->request_wait_list, 0, 1);
                aborted = (req->state == HTTP_REQUEST_STATE_ABORTED);
+               i_assert(req->refcount > 1 || aborted);
                http_client_request_unref(&req);
                
                conn->close_indicated = response->connection_close;
index 0dba7ef726c7b355c89a13c89f47f5da77b0e5ca..6c2ef75ae6610198a168479c62fbc6875ffa5b81 100644 (file)
@@ -191,7 +191,7 @@ int http_client_request_send(struct http_client_request *req,
                             const char **error_r);
 int http_client_request_send_more(struct http_client_request *req,
                                  const char **error_r);
-void http_client_request_callback(struct http_client_request *req,
+bool http_client_request_callback(struct http_client_request *req,
        struct http_response *response);
 void http_client_request_resubmit(struct http_client_request *req);
 void http_client_request_retry(struct http_client_request *req,
index 452599203640c09696bb7a1ec740fe4bc30a3aa3..814cba287d22d54b346fdfd0b9c4da022a476806 100644 (file)
@@ -412,16 +412,25 @@ int http_client_request_send(struct http_client_request *req,
        return ret;
 }
 
-void http_client_request_callback(struct http_client_request *req,
+bool http_client_request_callback(struct http_client_request *req,
                             struct http_response *response)
 {
        http_client_request_callback_t *callback = req->callback;
+       unsigned int orig_attempts = req->attempts;
 
        req->state = HTTP_REQUEST_STATE_GOT_RESPONSE;
 
        req->callback = NULL;
-       if (callback != NULL)
+       if (callback != NULL) {
                callback(response, req->context);
+               if (req->attempts != orig_attempts) {
+                       /* retrying */
+                       req->callback = callback;
+                       http_client_request_resubmit(req);
+                       return FALSE;
+               }
+       }
+       return TRUE;
 }
 
 static void
@@ -636,17 +645,21 @@ void http_client_request_resubmit(struct http_client_request *req)
 void http_client_request_retry(struct http_client_request *req,
        unsigned int status, const char *error)
 {
-       /* limit the number of attempts for each request */
-       if (++req->attempts >= req->client->set.max_attempts) {
-               /* return error */
+       if (!http_client_request_try_retry(req))
                http_client_request_error(req, status, error);
-               return;
-       }
+}
 
-       http_client_request_debug(req, "Retrying (attempts=%d)", req->attempts);
+bool http_client_request_try_retry(struct http_client_request *req)
+{
+       /* limit the number of attempts for each request */
+       if (req->attempts+1 >= req->client->set.max_attempts)
+               return FALSE;
+       req->attempts++;
 
-       /* resubmit */
-       http_client_request_resubmit(req);
+       http_client_request_debug(req, "Retrying (attempts=%d)", req->attempts);
+       if (req->callback != NULL)
+               http_client_request_resubmit(req);
+       return TRUE;
 }
 
 void http_client_request_set_destroy_callback(struct http_client_request *req,
index a83f47b1a4d81aa5ae1bf26e2e71fd622e707a58..0e0423c64a7d1e666756ea3f80ef96b3617bf5db 100644 (file)
@@ -90,6 +90,7 @@ void http_client_request_set_payload(struct http_client_request *req,
 enum http_request_state
 http_client_request_get_state(struct http_client_request *req);
 void http_client_request_submit(struct http_client_request *req);
+bool http_client_request_try_retry(struct http_client_request *req);
 void http_client_request_abort(struct http_client_request **req);
 
 /* Call the specified callback when HTTP request is destroyed. */