/pidgin/main: 935120490eb2: HTTP: isolate socket-related code in...

Tomasz Wasilczyk tomkiewicz at cpw.pidgin.im
Fri Jul 19 08:04:48 EDT 2013


Changeset: 935120490eb28ad5d7deaffa8ea422f063532b1b
Author:	 Tomasz Wasilczyk <tomkiewicz at cpw.pidgin.im>
Date:	 2013-07-19 14:03 +0200
Branch:	 default
URL: https://hg.pidgin.im/pidgin/main/rev/935120490eb2

Description:

HTTP: isolate socket-related code in http module; initial implementation for keep-alive connections

diffstat:

 libpurple/http.c |  402 +++++++++++++++++++++++++++++++++++++-----------------
 libpurple/http.h |   63 ++++++++
 2 files changed, 340 insertions(+), 125 deletions(-)

diffs (truncated from 665 to 300 lines):

diff --git a/libpurple/http.c b/libpurple/http.c
--- a/libpurple/http.c
+++ b/libpurple/http.c
@@ -44,6 +44,9 @@ typedef struct _PurpleHttpSocket PurpleH
 
 typedef struct _PurpleHttpHeaders PurpleHttpHeaders;
 
+typedef void (*PurpleHttpSocketConnectCb)(PurpleHttpSocket *hs,
+	const gchar *error, gpointer user_data);
+
 struct _PurpleHttpSocket
 {
 	gboolean is_ssl;
@@ -51,6 +54,9 @@ struct _PurpleHttpSocket
 	PurpleProxyConnectData *raw_connection;
 	int fd;
 	guint inpa;
+	PurpleInputFunction watch_cb;
+	PurpleHttpSocketConnectCb connect_cb;
+	gpointer cb_data;
 };
 
 struct _PurpleHttpRequest
@@ -61,6 +67,7 @@ struct _PurpleHttpRequest
 	gchar *method;
 	PurpleHttpHeaders *headers;
 	PurpleHttpCookieJar *cookie_jar;
+	PurpleHttpKeepalivePool *keepalive_pool;
 
 	gchar *contents;
 	int contents_length;
@@ -81,12 +88,13 @@ struct _PurpleHttpConnection
 	PurpleHttpCallback callback;
 	gpointer user_data;
 	gboolean is_reading;
+	gboolean is_keepalive;
 
 	PurpleHttpURL *url;
 	PurpleHttpRequest *request;
 	PurpleHttpResponse *response;
 
-	PurpleHttpSocket socket;
+	PurpleHttpSocket *socket;
 	GString *request_header;
 	int request_header_written, request_contents_written;
 	gboolean main_header_got, headers_got;
@@ -153,6 +161,11 @@ struct _PurpleHttpCookieJar
 	GHashTable *tab;
 };
 
+struct _PurpleHttpKeepalivePool
+{
+	int ref_count;
+};
+
 static time_t purple_http_rfc1123_to_time(const gchar *str);
 
 static gboolean purple_http_request_is_method(PurpleHttpRequest *request,
@@ -247,6 +260,163 @@ static time_t purple_http_rfc1123_to_tim
 	return t;
 }
 
