dovecot-2.2: lib-http: Added initial HTTP client implementation.

dovecot at dovecot.org dovecot at dovecot.org
Sat Nov 24 00:33:06 EET 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/107c8b2c9594
changeset: 15394:107c8b2c9594
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Sat Nov 24 00:30:14 2012 +0200
description:
lib-http: Added initial HTTP client implementation.

diffstat:

 src/lib-http/Makefile.am                 |   92 +++-
 src/lib-http/http-client-connection.c    |  788 +++++++++++++++++++++++++++++++
 src/lib-http/http-client-host.c          |  388 +++++++++++++++
 src/lib-http/http-client-peer.c          |  358 ++++++++++++++
 src/lib-http/http-client-private.h       |  250 +++++++++
 src/lib-http/http-client-request.c       |  386 +++++++++++++++
 src/lib-http/http-client.c               |  182 +++++++
 src/lib-http/http-client.h               |   83 +++
 src/lib-http/http-header-parser.c        |  282 +++++++++++
 src/lib-http/http-header-parser.h        |   15 +
 src/lib-http/http-parser.c               |  132 +++++
 src/lib-http/http-parser.h               |   53 ++
 src/lib-http/http-response-parser.c      |  503 +++++++++++++++++++
 src/lib-http/http-response-parser.h      |   37 +
 src/lib-http/http-transfer-chunked.c     |  479 ++++++++++++++++++
 src/lib-http/http-transfer.h             |    8 +
 src/lib-http/test-http-client.c          |  226 ++++++++
 src/lib-http/test-http-header-parser.c   |   18 +-
 src/lib-http/test-http-response-parser.c |  206 ++++++++
 src/lib-http/test-http-responses.c       |   39 +
 src/lib-http/test-http-transfer.c        |  126 ++++
 21 files changed, 4640 insertions(+), 11 deletions(-)

diffs (truncated from 4806 to 300 lines):

diff -r b40bda50541c -r 107c8b2c9594 src/lib-http/Makefile.am
--- a/src/lib-http/Makefile.am	Fri Nov 23 23:49:39 2012 +0200
+++ b/src/lib-http/Makefile.am	Sat Nov 24 00:30:14 2012 +0200
@@ -8,26 +8,51 @@
 
 libhttp_la_SOURCES = \
 	http-date.c \
-	http-url.c
+	http-url.c \
+	http-parser.c \
+	http-header-parser.c \
+	http-transfer-chunked.c \
+	http-response-parser.c \
+	http-client-request.c \
+	http-client-connection.c \
+	http-client-peer.c \
+	http-client-host.c \
+	http-client.c
 
 headers = \
 	http-date.h \
-	http-url.h
+	http-url.h \
+	http-parser.h \
+	http-header-parser.h \
+	http-transfer.h \
+	http-response-parser.h \
+	http-client-private.h \
+	http-client.h
 
 pkginc_libdir=$(pkgincludedir)
 pkginc_lib_HEADERS = $(headers)
 
 test_programs = \
 	test-http-date \
-	test-http-url
+	test-http-url \
+	test-http-header-parser \
+	test-http-transfer \
+	test-http-response-parser \
+	test-http-client
 
-noinst_PROGRAMS = $(test_programs)
+noinst_PROGRAMS = $(test_programs) test-http-responses
 
 test_libs = \
 	../lib-test/libtest.la \
-	../lib/liblib.la
+	../lib/liblib.la \
+	../lib/safe-memset.lo \
+	$(MODULE_LIBS)
 
-test_deps = $(noinst_LTLIBRARIES) $(test_libs)
+test_deps = \
+	$(noinst_LTLIBRARIES)
+	../lib-test/libtest.la \
+	../lib/liblib.la \
+	../lib/safe-memset.lo
 
 test_http_url_SOURCES = test-http-url.c
 test_http_url_LDADD = http-url.lo  $(test_libs)
@@ -37,6 +62,61 @@
 test_http_date_LDADD = http-date.lo  $(test_libs)
 test_http_date_DEPENDENCIES = $(test_deps)
 
+test_http_header_parser_SOURCES = test-http-header-parser.c
+test_http_header_parser_LDADD = http-parser.lo http-header-parser.lo $(test_libs)
+test_http_header_parser_DEPENDENCIES = $(test_deps)
+
+test_http_transfer_SOURCES = test-http-transfer.c
+test_http_transfer_LDADD = \
+	http-parser.lo \
+	http-header-parser.lo \
+	http-transfer-chunked.lo \
+	$(test_libs)
+test_http_transfer_DEPENDENCIES = $(test_deps)
+
+test_http_response_parser_SOURCES = test-http-response-parser.c
+test_http_response_parser_LDADD = \
+	http-date.lo \
+	http-parser.lo \
+	http-header-parser.lo \
+	http-transfer-chunked.lo \
+	http-response-parser.lo \
+	$(test_libs)
+test_http_response_parser_DEPENDENCIES = $(test_deps)
+
+test_http_client_SOURCES = test-http-client.c
+test_http_client_LDFLAGS = -export-dynamic
+test_http_client_LDADD = \
+	libhttp.la \
+	../lib-dns/libdns.la \
+	../lib-ssl-iostream/libssl_iostream.la \
+	$(test_libs)
+test_http_client_DEPENDENCIES = \
+	libhttp.la \
+	../lib-dns/libdns.la \
+	../lib-ssl-iostream/libssl_iostream.la \
+	$(test_deps)
+
+test_http_responses_SOURCES = test-http-responses.c
+test_http_responses_LDADD = \
+	http-date.lo \
+	http-parser.lo \
+	http-header-parser.lo \
+	http-transfer-chunked.lo \
+	http-response-parser.lo \
+	../lib/liblib.la \
+	../lib/safe-memset.lo \
+	$(MODULE_LIBS)
+test_http_responses_DEPENDENCIES = \
+	http-date.lo \
+	http-parser.lo \
+	http-header-parser.lo \
+	http-transfer-chunked.lo \
+	http-response-parser.lo \
+	$(noinst_LTLIBRARIES) \
+	../lib/liblib.la \
+	../lib/safe-memset.lo
+
 check: check-am check-test
 check-test: all-am
 	for bin in $(test_programs); do \
