[libsoup/carlosgc/msg-remote-address: 3/3] message: add API to get the remote address of a SoupMessage




commit 689e072db546042cf0f0681f8a0cf653075d1860
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Fri Apr 30 16:06:55 2021 +0200

    message: add API to get the remote address of a SoupMessage

 docs/reference/libsoup-3.0-sections.txt |  1 +
 libsoup/soup-connection.c               | 33 ++++++++++++---
 libsoup/soup-connection.h               |  1 +
 libsoup/soup-message.c                  | 71 +++++++++++++++++++++++++++++++++
 libsoup/soup-message.h                  |  3 ++
 tests/cache-test.c                      |  2 +
 tests/connection-test.c                 | 22 ++++++++++
 tests/misc-test.c                       | 40 +++++++++++++++++++
 tests/unix-socket-test.c                |  6 +++
 9 files changed, 174 insertions(+), 5 deletions(-)
---
diff --git a/docs/reference/libsoup-3.0-sections.txt b/docs/reference/libsoup-3.0-sections.txt
index f7cd2bb9..2a899a81 100644
--- a/docs/reference/libsoup-3.0-sections.txt
+++ b/docs/reference/libsoup-3.0-sections.txt
@@ -28,6 +28,7 @@ soup_message_get_response_headers
 <SUBSECTION>
 soup_message_is_keepalive
 soup_message_get_connection_id
