[libsoup/carlosgc/ssl: 1/5] connection: move client side impl from SoupSocket to SoupConnection




commit 446dc26155638c1b8b187119ae35d1f527d90fed
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Wed Oct 28 09:41:36 2020 +0100

    connection: move client side impl from SoupSocket to SoupConnection

 libsoup/soup-connection.c      | 660 ++++++++++++++++++++++++++++-------------
 libsoup/soup-connection.h      |  32 +-
 libsoup/soup-logger.c          |   8 +-
 libsoup/soup-message-io.c      |  14 +-
 libsoup/soup-message-private.h |   2 +-
 libsoup/soup-message.c         |  33 +--
 libsoup/soup-session.c         |  48 ++-
 tests/connection-test.c        |  25 +-
 tests/timeout-test.c           |   6 +-
 9 files changed, 536 insertions(+), 292 deletions(-)
---
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index d9f3af52..d585efd9 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -11,16 +11,20 @@
 
 #include "soup-connection.h"
 #include "soup.h"
+#include "soup-io-stream.h"
 #include "soup-message-queue.h"
 #include "soup-socket-private.h"
 #include "soup-private-enum-types.h"
+#include <gio/gnetworking.h>
 
 struct _SoupConnection {
         GObject parent_instance;
 };
 
 typedef struct {
-       SoupSocket  *socket;
+       GIOStream *connection;
+       GSocketConnectable *remote_connectable;
+       GIOStream *iostream;
        SoupSocketProperties *socket_props;
 
        SoupURI *remote_uri, *proxy_uri;
@@ -31,6 +35,8 @@ typedef struct {
        time_t       unused_timeout;
        GSource     *idle_timeout_src;
        gboolean     reusable;
+
+       GCancellable *cancellable;
 } SoupConnectionPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (SoupConnection, soup_connection, G_TYPE_OBJECT)
@@ -74,13 +80,22 @@ soup_connection_finalize (GObject *object)
        g_clear_pointer (&priv->remote_uri, soup_uri_free);
        g_clear_pointer (&priv->proxy_uri, soup_uri_free);
        g_clear_pointer (&priv->socket_props, soup_socket_properties_unref);
+       g_clear_object (&priv->remote_connectable);
        g_clear_object (&priv->current_msg);
 
-       if (priv->socket) {
-               g_signal_handlers_disconnect_by_data (priv->socket, object);
-               g_object_unref (priv->socket);
+       if (priv->cancellable) {
+               g_warning ("Disposing connection %p during connect", object);
+               g_object_unref (priv->cancellable);
+       }
+
+       if (priv->connection) {
+               g_warning ("Disposing connection %p while still connected", object);
+               g_io_stream_close (priv->connection, NULL, NULL);
+               g_object_unref (priv->connection);
        }
 
+       g_clear_object (&priv->iostream);
+
        G_OBJECT_CLASS (soup_connection_parent_class)->finalize (object);
 }
 
@@ -217,11 +232,8 @@ soup_connection_event (SoupConnection      *conn,
 {
        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
 
-       if (!connection && priv->socket)
-               connection = soup_socket_get_connection (priv->socket);
-
        g_signal_emit (conn, signals[EVENT], 0,
-                      event, connection);
+                      event, connection ? connection : priv->connection);
 }
 
 static gboolean
@@ -315,177 +327,313 @@ set_current_msg (SoupConnection *conn, SoupMessage *msg)
 }
 
 static void
-re_emit_socket_event (SoupSocket          *socket,
+soup_connection_set_connection (SoupConnection *conn,
+                               GIOStream      *connection)
+{
+       SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+
+       g_clear_object (&priv->connection);
+       priv->connection = connection;
+       g_clear_object (&priv->iostream);
+       priv->iostream = soup_io_stream_new (G_IO_STREAM (priv->connection), FALSE);
+}
+
+static void
+re_emit_socket_event (GSocketClient       *client,
                      GSocketClientEvent   event,
+                     GSocketConnectable  *connectable,
                      GIOStream           *connection,
-                     gpointer             user_data)
+                     SoupConnection      *conn)
 {
-       SoupConnection *conn = user_data;
-
        /* We handle COMPLETE ourselves */
-       if (event != G_SOCKET_CLIENT_COMPLETE)
-               soup_connection_event (conn, event, connection);
+       if (event == G_SOCKET_CLIENT_COMPLETE)
+               return;
+
+       soup_connection_event (conn, event, connection);
 }
 
-static void
-socket_connect_finished (GTask *task, SoupSocket *sock, GError *error)
+static GSocketClient *
+new_socket_client (SoupConnection *conn)
 {
-       SoupConnection *conn = g_task_get_source_object (task);
-       SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+        GSocketClient *client;
+        SoupSocketProperties *props = priv->socket_props;
 
-       if (!error) {
-               if (!priv->ssl || !priv->proxy_uri) {
-                       soup_connection_event (conn,
-                                              G_SOCKET_CLIENT_COMPLETE,
-                                              NULL);
-               }
+        client = g_socket_client_new ();
+        g_signal_connect_object (client, "event",
+                                 G_CALLBACK (re_emit_socket_event),
+                                 conn, 0);
 
-               soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
-               priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
-               start_idle_timer (conn);
+        if (props->proxy_resolver) {
+                g_socket_client_set_proxy_resolver (client, props->proxy_resolver);
+                g_socket_client_add_application_proxy (client, "http");
+        } else
+                g_socket_client_set_enable_proxy (client, FALSE);
+        if (props->io_timeout)
+                g_socket_client_set_timeout (client, props->io_timeout);
+        if (props->local_addr)
+                g_socket_client_set_local_address (client, G_SOCKET_ADDRESS (props->local_addr));
 
-               g_task_return_boolean (task, TRUE);
-       } else
-               g_task_return_error (task, error);
-       g_object_unref (task);
+        return client;
 }
 
