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