[libsoup/gnome-3-18] soup-server: fix SoupClientContext usage from SoupServerWebsocketCallback



commit c4d290d99529a0eb35149ac2e3b673858e0efdfb
Author: Dan Winship <danw gnome org>
Date:   Wed Oct 14 11:43:47 2015 -0400

    soup-server: fix SoupClientContext usage from SoupServerWebsocketCallback
    
    SoupServerWebsocketCallback gets passed the SoupClientContext, but
    calling most functions on it would spew errors and/or crash. Oops.
    
    Pointed out in email by Ruben Blanco.

 libsoup/soup-server.c  |   52 +++++++++++++++++++++++++++++++++--------------
 tests/websocket-test.c |   52 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 88 insertions(+), 16 deletions(-)
---
diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c
index a1fefeb..0c4201c 100644
--- a/libsoup/soup-server.c
+++ b/libsoup/soup-server.c
@@ -133,11 +133,13 @@ static guint signals[LAST_SIGNAL] = { 0 };
 struct SoupClientContext {
        SoupServer     *server;
        SoupSocket     *sock;
+       GSocket        *gsock;
        SoupMessage    *msg;
        SoupAuthDomain *auth_domain;
        char           *auth_user;
 
        GSocketAddress *remote_addr;
+       const char     *remote_ip;
        GSocketAddress *local_addr;
 
        int             ref_count;
@@ -1125,6 +1127,9 @@ soup_client_context_new (SoupServer *server, SoupSocket *sock)
 
        client->server = server;
        client->sock = g_object_ref (sock);
+       client->gsock = soup_socket_get_gsocket (sock);
+       if (client->gsock)
+               g_object_ref (client->gsock);
        g_signal_connect (sock, "disconnected",
                          G_CALLBACK (socket_disconnected), client);
        client->ref_count = 1;
@@ -1160,6 +1165,8 @@ soup_client_context_unref (SoupClientContext *client)
 
        g_signal_handlers_disconnect_by_func (client->sock, socket_disconnected, client);
        g_object_unref (client->sock);
+       g_clear_object (&client->gsock);
+       g_clear_pointer (&client->remote_ip, g_free);
        g_slice_free (SoupClientContext, client);
 }
 
@@ -1353,6 +1360,7 @@ complete_websocket_upgrade (SoupMessage *msg, gpointer user_data)
        if (!handler || !handler->websocket_callback)
                return;
 
+       soup_client_context_ref (client);
        stream = soup_client_context_steal_connection (client);
        conn = soup_websocket_connection_new (stream, uri,
                                              SOUP_WEBSOCKET_CONNECTION_SERVER,
@@ -1364,6 +1372,7 @@ complete_websocket_upgrade (SoupMessage *msg, gpointer user_data)
        (*handler->websocket_callback) (server, conn, uri->path, client,
                                        handler->websocket_user_data);
        g_object_unref (conn);
+       soup_client_context_unref (client);
 }
 
 static void