-static void
-socket_handshake_complete (GObject *object, GAsyncResult *result, gpointer user_data)
+static gboolean
+tls_connection_accept_certificate (GTlsConnection      *conn,
+                                   GTlsCertificate     *cert,
+                                   GTlsCertificateFlags errors,
+                                   gpointer             user_data)
 {
-       SoupSocket *sock = SOUP_SOCKET (object);
-       GTask *task = user_data;
-       GError *error = NULL;
+        return TRUE;
+}
+
+static GTlsClientConnection *
+new_tls_connection (SoupConnection    *conn,
+                    GSocketConnection *connection,
+                    GError           **error)
+{
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+        GTlsClientConnection *tls_connection;
+
+        tls_connection = g_initable_new (g_tls_backend_get_client_connection_type (g_tls_backend_get_default 
()),
+                                         priv->cancellable, error,
+                                         "base-io-stream", connection,
+                                         "server-identity", priv->remote_connectable,
+                                         "database", priv->socket_props->tlsdb,
+                                         "require-close-notify", FALSE,
+                                         "interaction", priv->socket_props->tls_interaction,
+                                         NULL);
+        if (!tls_connection)
+                return NULL;
+
+        if (!priv->socket_props->ssl_strict) {
+                g_signal_connect_object (tls_connection, "accept-certificate",
+                                         G_CALLBACK (tls_connection_accept_certificate),
+                                         conn, 0);
+        }
+
+        return tls_connection;
+}
+
+static gboolean
+soup_connection_connected (SoupConnection    *conn,
+                           GSocketConnection *connection,
+                           GError           **error)
+{
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+        GSocket *socket;
+        GSocketAddress *addr;
+
+        socket = g_socket_connection_get_socket (connection);
+        g_socket_set_timeout (socket, priv->socket_props->io_timeout);
+        g_socket_set_option (socket, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
 
-       soup_socket_handshake_finish (sock, result, &error);
-       socket_connect_finished (task, sock, error);
+        addr = g_socket_get_remote_address (socket, NULL);
+        if (addr && G_IS_PROXY_ADDRESS (addr)) {
+                GProxyAddress *paddr = G_PROXY_ADDRESS (addr);
+
+                if (strcmp (g_proxy_address_get_protocol (paddr), "http") == 0)
+                        priv->proxy_uri = soup_uri_new (g_proxy_address_get_uri (paddr));
+        }
+        g_clear_object (&addr);
+
+        if (priv->ssl && !priv->proxy_uri) {
+                GTlsClientConnection *tls_connection;
+
+                tls_connection = new_tls_connection (conn, connection, error);
+                if (!tls_connection)
+                        return FALSE;
+
+                g_object_unref (connection);
+                soup_connection_set_connection (conn, G_IO_STREAM (tls_connection));
+        } else {
+                soup_connection_set_connection (conn, G_IO_STREAM (connection));
+        }
+
+        return TRUE;
 }
 
 static void
-socket_connect_complete (GObject *object, GAsyncResult *result, gpointer user_data)
+soup_connection_complete (SoupConnection *conn)
 {
-       SoupSocket *sock = SOUP_SOCKET (object);
-       GTask *task = user_data;
-       SoupConnection *conn = g_task_get_source_object (task);
-       SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
-       GError *error = NULL;
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
 
-       if (!soup_socket_connect_finish_internal (sock, result, &error)) {
-               socket_connect_finished (task, sock, error);
-               return;
-       }
+        g_clear_object (&priv->cancellable);
 
-       priv->proxy_uri = soup_socket_get_http_proxy_uri (sock);
+        if (!priv->ssl || !priv->proxy_uri) {
+                soup_connection_event (conn,
+                                       G_SOCKET_CLIENT_COMPLETE,
+                                       NULL);
+        }
 
-       if (priv->ssl && !priv->proxy_uri) {
-               soup_socket_handshake_async (sock,
-                                            g_task_get_cancellable (task),
-                                            socket_handshake_complete, task);
-               return;
-       }
+        soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
+        priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
+        start_idle_timer (conn);
+}
+
+static void
+handshake_ready_cb (GTlsConnection *tls_connection,
+                    GAsyncResult   *result,
+                    GTask          *task)
+{
+        SoupConnection *conn = g_task_get_source_object (task);
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+        GError *error = NULL;
+
+        if (g_tls_connection_handshake_finish (tls_connection, result, &error)) {
+                soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
+                soup_connection_complete (conn);
+                g_task_return_boolean (task, TRUE);
+        } else {
+                g_clear_object (&priv->cancellable);
+                g_task_return_error (task, error);
+        }
+        g_object_unref (task);
+}
 
-       socket_connect_finished (task, sock, NULL);
+static void
+connect_async_ready_cb (GSocketClient *client,
+                        GAsyncResult  *result,
+                        GTask         *task)
+{
+        SoupConnection *conn = g_task_get_source_object (task);
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+        GSocketConnection *connection;
+        GError *error = NULL;
+
+        connection = g_socket_client_connect_finish (client, result, &error);
+        if (!connection) {
+                g_task_return_error (task, error);
+                g_object_unref (task);
+                g_clear_object (&priv->cancellable);
+                return;
+        }
+
+        if (!soup_connection_connected (conn, connection, &error)) {
+                g_task_return_error (task, error);
+                g_object_unref (task);
+                g_object_unref (connection);
+                g_clear_object (&priv->cancellable);
+                return;
+        }
+
+        if (G_IS_TLS_CONNECTION (priv->connection)) {
+                soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
+
+                g_tls_connection_handshake_async (G_TLS_CONNECTION (priv->connection),
+                                                  g_task_get_priority (task),
+                                                  priv->cancellable,
+                                                  (GAsyncReadyCallback)handshake_ready_cb,
+                                                  task);
+                return;
+        }
+
+        soup_connection_complete (conn);
+        g_task_return_boolean (task, TRUE);
+        g_object_unref (task);
 }
 
 void
 soup_connection_connect_async (SoupConnection      *conn,
-                              GCancellable        *cancellable,
-                              GAsyncReadyCallback  callback,
-                              gpointer             user_data)
+                               int                  io_priority,
+                               GCancellable        *cancellable,
+                               GAsyncReadyCallback  callback,
+                               gpointer             user_data)
 {
-       SoupConnectionPrivate *priv;
-       GInetSocketAddress *remote_addr;
-       GTask *task;
-
-       g_return_if_fail (SOUP_IS_CONNECTION (conn));
-       priv = soup_connection_get_instance_private (conn);
-       g_return_if_fail (priv->socket == NULL);
+        SoupConnectionPrivate *priv;
+        GTask *task;
+        GSocketClient *client;
 
-       soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
+        g_return_if_fail (SOUP_IS_CONNECTION (conn));
 
-       /* Set the protocol to ensure correct proxy resolution. */
-       remote_addr =
-               g_object_new (G_TYPE_NETWORK_ADDRESS,
-                             "hostname", priv->remote_uri->host,
-                             "port", priv->remote_uri->port,
-                             "scheme", priv->remote_uri->scheme,
-                             NULL);
+        priv = soup_connection_get_instance_private (conn);
 
-       priv->socket =
-               soup_socket_new ("remote-connectable", remote_addr,
-                                "socket-properties", priv->socket_props,
-                                NULL);
-       g_object_unref (remote_addr);
+        soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
 
-       g_signal_connect (priv->socket, "event",
-                         G_CALLBACK (re_emit_socket_event), conn);
+        /* Set the protocol to ensure correct proxy resolution. */
+        priv->remote_connectable =
+                g_object_new (G_TYPE_NETWORK_ADDRESS,
+                              "hostname", priv->remote_uri->host,
+                              "port", priv->remote_uri->port,
+                              "scheme", priv->remote_uri->scheme,
+                              NULL);
 
-       task = g_task_new (conn, cancellable, callback, user_data);
+        priv->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
+        task = g_task_new (conn, priv->cancellable, callback, user_data);
+        g_task_set_priority (task, io_priority);
 
-       soup_socket_connect_async_internal (priv->socket, cancellable,
-                                           socket_connect_complete, task);
+        client = new_socket_client (conn);
+        g_socket_client_connect_async (client,
+                                       priv->remote_connectable,
+                                       priv->cancellable,
+                                       (GAsyncReadyCallback)connect_async_ready_cb,
+                                       task);
+        g_object_unref (client);
 }
 
 gboolean
 soup_connection_connect_finish (SoupConnection  *conn,
-                               GAsyncResult    *result,
-                               GError         **error)
+                                GAsyncResult    *result,
+                                GError         **error)
 {
-       return g_task_propagate_boolean (G_TASK (result), error);
+        return g_task_propagate_boolean (G_TASK (result), error);
 }
 
 gboolean