+soup_message_get_remote_address
 soup_message_get_tls_peer_certificate
 soup_message_get_tls_peer_certificate_errors
 <SUBSECTION>
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index d74a6398..2f2a2a47 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -28,6 +28,7 @@ typedef struct {
        GIOStream *iostream;
        SoupSocketProperties *socket_props;
         guint64 id;
+        GSocketAddress *remote_address;
 
        GUri *proxy_uri;
        gboolean ssl;
@@ -58,6 +59,7 @@ enum {
 
         PROP_ID,
        PROP_REMOTE_CONNECTABLE,
+        PROP_REMOTE_ADDRESS,
        PROP_SOCKET_PROPERTIES,
        PROP_STATE,
        PROP_SSL,
@@ -88,6 +90,7 @@ soup_connection_finalize (GObject *object)
        g_clear_pointer (&priv->socket_props, soup_socket_properties_unref);
         g_clear_pointer (&priv->io_data, soup_client_message_io_destroy);
        g_clear_object (&priv->remote_connectable);
+        g_clear_object (&priv->remote_address);
        g_clear_object (&priv->current_msg);
 
        if (priv->cancellable) {
@@ -155,6 +158,9 @@ soup_connection_get_property (GObject *object, guint prop_id,
        case PROP_REMOTE_CONNECTABLE:
                g_value_set_object (value, priv->remote_connectable);
                break;
+        case PROP_REMOTE_ADDRESS:
+                g_value_set_object (value, priv->remote_address);
+               break;
        case PROP_SOCKET_PROPERTIES:
                g_value_set_boxed (value, priv->socket_props);
                break;
@@ -229,6 +235,14 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
                                      G_TYPE_SOCKET_CONNECTABLE,
                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                                      G_PARAM_STATIC_STRINGS));
+        g_object_class_install_property (
+                object_class, PROP_REMOTE_ADDRESS,
+                g_param_spec_object ("remote-address",
+                                     "Remote Address",
+                                     "Remote address of connection",
+                                     G_TYPE_SOCKET_ADDRESS,
+                                     G_PARAM_READABLE |
+                                     G_PARAM_STATIC_STRINGS));
        g_object_class_install_property (
                object_class, PROP_SOCKET_PROPERTIES,
                g_param_spec_boxed ("socket-properties",
@@ -488,15 +502,17 @@ soup_connection_connected (SoupConnection    *conn,
 {
         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);
 
-        addr = g_socket_get_remote_address (socket, NULL);
-        if (addr && G_IS_PROXY_ADDRESS (addr)) {
-                GProxyAddress *paddr = G_PROXY_ADDRESS (addr);
+        g_clear_object (&priv->remote_address);
+        priv->remote_address = g_socket_get_remote_address (socket, NULL);
+        g_object_notify (G_OBJECT (conn), "remote-address");
+
+        if (priv->remote_address && G_IS_PROXY_ADDRESS (priv->remote_address)) {
+                GProxyAddress *paddr = G_PROXY_ADDRESS (priv->remote_address);
 
                 if (strcmp (g_proxy_address_get_protocol (paddr), "http") == 0) {
                         GError *error = NULL;
@@ -507,7 +523,6 @@ soup_connection_connected (SoupConnection    *conn,
                         }
                 }
         }
-        g_clear_object (&addr);
 
         if (priv->ssl && !priv->proxy_uri) {
                 GTlsClientConnection *tls_connection;
@@ -1100,3 +1115,11 @@ soup_connection_get_id (SoupConnection *conn)
 
         return priv->id;
 }
+
+GSocketAddress *
+soup_connection_get_remote_address (SoupConnection *conn)
+{
+        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+
+        return priv->remote_address;
+}
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index ca4dcd5a..9c556029 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -74,6 +74,7 @@ GTlsCertificate     *soup_connection_get_tls_certificate        (SoupConnection
 GTlsCertificateFlags soup_connection_get_tls_certificate_errors (SoupConnection *conn);
 
 guint64              soup_connection_get_id                     (SoupConnection *conn);
+GSocketAddress      *soup_connection_get_remote_address         (SoupConnection *conn);
 
 G_END_DECLS
 
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index d761ce86..7bc7cf3d 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -94,6 +94,7 @@ typedef struct {
        gboolean is_top_level_navigation;
         gboolean is_options_ping;
         guint    last_connection_id;
+        GSocketAddress *remote_address;
 
         SoupMessageMetrics *metrics;
 } SoupMessagePrivate;
@@ -138,6 +139,7 @@ enum {
        PROP_RESPONSE_HEADERS,
        PROP_TLS_PEER_CERTIFICATE,
        PROP_TLS_PEER_CERTIFICATE_ERRORS,
+        PROP_REMOTE_ADDRESS,
        PROP_PRIORITY,
        PROP_SITE_FOR_COOKIES,
        PROP_IS_TOP_LEVEL_NAVIGATION,
@@ -177,6 +179,7 @@ soup_message_finalize (GObject *object)
        g_clear_pointer (&priv->disabled_features, g_hash_table_destroy);
 
        g_clear_object (&priv->tls_peer_certificate);
+        g_clear_object (&priv->remote_address);
 
        soup_message_headers_unref (priv->request_headers);
        soup_message_headers_unref (priv->response_headers);
@@ -274,6 +277,9 @@ soup_message_get_property (GObject *object, guint prop_id,
        case PROP_TLS_PEER_CERTIFICATE_ERRORS:
                g_value_set_flags (value, priv->tls_peer_certificate_errors);
                break;
+        case PROP_REMOTE_ADDRESS:
+                g_value_set_object (value, priv->remote_address);
+                break;
        case PROP_PRIORITY:
                g_value_set_enum (value, priv->priority);
                break;
@@ -738,6 +744,20 @@ soup_message_class_init (SoupMessageClass *message_class)
                                    G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
                                    G_PARAM_READABLE |
                                    G_PARAM_STATIC_STRINGS));
+        /**
+         * SoupMessage:remote-address:
+         *
+         * The remote #GSocketAddress of the connection associated with the message
+         *
+         */
+        g_object_class_install_property (
+                object_class, PROP_REMOTE_ADDRESS,
+                g_param_spec_object ("remote-address",
+                                     "Remote Address",
+                                     "The remote address of the connection associated with the message",
+                                     G_TYPE_SOCKET_ADDRESS,
+                                     G_PARAM_READABLE |
+                                     G_PARAM_STATIC_STRINGS));
        /**
         SoupMessage:priority:
         *
@@ -1307,6 +1327,20 @@ soup_message_set_tls_peer_certificate (SoupMessage         *msg,
         g_object_notify (G_OBJECT (msg), "tls-peer-certificate-errors");
 }
 
+static void
+soup_message_set_remote_address (SoupMessage    *msg,
+                                 GSocketAddress *address)
+{
+        SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
+
+        if (priv->remote_address == address)
+                return;
+
+        g_clear_object (&priv->remote_address);
+        priv->remote_address = address ? g_object_ref (address) : NULL;
+        g_object_notify (G_OBJECT (msg), "remote-address");
+}
+
 SoupConnection *
 soup_message_get_connection (SoupMessage *msg)
 {
@@ -1378,6 +1412,14 @@ re_emit_tls_certificate_changed (SoupMessage    *msg,
                                                soup_connection_get_tls_certificate_errors (conn));
 }
 
+static void
+connection_remote_address_changed (SoupMessage    *msg,
+                                   GParamSpec     *pspec,
+                                   SoupConnection *conn)
+{
+        soup_message_set_remote_address (msg, soup_connection_get_remote_address (conn));
+}
+
 void
 soup_message_set_connection (SoupMessage    *msg,
                             SoupConnection *conn)
@@ -1403,6 +1445,7 @@ soup_message_set_connection (SoupMessage    *msg,
         soup_message_set_tls_peer_certificate (msg,
                                                soup_connection_get_tls_certificate (priv->connection),
                                                soup_connection_get_tls_certificate_errors 
(priv->connection));
+        soup_message_set_remote_address (msg, soup_connection_get_remote_address (priv->connection));
 
        g_signal_connect_object (priv->connection, "event",
                                 G_CALLBACK (re_emit_connection_event),
@@ -1413,6 +1456,9 @@ soup_message_set_connection (SoupMessage    *msg,
        g_signal_connect_object (priv->connection, "notify::tls-certificate",
                                 G_CALLBACK (re_emit_tls_certificate_changed),
                                 msg, G_CONNECT_SWAPPED);
+        g_signal_connect_object (priv->connection, "notify::remote-address",
+                                 G_CALLBACK (connection_remote_address_changed),
+                                 msg, G_CONNECT_SWAPPED);
 }
 
 /**
@@ -2490,6 +2536,31 @@ soup_message_get_connection_id (SoupMessage *msg)
         return priv->last_connection_id;
 }
 
+/**
+ * soup_message_get_remote_address:
+ * @msg: The #SoupMessage
+ *
+ * Get the remote #GSocketAddress of the connection associated with the message.
+ * The returned address can be %NULL if the connection hasn't been established yet,
+ * or the resource was loaded from the disk cache.
+ * In case of proxy connections, the remote address returned is a #GProxyAddress.
+ * If #SoupSession::remote-connetable is set the returned address id for the connection
+ * ot the session's remote connectable.
+ *
+ * Returns: (transfer none) (nullable): a #GSocketAddress or %NULL if the connection
+ *     hasn't been established
+ */
+GSocketAddress *
+soup_message_get_remote_address (SoupMessage *msg)
+{
+        SoupMessagePrivate *priv;
+
+        g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
+
+        priv = soup_message_get_instance_private (msg);
+        return priv->remote_address;
+}
+
 /**
  * soup_message_get_metrics:
  * @msg: The #SoupMessage
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index 3b1f8811..93fd9af0 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -172,6 +172,9 @@ void                soup_message_set_is_options_ping  (SoupMessage  *msg,
 SOUP_AVAILABLE_IN_ALL
 guint64             soup_message_get_connection_id    (SoupMessage *msg);
 
+SOUP_AVAILABLE_IN_ALL
+GSocketAddress     *soup_message_get_remote_address   (SoupMessage *msg);
+
 SOUP_AVAILABLE_IN_ALL
 SoupMessageMetrics *soup_message_get_metrics          (SoupMessage  *msg);
 
diff --git a/tests/cache-test.c b/tests/cache-test.c
index f7b7f6fc..185def8b 100644
--- a/tests/cache-test.c
+++ b/tests/cache-test.c
@@ -783,6 +783,7 @@ do_metrics_test (gconstpointer data)
         stream = soup_test_request_send (session, msg, NULL, 0, NULL);
         g_assert_true (G_IS_INPUT_STREAM (stream));
         g_assert_false (is_network_stream (stream));
+        g_assert_null (soup_message_get_remote_address (msg));
 
         g_assert_cmpuint (soup_message_metrics_get_fetch_start (metrics), >, 0);
         g_assert_cmpuint (soup_message_metrics_get_dns_start (metrics), ==, 0);
@@ -832,6 +833,7 @@ do_metrics_test (gconstpointer data)
         stream = soup_test_request_send (session, msg, NULL, 0, NULL);
         g_assert_true (G_IS_INPUT_STREAM (stream));
         g_assert_false (is_network_stream (stream));
+        g_assert_null (soup_message_get_remote_address (msg));
         g_assert_true (last_request_validated);
 
         g_assert_cmpuint (soup_message_metrics_get_fetch_start (metrics), >, 0);
diff --git a/tests/connection-test.c b/tests/connection-test.c
index 4bb13027..cd9c71f1 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -935,6 +935,8 @@ do_one_connection_event_test (SoupSession *session,
        SoupMessage *msg;
        GBytes *body;
         SoupMessageMetrics *metrics;
+        GSocketAddress *remote_address;
+        char *ip_address;
 
        msg = soup_message_new ("GET", uri);
         if (collect_metrics) {
@@ -952,6 +954,7 @@ do_one_connection_event_test (SoupSession *session,
        g_signal_connect (msg, "network-event",
                          G_CALLBACK (network_event),
                          &events);
+        g_assert_null (soup_message_get_remote_address (msg));
        body = soup_session_send_and_read (session, msg, NULL, NULL);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        while (*events) {
@@ -979,6 +982,19 @@ do_one_connection_event_test (SoupSession *session,
                 g_assert_null (metrics);
         }
 
+        remote_address = soup_message_get_remote_address (msg);
+        g_assert_true (G_IS_INET_SOCKET_ADDRESS (remote_address));
+        ip_address = g_inet_address_to_string (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS 
(remote_address)));
+        g_assert_cmpstr (ip_address, ==, "127.0.0.1");
+        g_free (ip_address);
+        if (G_IS_PROXY_ADDRESS (remote_address)) {
+                g_assert_cmpuint (g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (remote_address)), 
==, 47526);
+                g_assert_cmpuint (g_proxy_address_get_destination_port (G_PROXY_ADDRESS (remote_address)), 
==, g_uri_get_port (soup_message_get_uri (msg)));
+                g_assert_cmpstr (g_proxy_address_get_destination_hostname (G_PROXY_ADDRESS 
(remote_address)), ==, "127.0.0.1");
+        } else {
+                g_assert_cmpuint (g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (remote_address)), 
==, g_uri_get_port (soup_message_get_uri (msg)));
+        }
+
        g_bytes_unref (body);
        g_object_unref (msg);
        soup_session_abort (session);
@@ -1052,6 +1068,12 @@ do_one_connection_event_fail_test (SoupSession *session,
                 g_assert_null (metrics);
         }
 
+        /* When failing the TLS handshake we got a remote address */
+        if (g_str_equal (uri, HTTPS_SERVER))
+                g_assert_nonnull (soup_message_get_remote_address (msg));
+        else
+                g_assert_null (soup_message_get_remote_address (msg));
+
         g_bytes_unref (body);
         g_object_unref (msg);
         soup_session_abort (session);
diff --git a/tests/misc-test.c b/tests/misc-test.c
index 7efa94bf..240a9c6a 100644
--- a/tests/misc-test.c
+++ b/tests/misc-test.c
@@ -655,6 +655,45 @@ do_connection_id_test (void)
         soup_test_session_abort_unref (session);
 }
 
+static void
+do_remote_address_test (void)
+{
+        SoupSession *session;
+        SoupMessage *msg1, *msg2;
+        GBytes *body;
+
+        session = soup_test_session_new (NULL);
+
+        msg1 = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
+        g_assert_null (soup_message_get_remote_address (msg1));
+        body = soup_test_session_async_send (session, msg1, NULL, NULL);
+        g_assert_nonnull (soup_message_get_remote_address (msg1));
+        g_bytes_unref (body);
+
+        /* In case of reusing an idle conection, we still get a remote address */
+        msg2 = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
+        g_assert_null (soup_message_get_remote_address (msg2));
+        body = soup_test_session_async_send (session, msg2, NULL, NULL);
+        g_assert_cmpuint (soup_message_get_connection_id (msg1), ==, soup_message_get_connection_id (msg2));
+        g_assert_true (soup_message_get_remote_address (msg1) == soup_message_get_remote_address (msg2));
+        g_bytes_unref (body);
+        g_object_unref (msg2);
+
+        /* We get a new one if we force a new connection */
+        msg2 = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
+        soup_message_add_flags (msg2, SOUP_MESSAGE_NEW_CONNECTION);
+        g_assert_null (soup_message_get_remote_address (msg2));
+        body = soup_test_session_async_send (session, msg2, NULL, NULL);
+        g_assert_nonnull (soup_message_get_remote_address (msg2));
+        g_assert_cmpuint (soup_message_get_connection_id (msg1), !=, soup_message_get_connection_id (msg2));
+        g_assert_false (soup_message_get_remote_address (msg1) == soup_message_get_remote_address (msg2));
+        g_bytes_unref (body);
+        g_object_unref (msg2);
+
+        g_object_unref (msg1);
+        soup_test_session_abort_unref (session);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -687,6 +726,7 @@ main (int argc, char **argv)
        g_test_add_func ("/misc/cancel-while-reading/req/preemptive", 
do_cancel_while_reading_preemptive_req_test);
        g_test_add_func ("/misc/msg-flags", do_msg_flags_test);
         g_test_add_func ("/misc/connection-id", do_connection_id_test);
+        g_test_add_func ("/misc/remote-address", do_remote_address_test);
 
        ret = g_test_run ();
 
diff --git a/tests/unix-socket-test.c b/tests/unix-socket-test.c
index 41449b6d..3979a6be 100644
--- a/tests/unix-socket-test.c
+++ b/tests/unix-socket-test.c
@@ -35,6 +35,7 @@ do_load_uri_test (void)
         GBytes *body;
         const char *content_type;
         char *json;
+        GSocketAddress *remote_address;
         GError *error = NULL;
 
         address = g_unix_socket_address_new (soup_test_server_get_unix_path (server));
@@ -46,6 +47,11 @@ do_load_uri_test (void)
         g_assert_no_error (error);
         g_assert_nonnull (body);
 
+        remote_address = soup_message_get_remote_address (msg);
+        g_assert_nonnull (remote_address);
+        g_assert_true (G_IS_UNIX_SOCKET_ADDRESS (remote_address));
+        g_assert_cmpstr (g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (remote_address)), ==, 
soup_test_server_get_unix_path (server));
+
         content_type = soup_message_headers_get_one (soup_message_get_response_headers (msg), 
"Content-Type");
         g_assert_cmpstr (content_type, ==, "application/json");
         g_object_unref (msg);


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