dovecot-2.2: lib-http: Added connect and request timeout settings.
dovecot at dovecot.org
dovecot at dovecot.org
Wed Jun 5 16:19:56 EEST 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/a551409911f9
changeset: 16451:a551409911f9
user: Timo Sirainen <tss at iki.fi>
date: Wed Jun 05 16:19:38 2013 +0300
description:
lib-http: Added connect and request timeout settings.
diffstat:
src/lib-http/http-client-connection.c | 72 ++++++++++++++++++++++++++++++++++-
src/lib-http/http-client-private.h | 5 +-
src/lib-http/http-client.c | 2 +
src/lib-http/http-client.h | 7 +++
4 files changed, 83 insertions(+), 3 deletions(-)
diffs (218 lines):
diff -r 20b065a5299d -r a551409911f9 src/lib-http/http-client-connection.c
--- a/src/lib-http/http-client-connection.c Wed Jun 05 15:43:42 2013 +0300
+++ b/src/lib-http/http-client-connection.c Wed Jun 05 16:19:38 2013 +0300
@@ -8,6 +8,7 @@
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
+#include "time-util.h"
#include "iostream-rawlog.h"
#include "iostream-ssl.h"
#include "http-response-parser.h"
@@ -202,6 +203,17 @@
}
static void
+http_client_connection_request_timeout(struct http_client_connection *conn)
+{
+ unsigned int msecs = conn->client->set.request_timeout_msecs;
+
+ http_client_connection_abort_temp_error(&conn,
+ HTTP_CLIENT_REQUEST_ERROR_TIMED_OUT, t_strdup_printf(
+ "No response for request in %u.%03u secs",
+ msecs/1000, msecs%1000));
+}
+
+static void
http_client_connection_continue_timeout(struct http_client_connection *conn)
{
struct http_client_request *const *req_idx;
@@ -249,6 +261,11 @@
if (conn->to_idle != NULL)
timeout_remove(&conn->to_idle);
+ if (conn->client->set.request_timeout_msecs > 0 &&
+ conn->to_requests == NULL) {
+ conn->to_requests = timeout_add(conn->client->set.request_timeout_msecs,
+ http_client_connection_request_timeout, conn);
+ }
req->conn = conn;
conn->payload_continue = FALSE;
if (conn->peer->no_payload_sync)
@@ -293,14 +310,26 @@
struct http_client_connection *conn =
(struct http_client_connection *)_conn;
const char *error;
+ unsigned int msecs;
conn->closing = TRUE;
conn->connected = FALSE;
switch (_conn->disconnect_reason) {
case CONNECTION_DISCONNECT_CONNECT_TIMEOUT:
- http_client_peer_connection_failure(conn->peer, t_strdup_printf(
- "connect(%s) failed: Connection timed out", _conn->name));
+ if (conn->connected_timestamp.tv_sec == 0) {
+ msecs = timeval_diff_msecs(&ioloop_timeval,
+ &conn->connect_start_timestamp);
+ http_client_peer_connection_failure(conn->peer, t_strdup_printf(
+ "connect(%s) failed: Connection timed out in %u.%03u secs",
+ _conn->name, msecs/1000, msecs%1000));
+ } else {
+ msecs = timeval_diff_msecs(&ioloop_timeval,
+ &conn->connected_timestamp);
+ http_client_peer_connection_failure(conn->peer, t_strdup_printf(
+ "SSL handshaking to %s failed: Connection timed out in %u.%03u secs",
+ _conn->name, msecs/1000, msecs%1000));
+ }
break;
case CONNECTION_DISCONNECT_CONN_CLOSED:
/* retry pending requests if possible */
@@ -453,6 +482,8 @@
http_client_payload_finished(conn);
finished++;
}
+ if (conn->to_requests != NULL)
+ timeout_reset(conn->to_requests);
/* get first waiting request */
if (array_count(&conn->request_wait_list) > 0) {
@@ -560,6 +591,9 @@
req = req_idx[0];
no_payload = (strcmp(req->method, "HEAD") == 0);
} else {
+ /* no more requests waiting for the connection */
+ if (conn->to_requests != NULL)
+ timeout_remove(&conn->to_requests);
req = NULL;
no_payload = FALSE;
}
@@ -597,6 +631,9 @@
const char *error;
int ret;
+ if (conn->to_requests != NULL)
+ timeout_reset(conn->to_requests);
+
if ((ret = o_stream_flush(output)) <= 0) {
if (ret < 0) {
http_client_connection_abort_temp_error(&conn,
@@ -635,6 +672,8 @@
conn->connected = TRUE;
conn->peer->last_connect_failed = FALSE;
+ if (conn->to_connect != NULL)
+ timeout_remove(&conn->to_connect);
if (conn->client->set.rawlog_dir != NULL &&
stat(conn->client->set.rawlog_dir, &st) == 0) {
@@ -718,6 +757,7 @@
http_client_peer_connection_failure(conn->peer, t_strdup_printf(
"connect(%s) failed: %m", _conn->name));
} else {
+ conn->connected_timestamp = ioloop_timeval;
http_client_connection_debug(conn, "Connected");
if (conn->peer->addr.https_name != NULL) {
if (http_client_connection_ssl_init(conn, &error) < 0) {
@@ -758,12 +798,32 @@
http_client_connection_unref(&conn);
}
+static void http_client_connect_timeout(struct http_client_connection *conn)
+{
+ conn->conn.disconnect_reason = CONNECTION_DISCONNECT_CONNECT_TIMEOUT;
+ http_client_connection_destroy(&conn->conn);
+}
+
static void http_client_connection_connect(struct http_client_connection *conn)
{
+ unsigned int msecs;
+
+ conn->connect_start_timestamp = ioloop_timeval;
if (connection_client_connect(&conn->conn) < 0) {
conn->connect_errno = errno;
conn->to_input = timeout_add_short(0,
http_client_connection_delayed_connect_error, conn);
+ return;
+ }
+
+ /* don't use connection.h timeout because we want this timeout
+ to include also the SSL handshake */
+ msecs = conn->client->set.connect_timeout_msecs;
+ if (msecs == 0)
+ msecs = conn->client->set.request_timeout_msecs;
+ if (msecs > 0) {
+ conn->to_connect =
+ timeout_add(msecs, http_client_connect_timeout, conn);
}
}
@@ -831,6 +891,10 @@
ssl_iostream_unref(&conn->ssl_iostream);
connection_deinit(&conn->conn);
+ if (conn->to_requests != NULL)
+ timeout_remove(&conn->to_requests);
+ if (conn->to_connect != NULL)
+ timeout_remove(&conn->to_connect);
if (conn->to_input != NULL)
timeout_remove(&conn->to_input);
if (conn->to_idle != NULL)
@@ -855,6 +919,10 @@
void http_client_connection_switch_ioloop(struct http_client_connection *conn)
{
+ if (conn->to_requests != NULL)
+ conn->to_requests = io_loop_move_timeout(&conn->to_requests);
+ if (conn->to_connect != NULL)
+ conn->to_requests = io_loop_move_timeout(&conn->to_connect);
if (conn->to_input != NULL)
conn->to_input = io_loop_move_timeout(&conn->to_input);
if (conn->to_idle != NULL)
diff -r 20b065a5299d -r a551409911f9 src/lib-http/http-client-private.h
--- a/src/lib-http/http-client-private.h Wed Jun 05 15:43:42 2013 +0300
+++ b/src/lib-http/http-client-private.h Wed Jun 05 16:19:38 2013 +0300
@@ -134,10 +134,13 @@
unsigned int id; // DEBUG: identify parallel connections
int connect_errno;
+ struct timeval connect_start_timestamp;
+ struct timeval connected_timestamp;
struct ssl_iostream *ssl_iostream;
struct http_response_parser *http_parser;
- struct timeout *to_input, *to_idle, *to_response;
+ struct timeout *to_connect, *to_input, *to_idle, *to_response;
+ struct timeout *to_requests;
struct http_client_request *pending_request;
struct istream *incoming_payload;
diff -r 20b065a5299d -r a551409911f9 src/lib-http/http-client.c
--- a/src/lib-http/http-client.c Wed Jun 05 15:43:42 2013 +0300
+++ b/src/lib-http/http-client.c Wed Jun 05 16:19:38 2013 +0300
@@ -96,6 +96,8 @@
(set->max_pipelined_requests > 0 ? set->max_pipelined_requests : 1);
client->set.max_attempts = set->max_attempts;
client->set.max_redirects = set->max_redirects;
+ client->set.request_timeout_msecs = set->request_timeout_msecs;
+ client->set.connect_timeout_msecs = set->connect_timeout_msecs;
client->set.debug = set->debug;
client->conn_list = http_client_connection_list_init();
diff -r 20b065a5299d -r a551409911f9 src/lib-http/http-client.h
--- a/src/lib-http/http-client.h Wed Jun 05 15:43:42 2013 +0300
+++ b/src/lib-http/http-client.h Wed Jun 05 16:19:38 2013 +0300
@@ -57,6 +57,13 @@
/* maximum number of attempts for a request */
unsigned int max_attempts;
+ /* max time to wait for HTTP request to finish before retrying
+ (default = unlimited) */
+ unsigned int request_timeout_msecs;
+ /* max time to wait for connect() (and SSL handshake) to finish before
+ retrying (default = request_timeout_msecs) */
+ unsigned int connect_timeout_msecs;
+
bool debug;
};
More information about the dovecot-cvs
mailing list