-soup_connection_connect_sync (SoupConnection  *conn,
-                             GCancellable    *cancellable,
-                             GError         **error)
+soup_connection_connect (SoupConnection  *conn,
+                        GCancellable    *cancellable,
+                        GError         **error)
 {
-       SoupConnectionPrivate *priv;
-       GNetworkAddress *remote_addr;
+        SoupConnectionPrivate *priv;
+        GSocketClient *client;
+        GSocketConnection *connection;
 
-       g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
-       priv = soup_connection_get_instance_private (conn);
-       g_return_val_if_fail (priv->socket == NULL, FALSE);
-
-       soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
-
-       /* Set the protocol to ensure correct proxy resolution. */
-       remote_addr =
-               g_object_new (G_TYPE_NETWORK_ADDRESS,
-                             "hostname", priv->remote_uri->host,
-                             "port", priv->remote_uri->port,
-                             "scheme", priv->remote_uri->scheme,
-                             NULL);
-
-       priv->socket =
-               soup_socket_new ("remote-connectable", remote_addr,
-                                "socket-properties", priv->socket_props,
-                                "non-blocking", FALSE,
-                                NULL);
-       g_object_unref (remote_addr);
-
-       g_signal_connect (priv->socket, "event",
-                         G_CALLBACK (re_emit_socket_event), conn);
-       if (!soup_socket_connect_sync_internal (priv->socket, cancellable, error))
-               return FALSE;
+        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
 
-       priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
+        priv = soup_connection_get_instance_private (conn);
 
-       if (priv->ssl && !priv->proxy_uri) {
-               if (!soup_socket_handshake_sync (priv->socket,
-                                                cancellable, error))
-                       return FALSE;
-       }
+        soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
 
-       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);
+        /* Set the protocol to ensure correct proxy resolution. */
+        priv->remote_connectable =
+                g_object_new (G_TYPE_NETWORK_ADDRESS,
+                              "hostname", priv->remote_uri->host,
+                              "port", priv->remote_uri->port,
+                              "scheme", priv->remote_uri->scheme,
+                              NULL);
 
