[libsoup] SoupSocket: make handshaking methods gio-like



commit 88103312ffac176b8ffeb159bd75fc3bbe2c452e
Author: Dan Winship <danw gnome org>
Date:   Thu Jul 4 11:35:29 2013 -0400

    SoupSocket: make handshaking methods gio-like
    
    and update SoupConnection to use them

 libsoup/soup-connection.c   |  150 ++++++++++++++++++++++-------------------
 libsoup/soup-misc-private.h |   18 ++++--
 libsoup/soup-socket.c       |  155 +++++++++++++++++++++----------------------
 3 files changed, 170 insertions(+), 153 deletions(-)
---
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 00fe72b..f8b6cef 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 7ea2cde..948470f 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 baa9290..9caf0d2 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);
 }
 
 /**


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]