diff -r b40bda50541c -r 107c8b2c9594 src/lib-http/http-client-connection.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-http/http-client-connection.c	Sat Nov 24 00:30:14 2012 +0200
@@ -0,0 +1,788 @@
+/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "net.h"
+#include "str.h"
+#include "hash.h"
+#include "array.h"
+#include "ioloop.h"
+#include "istream.h"
+#include "ostream.h"
+#include "iostream-rawlog.h"
+#include "iostream-ssl.h"
+#include "http-response-parser.h"
+
+#include "http-client-private.h"
+
+/*
+ * Logging
+ */
+
+static inline void
+http_client_connection_debug(struct http_client_connection *conn,
+	const char *format, ...) ATTR_FORMAT(2, 3);
+static inline void
+http_client_connection_error(struct http_client_connection *conn,
+	const char *format, ...) ATTR_FORMAT(2, 3);
+
+static inline void
+http_client_connection_debug(struct http_client_connection *conn,
+	const char *format, ...)
+{
+	va_list args;
+
+	if (conn->client->set.debug) {
+
+		va_start(args, format);	
+		i_debug("http-client: conn %s: %s",
+			http_client_connection_label(conn),	t_strdup_vprintf(format, args));
+		va_end(args);
+	}
+}
+
+static inline void
+http_client_connection_error(struct http_client_connection *conn,
+	const char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);	
+	i_error("http-client: conn %s: %s",
+		http_client_connection_label(conn),	t_strdup_vprintf(format, args));
+	va_end(args);
+}
+
+
+/*
+ * Connection
+ */
+
+static void http_client_connection_input(struct connection *_conn);
+
+bool http_client_connection_is_ready(struct http_client_connection *conn)
+{
+	return (conn->connected && !conn->output_locked &&
+		array_count(&conn->request_wait_list) <
+			conn->client->set.max_pipelined_requests);
+}
+
+static void
+http_client_connection_retry_requests(struct http_client_connection *conn,
+	unsigned int status, const char *error)
+{
+	struct http_client_request **req;
+
+	array_foreach_modifiable(&conn->request_wait_list, req) {
+		http_client_request_retry(*req, status, error);
+	}	
+	array_clear(&conn->request_wait_list);
+}
+
+static void
+http_client_connection_server_close(struct http_client_connection **_conn)
+{
+	struct http_client_connection *conn = *_conn;
+	struct http_client_request **req;
+
+	conn->connected = FALSE;
+	conn->closing = TRUE;
+
+	http_client_connection_debug(conn,
+		"Server explicitly closed connection");
+
+	array_foreach_modifiable(&conn->request_wait_list, req) {
+		http_client_request_resubmit(*req);
+	}	
+	array_clear(&conn->request_wait_list);
+
+	if (conn->client->ioloop != NULL)
+		io_loop_stop(conn->client->ioloop);
+
+	http_client_connection_free(_conn);
+}
+
+static void
+http_client_connection_abort_temp_error(struct http_client_connection **_conn,
+	unsigned int status, const char *error)
+{
+	struct http_client_connection *conn = *_conn;
+
+	conn->connected = FALSE;
+	conn->closing = TRUE;
+	
+	http_client_connection_retry_requests(conn, status, error);
+	http_client_connection_free(_conn);
+}
+
+static void
+http_client_connection_abort_error(struct http_client_connection **_conn,
+	unsigned int status, const char *error)
+{
+	struct http_client_connection *conn = *_conn;
+	struct http_client_request **req;
+
+	conn->connected = FALSE;
+	conn->closing = TRUE;
+	
+	array_foreach_modifiable(&conn->request_wait_list, req) {
+		http_client_request_error(*req, status, error);
+	}	
+	array_clear(&conn->request_wait_list);
+	http_client_connection_free(_conn);
+}
+
+static void
+http_client_connection_idle_timeout(struct http_client_connection *conn)
+{
+	http_client_connection_debug(conn, "Idle connection timed out");
+
+	http_client_connection_free(&conn);
+}
+
+static void
+http_client_connection_check_idle(struct http_client_connection *conn)
+{
+	unsigned int timeout, count;
+
+	if (array_count(&conn->request_wait_list) == 0 &&
+		conn->incoming_payload == NULL &&
+		conn->client->set.max_idle_time_msecs > 0) {
+
+		if (conn->to_idle != NULL) {
+			/* timeout already set */
+			return;
+		}
+
+		http_client_connection_debug(conn, 
+			"No more requests queued; going idle");
+
+		if (conn->client->ioloop != NULL)
+			io_loop_stop(conn->client->ioloop);
+
+		count = array_count(&conn->peer->conns);
+		i_assert(count > 0);
+
+		/* set timeout for this connection */
+		if (count > conn->client->set.max_parallel_connections) {
+			/* instant death for (urgent) connections above limit */
+			timeout = 0;
+		} else {
+			/* kill duplicate connections quicker;
+				 linearly based on the number of connections */
+			timeout = (conn->client->set.max_parallel_connections - count) *
+				(conn->client->set.max_idle_time_msecs /


More information about the dovecot-cvs mailing list