summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2013-07-03 17:28:23 -0400
committerDan Winship <danw@gnome.org>2013-10-19 20:39:08 -0400
commit665a6e44005b4a0d5e4911b81e89d9984695e40b (patch)
tree320b6916f4a41841d4d1336fedd44f0d48163628
parent88103312ffac176b8ffeb159bd75fc3bbe2c452e (diff)
downloadlibsoup-665a6e44005b4a0d5e4911b81e89d9984695e40b.tar.gz
SoupConnection: make methods gio-like
Port the SoupConnection methods to be gio-like, using GAsyncReadyCallback for the async ones, and returning GErrors rather than libsoup status codes. Add internal-gio-like SoupSocket connect methods for the SoupConnection methods to use.
-rw-r--r--libsoup/soup-connection.c268
-rw-r--r--libsoup/soup-connection.h36
-rw-r--r--libsoup/soup-misc-private.h11
-rw-r--r--libsoup/soup-session.c139
-rw-r--r--libsoup/soup-socket.c171
5 files changed, 374 insertions, 251 deletions
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index f8b6cef7..2b5dc49e 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -442,113 +442,89 @@ re_emit_socket_event (SoupSocket *socket,
soup_connection_event (conn, event, connection);
}
-typedef struct {
- SoupConnection *conn;
- SoupConnectionCallback callback;
- gpointer callback_data;
- GCancellable *cancellable;
- guint event_id;
-} SoupConnectionAsyncConnectData;
-
static void
-socket_connect_finished (SoupConnectionAsyncConnectData *data, guint status)
+socket_connect_finished (GTask *task, SoupSocket *sock, GError *error)
{
- SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
+ SoupConnection *conn = g_task_get_source_object (task);
+ SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
- if (priv->socket)
- g_signal_handler_disconnect (priv->socket, data->event_id);
+ if (priv->async_context && !priv->use_thread_context)
+ g_main_context_pop_thread_default (priv->async_context);
- if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
+ g_signal_handlers_disconnect_by_func (sock, G_CALLBACK (re_emit_socket_event), conn);
+
+ if (!error) {
if (priv->ssl && !priv->proxy_uri) {
- soup_connection_event (data->conn,
+ soup_connection_event (conn,
G_SOCKET_CLIENT_TLS_HANDSHAKED,
NULL);
}
if (!priv->ssl || !priv->proxy_uri) {
- soup_connection_event (data->conn,
+ soup_connection_event (conn,
G_SOCKET_CLIENT_COMPLETE,
NULL);
}
- soup_connection_set_state (data->conn, SOUP_CONNECTION_IN_USE);
+ soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
- start_idle_timer (data->conn);
- }
+ start_idle_timer (conn);
- if (data->callback) {
- if (priv->proxy_uri != NULL)
- status = soup_status_proxify (status);
- data->callback (data->conn, status, data->callback_data);
- }
- g_object_unref (data->conn);
- if (data->cancellable)
- g_object_unref (data->cancellable);
- g_slice_free (SoupConnectionAsyncConnectData, data);
+ g_task_return_boolean (task, TRUE);
+ } else
+ g_task_return_error (task, error);
+ g_object_unref (task);
}
-
static void
socket_handshake_complete (GObject *object, GAsyncResult *result, gpointer user_data)
{
- SoupConnectionAsyncConnectData *data = user_data;
- SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
+ SoupSocket *sock = SOUP_SOCKET (object);
+ GTask *task = user_data;
GError *error = NULL;
- guint status;
-
- if (priv->async_context && !priv->use_thread_context)
- g_main_context_pop_thread_default (priv->async_context);
- if (soup_socket_handshake_finish (priv->socket, result, &error))
- status = SOUP_STATUS_OK;
- else if (!priv->ssl_fallback &&
- g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) {
- priv->ssl_fallback = TRUE;
- status = SOUP_STATUS_TRY_AGAIN;
- } else
- status = SOUP_STATUS_SSL_FAILED;
- g_clear_error (&error);
-
- socket_connect_finished (data, status);
+ soup_socket_handshake_finish (sock, result, &error);
+ socket_connect_finished (task, sock, error);
}
static void
-socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
+socket_connect_complete (GObject *object, GAsyncResult *result, gpointer user_data)
{
- SoupConnectionAsyncConnectData *data = user_data;
- SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
+ SoupSocket *sock = SOUP_SOCKET (object);
+ GTask *task = user_data;
+ SoupConnection *conn = g_task_get_source_object (task);
+ SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
+ GError *error = NULL;
- if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
- socket_connect_finished (data, status);
+ if (!soup_socket_connect_finish_internal (sock, result, &error)) {
+ socket_connect_finished (task, sock, error);
return;
}
- priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
+ priv->proxy_uri = soup_socket_get_http_proxy_uri (sock);
if (priv->ssl && !priv->proxy_uri) {
- soup_connection_event (data->conn,
+ soup_connection_event (conn,
G_SOCKET_CLIENT_TLS_HANDSHAKING,
NULL);
- if (priv->async_context && !priv->use_thread_context)
- g_main_context_push_thread_default (priv->async_context);
soup_socket_handshake_async (sock, priv->remote_uri->host,
- data->cancellable,
- socket_handshake_complete, data);
+ g_task_get_cancellable (task),
+ socket_handshake_complete, task);
return;
}
- socket_connect_finished (data, status);
+ socket_connect_finished (task, sock, NULL);
}
void
-soup_connection_connect_async (SoupConnection *conn,
- GCancellable *cancellable,
- SoupConnectionCallback callback,
- gpointer user_data)
+soup_connection_connect_async (SoupConnection *conn,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- SoupConnectionAsyncConnectData *data;
SoupConnectionPrivate *priv;
SoupAddress *remote_addr;
+ GTask *task;
g_return_if_fail (SOUP_IS_CONNECTION (conn));
priv = SOUP_CONNECTION_GET_PRIVATE (conn);
@@ -556,12 +532,6 @@ soup_connection_connect_async (SoupConnection *conn,
soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
- data = g_slice_new (SoupConnectionAsyncConnectData);
- data->conn = g_object_ref (conn);
- data->callback = callback;
- data->callback_data = user_data;
- data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
-
remote_addr = soup_address_new (priv->remote_uri->host,
priv->remote_uri->port);
priv->socket =
@@ -578,24 +548,38 @@ soup_connection_connect_async (SoupConnection *conn,
NULL);
g_object_unref (remote_addr);
- data->event_id = g_signal_connect (priv->socket, "event",
- G_CALLBACK (re_emit_socket_event),
- data->conn);
+ g_signal_connect (priv->socket, "event",
+ G_CALLBACK (re_emit_socket_event), conn);
- soup_socket_connect_async (priv->socket, data->cancellable,
- socket_connect_result, data);
+ if (priv->async_context && !priv->use_thread_context)
+ g_main_context_push_thread_default (priv->async_context);
+ task = g_task_new (conn, cancellable, callback, user_data);
+
+ soup_socket_connect_async_internal (priv->socket, cancellable,
+ socket_connect_complete, task);
+}
+
+gboolean
+soup_connection_connect_finish (SoupConnection *conn,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (result), error);
}
-guint
-soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
+gboolean
+soup_connection_connect_sync (SoupConnection *conn,
+ GCancellable *cancellable,
+ GError **error)
{
SoupConnectionPrivate *priv;
- guint status, event_id = 0;
+ guint event_id = 0;
SoupAddress *remote_addr;
+ gboolean success = TRUE;
- g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
+ g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
priv = SOUP_CONNECTION_GET_PRIVATE (conn);
- g_return_val_if_fail (priv->socket == NULL, SOUP_STATUS_MALFORMED);
+ g_return_val_if_fail (priv->socket == NULL, FALSE);
soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
@@ -615,53 +599,42 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
event_id = g_signal_connect (priv->socket, "event",
G_CALLBACK (re_emit_socket_event), conn);
- status = soup_socket_connect_sync (priv->socket, cancellable);
-
- if (!SOUP_STATUS_IS_SUCCESSFUL (status))
- goto fail;
+ if (!soup_socket_connect_sync_internal (priv->socket, cancellable, error)) {
+ success = FALSE;
+ goto done;
+ }
priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
if (priv->ssl && !priv->proxy_uri) {
- GError *error = NULL;
-
soup_connection_event (conn,
G_SOCKET_CLIENT_TLS_HANDSHAKING,
NULL);
- if (soup_socket_handshake_sync (priv->socket,
- priv->remote_uri->host,
- cancellable, &error)) {
- soup_connection_event (conn,
- G_SOCKET_CLIENT_TLS_HANDSHAKED,
- NULL);
- status = SOUP_STATUS_OK;
- } else if (!priv->ssl_fallback &&
- g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) {
- priv->ssl_fallback = TRUE;
- status = SOUP_STATUS_TRY_AGAIN;
- } else
- status = SOUP_STATUS_SSL_FAILED;
- g_clear_error (&error);
+ if (!soup_socket_handshake_sync (priv->socket,
+ priv->remote_uri->host,
+ cancellable, error)) {
+ success = FALSE;
+ goto done;
+ }
+ soup_connection_event (conn,
+ G_SOCKET_CLIENT_TLS_HANDSHAKED,
+ NULL);
}
- if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
- if (!priv->ssl || !priv->proxy_uri) {
- soup_connection_event (conn,
- G_SOCKET_CLIENT_COMPLETE,
- NULL);
- }
- soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
- priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
- start_idle_timer (conn);
+ if (!priv->ssl || !priv->proxy_uri) {
+ soup_connection_event (conn,
+ G_SOCKET_CLIENT_COMPLETE,
+ NULL);
}
+ soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
+ priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
+ start_idle_timer (conn);
- fail:
+ done:
if (priv->socket && event_id)
g_signal_handler_disconnect (priv->socket, event_id);
- if (priv->proxy_uri != NULL)
- status = soup_status_proxify (status);
- return status;
+ return success;
}
gboolean
@@ -675,83 +648,74 @@ soup_connection_is_tunnelled (SoupConnection *conn)
return priv->ssl && priv->proxy_uri != NULL;
}
-guint
-soup_connection_start_ssl_sync (SoupConnection *conn,
- GCancellable *cancellable)
+gboolean
+soup_connection_start_ssl_sync (SoupConnection *conn,
+ GCancellable *cancellable,
+ GError **error)
{
SoupConnectionPrivate *priv;
- guint status;
- GError *error = NULL;
g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
priv = SOUP_CONNECTION_GET_PRIVATE (conn);
soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
if (soup_socket_handshake_sync (priv->socket, priv->remote_uri->host,
- cancellable, &error)) {
+ cancellable, error)) {
soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
- status = SOUP_STATUS_OK;
- } else if (!priv->ssl_fallback &&
- g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) {
- priv->ssl_fallback = TRUE;
- status = SOUP_STATUS_TRY_AGAIN;
- }
-
- return status;
+ return TRUE;
+ } else
+ return FALSE;
}
static void
start_ssl_completed (GObject *object, GAsyncResult *result, gpointer user_data)
{
- SoupConnectionAsyncConnectData *data = user_data;
- SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
- guint status;
+ GTask *task = user_data;
+ SoupConnection *conn = g_task_get_source_object (task);
+ SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
GError *error = NULL;
if (priv->async_context && !priv->use_thread_context)
g_main_context_pop_thread_default (priv->async_context);
if (soup_socket_handshake_finish (priv->socket, result, &error)) {
- soup_connection_event (data->conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
- soup_connection_event (data->conn, G_SOCKET_CLIENT_COMPLETE, NULL);
- status = SOUP_STATUS_OK;
- } else if (!priv->ssl_fallback &&
- g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) {
- priv->ssl_fallback = TRUE;
- status = SOUP_STATUS_TRY_AGAIN;
+ soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
+ soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
+ g_task_return_boolean (task, TRUE);
} else
- status = SOUP_STATUS_SSL_FAILED;
- g_clear_error (&error);
-
- data->callback (data->conn, status, data->callback_data);
- g_object_unref (data->conn);
- g_slice_free (SoupConnectionAsyncConnectData, data);
+ g_task_return_error (task, error);
+ g_object_unref (task);
}
void
-soup_connection_start_ssl_async (SoupConnection *conn,
- GCancellable *cancellable,
- SoupConnectionCallback callback,
- gpointer user_data)
+soup_connection_start_ssl_async (SoupConnection *conn,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
SoupConnectionPrivate *priv;
- SoupConnectionAsyncConnectData *data;
+ GTask *task;
g_return_if_fail (SOUP_IS_CONNECTION (conn));
priv = SOUP_CONNECTION_GET_PRIVATE (conn);
- data = g_slice_new (SoupConnectionAsyncConnectData);
- data->conn = g_object_ref (conn);
- data->callback = callback;
- data->callback_data = user_data;
-
soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
if (priv->async_context && !priv->use_thread_context)
g_main_context_push_thread_default (priv->async_context);
+ task = g_task_new (conn, cancellable, callback, user_data);
+
soup_socket_handshake_async (priv->socket, priv->remote_uri->host,
- cancellable, start_ssl_completed, data);
+ cancellable, start_ssl_completed, task);
+}
+
+gboolean
+soup_connection_start_ssl_finish (SoupConnection *conn,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (result), error);
}
/**
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 50fb7018..b70a8a36 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -35,10 +35,6 @@ typedef struct {
GType soup_connection_get_type (void);
-typedef void (*SoupConnectionCallback) (SoupConnection *conn,
- guint status,
- gpointer data);
-
#define SOUP_CONNECTION_LOCAL_ADDRESS "local-address"
#define SOUP_CONNECTION_REMOTE_URI "remote-uri"
#define SOUP_CONNECTION_PROXY_RESOLVER "proxy-resolver"
@@ -53,18 +49,26 @@ typedef void (*SoupConnectionCallback) (SoupConnection *conn,
#define SOUP_CONNECTION_STATE "state"
#define SOUP_CONNECTION_MESSAGE "message"
-void soup_connection_connect_async (SoupConnection *conn,
- GCancellable *cancellable,
- SoupConnectionCallback callback,
- gpointer user_data);
-guint soup_connection_connect_sync (SoupConnection *conn,
- GCancellable *cancellable);
-guint soup_connection_start_ssl_sync (SoupConnection *conn,
- GCancellable *cancellable);
-void soup_connection_start_ssl_async (SoupConnection *conn,
- GCancellable *cancellable,
- SoupConnectionCallback callback,
- gpointer user_data);
+void soup_connection_connect_async (SoupConnection *conn,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean soup_connection_connect_finish (SoupConnection *conn,
+ GAsyncResult *result,
+ GError **error);
+gboolean soup_connection_connect_sync (SoupConnection *conn,
+ GCancellable *cancellable,
+ GError **error);
+gboolean soup_connection_start_ssl_sync (SoupConnection *conn,
+ GCancellable *cancellable,
+ GError **error);
+void soup_connection_start_ssl_async (SoupConnection *conn,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean soup_connection_start_ssl_finish (SoupConnection *conn,
+ GAsyncResult *result,
+ GError **error);
void soup_connection_disconnect (SoupConnection *conn);
diff --git a/libsoup/soup-misc-private.h b/libsoup/soup-misc-private.h
index 948470ff..50a3b988 100644
--- a/libsoup/soup-misc-private.h
+++ b/libsoup/soup-misc-private.h
@@ -16,6 +16,17 @@ char *soup_uri_to_string_internal (SoupURI *uri, gboolean just_path_and_query,
gboolean soup_uri_is_http (SoupURI *uri, char **aliases);
gboolean soup_uri_is_https (SoupURI *uri, char **aliases);
+gboolean soup_socket_connect_sync_internal (SoupSocket *sock,
+ GCancellable *cancellable,
+ GError **error);
+void soup_socket_connect_async_internal (SoupSocket *sock,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean soup_socket_connect_finish_internal (SoupSocket *sock,
+ GAsyncResult *result,
+ GError **error);
+
gboolean soup_socket_handshake_sync (SoupSocket *sock,
const char *host,
GCancellable *cancellable,
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index bd586cd3..0fa65cda 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1508,10 +1508,59 @@ message_completed (SoupMessage *msg, gpointer user_data)
}
}
+static guint
+status_from_connect_error (SoupMessageQueueItem *item, GError *error)
+{
+ guint status;
+
+ if (!error)
+ return SOUP_STATUS_OK;
+
+ if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) {
+ SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (item->session);
+ SoupSessionHost *host;
+
+ g_mutex_lock (&priv->conn_lock);
+ host = get_host_for_message (item->session, item->msg);
+ if (!host->ssl_fallback) {
+ host->ssl_fallback = TRUE;
+ status = SOUP_STATUS_TRY_AGAIN;
+ } else
+ status = SOUP_STATUS_SSL_FAILED;
+ g_mutex_unlock (&priv->conn_lock);
+ } else if (error->domain == G_TLS_ERROR)
+ status = SOUP_STATUS_SSL_FAILED;
+ else if (error->domain == G_RESOLVER_ERROR)
+ status = SOUP_STATUS_CANT_RESOLVE;
+ else if (error->domain == G_IO_ERROR) {
+ if (error->code == G_IO_ERROR_CANCELLED)
+ status = SOUP_STATUS_CANCELLED;
+ else if (error->code == G_IO_ERROR_HOST_UNREACHABLE ||
+ error->code == G_IO_ERROR_NETWORK_UNREACHABLE ||
+ error->code == G_IO_ERROR_CONNECTION_REFUSED)
+ status = SOUP_STATUS_CANT_CONNECT;
+ else if (error->code == G_IO_ERROR_PROXY_FAILED ||
+ error->code == G_IO_ERROR_PROXY_AUTH_FAILED ||
+ error->code == G_IO_ERROR_PROXY_NEED_AUTH ||
+ error->code == G_IO_ERROR_PROXY_NOT_ALLOWED)
+ status = SOUP_STATUS_CANT_CONNECT_PROXY;
+ else
+ status = SOUP_STATUS_IO_ERROR;
+ } else
+ status = SOUP_STATUS_IO_ERROR;
+
+ g_error_free (error);
+
+ if (item->conn && soup_connection_is_via_proxy (item->conn))
+ return soup_status_proxify (status);
+ else
+ return status;
+}
+
static void
-tunnel_complete (SoupConnection *conn, guint status, gpointer user_data)
+tunnel_complete (SoupMessageQueueItem *tunnel_item,
+ guint status, GError *error)
{
- SoupMessageQueueItem *tunnel_item = user_data;
SoupMessageQueueItem *item = tunnel_item->related;
SoupSession *session = tunnel_item->session;
@@ -1522,8 +1571,10 @@ tunnel_complete (SoupConnection *conn, guint status, gpointer user_data)
item->state = SOUP_MESSAGE_FINISHING;
soup_message_set_https_status (item->msg, item->conn);
+ if (!status)
+ status = status_from_connect_error (item, error);
if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
- soup_connection_disconnect (conn);
+ soup_connection_disconnect (item->conn);
soup_session_set_item_connection (session, item, NULL);
soup_session_set_item_status (session, item, status);
}
@@ -1535,6 +1586,19 @@ tunnel_complete (SoupConnection *conn, guint status, gpointer user_data)
}
static void
+tunnel_handshake_complete (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SoupConnection *conn = SOUP_CONNECTION (object);
+ SoupMessageQueueItem *tunnel_item = user_data;
+ GError *error = NULL;
+
+ soup_connection_start_ssl_finish (conn, result, &error);
+ tunnel_complete (tunnel_item, 0, error);
+}
+
+static void
tunnel_message_completed (SoupMessage *msg, gpointer user_data)
{
SoupMessageQueueItem *tunnel_item = user_data;
@@ -1559,16 +1623,19 @@ tunnel_message_completed (SoupMessage *msg, gpointer user_data)
status = tunnel_item->msg->status_code;
if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
- tunnel_complete (item->conn, status, tunnel_item);
+ tunnel_complete (tunnel_item, status, NULL);
return;
}
if (tunnel_item->async) {
soup_connection_start_ssl_async (item->conn, item->cancellable,
- tunnel_complete, tunnel_item);
+ tunnel_handshake_complete,
+ tunnel_item);
} else {
- status = soup_connection_start_ssl_sync (item->conn, item->cancellable);
- tunnel_complete (item->conn, status, tunnel_item);
+ GError *error = NULL;
+
+ soup_connection_start_ssl_sync (item->conn, item->cancellable, &error);
+ tunnel_complete (tunnel_item, 0, error);
}
}
@@ -1602,34 +1669,48 @@ tunnel_connect (SoupMessageQueueItem *item)
}
static void
-got_connection (SoupConnection *conn, guint status, gpointer user_data)
+connect_complete (SoupMessageQueueItem *item, SoupConnection *conn, GError *error)
{
- SoupMessageQueueItem *item = user_data;
SoupSession *session = item->session;
+ guint status;
soup_message_set_https_status (item->msg, item->conn);
- if (status != SOUP_STATUS_OK) {
- soup_connection_disconnect (conn);
- if (item->state == SOUP_MESSAGE_CONNECTING) {
- soup_session_set_item_status (session, item, status);
- soup_session_set_item_connection (session, item, NULL);
- item->state = SOUP_MESSAGE_READY;
- }
- } else
+ if (!error) {
item->state = SOUP_MESSAGE_CONNECTED;
+ return;
+ }
- if (item->async) {
- if (item->state == SOUP_MESSAGE_CONNECTED ||
- item->state == SOUP_MESSAGE_READY)
- async_run_queue (item->session);
- else
- soup_session_kick_queue (item->session);
-
- soup_message_queue_item_unref (item);
+ status = status_from_connect_error (item, error);
+ soup_connection_disconnect (conn);
+ if (item->state == SOUP_MESSAGE_CONNECTING) {
+ soup_session_set_item_status (session, item, status);
+ soup_session_set_item_connection (session, item, NULL);
+ item->state = SOUP_MESSAGE_READY;
}
}
+static void
+connect_async_complete (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SoupConnection *conn = SOUP_CONNECTION (object);
+ SoupMessageQueueItem *item = user_data;
+ GError *error = NULL;
+
+ soup_connection_connect_finish (conn, result, &error);
+ connect_complete (item, conn, error);
+
+ if (item->state == SOUP_MESSAGE_CONNECTED ||
+ item->state == SOUP_MESSAGE_READY)
+ async_run_queue (item->session);
+ else
+ soup_session_kick_queue (item->session);
+
+ soup_message_queue_item_unref (item);
+}
+
/* requires conn_lock */
static SoupConnection *
get_connection_for_host (SoupSession *session,
@@ -1783,13 +1864,13 @@ get_connection (SoupMessageQueueItem *item, gboolean *should_cleanup)
if (item->async) {
soup_message_queue_item_ref (item);
soup_connection_connect_async (item->conn, item->cancellable,
- got_connection, item);
+ connect_async_complete, item);
return FALSE;
} else {
- guint status;
+ GError *error = NULL;
- status = soup_connection_connect_sync (item->conn, item->cancellable);
- got_connection (item->conn, status, item);
+ soup_connection_connect_sync (item->conn, item->cancellable, &error);
+ connect_complete (item, conn, error);
return TRUE;
}
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index 9caf0d2c..d4046ec2 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -666,38 +666,36 @@ re_emit_socket_client_event (GSocketClient *client,
event, connection);
}
-static guint
-socket_connected (SoupSocket *sock, GSocketConnection *conn, GError *error)
+static gboolean
+socket_connect_finish (SoupSocket *sock, GSocketConnection *conn)
{
SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
- if (priv->connect_cancel) {
- GCancellable *cancellable = priv->connect_cancel;
- gboolean cancelled = g_cancellable_is_cancelled (cancellable);
+ g_clear_object (&priv->connect_cancel);
- g_object_unref (priv->connect_cancel);
- priv->connect_cancel = NULL;
- if (cancelled) {
- g_clear_error (&error);
- return SOUP_STATUS_CANCELLED;
- }
- }
+ if (conn) {
+ priv->conn = (GIOStream *)conn;
+ priv->gsock = g_object_ref (g_socket_connection_get_socket (conn));
+ finish_socket_setup (priv);
+ return TRUE;
+ } else
+ return FALSE;
+}
- if (error) {
- if (error->domain == G_RESOLVER_ERROR) {
- g_error_free (error);
- return SOUP_STATUS_CANT_RESOLVE;
- } else {
- g_error_free (error);
- return SOUP_STATUS_CANT_CONNECT;
- }
- }
+static guint
+socket_legacy_error (SoupSocket *sock, GError *error)
+{
+ guint status;
- priv->conn = (GIOStream *)conn;
- priv->gsock = g_object_ref (g_socket_connection_get_socket (conn));
- finish_socket_setup (priv);
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ status = SOUP_STATUS_CANCELLED;
+ else if (error->domain == G_RESOLVER_ERROR)
+ status = SOUP_STATUS_CANT_RESOLVE;
+ else
+ status = SOUP_STATUS_CANT_CONNECT;
- return SOUP_STATUS_OK;
+ g_error_free (error);
+ return status;
}
static GSocketClient *
@@ -722,6 +720,57 @@ new_socket_client (SoupSocket *sock)
return client;
}
+static void
+async_connected (GObject *client, GAsyncResult *result, gpointer data)
+{
+ GTask *task = data;
+ SoupSocket *sock = g_task_get_source_object (task);
+ GSocketConnection *conn;
+ GError *error = NULL;
+
+ conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client),
+ result, &error);
+ if (socket_connect_finish (sock, conn))
+ g_task_return_boolean (task, TRUE);
+ else
+ g_task_return_error (task, error);
+}
+
+gboolean
+soup_socket_connect_finish_internal (SoupSocket *sock,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+void
+soup_socket_connect_async_internal (SoupSocket *sock,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SoupSocketPrivate *priv;
+ GSocketClient *client;
+ GTask *task;
+
+ g_return_if_fail (SOUP_IS_SOCKET (sock));
+ priv = SOUP_SOCKET_GET_PRIVATE (sock);
+ g_return_if_fail (!priv->is_server);
+ g_return_if_fail (priv->gsock == NULL);
+ g_return_if_fail (priv->remote_addr != NULL);
+
+ priv->connect_cancel = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
+ task = g_task_new (sock, priv->connect_cancel, callback, user_data);
+
+ client = new_socket_client (sock);
+ g_socket_client_connect_async (client,
+ G_SOCKET_CONNECTABLE (priv->remote_addr),
+ priv->connect_cancel,
+ async_connected, task);
+ g_object_unref (client);
+}
+
/**
* SoupSocketCallback:
* @sock: the #SoupSocket
@@ -738,22 +787,25 @@ typedef struct {
} SoupSocketAsyncConnectData;
static void
-async_connected (GObject *client, GAsyncResult *result, gpointer data)
+legacy_connect_async_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- SoupSocketAsyncConnectData *sacd = data;
- SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
+ SoupSocket *sock = SOUP_SOCKET (object);
+ SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+ SoupSocketAsyncConnectData *sacd = user_data;
GError *error = NULL;
- GSocketConnection *conn;
guint status;
if (priv->async_context && !priv->use_thread_context)
g_main_context_pop_thread_default (priv->async_context);
- conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client),
- result, &error);
- status = socket_connected (sacd->sock, conn, error);
+ if (soup_socket_connect_finish_internal (sock, result, &error))
+ status = SOUP_STATUS_OK;
+ else
+ status = socket_legacy_error (sock, error);
- sacd->callback (sacd->sock, status, sacd->user_data);
+ sacd->callback (sock, status, sacd->user_data);
g_object_unref (sacd->sock);
g_slice_free (SoupSocketAsyncConnectData, sacd);
}
@@ -779,10 +831,11 @@ soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
{
SoupSocketPrivate *priv;
SoupSocketAsyncConnectData *sacd;
- GSocketClient *client;
g_return_if_fail (SOUP_IS_SOCKET (sock));
priv = SOUP_SOCKET_GET_PRIVATE (sock);
+ g_return_if_fail (!priv->is_server);
+ g_return_if_fail (priv->gsock == NULL);
g_return_if_fail (priv->remote_addr != NULL);
sacd = g_slice_new0 (SoupSocketAsyncConnectData);
@@ -790,17 +843,38 @@ soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
sacd->callback = callback;
sacd->user_data = user_data;
- priv->connect_cancel = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
-
if (priv->async_context && !priv->use_thread_context)
g_main_context_push_thread_default (priv->async_context);
+ soup_socket_connect_async_internal (sock, cancellable,
+ legacy_connect_async_cb,
+ sacd);
+}
+
+gboolean
+soup_socket_connect_sync_internal (SoupSocket *sock,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupSocketPrivate *priv;
+ GSocketClient *client;
+ GSocketConnection *conn;
+
+ g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
+ priv = SOUP_SOCKET_GET_PRIVATE (sock);
+ g_return_val_if_fail (!priv->is_server, SOUP_STATUS_MALFORMED);
+ g_return_val_if_fail (priv->gsock == NULL, SOUP_STATUS_MALFORMED);
+ g_return_val_if_fail (priv->remote_addr != NULL, SOUP_STATUS_MALFORMED);
+
+ priv->connect_cancel = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
+
client = new_socket_client (sock);
- g_socket_client_connect_async (client,
- G_SOCKET_CONNECTABLE (priv->remote_addr),
- priv->connect_cancel,
- async_connected, sacd);
+ conn = g_socket_client_connect (client,
+ G_SOCKET_CONNECTABLE (priv->remote_addr),
+ priv->connect_cancel, error);
g_object_unref (client);
+
+ return socket_connect_finish (sock, conn);
}
/**
@@ -820,8 +894,6 @@ guint
soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
{
SoupSocketPrivate *priv;
- GSocketClient *client;
- GSocketConnection *conn;
GError *error = NULL;
g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
@@ -830,19 +902,10 @@ soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
g_return_val_if_fail (priv->gsock == NULL, SOUP_STATUS_MALFORMED);
g_return_val_if_fail (priv->remote_addr != NULL, SOUP_STATUS_MALFORMED);
- if (cancellable)
- g_object_ref (cancellable);
+ if (soup_socket_connect_sync_internal (sock, cancellable, &error))
+ return SOUP_STATUS_OK;
else
- cancellable = g_cancellable_new ();
- priv->connect_cancel = cancellable;
-
- client = new_socket_client (sock);
- conn = g_socket_client_connect (client,
- G_SOCKET_CONNECTABLE (priv->remote_addr),
- priv->connect_cancel, &error);
- g_object_unref (client);
-
- return socket_connected (sock, conn, error);
+ return socket_legacy_error (sock, error);
}
/**