/cpw/tomkiewicz/http: 013c5aebb665: Let's connect

Tomasz Wasilczyk tomkiewicz at cpw.pidgin.im
Fri Oct 12 22:14:01 EDT 2012


Changeset: 013c5aebb665e0c3c159b9f6c4b59142907e310e
Author:	 Tomasz Wasilczyk <tomkiewicz at cpw.pidgin.im>
Date:	 2012-10-13 04:13 +0200
Branch:	 default
URL: http://hg.pidgin.im/cpw/tomkiewicz/http/rev/013c5aebb665

Description:

Let's connect

diffstat:

 libpurple/http.c            |  228 ++++++++++++++++++++++++++++++++++++++++---
 libpurple/http.h            |   14 +-
 libpurple/protocols/gg/gg.c |    6 +-
 3 files changed, 227 insertions(+), 21 deletions(-)

diffs (truncated from 381 to 300 lines):

diff --git a/libpurple/http.c b/libpurple/http.c
--- a/libpurple/http.c
+++ b/libpurple/http.c
@@ -31,6 +31,18 @@
 
 typedef struct _PurpleHttpURL PurpleHttpURL;
 
+typedef struct _PurpleHttpSocket PurpleHttpSocket;
+
+struct _PurpleHttpSocket
+{
+	gboolean is_connected;
+	gboolean is_ssl;
+	PurpleSslConnection *ssl_connection;
+	PurpleProxyConnectData *raw_connection;
+	int fd;
+	guint inpa;
+};
+
 struct _PurpleHttpRequest
 {
 	int ref_count;
@@ -47,11 +59,14 @@ struct _PurpleHttpConnection
 	PurpleHttpURL *url;
 	PurpleHttpRequest *request;
 	PurpleHttpResponse *response;
+
+	PurpleHttpSocket socket;
 };
 
 struct _PurpleHttpResponse
 {
 	int code;
+	gchar *error;
 
 	gchar *data;
 	gsize data_len;
@@ -79,6 +94,178 @@ static void purple_http_url_free(PurpleH
 
 static const gchar * purple_http_url_debug(PurpleHttpURL *parsed_url);
 
+/*** HTTP protocol backend ****************************************************/
+
+static void purple_http_dummy_success(PurpleHttpConnection *hc)
+{
+	PurpleHttpResponse *response = hc->response;
+
+	response->code = 200;
+	response->data = g_strdup(purple_http_url_debug(hc->url));
+	response->data_len = strlen(response->data);
+
+	purple_http_conn_cancel(hc);
+}
+
+static void _purple_http_disconnect(PurpleHttpConnection *hc);
+
+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);
+
+static void _purple_http_error(PurpleHttpConnection *hc, const char *format,
+	...) G_GNUC_PRINTF(2, 3);
+
+static void _purple_http_error(PurpleHttpConnection *hc, const char *format,
+	...)
+{
+	va_list args;
+
+	va_start(args, format);
+	hc->response->error = g_strdup_vprintf(format, args);
+	va_end(args);
+
+	purple_http_conn_cancel(hc);
+}
+
+static void _purple_http_send(gpointer _hc, gint fd, PurpleInputCondition cond)
+{ // url_fetch_send_cb
+	PurpleHttpConnection *hc = _hc;
+
+	purple_debug_misc("http", "[tmp] sending...\n");
+
+	purple_http_dummy_success(hc);
+}
+
+static void _purple_http_connected_raw(gpointer _hc, gint fd,
+	const gchar *error_message)
+{
+	PurpleHttpConnection *hc = _hc;
+	PurpleHttpSocket *hs = &hc->socket;
+
+	hs->raw_connection = NULL;
+
+	if (fd == -1) {
+		_purple_http_error(hc, _("Unable to connect to %s: %s"),
+			hc->url->host, error_message);
+		return;
+	}
+
+	hs->fd = fd;
+	hs->inpa = purple_input_add(fd, PURPLE_INPUT_WRITE,
+		_purple_http_send, hc);
+	_purple_http_send(hc, fd, PURPLE_INPUT_WRITE);
+}
+
+static void _purple_http_connected_ssl(gpointer _hc,
+	PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
+{
+	PurpleHttpConnection *hc = _hc;
+	PurpleHttpSocket *hs = &hc->socket;
+
+	hs->fd = hs->ssl_connection->fd;
+	hs->inpa = purple_input_add(hs->fd, PURPLE_INPUT_WRITE,
+		_purple_http_send, hc);
+	_purple_http_send(hc, hs->fd, PURPLE_INPUT_WRITE);
+}
+
+static void _purple_http_connected_ssl_error(
+	PurpleSslConnection *ssl_connection, PurpleSslErrorType error,
+	gpointer _hc)
+{
+	PurpleHttpConnection *hc = _hc;
+	PurpleHttpSocket *hs = &hc->socket;
+
+	hs->ssl_connection = NULL;
+	_purple_http_error(hc, _("Unable to connect to %s: %s"),
+		hc->url->host, purple_ssl_strerror(error));
+}
+
+static void _purple_http_disconnect(PurpleHttpConnection *hc)
+{
+	PurpleHttpSocket *hs;
+
+	g_return_if_fail(hc != NULL);
+
+	hs = &hc->socket;
+
+	if (!hs->is_connected)
+		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);
+	}
+
+	memset(hs, 0, sizeof(PurpleHttpSocket));
+}
+
+static gboolean _purple_http_reconnect(PurpleHttpConnection *hc)
+{
+	PurpleHttpURL *url;
+	gboolean is_ssl = FALSE;
+	PurpleAccount *account = NULL;
+
+	g_return_val_if_fail(hc != NULL, FALSE);
+	g_return_val_if_fail(hc->url != NULL, FALSE);
+
+	_purple_http_disconnect(hc);
+
+	if (hc->gc)
+		account = purple_connection_get_account(hc->gc);
+
+	url = hc->url;
+	if (url->protocol[0] == '\0' ||
+		g_ascii_strcasecmp(url->protocol, "http") == 0) {
+		/* do nothing */
+	} else if (g_ascii_strcasecmp(url->protocol, "https") == 0) {
+		is_ssl = TRUE;
+	} else {
+		_purple_http_error(hc, _("Unsupported protocol: %s"),
+			url->protocol);
+		return FALSE;
+	}
+
+	hc->socket.is_ssl = is_ssl;
+	if (is_ssl) {
+		hc->socket.ssl_connection = purple_ssl_connect(account,
+			url->host, url->port,
+			_purple_http_connected_ssl,
+			_purple_http_connected_ssl_error, hc);
+	} else {
+		hc->socket.raw_connection = purple_proxy_connect(hc->gc, account,
+			url->host, url->port,
+			_purple_http_connected_raw, hc);
+	}
+
+	if (hc->socket.ssl_connection == NULL &&
+		hc->socket.raw_connection == NULL) {
+		_purple_http_error(hc, _("Unable to connect to %s"), url->host);
+		return FALSE;
+	}
+	hc->socket.is_connected = TRUE;
+
+	return TRUE;
+}
+
 /*** Performing HTTP requests *************************************************/
 
 PurpleHttpConnection * purple_http_get(PurpleConnection *gc, const gchar *url,
@@ -96,20 +283,6 @@ PurpleHttpConnection * purple_http_get(P
 	return hc;
 }
 
-static gboolean purple_http_request_dummy_timeout(gpointer user_data)
-{
-	PurpleHttpConnection *hc = user_data;
-	PurpleHttpResponse *response = hc->response;
-
-	response->code = 200;
-	response->data = g_strdup(purple_http_url_debug(hc->url));
-	response->data_len = strlen(response->data);
-
-	purple_http_connection_terminate(hc);
-
-	return FALSE;
-}
-
 PurpleHttpConnection * purple_http_request(PurpleConnection *gc,
 	PurpleHttpRequest *request, PurpleHttpCallback callback,
 	gpointer user_data)
@@ -130,13 +303,15 @@ PurpleHttpConnection * purple_http_reque
 		purple_debug_misc("http", "Performing new request %p.\n", hc);
 
 	hc->url = purple_http_url_parse(request->url);
-	if (!hc->url) {
+	if (!hc->url || hc->url->host[0] == '\0') {
 		purple_debug_error("http", "Invalid URL requested.\n");
 		purple_http_connection_terminate(hc);
 		return NULL;
 	}
 
-	purple_timeout_add_seconds(1, purple_http_request_dummy_timeout, hc);
+	_purple_http_reconnect(hc);
+
+	/* TODO: timeout */
 
 	return hc;
 }
@@ -161,6 +336,10 @@ static void purple_http_connection_free(
 	purple_http_url_free(hc->url);
 	purple_http_request_unref(hc->request);
 	purple_http_response_free(hc->response);
+
+	if (hc->socket.is_connected)
+		purple_debug_error("http", "Socket is still connected!");
+
 	g_free(hc);
 }
 
@@ -179,6 +358,13 @@ static void purple_http_connection_termi
 	purple_http_connection_free(hc);
 }
 
+void purple_http_conn_cancel(PurpleHttpConnection *http_conn)
+{
+	http_conn->response->code = 0;
+	_purple_http_disconnect(http_conn);
+	purple_http_connection_terminate(http_conn);
+}
+
 void purple_http_conn_cancel_all(PurpleConnection *gc)
 {
 	purple_debug_warning("http", "purple_http_conn_cancel_all: To be implemented\n");
@@ -241,6 +427,7 @@ static PurpleHttpResponse * purple_http_
 
 static void purple_http_response_free(PurpleHttpResponse *response)
 {
+	g_free(response->error);
 	g_free(response);
 }
 
@@ -258,6 +445,13 @@ int purple_http_response_get_code(Purple
 	return response->code;
 }
 
+const gchar * purple_http_response_get_error(PurpleHttpResponse *response)
+{
+	g_return_val_if_fail(response != NULL, NULL);
+
+	return response->error;
+}
+
 gsize purple_http_response_get_data_len(PurpleHttpResponse *response)



More information about the Commits mailing list