From: Timo Sirainen Date: Sun, 10 Mar 2013 18:37:41 +0000 (+0200) Subject: lib-http: Callback can now request a retry with http_client_request_try_retry() X-Git-Tag: 2.2.rc3~60 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6c768e0e1ca2da178e79f7435c32ced01f6bcb24;p=thirdparty%2Fdovecot%2Fcore.git lib-http: Callback can now request a retry with http_client_request_try_retry() This can be useful for handling "try again" errors from HTTP servers. --- diff --git a/src/lib-http/http-client-connection.c b/src/lib-http/http-client-connection.c index 949af799f0..d4bc06590c 100644 --- a/src/lib-http/http-client-connection.c +++ b/src/lib-http/http-client-connection.c @@ -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; diff --git a/src/lib-http/http-client-private.h b/src/lib-http/http-client-private.h index 0dba7ef726..6c2ef75ae6 100644 --- a/src/lib-http/http-client-private.h +++ b/src/lib-http/http-client-private.h @@ -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, diff --git a/src/lib-http/http-client-request.c b/src/lib-http/http-client-request.c index 4525992036..814cba287d 100644 --- a/src/lib-http/http-client-request.c +++ b/src/lib-http/http-client-request.c @@ -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, diff --git a/src/lib-http/http-client.h b/src/lib-http/http-client.h index a83f47b1a4..0e0423c64a 100644 --- a/src/lib-http/http-client.h +++ b/src/lib-http/http-client.h @@ -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. */