@@ -2231,7 +2240,7 @@ soup_client_context_get_gsocket (SoupClientContext *client)
 {
        g_return_val_if_fail (client != NULL, NULL);
 
-       return soup_socket_get_gsocket (client->sock);
+       return client->gsock;
 }
 
 /**
@@ -2272,16 +2281,13 @@ soup_client_context_get_address (SoupClientContext *client)
 GSocketAddress *
 soup_client_context_get_remote_address (SoupClientContext *client)
 {
-       GSocket *sock;
-
        g_return_val_if_fail (client != NULL, NULL);
 
        if (client->remote_addr)
                return client->remote_addr;
 
-       sock = soup_client_context_get_gsocket (client);
-       client->remote_addr = sock ?
-               g_socket_get_remote_address (sock, NULL) :
+       client->remote_addr = client->gsock ?
+               g_socket_get_remote_address (client->gsock, NULL) :
                soup_address_get_gsockaddr (soup_socket_get_remote_address (client->sock));
 
        return client->remote_addr;
@@ -2303,16 +2309,13 @@ soup_client_context_get_remote_address (SoupClientContext *client)
 GSocketAddress *
 soup_client_context_get_local_address (SoupClientContext *client)
 {
-       GSocket *sock;
-
        g_return_val_if_fail (client != NULL, NULL);
 
        if (client->local_addr)
                return client->local_addr;
 
-       sock = soup_client_context_get_gsocket (client);
-       client->local_addr = sock ?
-               g_socket_get_local_address (sock, NULL) :
+       client->local_addr = client->gsock ?
+               g_socket_get_local_address (client->gsock, NULL) :
                soup_address_get_gsockaddr (soup_socket_get_local_address (client->sock));
 
        return client->local_addr;
@@ -2332,12 +2335,29 @@ soup_client_context_get_local_address (SoupClientContext *client)
 const char *
 soup_client_context_get_host (SoupClientContext *client)
 {
-       SoupAddress *address;
+       g_return_val_if_fail (client != NULL, NULL);
+
+       if (client->remote_ip)
+               return client->remote_ip;
+
+       if (client->gsock) {
+               GSocketAddress *addr = soup_client_context_get_remote_address (client);
+               GInetAddress *iaddr;
+
+               if (!addr || !G_IS_INET_SOCKET_ADDRESS (addr))
+                       return NULL;
+               iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
+               client->remote_ip = g_inet_address_to_string (iaddr);
+       } else {
+               SoupAddress *addr;
+
+               G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+               addr = soup_client_context_get_address (client);
+               G_GNUC_END_IGNORE_DEPRECATIONS;
+               client->remote_ip = g_strdup (soup_address_get_physical (addr));
+       }
 
-       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-       address = soup_client_context_get_address (client);
-       G_GNUC_END_IGNORE_DEPRECATIONS;
-       return soup_address_get_physical (address);
+       return client->remote_ip;
 }
 
 /**
diff --git a/tests/websocket-test.c b/tests/websocket-test.c
index 78dced5..c4f5b39 100644
--- a/tests/websocket-test.c
+++ b/tests/websocket-test.c
@@ -783,6 +783,54 @@ test_receive_fragmented (Test *test,
        WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
 }
 
+static void
+test_client_context_got_server_connection (SoupServer              *server,
+                                          SoupWebsocketConnection *connection,
+                                          const char              *path,
+                                          SoupClientContext       *client,
+                                          gpointer                 user_data)
+{
+       Test *test = user_data;
+       GSocketAddress *addr;
+       GInetAddress *iaddr;
+       char *str;
+       const char *remote_ip;
+
+       addr = soup_client_context_get_local_address (client);
+       iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
+       str = g_inet_address_to_string (iaddr);
+       if (g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV4)
+               g_assert_cmpstr (str, ==, "127.0.0.1");
+       else
+               g_assert_cmpstr (str, ==, "::1");
+       g_free (str);
+
+       addr = soup_client_context_get_remote_address (client);
+       iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
+       str = g_inet_address_to_string (iaddr);
+       if (g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV4)
+               g_assert_cmpstr (str, ==, "127.0.0.1");
+       else
+               g_assert_cmpstr (str, ==, "::1");
+
+       remote_ip = soup_client_context_get_host (client);
+       g_assert_cmpstr (remote_ip, ==, str);
+       g_free (str);
+
+       test->server = g_object_ref (connection);
+}
+
+static void
+test_client_context (Test *test,
+                    gconstpointer unused)
+{
+       setup_soup_server (test, NULL, NULL, test_client_context_got_server_connection, test);
+       client_connect (test, NULL, NULL, got_client_connection, test);
+       WAIT_UNTIL (test->server != NULL);
+       WAIT_UNTIL (test->client != NULL || test->client_error != NULL);
+       g_assert_no_error (test->client_error);
+}
+
 int
 main (int argc,
       char *argv[])
@@ -901,6 +949,10 @@ main (int argc,
                            teardown_direct_connection);
        }
 
+       g_test_add ("/websocket/soup/client-context", Test, NULL, NULL,
+                   test_client_context,
+                   teardown_soup_connection);
+
        ret = g_test_run ();
 
        test_cleanup ();


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