-       return TRUE;
+        priv->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
+
+        client = new_socket_client (conn);
+        connection = g_socket_client_connect (client,
+                                              priv->remote_connectable,
+                                              priv->cancellable,
+                                              error);
+        g_object_unref (client);
+
+        if (!connection) {
+                g_clear_object (&priv->cancellable);
+                return FALSE;
+        }
+
+        if (!soup_connection_connected (conn, connection, error)) {
+                g_object_unref (connection);
+                g_clear_object (&priv->cancellable);
+                return FALSE;
+        }
+
+        if (G_IS_TLS_CONNECTION (priv->connection)) {
+                soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
+                if (!g_tls_connection_handshake (G_TLS_CONNECTION (priv->connection),
+                                                 priv->cancellable, error)) {
+                        g_clear_object (&priv->cancellable);
+                        return FALSE;
+                }
+                soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
+        }
+
+        soup_connection_complete (conn);
+
+        return TRUE;
 }
 
 gboolean
@@ -499,64 +647,109 @@ soup_connection_is_tunnelled (SoupConnection *conn)
        return priv->ssl && priv->proxy_uri != NULL;
 }
 
-gboolean
-soup_connection_start_ssl_sync (SoupConnection  *conn,
-                               GCancellable    *cancellable,
-                               GError         **error)
+static void
+tunnel_handshake_ready_cb (GTlsConnection *tls_connection,
+                           GAsyncResult   *result,
+                           GTask          *task)
 {
-       SoupConnectionPrivate *priv;
+        SoupConnection *conn = g_task_get_source_object (task);
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+        GError *error = NULL;
 
-       g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
-       priv = soup_connection_get_instance_private (conn);
+        g_clear_object (&priv->cancellable);
 
-       if (soup_socket_handshake_sync (priv->socket,
-                                       cancellable, error)) {
-               soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
-               return TRUE;
-       } else
-               return FALSE;
+        if (g_tls_connection_handshake_finish (tls_connection, result, &error)) {
+                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 {
+                g_task_return_error (task, error);
+        }
+        g_object_unref (task);
 }
 
-static void
-start_ssl_completed (GObject *object, GAsyncResult *result, gpointer user_data)
+void
+soup_connection_tunnel_handshake_async (SoupConnection     *conn,
+                                        int                 io_priority,
+                                        GCancellable       *cancellable,
+                                        GAsyncReadyCallback callback,
+                                        gpointer            user_data)
+{
+        SoupConnectionPrivate *priv;
+        GTask *task;
+        GTlsClientConnection *tls_connection;
+        GError *error = NULL;
+
+        g_return_if_fail (SOUP_IS_CONNECTION (conn));
+
+        priv = soup_connection_get_instance_private (conn);
+        g_return_if_fail (G_IS_SOCKET_CONNECTION (priv->connection));
+        g_return_if_fail (priv->cancellable == NULL);
+
+        priv->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
+        task = g_task_new (conn, priv->cancellable, callback, user_data);
+        g_task_set_priority (task, io_priority);
+
+        tls_connection = new_tls_connection (conn, G_SOCKET_CONNECTION (priv->connection), &error);
+        if (!tls_connection) {
+                g_task_return_error (task, error);
+                g_object_unref (task);
+                g_clear_object (&priv->cancellable);
+                return;
+        }
+
+        soup_connection_set_connection (conn, G_IO_STREAM (tls_connection));
+        soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
+        g_tls_connection_handshake_async (G_TLS_CONNECTION (priv->connection),
+                                          g_task_get_priority (task),
+                                          priv->cancellable,
+                                          (GAsyncReadyCallback)tunnel_handshake_ready_cb,
+                                          task);
+}
+
+gboolean
+soup_connection_tunnel_handshake_finish (SoupConnection *conn,
+                                         GAsyncResult   *result,
+                                         GError        **error)
 {
-       GTask *task = user_data;
-       SoupConnection *conn = g_task_get_source_object (task);
-       SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
-       GError *error = NULL;
+        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
 
-       if (soup_socket_handshake_finish (priv->socket, result, &error)) {
-               soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
-               g_task_return_boolean (task, TRUE);
-       } else
-               g_task_return_error (task, error);
-       g_object_unref (task);
+        return g_task_propagate_boolean (G_TASK (result), error);
 }
 
-void
-soup_connection_start_ssl_async (SoupConnection      *conn,
-                                GCancellable        *cancellable,
-                                GAsyncReadyCallback  callback,
-                                gpointer             user_data)
+gboolean
+soup_connection_tunnel_handshake (SoupConnection *conn,
+                                  GCancellable   *cancellable,
+                                  GError        **error)
 {
-       SoupConnectionPrivate *priv;
-       GTask *task;
+        SoupConnectionPrivate *priv;
+        GTlsClientConnection *tls_connection;
 
-       g_return_if_fail (SOUP_IS_CONNECTION (conn));
-       priv = soup_connection_get_instance_private (conn);
+        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
 
-       task = g_task_new (conn, cancellable, callback, user_data);
+        priv = soup_connection_get_instance_private (conn);
+        g_return_val_if_fail (G_IS_SOCKET_CONNECTION (priv->connection), FALSE);
+        g_return_val_if_fail (priv->cancellable == NULL, FALSE);
 
-       soup_socket_handshake_async (priv->socket,
-                                    cancellable, start_ssl_completed, task);
-}
+        tls_connection = new_tls_connection (conn, G_SOCKET_CONNECTION (priv->connection), error);
+        if (!tls_connection)
+                return FALSE;
 
-gboolean
-soup_connection_start_ssl_finish (SoupConnection  *conn,
-                                 GAsyncResult    *result,
-                                 GError         **error)
-{
-       return g_task_propagate_boolean (G_TASK (result), error);
+        soup_connection_set_connection (conn, G_IO_STREAM (tls_connection));
+        soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
+
+        priv->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
+        if (!g_tls_connection_handshake (G_TLS_CONNECTION (priv->connection),
+                                         priv->cancellable, error)) {
+                g_clear_object (&priv->cancellable);
+                return FALSE;
+        }
+        g_clear_object (&priv->cancellable);
+
+        soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
+        soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
+
+        return TRUE;
 }
 
 /**
@@ -569,38 +762,84 @@ soup_connection_start_ssl_finish (SoupConnection  *conn,
 void
 soup_connection_disconnect (SoupConnection *conn)
 {
-       SoupConnectionPrivate *priv;
-       SoupConnectionState old_state;
+        SoupConnectionPrivate *priv;
+        SoupConnectionState old_state;
 
-       g_return_if_fail (SOUP_IS_CONNECTION (conn));
-       priv = soup_connection_get_instance_private (conn);
+        g_return_if_fail (SOUP_IS_CONNECTION (conn));
+        priv = soup_connection_get_instance_private (conn);
 
-       old_state = priv->state;
-       if (old_state != SOUP_CONNECTION_DISCONNECTED)
-               soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED);
+        old_state = priv->state;
+        if (old_state != SOUP_CONNECTION_DISCONNECTED)
+                soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED);
 
-       if (priv->socket) {
-               SoupSocket *socket = priv->socket;
+        if (priv->cancellable) {
+                g_cancellable_cancel (priv->cancellable);
+                priv->cancellable = NULL;
+        }
 
-               g_signal_handlers_disconnect_by_func (socket, G_CALLBACK (re_emit_socket_event), conn);
+        if (priv->connection) {
+                GIOStream *connection;
 
-               priv->socket = NULL;
-               soup_socket_disconnect (socket);
-               g_object_unref (socket);
-       }
+                connection = priv->connection;
+                priv->connection = NULL;
 
-       if (old_state != SOUP_CONNECTION_DISCONNECTED)
-               g_signal_emit (conn, signals[DISCONNECTED], 0);
+                g_io_stream_close (connection, NULL, NULL);
+                g_signal_handlers_disconnect_by_data (connection, conn);
+                g_object_unref (connection);
+        }
+
+        if (old_state != SOUP_CONNECTION_DISCONNECTED)
+                g_signal_emit (conn, signals[DISCONNECTED], 0);
 }
 
-SoupSocket *
+GSocket *
 soup_connection_get_socket (SoupConnection *conn)
 {
-       SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+        GSocketConnection *connection = NULL;
 
-       g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
+        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
+
+        if (G_IS_TLS_CONNECTION (priv->connection)) {
+                g_object_get (priv->connection, "base-io-stream", &connection, NULL);
+                g_object_unref (connection);
+        } else if (G_IS_SOCKET_CONNECTION (priv->connection))
+                connection = G_SOCKET_CONNECTION (priv->connection);
+
+        return connection ? g_socket_connection_get_socket (connection) : NULL;
+}
+
+GIOStream *
+soup_connection_get_iostream (SoupConnection *conn)
+{
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
 
-       return priv->socket;
+        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
+
+        return priv->iostream;
+}
+
+GIOStream *
+soup_connection_steal_iostream (SoupConnection *conn)
+{
+        SoupConnectionPrivate *priv;
+        GSocket *socket;
+        GIOStream *iostream;
+
+        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
+
+        socket = soup_connection_get_socket (conn);
+        g_socket_set_timeout (socket, 0);
+
+        priv = soup_connection_get_instance_private (conn);
+        iostream = priv->iostream;
+        priv->iostream = NULL;
+
+        g_object_set_data_full (G_OBJECT (iostream), "GSocket",
+                                g_object_ref (socket), g_object_unref);
+        g_clear_object (&priv->connection);
+
+        return iostream;
 }
 
 SoupURI *
@@ -633,23 +872,44 @@ soup_connection_is_via_proxy (SoupConnection *conn)
        return priv->proxy_uri != NULL;
 }
 
+gboolean
+soup_connection_get_tls_info (SoupConnection       *conn,
+                             GTlsCertificate     **certificate,
+                             GTlsCertificateFlags *errors)
+{
+       SoupConnectionPrivate *priv;
+       GTlsConnection *tls_connection;
+
+       g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
+
+       priv = soup_connection_get_instance_private (conn);
+       if (!G_IS_TLS_CONNECTION (priv->connection))
+               return FALSE;
+
+       tls_connection = G_TLS_CONNECTION (priv->connection);
+       if (certificate)
+               *certificate = g_tls_connection_get_peer_certificate (tls_connection);
+       if (errors)
+               *errors = g_tls_connection_get_peer_certificate_errors (tls_connection);
+
+       return TRUE;
+}
+
 static gboolean
 is_idle_connection_disconnected (SoupConnection *conn)
 {
        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
-       GIOStream *iostream;
        GInputStream *istream;
        char buffer[1];
        GError *error = NULL;
 
-       if (!soup_socket_is_connected (priv->socket))
+       if (!g_socket_is_connected (soup_connection_get_socket (conn)))
                return TRUE;
 
        if (priv->unused_timeout && priv->unused_timeout < time (NULL))
                return TRUE;
 
-       iostream = soup_socket_get_iostream (priv->socket);
-       istream = g_io_stream_get_input_stream (iostream);
+       istream = g_io_stream_get_input_stream (priv->iostream);
 
        /* This is tricky. The goal is to check if the socket is readable. If
         * so, that means either the server has disconnected or it's broken (it
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 9f613a15..53b67337 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -25,33 +25,39 @@ typedef enum {
 } SoupConnectionState;
 
 void            soup_connection_connect_async    (SoupConnection       *conn,
+                                                 int                   io_priority,
                                                  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,
+gboolean        soup_connection_connect          (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_tunnel_handshake_async  (SoupConnection     *conn,
+                                                        int                 io_priority,
+                                                        GCancellable       *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer            user_data);
+gboolean        soup_connection_tunnel_handshake_finish (SoupConnection *conn,
+                                                        GAsyncResult   *result,
+                                                        GError        **error);
+gboolean        soup_connection_tunnel_handshake        (SoupConnection *conn,
+                                                        GCancellable   *cancellable,
+                                                        GError        **error);
 void            soup_connection_disconnect     (SoupConnection   *conn);
 
-SoupSocket     *soup_connection_get_socket     (SoupConnection   *conn);
+GSocket        *soup_connection_get_socket     (SoupConnection   *conn);
+GIOStream      *soup_connection_get_iostream   (SoupConnection   *conn);
+GIOStream      *soup_connection_steal_iostream (SoupConnection   *conn);
 SoupURI        *soup_connection_get_remote_uri (SoupConnection   *conn);
 SoupURI        *soup_connection_get_proxy_uri  (SoupConnection   *conn);
 gboolean        soup_connection_is_via_proxy   (SoupConnection   *conn);
 gboolean        soup_connection_is_tunnelled   (SoupConnection   *conn);
+gboolean        soup_connection_get_tls_info   (SoupConnection   *conn,
+                                               GTlsCertificate **certificate,
+                                               GTlsCertificateFlags *errors);
 
 SoupConnectionState soup_connection_get_state  (SoupConnection   *conn);
 void                soup_connection_set_state  (SoupConnection   *conn,
diff --git a/libsoup/soup-logger.c b/libsoup/soup-logger.c
index 5a128104..63b5a78c 100644
--- a/libsoup/soup-logger.c
+++ b/libsoup/soup-logger.c
@@ -41,7 +41,7 @@
  * <informalexample><screen>
  * > POST /unauth HTTP/1.1
  * > Soup-Debug-Timestamp: 1200171744
- * > Soup-Debug: SoupSessionAsync 1 (0x612190), SoupMessage 1 (0x617000), SoupSocket 1 (0x612220)
+ * > Soup-Debug: SoupSessionAsync 1 (0x612190), SoupMessage 1 (0x617000), GSocket 1 (0x612220)
  * > Host: localhost
  * > Content-Type: text/plain
  * > Connection: close
@@ -60,7 +60,7 @@
  * received.
  *
  * The <literal>Soup-Debug</literal> line gives further debugging
- * information about the #SoupSession, #SoupMessage, and #SoupSocket
+ * information about the #SoupSession, #SoupMessage, and #GSocket
  * involved; the hex numbers are the addresses of the objects in
  * question (which may be useful if you are running in a debugger).
  * The decimal IDs are simply counters that uniquely identify objects
@@ -502,7 +502,7 @@ soup_logger_print_basic_auth (SoupLogger *logger, const char *value)
 
 static void
 print_request (SoupLogger *logger, SoupMessage *msg,
-              SoupSocket *socket, gboolean restarted)
+              GSocket *socket, gboolean restarted)
 {
        SoupLoggerPrivate *priv = soup_logger_get_instance_private (logger);
        SoupLoggerLogLevel log_level;
@@ -686,7 +686,7 @@ starting (SoupMessage *msg, gpointer user_data)
        gboolean restarted;
        guint msg_id;
        SoupConnection *conn;
-       SoupSocket *socket;
+       GSocket *socket;
 
        msg_id = soup_logger_get_id (logger, msg);
        if (msg_id)
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index b15c7c8a..f2b13fdd 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -91,19 +91,17 @@ soup_message_io_finished (SoupMessage *msg)
        g_object_unref (msg);
 }
 
-GIOStream *
-soup_message_io_steal (SoupMessage *msg)
+void
+soup_message_io_stolen (SoupMessage *msg)
 {
        SoupClientMessageIOData *io;
        SoupMessageIOCompletionFn completion_cb;
        gpointer completion_data;
-       GIOStream *iostream;
 
        io = soup_message_get_io_data (msg);
-       if (!io || !io->base.iostream)
-               return NULL;
+       if (!io)
+               return;
 
-       iostream = g_object_ref (io->base.iostream);
        completion_cb = io->base.completion_cb;
        completion_data = io->base.completion_data;
 
@@ -112,8 +110,6 @@ soup_message_io_steal (SoupMessage *msg)
        if (completion_cb)
                completion_cb (G_OBJECT (msg), SOUP_MESSAGE_IO_STOLEN, completion_data);
        g_object_unref (msg);
-
-       return iostream;
 }
 
 static gint
@@ -1021,7 +1017,7 @@ soup_message_send_request (SoupMessageQueueItem      *item,
        io->item = item;
        soup_message_queue_item_ref (item);
        io->cancellable = io->item->cancellable;
-       io->base.iostream = g_object_ref (soup_socket_get_iostream (soup_connection_get_socket 
(io->item->conn)));
+       io->base.iostream = g_object_ref (soup_connection_get_iostream (io->item->conn));
        io->base.istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->base.iostream));
        io->base.ostream = g_io_stream_get_output_stream (io->base.iostream);
        io->base.async_context = g_main_context_ref_thread_default ();
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index d85445fa..ffeea9a6 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -52,7 +52,7 @@ void       soup_message_io_pause       (SoupMessage *msg);
 void       soup_message_io_unpause     (SoupMessage *msg);
 gboolean   soup_message_is_io_paused   (SoupMessage *msg);
 gboolean   soup_message_io_in_progress (SoupMessage *msg);
-GIOStream *soup_message_io_steal       (SoupMessage *msg);
+void       soup_message_io_stolen      (SoupMessage *msg);
 
 gboolean soup_message_io_read_headers          (SoupMessage           *msg,
                                                 SoupFilterInputStream *stream,
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 7ed50b83..ba034832 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -1704,29 +1704,16 @@ soup_message_get_is_top_level_navigation (SoupMessage *msg)
 void
 soup_message_set_https_status (SoupMessage *msg, SoupConnection *conn)
 {
-       SoupSocket *sock;
-
-       sock = conn ? soup_connection_get_socket (conn) : NULL;
-       if (sock && soup_socket_is_ssl (sock)) {
-               GTlsCertificate *certificate;
-               GTlsCertificateFlags errors;
-
-               g_object_get (sock,
-                             "tls-certificate", &certificate,
-                             "tls-errors", &errors,
-                             NULL);
-               g_object_set (msg,
-                             "tls-certificate", certificate,
-                             "tls-errors", errors,
-                             NULL);
-               if (certificate)
-                       g_object_unref (certificate);
-       } else {
-               g_object_set (msg,
-                             "tls-certificate", NULL,
-                             "tls-errors", 0,
-                             NULL);
-       }
+       GTlsCertificate *certificate = NULL;
+       GTlsCertificateFlags errors = 0;
+
+       if (conn)
+               soup_connection_get_tls_info (conn, &certificate, &errors);
+
+       g_object_set (msg,
+                     "tls-certificate", certificate,
+                     "tls-errors", errors,
+                     NULL);
 }
 
 /**
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 76f3ea88..6e9e4aca 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1360,15 +1360,13 @@ tunnel_complete (SoupMessageQueueItem *tunnel_item,
 }
 
 static void
-tunnel_handshake_complete (GObject      *object,
-                          GAsyncResult *result,
-                          gpointer      user_data)
+tunnel_handshake_complete (SoupConnection       *conn,
+                          GAsyncResult         *result,
+                          SoupMessageQueueItem *tunnel_item)
 {
-       SoupConnection *conn = SOUP_CONNECTION (object);
-       SoupMessageQueueItem *tunnel_item = user_data;
        GError *error = NULL;
 
-       soup_connection_start_ssl_finish (conn, result, &error);
+       soup_connection_tunnel_handshake_finish (conn, result, &error);
        tunnel_complete (tunnel_item, 0, error);
 }
 
@@ -1404,13 +1402,17 @@ tunnel_message_completed (SoupMessage *msg, SoupMessageIOCompletion completion,
        }
 
        if (tunnel_item->async) {
-               soup_connection_start_ssl_async (item->conn, item->cancellable,
-                                                tunnel_handshake_complete,
-                                                tunnel_item);
+               soup_connection_tunnel_handshake_async (item->conn,
+                                                       item->task ?
+                                                       g_task_get_priority (item->task) :
+                                                       G_PRIORITY_DEFAULT,
+                                                       item->cancellable,
+                                                       (GAsyncReadyCallback)tunnel_handshake_complete,
+                                                       tunnel_item);
        } else {
                GError *error = NULL;
 
-               soup_connection_start_ssl_sync (item->conn, item->cancellable, &error);
+               soup_connection_tunnel_handshake (item->conn, item->cancellable, &error);
                tunnel_complete (tunnel_item, 0, error);
        }
 }
@@ -1643,13 +1645,17 @@ get_connection (SoupMessageQueueItem *item, gboolean *should_cleanup)
 
        if (item->async) {
                soup_message_queue_item_ref (item);
-               soup_connection_connect_async (item->conn, item->cancellable,
+               soup_connection_connect_async (item->conn,
+                                              item->task ?
+                                              g_task_get_priority (item->task) :
+                                              G_PRIORITY_DEFAULT,
+                                              item->cancellable,
                                               connect_async_complete, item);
                return FALSE;
        } else {
                GError *error = NULL;
 
-               soup_connection_connect_sync (item->conn, item->cancellable, &error);
+               soup_connection_connect (item->conn, item->cancellable, &error);
                connect_complete (item, conn, error);
 
                return TRUE;
@@ -3934,7 +3940,6 @@ steal_connection (SoupSession          *session,
 {
         SoupSessionPrivate *priv = soup_session_get_instance_private (session);
         SoupConnection *conn;
-        SoupSocket *sock;
         SoupSessionHost *host;
         GIOStream *stream;
 
@@ -3947,19 +3952,10 @@ steal_connection (SoupSession          *session,
         drop_connection (session, host, conn);
         g_mutex_unlock (&priv->conn_lock);
 
-        sock = soup_connection_get_socket (conn);
-        g_object_set (sock,
-                      "timeout", 0,
-                      NULL);
-
-       if (item->connect_only)
-               stream = g_object_ref (soup_socket_get_connection (sock));
-       else
-               stream = soup_message_io_steal (item->msg);
-        g_object_set_data_full (G_OBJECT (stream), "GSocket",
-                                soup_socket_steal_gsocket (sock),
-                                g_object_unref);
-        g_object_unref (conn);
+       stream = soup_connection_steal_iostream (conn);
+       if (!item->connect_only)
+               soup_message_io_stolen (item->msg);
+       g_object_unref (conn);
 
        return stream;
 }
diff --git a/tests/connection-test.c b/tests/connection-test.c
index 2021cad2..46fdbcb4 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -228,10 +228,10 @@ do_content_length_framing_test (void)
 
 static void
 message_started_socket_collector (SoupMessage *msg,
-                                 SoupSocket **sockets)
+                                 GSocket    **sockets)
 {
         SoupConnection *conn = soup_message_get_connection (msg);
-        SoupSocket *socket = soup_connection_get_socket (conn);
+        GSocket *socket = soup_connection_get_socket (conn);
        int i;
 
        debug_printf (2, "      msg %p => socket %p\n", msg, socket);
@@ -265,7 +265,7 @@ static void
 do_timeout_test_for_session (SoupSession *session)
 {
        SoupMessage *msg;
-       SoupSocket *sockets[4] = { NULL, NULL, NULL, NULL };
+       GSocket *sockets[4] = { NULL, NULL, NULL, NULL };
        SoupURI *timeout_uri;
        int i;
        GBytes *body;
@@ -332,7 +332,7 @@ do_persistent_connection_timeout_test_with_cancellation (void)
 {
        SoupSession *session;
        SoupMessage *msg;
-       SoupSocket *sockets[4] = { NULL, NULL, NULL, NULL };
+       GSocket *sockets[4] = { NULL, NULL, NULL, NULL };
        SoupURI *timeout_uri;
        GCancellable *cancellable;
        GInputStream *response;
@@ -549,10 +549,10 @@ do_max_conns_test (void)
 
 static void
 np_message_started (SoupMessage *msg,
-                   SoupSocket **save_socket)
+                   GSocket    **save_socket)
 {
         SoupConnection *conn = soup_message_get_connection (msg);
-        SoupSocket *socket = soup_connection_get_socket (conn);
+        GSocket *socket = soup_connection_get_socket (conn);
 
        *save_socket = g_object_ref (socket);
 }
@@ -568,12 +568,11 @@ np_request_queued (SoupSession *session,
 }
 
 static void
-np_request_unqueued (SoupSession *session, SoupMessage *msg,
-                    gpointer user_data)
+np_request_unqueued (SoupSession *session,
+                    SoupMessage *msg,
+                    GSocket    **socket)
 {
-       SoupSocket *socket = *(SoupSocket **)user_data;
-
-       g_assert_false (soup_socket_is_connected (socket));
+       g_assert_false (g_socket_is_connected (*socket));
 }
 
 static void
@@ -589,7 +588,7 @@ static void
 do_non_persistent_test_for_session (SoupSession *session)
 {
        SoupMessage *msg;
-       SoupSocket *socket = NULL;
+       GSocket *socket = NULL;
        GMainLoop *loop;
 
        loop = g_main_loop_new (NULL, FALSE);
@@ -631,7 +630,7 @@ static void
 do_non_idempotent_test_for_session (SoupSession *session)
 {
        SoupMessage *msg;
-       SoupSocket *sockets[4] = { NULL, NULL, NULL, NULL };
+       GSocket *sockets[4] = { NULL, NULL, NULL, NULL };
        int i;
        GBytes *body;
 
diff --git a/tests/timeout-test.c b/tests/timeout-test.c
index 217a0784..38cd7072 100644
--- a/tests/timeout-test.c
+++ b/tests/timeout-test.c
@@ -17,7 +17,7 @@ message_finished (SoupMessage *msg, gpointer user_data)
 static void
 request_started_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
 {
-       SoupSocket **ret = user_data;
+       GSocket **ret = user_data;
         SoupConnection *conn = soup_message_get_connection (msg);
 
        *ret = soup_connection_get_socket (conn);
@@ -58,8 +58,8 @@ do_msg_tests_for_session (SoupSession *timeout_session,
                          SoupURI *fast_uri,
                          SoupURI *slow_uri)
 {
-       SoupSocket *ret, *idle_first = NULL, *idle_second;
-       SoupSocket *plain_first = NULL, *plain_second;
+       GSocket *ret, *idle_first = NULL, *idle_second;
+       GSocket *plain_first = NULL, *plain_second;
 
        if (idle_session) {
                g_signal_connect (idle_session, "request-started",



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