changeset 21334:919df3038bf5

lib-http: client: Treat connections that get disconnected prematurely as connection failures. This means that the backoff time is increased when this happens. A premature disconnection happens when the connection is disconnected before any data is received from the server.
author Stephan Bosch <stephan.bosch@dovecot.fi>
date Fri, 16 Dec 2016 23:36:19 +0100
parents f7bc77720fe5
children aeadca02bfe1
files src/lib-http/http-client-connection.c src/lib-http/http-client-peer.c src/lib-http/http-client-private.h
diffstat 3 files changed, 20 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-http/http-client-connection.c	Fri Dec 16 22:30:42 2016 +0100
+++ b/src/lib-http/http-client-connection.c	Fri Dec 16 23:36:19 2016 +0100
@@ -298,6 +298,9 @@
 		}
 	}
 
+	conn->lost_prematurely = (conn->conn.input != NULL &&
+		conn->conn.input->v_offset == 0 &&
+		i_stream_get_data_size(conn->conn.input) == 0);
 	http_client_connection_abort_temp_error(_conn,
 		HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, error);
 }
@@ -1546,7 +1549,7 @@
 	}
 
 	if (conn->connect_succeeded)
-		http_client_peer_connection_lost(peer);
+		http_client_peer_connection_lost(peer, conn->lost_prematurely);
 }
 
 bool http_client_connection_unref(struct http_client_connection **_conn)
--- a/src/lib-http/http-client-peer.c	Fri Dec 16 22:30:42 2016 +0100
+++ b/src/lib-http/http-client-peer.c	Fri Dec 16 23:36:19 2016 +0100
@@ -813,7 +813,8 @@
 	}
 }
 
-void http_client_peer_connection_lost(struct http_client_peer *peer)
+void http_client_peer_connection_lost(struct http_client_peer *peer,
+	bool premature)
 {
 	unsigned int num_pending, num_urgent;
 
@@ -827,11 +828,21 @@
 	num_pending = http_client_peer_requests_pending(peer, &num_urgent);
 
 	http_client_peer_debug(peer,
-		"Lost a connection (%u queues linked, %u connections left, "
+		"Lost a connection%s (%u queues linked, %u connections left, "
 			"%u requests pending, %u requests urgent)",
+		(premature ? " prematurely" : ""),
 		array_count(&peer->queues), array_count(&peer->conns),
 		num_pending, num_urgent);
 
+	/* update backoff timer if the connection was lost prematurely.
+	   this prevents reconnecting immediately to a server that is
+	   misbehaving by disconnecting before sending a response.
+	 */
+	if (premature) {
+		peer->last_failure = ioloop_timeval;
+		http_client_peer_increase_backoff_timer(peer);
+	}
+
 	if (peer->handling_requests) {
 		/* we got here from the request handler loop */
 		http_client_peer_debug(peer,
--- a/src/lib-http/http-client-private.h	Fri Dec 16 22:30:42 2016 +0100
+++ b/src/lib-http/http-client-private.h	Fri Dec 16 23:36:19 2016 +0100
@@ -178,6 +178,7 @@
 	unsigned int connect_initialized:1; /* connection was initialized */
 	unsigned int connect_succeeded:1;   /* connection succeeded including SSL */
 	unsigned int connect_failed:1;      /* connection failed */
+	unsigned int lost_prematurely:1;    /* lost connection before receiving any data */
 	unsigned int closing:1;
 	unsigned int disconnected:1;
 	unsigned int close_indicated:1;
@@ -465,7 +466,8 @@
 void http_client_peer_connection_success(struct http_client_peer *peer);
 void http_client_peer_connection_failure(struct http_client_peer *peer,
 					 const char *reason);
-void http_client_peer_connection_lost(struct http_client_peer *peer);
+void http_client_peer_connection_lost(struct http_client_peer *peer,
+	bool premature);
 bool http_client_peer_is_connected(struct http_client_peer *peer);
 unsigned int
 http_client_peer_idle_connections(struct http_client_peer *peer);