summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2013-07-04 11:35:29 -0400
committerDan Winship <danw@gnome.org>2013-10-19 20:33:38 -0400
commit88103312ffac176b8ffeb159bd75fc3bbe2c452e (patch)
treea9702a746bd4d7b67d6cc743492c51c0ebd9cb5f
parentcaa68752e295d48a3d1d9c6e5334f6c17a576000 (diff)
downloadlibsoup-88103312ffac176b8ffeb159bd75fc3bbe2c452e.tar.gz
SoupSocket: make handshaking methods gio-like
and update SoupConnection to use them
-rw-r--r--libsoup/soup-connection.c150
-rw-r--r--libsoup/soup-misc-private.h18
-rw-r--r--libsoup/soup-socket.c155
3 files changed, 170 insertions, 153 deletions
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 00fe72b9..f8b6cef7 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -451,12 +451,12 @@ typedef struct {
} SoupConnectionAsyncConnectData;
static void
-socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data)
+socket_connect_finished (SoupConnectionAsyncConnectData *data, guint status)
{
- SoupConnectionAsyncConnectData *data = user_data;
SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
- g_signal_handler_disconnect (socket, data->event_id);
+ if (priv->socket)
+ g_signal_handler_disconnect (priv->socket, data->event_id);
if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
if (priv->ssl && !priv->proxy_uri) {
@@ -473,9 +473,6 @@ socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data)
soup_connection_set_state (data->conn, SOUP_CONNECTION_IN_USE);
priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
start_idle_timer (data->conn);
- } else if (status == SOUP_STATUS_TLS_FAILED) {
- priv->ssl_fallback = TRUE;
- status = SOUP_STATUS_TRY_AGAIN;
}
if (data->callback) {
@@ -489,6 +486,31 @@ socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data)
g_slice_free (SoupConnectionAsyncConnectData, data);
}
+
+static void
+socket_handshake_complete (GObject *object, GAsyncResult *result, gpointer user_data)
+{
+ SoupConnectionAsyncConnectData *data = user_data;
+ SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
+ 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);
+}
+
static void
socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
{
@@ -496,26 +518,26 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
- socket_connect_finished (sock, status, data);
+ socket_connect_finished (data, status);
return;
}
priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
if (priv->ssl && !priv->proxy_uri) {
- if (soup_socket_start_ssl (sock, data->cancellable)) {
- soup_connection_event (data->conn,
- G_SOCKET_CLIENT_TLS_HANDSHAKING,
- NULL);
- soup_socket_handshake_async (sock, data->cancellable,
- socket_connect_finished, data);
- return;
- }
-
- status = SOUP_STATUS_SSL_FAILED;
+ soup_connection_event (data->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);
+ return;
}
- socket_connect_finished (sock, status, data);
+ socket_connect_finished (data, status);
}
void
@@ -601,22 +623,25 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
if (priv->ssl && !priv->proxy_uri) {
- if (!soup_socket_start_ssl (priv->socket, cancellable))
- status = SOUP_STATUS_SSL_FAILED;
- else {
+ 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_HANDSHAKING,
+ G_SOCKET_CLIENT_TLS_HANDSHAKED,
NULL);
- status = soup_socket_handshake_sync (priv->socket, cancellable);
- if (status == SOUP_STATUS_OK) {
- soup_connection_event (conn,
- G_SOCKET_CLIENT_TLS_HANDSHAKED,
- NULL);
- } else if (status == SOUP_STATUS_TLS_FAILED) {
- priv->ssl_fallback = TRUE;
- status = SOUP_STATUS_TRY_AGAIN;
- }
- }
+ 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_STATUS_IS_SUCCESSFUL (status)) {
@@ -656,21 +681,19 @@ soup_connection_start_ssl_sync (SoupConnection *conn,
{
SoupConnectionPrivate *priv;
guint status;
+ GError *error = NULL;
g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
priv = SOUP_CONNECTION_GET_PRIVATE (conn);
- if (!soup_socket_start_proxy_ssl (priv->socket,
- priv->remote_uri->host,
- cancellable))
- return SOUP_STATUS_SSL_FAILED;
-
soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
- status = soup_socket_handshake_sync (priv->socket, cancellable);
- if (status == SOUP_STATUS_OK) {
+ if (soup_socket_handshake_sync (priv->socket, priv->remote_uri->host,
+ cancellable, &error)) {
soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
- } else if (status == SOUP_STATUS_TLS_FAILED) {
+ 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;
}
@@ -679,33 +702,33 @@ soup_connection_start_ssl_sync (SoupConnection *conn,
}
static void
-start_ssl_completed (SoupSocket *socket, guint status, gpointer user_data)
+start_ssl_completed (GObject *object, GAsyncResult *result, gpointer user_data)
{
SoupConnectionAsyncConnectData *data = user_data;
SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
+ guint status;
+ GError *error = NULL;
- if (status == SOUP_STATUS_OK) {
+ 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);
- } else if (status == SOUP_STATUS_TLS_FAILED) {
+ 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);
data->callback (data->conn, status, data->callback_data);
g_object_unref (data->conn);
g_slice_free (SoupConnectionAsyncConnectData, data);
}
-static gboolean
-idle_start_ssl_completed (gpointer user_data)
-{
- SoupConnectionAsyncConnectData *data = user_data;
-
- start_ssl_completed (NULL, SOUP_STATUS_SSL_FAILED, data);
- return FALSE;
-}
-
void
soup_connection_start_ssl_async (SoupConnection *conn,
GCancellable *cancellable,
@@ -714,7 +737,6 @@ soup_connection_start_ssl_async (SoupConnection *conn,
{
SoupConnectionPrivate *priv;
SoupConnectionAsyncConnectData *data;
- GMainContext *async_context;
g_return_if_fail (SOUP_IS_CONNECTION (conn));
priv = SOUP_CONNECTION_GET_PRIVATE (conn);
@@ -724,22 +746,12 @@ soup_connection_start_ssl_async (SoupConnection *conn,
data->callback = callback;
data->callback_data = user_data;
- if (priv->use_thread_context)
- async_context = g_main_context_get_thread_default ();
- else
- async_context = priv->async_context;
-
- if (!soup_socket_start_proxy_ssl (priv->socket,
- priv->remote_uri->host,
- cancellable)) {
- soup_add_completion (async_context,
- idle_start_ssl_completed, data);
- return;
- }
-
soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
- soup_socket_handshake_async (priv->socket, cancellable,
- start_ssl_completed, data);
+
+ if (priv->async_context && !priv->use_thread_context)
+ g_main_context_push_thread_default (priv->async_context);
+ soup_socket_handshake_async (priv->socket, priv->remote_uri->host,
+ cancellable, start_ssl_completed, data);
}
/**
diff --git a/libsoup/soup-misc-private.h b/libsoup/soup-misc-private.h
index 7ea2cdea..948470ff 100644
--- a/libsoup/soup-misc-private.h
+++ b/libsoup/soup-misc-private.h
@@ -16,12 +16,18 @@ 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);
-guint soup_socket_handshake_sync (SoupSocket *sock,
- GCancellable *cancellable);
-void soup_socket_handshake_async (SoupSocket *sock,
- GCancellable *cancellable,
- SoupSocketCallback callback,
- gpointer user_data);
+gboolean soup_socket_handshake_sync (SoupSocket *sock,
+ const char *host,
+ GCancellable *cancellable,
+ GError **error);
+void soup_socket_handshake_async (SoupSocket *sock,
+ const char *host,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean soup_socket_handshake_finish (SoupSocket *sock,
+ GAsyncResult *result,
+ GError **error);
GSocket *soup_socket_get_gsocket (SoupSocket *sock);
GIOStream *soup_socket_get_connection (SoupSocket *sock);
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index baa9290c..9caf0d2c 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -1035,37 +1035,11 @@ soup_socket_accept_certificate (GTlsConnection *conn, GTlsCertificate *cert,
return TRUE;
}
-/**
- * soup_socket_start_ssl:
- * @sock: the socket
- * @cancellable: a #GCancellable
- *
- * Starts using SSL on @socket.
- *
- * Return value: success or failure
- **/
-gboolean
-soup_socket_start_ssl (SoupSocket *sock, GCancellable *cancellable)
-{
- SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
-
- return soup_socket_start_proxy_ssl (sock, soup_address_get_name (priv->remote_addr), cancellable);
-}
-
-/**
- * soup_socket_start_proxy_ssl:
- * @sock: the socket
- * @ssl_host: hostname of the SSL server
- * @cancellable: a #GCancellable
- *
- * Starts using SSL on @socket, expecting to find a host named
- * @ssl_host.
- *
- * Return value: success or failure
- **/
-gboolean
-soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
- GCancellable *cancellable)
+static gboolean
+soup_socket_setup_ssl (SoupSocket *sock,
+ const char *ssl_host,
+ GCancellable *cancellable,
+ GError **error)
{
SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
GTlsBackend *backend = g_tls_backend_get_default ();
@@ -1073,7 +1047,7 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
if (G_IS_TLS_CONNECTION (priv->conn))
return TRUE;
- if (g_cancellable_is_cancelled (cancellable))
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
priv->ssl = TRUE;
@@ -1084,7 +1058,7 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
identity = g_network_address_new (ssl_host, 0);
conn = g_initable_new (g_tls_backend_get_client_connection_type (backend),
- NULL, NULL,
+ cancellable, error,
"base-io-stream", priv->conn,
"server-identity", identity,
"database", priv->ssl_creds,
@@ -1108,7 +1082,7 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
GTlsServerConnection *conn;
conn = g_initable_new (g_tls_backend_get_server_connection_type (backend),
- NULL, NULL,
+ cancellable, error,
"base-io-stream", priv->conn,
"certificate", priv->ssl_creds,
"use-system-certdb", FALSE,
@@ -1133,76 +1107,101 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
return TRUE;
}
+
+/**
+ * soup_socket_start_ssl:
+ * @sock: the socket
+ * @cancellable: a #GCancellable
+ *
+ * Starts using SSL on @socket.
+ *
+ * Return value: success or failure
+ **/
+gboolean
+soup_socket_start_ssl (SoupSocket *sock, GCancellable *cancellable)
+{
+ SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+
+ return soup_socket_setup_ssl (sock, soup_address_get_name (priv->remote_addr),
+ cancellable, NULL);
+}
-guint
+/**
+ * soup_socket_start_proxy_ssl:
+ * @sock: the socket
+ * @ssl_host: hostname of the SSL server
+ * @cancellable: a #GCancellable
+ *
+ * Starts using SSL on @socket, expecting to find a host named
+ * @ssl_host.
+ *
+ * Return value: success or failure
+ **/
+gboolean
+soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
+ GCancellable *cancellable)
+{
+ return soup_socket_setup_ssl (sock, ssl_host, cancellable, NULL);
+}
+
+gboolean
soup_socket_handshake_sync (SoupSocket *sock,
- GCancellable *cancellable)
+ const char *ssl_host,
+ GCancellable *cancellable,
+ GError **error)
{
SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
- GError *error = NULL;
- priv->ssl = TRUE;
- if (g_tls_connection_handshake (G_TLS_CONNECTION (priv->conn),
- cancellable, &error))
- return SOUP_STATUS_OK;
- else if (!priv->ssl_fallback &&
- g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) {
- g_error_free (error);
- return SOUP_STATUS_TLS_FAILED;
- } else {
- g_error_free (error);
- return SOUP_STATUS_SSL_FAILED;
- }
+ if (!soup_socket_setup_ssl (sock, ssl_host, cancellable, error))
+ return FALSE;
+
+ return g_tls_connection_handshake (G_TLS_CONNECTION (priv->conn),
+ cancellable, error);
}
static void
handshake_async_ready (GObject *source, GAsyncResult *result, gpointer user_data)
{
- SoupSocketAsyncConnectData *data = user_data;
- SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (data->sock);
+ 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 (g_tls_connection_handshake_finish (G_TLS_CONNECTION (source),
result, &error))
- status = SOUP_STATUS_OK;
- else if (!priv->ssl_fallback &&
- g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS))
- status = SOUP_STATUS_TLS_FAILED;
+ g_task_return_boolean (task, TRUE);
else
- status = SOUP_STATUS_SSL_FAILED;
- g_clear_error (&error);
-
- data->callback (data->sock, status, data->user_data);
- g_object_unref (data->sock);
- g_slice_free (SoupSocketAsyncConnectData, data);
+ g_task_return_error (task, error);
}
void
-soup_socket_handshake_async (SoupSocket *sock,
- GCancellable *cancellable,
- SoupSocketCallback callback,
- gpointer user_data)
+soup_socket_handshake_async (SoupSocket *sock,
+ const char *ssl_host,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
- SoupSocketAsyncConnectData *data;
+ GTask *task;
+ GError *error = NULL;
- priv->ssl = TRUE;
+ task = g_task_new (sock, cancellable, callback, user_data);
- data = g_slice_new (SoupSocketAsyncConnectData);
- data->sock = g_object_ref (sock);
- data->callback = callback;
- data->user_data = user_data;
+ if (!soup_socket_setup_ssl (sock, ssl_host, cancellable, &error)) {
+ g_task_return_error (task, error);
+ return;
+ }
- if (priv->async_context && !priv->use_thread_context)
- g_main_context_push_thread_default (priv->async_context);
g_tls_connection_handshake_async (G_TLS_CONNECTION (priv->conn),
G_PRIORITY_DEFAULT,
cancellable, handshake_async_ready,
- data);
+ task);
+}
+
+gboolean
+soup_socket_handshake_finish (SoupSocket *sock,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (result), error);
}
/**