[libsoup] Set SoupMessage:tls-certificate from SoupSocket:tls-certificate sooner



commit 5f781fef6c2988e58c27da5bcc9ff03275e1edb1
Author: Dan Winship <danw gnome org>
Date:   Tue Dec 7 15:12:08 2010 +0100

    Set SoupMessage:tls-certificate from SoupSocket:tls-certificate sooner
    
    Use the new GTlsConnection:peer-certificate semantics to guarantee we
    set the certificate on the message as soon as it's been accepted.

 libsoup/soup-message-io.c |   46 ++++++++++++++++++++++++++------------------
 libsoup/soup-socket.c     |   39 +++++++++++++++++++++++++++++++------
 2 files changed, 59 insertions(+), 26 deletions(-)
---
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index a2d2ec5..865f208 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -68,7 +68,7 @@ typedef struct {
 	goffset               write_length;
 	goffset               written;
 
-	guint read_tag, write_tag, err_tag;
+	guint read_tag, write_tag, err_tag, tls_signal_id;
 	GSource *unpause_source;
 
 	SoupMessageGetHeadersFn   get_headers_cb;
@@ -102,6 +102,8 @@ soup_message_io_cleanup (SoupMessage *msg)
 		return;
 	priv->io_data = NULL;
 
+	if (io->tls_signal_id)
+		g_signal_handler_disconnect (io->sock, io->tls_signal_id);
 	if (io->sock)
 		g_object_unref (io->sock);
 	if (io->item)
@@ -820,24 +822,6 @@ io_read (SoupSocket *sock, SoupMessage *msg)
 		if (!read_metadata (msg, TRUE))
 			return;
 
-		if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
-		    soup_socket_is_ssl (io->sock)) {
-			GTlsCertificate *certificate;
-			GTlsCertificateFlags errors;
-
-			g_object_get (io->sock,
-				      SOUP_SOCKET_TLS_CERTIFICATE, &certificate,
-				      SOUP_SOCKET_TLS_ERRORS, &errors,
-				      NULL);
-			if (certificate) {
-				g_object_set (msg,
-					      SOUP_MESSAGE_TLS_CERTIFICATE, certificate,
-					      SOUP_MESSAGE_TLS_ERRORS, errors,
-					      NULL);
-				g_object_unref (certificate);
-			}
-		}
-
 		/* We need to "rewind" io->read_meta_buf back one line.
 		 * That SHOULD be two characters (CR LF), but if the
 		 * web server was stupid, it might only be one.
@@ -1038,6 +1022,25 @@ io_read (SoupSocket *sock, SoupMessage *msg)
 	goto read_more;
 }
 
+static void
+socket_tls_certificate_changed (GObject *sock, GParamSpec *pspec,
+				gpointer msg)
+{
+	GTlsCertificate *certificate;
+	GTlsCertificateFlags errors;
+
+	g_object_get (sock,
+		      SOUP_SOCKET_TLS_CERTIFICATE, &certificate,
+		      SOUP_SOCKET_TLS_ERRORS, &errors,
+		      NULL);
+	g_object_set (msg,
+		      SOUP_MESSAGE_TLS_CERTIFICATE, certificate,
+		      SOUP_MESSAGE_TLS_ERRORS, errors,
+		      NULL);
+	if (certificate)
+		g_object_unref (certificate);
+}
+
 static SoupMessageIOData *
 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
 	     SoupMessageGetHeadersFn get_headers_cb,
@@ -1071,6 +1074,11 @@ new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
 	io->read_state  = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
 	io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
 
+	if (soup_socket_is_ssl (io->sock)) {
+		io->tls_signal_id = g_signal_connect (io->sock, "notify::tls-certificate",
+						      G_CALLBACK (socket_tls_certificate_changed), msg);
+	}
+
 	if (priv->io_data)
 		soup_message_io_cleanup (msg);
 	priv->io_data = io;
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index 96545ea..3e7d725 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -74,6 +74,7 @@ typedef struct {
 	guint non_blocking:1;
 	guint is_server:1;
 	guint ssl_strict:1;
+	guint ssl_ca_in_creds:1;
 	guint clean_dispose:1;
 	gpointer ssl_creds;
 
@@ -94,6 +95,10 @@ static void set_property (GObject *object, guint prop_id,
 static void get_property (GObject *object, guint prop_id,
 			  GValue *value, GParamSpec *pspec);
 
+static void soup_socket_peer_certificate_changed (GObject *conn,
+						  GParamSpec *pspec,
+						  gpointer user_data);
+
 static void
 soup_socket_init (SoupSocket *sock)
 {
@@ -105,14 +110,18 @@ soup_socket_init (SoupSocket *sock)
 }
 
 static void
-disconnect_internal (SoupSocketPrivate *priv)
+disconnect_internal (SoupSocket *sock)
 {
+	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+
 	if (priv->gsock) {
 		g_socket_close (priv->gsock, NULL);
 		g_object_unref (priv->gsock);
 		priv->gsock = NULL;
 	}
 	if (priv->conn) {
+		if (G_IS_TLS_CONNECTION (priv->conn))
+			g_signal_handlers_disconnect_by_func (priv->conn, soup_socket_peer_certificate_changed, sock);
 		g_object_unref (priv->conn);
 		priv->conn = NULL;
 		priv->istream = NULL;
@@ -142,7 +151,7 @@ finalize (GObject *object)
 	if (priv->conn) {
 		if (priv->clean_dispose)
 			g_warning ("Disposing socket %p while still connected", object);
-		disconnect_internal (priv);
+		disconnect_internal (SOUP_SOCKET (object));
 	}
 
 	if (priv->local_addr)
@@ -838,21 +847,34 @@ soup_socket_listen (SoupSocket *sock)
 
  cant_listen:
 	if (priv->conn)
-		disconnect_internal (priv);
+		disconnect_internal (sock);
 
 	return FALSE;
 }
 
+static void
+soup_socket_peer_certificate_changed (GObject *conn, GParamSpec *pspec,
+				      gpointer sock)
+{
+	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+
+	priv->tls_errors = g_tls_connection_get_peer_certificate_errors (G_TLS_CONNECTION (priv->conn));
+	if (priv->ssl_ca_in_creds)
+		priv->tls_errors &= ~G_TLS_CERTIFICATE_UNKNOWN_CA;
+
+	g_object_notify (sock, "tls-certificate");
+	g_object_notify (sock, "tls-errors");
+}
+
 static gboolean
 soup_socket_accept_certificate (GTlsConnection *conn, GTlsCertificate *cert,
 				GTlsCertificateFlags errors, gpointer sock)
 {
 	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
 
-	priv->tls_errors = errors;
 	if (soup_ssl_credentials_verify_certificate (priv->ssl_creds,
 						     cert, errors)) {
-		priv->tls_errors &= ~G_TLS_CERTIFICATE_UNKNOWN_CA;
+		priv->ssl_ca_in_creds = TRUE;
 		return TRUE;
 	}
 
@@ -920,7 +942,6 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
 		g_object_unref (priv->conn);
 		priv->conn = G_IO_STREAM (conn);
 
-		priv->tls_errors = 0;
 		g_signal_connect (conn, "accept-certificate",
 				  G_CALLBACK (soup_socket_accept_certificate),
 				  sock);
@@ -941,6 +962,10 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
 		priv->conn = G_IO_STREAM (conn);
 	}
 
+	priv->ssl_ca_in_creds = FALSE;
+	g_signal_connect (priv->conn, "notify::peer-certificate",
+			  G_CALLBACK (soup_socket_peer_certificate_changed), sock);
+
 	priv->istream = G_POLLABLE_INPUT_STREAM (g_io_stream_get_input_stream (priv->conn));
 	priv->ostream = G_POLLABLE_OUTPUT_STREAM (g_io_stream_get_output_stream (priv->conn));
 	return TRUE;
@@ -985,7 +1010,7 @@ soup_socket_disconnect (SoupSocket *sock)
 		return;
 	} else if (g_mutex_trylock (priv->iolock)) {
 		if (priv->conn)
-			disconnect_internal (priv);
+			disconnect_internal (sock);
 		else
 			already_disconnected = TRUE;
 		g_mutex_unlock (priv->iolock);



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