[libsoup/carlosgc/msg-remote-address: 3/3] message: add API to get the remote address of a SoupMessage
- From: Carlos Garcia Campos <carlosgc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/carlosgc/msg-remote-address: 3/3] message: add API to get the remote address of a SoupMessage
- Date: Fri, 30 Apr 2021 15:18:46 +0000 (UTC)
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]