+/*** HTTP Sockets *************************************************************/
+
+static void _purple_http_socket_connected_raw(gpointer _hs, gint fd,
+	const gchar *error_message)
+{
+	PurpleHttpSocket *hs = _hs;
+
+	hs->raw_connection = NULL;
+
+	if (fd == -1 || error_message != NULL) {
+		if (error_message == NULL)
+			error_message = _("Unknown error");
+		hs->connect_cb(hs, error_message, hs->cb_data);
+		return;
+	}
+
+	hs->fd = fd;
+	hs->connect_cb(hs, NULL, hs->cb_data);
+}
+
+static void _purple_http_socket_connected_ssl(gpointer _hs,
+	PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
+{
+	PurpleHttpSocket *hs = _hs;
+
+	hs->fd = hs->ssl_connection->fd;
+	hs->connect_cb(hs, NULL, hs->cb_data);
+}
+
+static void _purple_http_socket_connected_ssl_error(
+	PurpleSslConnection *ssl_connection, PurpleSslErrorType error,
+	gpointer _hs)
+{
+	PurpleHttpSocket *hs = _hs;
+
+	hs->ssl_connection = NULL;
+	hs->connect_cb(hs, purple_ssl_strerror(error), hs->cb_data);
+}
+
+static PurpleHttpSocket *
+purple_http_socket_connect_new(PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl, PurpleHttpSocketConnectCb cb, gpointer user_data)
+{
+	PurpleHttpSocket *hs = g_new0(PurpleHttpSocket, 1);
+	PurpleAccount *account = NULL;
+
+	if (gc != NULL)
+		account = purple_connection_get_account(gc);
+
+	hs->is_ssl = is_ssl;
+	hs->connect_cb = cb;
+	hs->cb_data = user_data;
+	hs->fd = -1;
+
+	if (is_ssl) {
+		if (!purple_ssl_is_supported()) {
+			g_free(hs);
+			return NULL;
+		}
+
+		hs->ssl_connection = purple_ssl_connect(account,
+			host, port,
+			_purple_http_socket_connected_ssl,
+			_purple_http_socket_connected_ssl_error, hs);
+/* TODO
+		purple_ssl_set_compatibility_level(hs->ssl_connection,
+			PURPLE_SSL_COMPATIBILITY_SECURE);
+*/
+	} else {
+		hs->raw_connection = purple_proxy_connect(gc, account,
+			host, port,
+			_purple_http_socket_connected_raw, hs);
+	}
+
+	if (hs->ssl_connection == NULL &&
+		hs->raw_connection == NULL) {
+		g_free(hs);
+		return NULL;
+	}
+
+	return hs;
+}
+
+static int
+purple_http_socket_read(PurpleHttpSocket *hs, gchar *buf, size_t len)
+{
+	g_return_val_if_fail(hs != NULL, -1);
+	g_return_val_if_fail(buf != NULL, -1);
+
+	if (hs->is_ssl)
+		return purple_ssl_read(hs->ssl_connection, buf, sizeof(buf));
+	else
+		return read(hs->fd, buf, sizeof(buf));
+}
+
+static int
+purple_http_socket_write(PurpleHttpSocket *hs, const gchar *buf, size_t len)
+{
+	g_return_val_if_fail(hs != NULL, -1);
+	g_return_val_if_fail(buf != NULL, -1);
+
+	if (hs->is_ssl)
+		return purple_ssl_write(hs->ssl_connection, buf, len);
+	else
+		return write(hs->fd, buf, len);
+}
+
+static void _purple_http_socket_watch_recv_ssl(gpointer _hs,
+	PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
+{
+	PurpleHttpSocket *hs = _hs;
+
+	g_return_if_fail(hs != NULL);
+
+	hs->watch_cb(hs->cb_data, hs->fd, cond);
+}
+
+static void
+purple_http_socket_watch(PurpleHttpSocket *hs, PurpleInputCondition cond,
+	PurpleInputFunction func, gpointer user_data)
+{
+	g_return_if_fail(hs != NULL);
+
+	if (hs->inpa > 0)
+		purple_input_remove(hs->inpa);
+	hs->inpa = 0;
+
+	if (cond == PURPLE_INPUT_READ && hs->is_ssl) {
+		hs->watch_cb = func;
+		hs->cb_data = user_data;
+		purple_ssl_input_add(hs->ssl_connection,
+			_purple_http_socket_watch_recv_ssl, hs);
+	}
+	else
+		hs->inpa = purple_input_add(hs->fd, cond, func, user_data);
+}
+
+static void
+purple_http_socket_close_free(PurpleHttpSocket *hs)
+{
+	if (hs == NULL)
+		return;
+
+	if (hs->inpa != 0)
+		purple_input_remove(hs->inpa);
+
+	if (hs->is_ssl) {
+		if (hs->ssl_connection != NULL)
+			purple_ssl_close(hs->ssl_connection);
+	} else {
+		if (hs->raw_connection != NULL)
+			purple_proxy_connect_cancel(hs->raw_connection);
+		if (hs->fd > 0)
+			close(hs->fd);
+	}
+	g_free(hs);
+}
+
 /*** Headers collection *******************************************************/
 
 static PurpleHttpHeaders * purple_http_headers_new(void);
@@ -431,18 +601,8 @@ static void _purple_http_gen_headers(Pur
 static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc, gint fd);
 static void _purple_http_recv(gpointer _hc, gint fd,
 	PurpleInputCondition cond);
-static void _purple_http_recv_ssl(gpointer _hc,
-	PurpleSslConnection *ssl_connection, PurpleInputCondition cond);
 static void _purple_http_send(gpointer _hc, gint fd, PurpleInputCondition cond);
 
-static void _purple_http_connected_raw(gpointer _hc, gint source,
-	const gchar *error_message);
-static void _purple_http_connected_ssl(gpointer _hc,
-	PurpleSslConnection *ssl_connection, PurpleInputCondition cond);
-static void _purple_http_connected_ssl_error(
-	PurpleSslConnection *ssl_connection, PurpleSslErrorType error,
-	gpointer _hc);
-
 /* closes current connection (if exists), estabilishes one and proceeds with
  * request */
 static gboolean _purple_http_reconnect(PurpleHttpConnection *hc);
@@ -511,8 +671,11 @@ static void _purple_http_gen_headers(Pur
 
 	if (!purple_http_headers_get(hdrs, "host"))
 		g_string_append_printf(h, "Host: %s\r\n", url->host);
-	if (!purple_http_headers_get(hdrs, "connection"))
-		g_string_append(h, "Connection: close\r\n");
+	if (!purple_http_headers_get(hdrs, "connection")) {
+		g_string_append(h, "Connection: ");
+		g_string_append(h, hc->is_keepalive ?
+			"Keep-Alive\r\n" : "close\r\n");
+	}
 	if (!purple_http_headers_get(hdrs, "accept"))
 		g_string_append(h, "Accept: */*\r\n");
 
@@ -525,7 +688,7 @@ static void _purple_http_gen_headers(Pur
 	}
 
 	if (proxy_http)
-		g_string_append(h, "Proxy-Connection: close\r\n");
+		g_string_append(h, "Proxy-Connection: close\r\n"); /* TEST: proxy+KeepAlive */
 
 	proxy_username = purple_proxy_info_get_username(proxy);
 	if (proxy_http && proxy_username != NULL && proxy_username[0] != '\0') {
@@ -548,7 +711,7 @@ static void _purple_http_gen_headers(Pur
 			proxy_auth);
 		g_string_append_printf(h, "Proxy-Authorization: NTLM %s\r\n",
 			ntlm_type1);
-		g_string_append(h, "Proxy-Connection: Close\r\n");
+		g_string_append(h, "Proxy-Connection: close\r\n"); /* TEST: proxy+KeepAlive */
 
 		memset(proxy_auth, 0, strlen(proxy_auth));
 		g_free(proxy_auth);
@@ -799,15 +962,11 @@ static gboolean _purple_http_recv_body(P
 
 static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc, gint fd)
 {
-	PurpleHttpSocket *hs = &hc->socket;
 	int len;
 	gchar buf[4096];
 	gboolean got_anything;
 
-	if (hs->is_ssl)
-		len = purple_ssl_read(hs->ssl_connection, buf, sizeof(buf));
-	else
-		len = read(fd, buf, sizeof(buf));
+	len = purple_http_socket_read(hc->socket, buf, sizeof(buf));
 	got_anything = (len > 0);
 
 	if (len < 0 && errno == EAGAIN)
@@ -946,12 +1105,6 @@ static void _purple_http_recv(gpointer _
 	while (_purple_http_recv_loopbody(hc, fd));
 }
 
-static void _purple_http_recv_ssl(gpointer _hc,
-	PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
-{
-	_purple_http_recv(_hc, -1, cond);
-}
-



More information about the Commits mailing list