dovecot-2.2: lib-http: Various bugfixes
dovecot at dovecot.org
dovecot at dovecot.org
Fri Feb 1 01:40:12 EET 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/c5230b8ffd40
changeset: 15710:c5230b8ffd40
user: Stephan Bosch <stephan at rename-it.nl>
date: Fri Feb 01 01:39:41 2013 +0200
description:
lib-http: Various bugfixes
diffstat:
src/lib-http/http-client-connection.c | 70 ++++++++++++++------
src/lib-http/http-client-host.c | 4 +-
src/lib-http/http-client-peer.c | 18 ++++-
src/lib-http/http-client-private.h | 7 +-
src/lib-http/http-client-request.c | 113 ++++++++++++++++++++++++++++++---
src/lib-http/http-client.c | 10 +-
src/lib-http/http-client.h | 8 ++
src/lib-http/test-http-client.c | 46 +++++++++++--
8 files changed, 228 insertions(+), 48 deletions(-)
diffs (truncated from 643 to 300 lines):
diff -r 18661d1d6ed0 -r c5230b8ffd40 src/lib-http/http-client-connection.c
--- a/src/lib-http/http-client-connection.c Fri Feb 01 01:03:05 2013 +0200
+++ b/src/lib-http/http-client-connection.c Fri Feb 01 01:39:41 2013 +0200
@@ -66,6 +66,11 @@
conn->client->set.max_pipelined_requests);
}
+bool http_client_connection_is_idle(struct http_client_connection *conn)
+{
+ return (conn->to_idle != NULL);
+}
+
static void
http_client_connection_retry_requests(struct http_client_connection *conn,
unsigned int status, const char *error)
@@ -92,13 +97,14 @@
array_foreach_modifiable(&conn->request_wait_list, req) {
http_client_request_resubmit(*req);
+ http_client_request_unref(req);
}
array_clear(&conn->request_wait_list);
if (conn->client->ioloop != NULL)
io_loop_stop(conn->client->ioloop);
- http_client_connection_free(_conn);
+ http_client_connection_unref(_conn);
}
static void
@@ -111,7 +117,7 @@
conn->closing = TRUE;
http_client_connection_retry_requests(conn, status, error);
- http_client_connection_free(_conn);
+ http_client_connection_unref(_conn);
}
static void
@@ -128,7 +134,7 @@
http_client_request_error(*req, status, error);
}
array_clear(&conn->request_wait_list);
- http_client_connection_free(_conn);
+ http_client_connection_unref(_conn);
}
static void
@@ -136,7 +142,7 @@
{
http_client_connection_debug(conn, "Idle connection timed out");
- http_client_connection_free(&conn);
+ http_client_connection_unref(&conn);
}
static void
@@ -153,9 +159,6 @@
return;
}
- http_client_connection_debug(conn,
- "No more requests queued; going idle");
-
if (conn->client->ioloop != NULL)
io_loop_stop(conn->client->ioloop);
@@ -167,13 +170,20 @@
/* instant death for (urgent) connections above limit */
timeout = 0;
} else {
+ unsigned int idle_count = http_client_peer_idle_connections(conn->peer);
+
/* kill duplicate connections quicker;
linearly based on the number of connections */
- timeout = (conn->client->set.max_parallel_connections - count) *
+ i_assert(count >= idle_count + 1);
+ timeout = (conn->client->set.max_parallel_connections - idle_count) *
(conn->client->set.max_idle_time_msecs /
conn->client->set.max_parallel_connections);
}
+ http_client_connection_debug(conn,
+ "No more requests queued; going idle (timeout = %u msecs)",
+ timeout);
+
conn->to_idle =
timeout_add(timeout, http_client_connection_idle_timeout, conn);
@@ -199,7 +209,6 @@
req_idx = array_idx(&conn->request_wait_list, 0);
req = req_idx[0];
- // FIXME: we should mark this in the peer object for next requests
conn->payload_continue = TRUE;
if (http_client_request_send_more(req) < 0) {
http_client_connection_abort_temp_error(&conn,
@@ -236,6 +245,9 @@
array_append(&conn->request_wait_list, &req, 1);
http_client_request_ref(req);
+ http_client_connection_debug(conn, "Claimed request %s",
+ http_client_request_label(req));
+
if (http_client_request_send(req) < 0) {
http_client_connection_abort_temp_error(&conn,
HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
@@ -255,7 +267,7 @@
period before sending the payload body.
*/
if (req->payload_sync) {
- i_assert(req->payload_size > 0);
+ i_assert(req->payload_chunked || req->payload_size > 0);
i_assert(conn->to_response == NULL);
conn->to_response = timeout_add(HTTP_CLIENT_CONTINUE_TIMEOUT_MSECS,
http_client_connection_continue_timeout, conn);
@@ -284,7 +296,7 @@
break;
}
- http_client_connection_free(&conn);
+ http_client_connection_unref(&conn);
}
static void http_client_payload_finished(struct http_client_connection *conn)
@@ -425,7 +437,7 @@
if (req == NULL) {
/* server sent response without any requests in the wait list */
http_client_connection_error(conn, "Got unexpected input from server");
- http_client_connection_free(&conn);
+ http_client_connection_unref(&conn);
return;
}
@@ -433,10 +445,6 @@
if (conn->to_response != NULL)
timeout_remove(&conn->to_response);
- /* Got some response; cancel response timeout */
- if (conn->to_response != NULL)
- timeout_remove(&conn->to_response);
-
/* https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-21
Section 7.2:
@@ -459,8 +467,11 @@
/* ignore them for now */
http_client_connection_debug(conn,
"Got unexpected %u response; ignoring", response->status);
+ /* restart timeout */
+ conn->to_response = timeout_add(HTTP_CLIENT_CONTINUE_TIMEOUT_MSECS,
+ http_client_connection_continue_timeout, conn);
continue;
- } // FIXME: handle 417 Expectation Failed
+ }
http_client_connection_debug(conn,
"Got %u response for request %s",
@@ -474,7 +485,13 @@
conn->close_indicated = response->connection_close;
if (!aborted) {
- if (response->status / 100 == 3) {
+ if (response->status == 417 && req->payload_sync) {
+ /* drop Expect: continue */
+ req->payload_sync = FALSE;
+ conn->peer->no_payload_sync = TRUE;
+ http_client_request_retry(req, response->status, response->reason);
+ return;
+ } else if (response->status / 100 == 3) {
/* redirect */
http_client_request_redirect(req, response->status, response->location);
} else {
@@ -568,7 +585,7 @@
conn->connected = TRUE;
- if (*conn->client->set.rawlog_dir != '\0' &&
+ if (conn->client->set.rawlog_dir != NULL &&
stat(conn->client->set.rawlog_dir, &st) == 0) {
iostream_rawlog_create(conn->client->set.rawlog_dir,
&conn->conn.input, &conn->conn.output);
@@ -716,6 +733,7 @@
static unsigned int id = 0;
conn = i_new(struct http_client_connection, 1);
+ conn->refcount = 1;
conn->client = peer->client;
conn->peer = peer;
i_array_init(&conn->request_wait_list, 16);
@@ -724,7 +742,7 @@
(peer->client->conn_list, &conn->conn, &peer->addr.ip, peer->addr.port);
if (http_client_connection_connect(conn) < 0) {
- http_client_connection_free(&conn);
+ http_client_connection_unref(&conn);
return NULL;
}
@@ -737,13 +755,23 @@
return conn;
}
-void http_client_connection_free(struct http_client_connection **_conn)
+void http_client_connection_ref(struct http_client_connection *conn)
+{
+ conn->refcount++;
+}
+
+void http_client_connection_unref(struct http_client_connection **_conn)
{
struct http_client_connection *conn = *_conn;
struct http_client_connection *const *conn_idx;
struct http_client_peer *peer = conn->peer;
struct http_client_request **req;
+ i_assert(conn->refcount > 0);
+
+ if (--conn->refcount > 0)
+ return;
+
http_client_connection_debug(conn, "Connection destroy");
conn->connected = FALSE;
diff -r 18661d1d6ed0 -r c5230b8ffd40 src/lib-http/http-client-host.c
--- a/src/lib-http/http-client-host.c Fri Feb 01 01:03:05 2013 +0200
+++ b/src/lib-http/http-client-host.c Fri Feb 01 01:39:41 2013 +0200
@@ -236,7 +236,7 @@
host->ips_count = 1;
host->ips = i_new(struct ip_addr, host->ips_count);
host->ips[0] = ip;
- } else if (*dns_set.dns_client_socket_path == '\0') {
+ } else if (dns_set.dns_client_socket_path == NULL) {
ret = net_gethostbyname(host->name, &ips, &ips_count);
if (ret != 0) {
i_error("http-client: net_gethostbyname(%s) failed: %s",
@@ -327,7 +327,7 @@
}
http_client_host_debug(host,
- "Connection %s:%u claimed request %s %s",
+ "Connection to peer %s:%u claimed request %s %s",
net_ip2addr(&addr->ip), addr->port, http_client_request_label(req),
(req->urgent ? "(urgent)" : ""));
diff -r 18661d1d6ed0 -r c5230b8ffd40 src/lib-http/http-client-peer.c
--- a/src/lib-http/http-client-peer.c Fri Feb 01 01:03:05 2013 +0200
+++ b/src/lib-http/http-client-peer.c Fri Feb 01 01:39:41 2013 +0200
@@ -257,7 +257,7 @@
array_copy(&conns.arr, 0, &peer->conns.arr, 0, array_count(&peer->conns));
array_foreach_modifiable(&conns, conn) {
- http_client_connection_free(conn);
+ http_client_connection_unref(conn);
}
i_assert(array_count(&peer->conns) == 0);
@@ -343,7 +343,7 @@
if (peer->destroyed)
return;
- http_client_peer_debug(peer, "Lost connection (%d connections left)",
+ http_client_peer_debug(peer, "Lost a connection (%d connections left)",
array_count(&peer->conns));
if (array_count(&peer->conns) == 0) {
@@ -356,3 +356,17 @@
}
}
+unsigned int http_client_peer_idle_connections(struct http_client_peer *peer)
+{
+ struct http_client_connection *const *conn_idx;
+ unsigned int idle = 0;
+
+ /* find the least busy connection */
+ array_foreach(&peer->conns, conn_idx) {
+ if (http_client_connection_is_idle(*conn_idx))
+ idle++;
+ }
+
+ return idle;
+}
+
diff -r 18661d1d6ed0 -r c5230b8ffd40 src/lib-http/http-client-private.h
--- a/src/lib-http/http-client-private.h Fri Feb 01 01:03:05 2013 +0200
+++ b/src/lib-http/http-client-private.h Fri Feb 01 01:39:41 2013 +0200
@@ -70,6 +70,7 @@
unsigned int payload_sync:1;
unsigned int payload_chunked:1;
+ unsigned int payload_wait:1;
unsigned int ssl:1;
unsigned int urgent:1;
};
@@ -133,6 +134,7 @@
struct connection conn;
struct http_client_peer *peer;
struct http_client *client;
More information about the dovecot-cvs
mailing list