--- a/libpurple/http.c Thu Sep 01 02:21:01 2016 -0500
+++ b/libpurple/http.c Sun Sep 11 11:39:25 2016 -0500
@@ -28,7 +28,7 @@
-#include "purple-socket.h"
@@ -57,9 +57,15 @@
typedef struct _PurpleHttpGzStream PurpleHttpGzStream;
+typedef void (*PurpleHttpSocketConnectCb)(PurpleHttpSocket *hs, + const gchar *error, gpointer _hc);
+ GSocketConnection *conn; + GCancellable *cancellable; @@ -175,7 +181,7 @@
struct _PurpleHttpKeepaliveRequest
- PurpleSocketConnectCb cb;
+ PurpleHttpSocketConnectCb cb; PurpleHttpKeepaliveHost *host;
@@ -247,7 +253,7 @@
static PurpleHttpKeepaliveRequest *
purple_http_keepalive_pool_request(PurpleHttpKeepalivePool *pool,
PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl,
- PurpleSocketConnectCb cb, gpointer user_data);
+ PurpleHttpSocketConnectCb cb, gpointer user_data); purple_http_keepalive_pool_request_cancel(PurpleHttpKeepaliveRequest *req);
@@ -463,23 +469,65 @@
return g_strdup_printf("%c:%s:%d", (is_ssl ? 'S' : 'R'), host, port);
+purple_http_socket_connect_new_cb(GObject *source, GAsyncResult *res, + PurpleHttpSocket *hs = user_data; + GSocketConnection *conn; + PurpleHttpSocketConnectCb cb; + conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source), + cb = g_object_steal_data(source, "cb"); + cb_data = g_object_steal_data(source, "cb_data"); + cb(hs, error->message, cb_data); static PurpleHttpSocket *
purple_http_socket_connect_new(PurpleConnection *gc, const gchar *host,
- int port, gboolean is_ssl, PurpleSocketConnectCb cb, gpointer user_data)
+ int port, gboolean is_ssl, + PurpleHttpSocketConnectCb cb, gpointer user_data) - PurpleHttpSocket *hs = g_new0(PurpleHttpSocket, 1);
- hs->ps = purple_socket_new(gc);
- purple_socket_set_data(hs->ps, "hs", hs);
- purple_socket_set_tls(hs->ps, is_ssl);
- purple_socket_set_host(hs->ps, host);
- purple_socket_set_port(hs->ps, port);
- if (!purple_socket_connect(hs->ps, cb, user_data)) {
- purple_socket_destroy(hs->ps);
+ client = purple_gio_socket_client_new( + purple_connection_get_account(gc), &error); + purple_debug_error("http", "Error connecting to '%s:%d': %s", + host, port, error->message); + hs = g_new0(PurpleHttpSocket, 1); + hs->cancellable = g_cancellable_new(); + g_socket_client_set_tls(client, is_ssl); + g_object_set_data(G_OBJECT(client), "cb", cb); + g_object_set_data(G_OBJECT(client), "cb_data", user_data); + g_socket_client_connect_to_host_async(client, + host, port, hs->cancellable, + purple_http_socket_connect_new_cb, hs); + g_object_unref(client); if (purple_debug_is_verbose())
purple_debug_misc("http", "new socket created: %p\n", hs);
@@ -495,7 +543,26 @@
if (purple_debug_is_verbose())
purple_debug_misc("http", "destroying socket: %p\n", hs);
- purple_socket_destroy(hs->ps);
+ if (hs->input_source > 0) { + g_source_remove(hs->input_source); + if (hs->output_source > 0) { + g_source_remove(hs->output_source); + if (hs->cancellable != NULL) { + g_cancellable_cancel(hs->cancellable); + g_clear_object(&hs->cancellable); + if (hs->conn != NULL) { + purple_gio_graceful_close(G_IO_STREAM(hs->conn), NULL, NULL); + g_clear_object(&hs->conn); @@ -682,10 +749,9 @@
static void _purple_http_gen_headers(PurpleHttpConnection *hc);
-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_send(gpointer _hc, gint fd, PurpleInputCondition cond);
+static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc); +static gboolean _purple_http_recv(GObject *source, gpointer _hc); +static gboolean _purple_http_send(GObject *source, gpointer _hc); /* closes current connection (if exists), estabilishes one and proceeds with
@@ -1077,21 +1143,31 @@
return _purple_http_recv_body_data(hc, buf, len);
-static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc, gint fd)
+static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc)
- len = purple_socket_read(hc->socket->ps, (guchar*)buf, sizeof(buf));
+ len = g_pollable_input_stream_read_nonblocking( + G_POLLABLE_INPUT_STREAM( + g_io_stream_get_input_stream( + G_IO_STREAM(hc->socket->conn))), + buf, sizeof(buf), hc->socket->cancellable, got_anything = (len > 0);
- if (len < 0 && errno == EAGAIN)
+ if (len < 0 && g_error_matches(error, + G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { _purple_http_error(hc, _("Error reading from %s: %s"),
- hc->url->host, g_strerror(errno));
+ hc->url->host, error->message); @@ -1270,11 +1346,13 @@
-static void _purple_http_recv(gpointer _hc, gint fd, PurpleInputCondition cond)
+static gboolean _purple_http_recv(GObject *source, gpointer _hc) PurpleHttpConnection *hc = _hc;
- while (_purple_http_recv_loopbody(hc, fd));
+ while (_purple_http_recv_loopbody(hc)); + return G_SOURCE_CONTINUE; static void _purple_http_send_got_data(PurpleHttpConnection *hc,
@@ -1305,17 +1383,19 @@
hc->request->contents_length = estimated_length;
-static void _purple_http_send(gpointer _hc, gint fd, PurpleInputCondition cond)
+static gboolean _purple_http_send(GObject *source, gpointer _hc) PurpleHttpConnection *hc = _hc;
gboolean writing_headers;
/* Waiting for data. This could be written more efficiently, by removing
* (and later, adding) hs->inpa. */
if (hc->contents_reader_requested)
+ return G_SOURCE_CONTINUE; _purple_http_gen_headers(hc);
@@ -1328,7 +1408,7 @@
hc->request_header_written;
} else if (hc->request->contents_reader) {
if (hc->contents_reader_requested)
- return; /* waiting for data */
+ return G_SOURCE_CONTINUE; /* waiting for data */ if (!hc->contents_reader_buffer)
hc->contents_reader_buffer = g_string_new("");
if (hc->contents_reader_buffer->len == 0) {
@@ -1341,7 +1421,7 @@
PURPLE_HTTP_MAX_READ_BUFFER_LEN,
hc->request->contents_reader_data,
_purple_http_send_got_data);
+ return G_SOURCE_CONTINUE; write_from = hc->contents_reader_buffer->str;
write_len = hc->contents_reader_buffer->len;
@@ -1356,12 +1436,19 @@
purple_debug_warning("http", "Nothing to write\n");
- written = purple_socket_write(hc->socket->ps,
- (const guchar*)write_from, write_len);
+ written = g_pollable_output_stream_write_nonblocking( + G_POLLABLE_OUTPUT_STREAM( + g_io_stream_get_output_stream( + G_IO_STREAM(hc->socket->conn))), + write_from, write_len, hc->socket->cancellable, - if (written < 0 && errno == EAGAIN)
+ if (written < 0 && g_error_matches(error, + G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { + return G_SOURCE_CONTINUE; if (hc->request_header_written == 0 &&
@@ -1370,21 +1457,22 @@
purple_debug_info("http", "Keep-alive connection "
"expired (when writing), retrying...\n");
purple_http_conn_retry(hc);
+ _purple_http_error(hc, _("Error writing to %s: %s"), + hc->url->host, error->message); - _purple_http_error(hc, _("Error writing to %s: %s"),
- hc->url->host, g_strerror(errno));
+ return G_SOURCE_CONTINUE; hc->request_header_written += written;
purple_http_conn_notify_progress_watcher(hc);
if (hc->request_header_written < hc->request_header->len)
+ return G_SOURCE_CONTINUE; if (hc->request->contents_length > 0)
+ return G_SOURCE_CONTINUE; hc->request_contents_written += written;
purple_http_conn_notify_progress_watcher(hc);
@@ -1394,14 +1482,24 @@
hc->request_contents_written <
(guint)hc->request->contents_length)
+ return G_SOURCE_CONTINUE; /* request is completely written, let's read the response */
- purple_socket_watch(hc->socket->ps, PURPLE_INPUT_READ,
- _purple_http_recv, hc);
+ gsource = g_pollable_input_stream_create_source( + G_POLLABLE_INPUT_STREAM( + g_io_stream_get_input_stream( + G_IO_STREAM(hc->socket->conn))), + g_source_set_callback(gsource, + (GSourceFunc)_purple_http_recv, hc, NULL); + hc->socket->input_source = g_source_attach(gsource, NULL); + g_source_unref(gsource); + hc->socket->output_source = 0; + return G_SOURCE_REMOVE; static void _purple_http_disconnect(PurpleHttpConnection *hc,
@@ -1426,13 +1524,10 @@
-_purple_http_connected(PurpleSocket *ps, const gchar *error, gpointer _hc)
+_purple_http_connected(PurpleHttpSocket *hs, const gchar *error, gpointer _hc) - PurpleHttpSocket *hs = NULL;
PurpleHttpConnection *hc = _hc;
- hs = purple_socket_get_data(ps, "hs");
hc->socket_request = NULL;
@@ -1443,7 +1538,14 @@
- purple_socket_watch(ps, PURPLE_INPUT_WRITE, _purple_http_send, hc);
+ source = g_pollable_output_stream_create_source( + G_POLLABLE_OUTPUT_STREAM( + g_io_stream_get_output_stream(G_IO_STREAM(hs->conn))), + g_source_set_callback(source, + (GSourceFunc)_purple_http_send, hc, NULL); + hc->socket->output_source = g_source_attach(source, NULL); + g_source_unref(source); static gboolean _purple_http_reconnect(PurpleHttpConnection *hc)
@@ -2155,7 +2257,7 @@
static PurpleHttpKeepaliveRequest *
purple_http_keepalive_pool_request(PurpleHttpKeepalivePool *pool,
PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl,
- PurpleSocketConnectCb cb, gpointer user_data)
+ PurpleHttpSocketConnectCb cb, gpointer user_data) PurpleHttpKeepaliveRequest *req;
PurpleHttpKeepaliveHost *kahost;
@@ -2198,19 +2300,15 @@
-_purple_http_keepalive_socket_connected(PurpleSocket *ps,
+_purple_http_keepalive_socket_connected(PurpleHttpSocket *hs, const gchar *error, gpointer _req)
- PurpleHttpSocket *hs = NULL;
PurpleHttpKeepaliveRequest *req = _req;
- hs = purple_socket_get_data(ps, "hs");
- req->cb(ps, error, req->user_data);
+ req->cb(hs, error, req->user_data); @@ -2266,7 +2364,7 @@
purple_http_keepalive_host_process_queue(host);
- req->cb(hs->ps, NULL, req->user_data);
+ req->cb(hs, NULL, req->user_data); @@ -2337,7 +2435,16 @@
if (purple_debug_is_verbose())
purple_debug_misc("http", "releasing a socket: %p\n", hs);
- purple_socket_watch(hs->ps, 0, NULL, NULL);
+ if (hs->input_source > 0) { + g_source_remove(hs->input_source); + if (hs->output_source > 0) { + g_source_remove(hs->output_source);