diff options
author | Dan Winship <danw@gnome.org> | 2010-12-07 15:12:08 +0100 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2010-12-07 15:12:08 +0100 |
commit | 5f781fef6c2988e58c27da5bcc9ff03275e1edb1 (patch) | |
tree | deb954938222067a90fd2a6ca18d1545a88d01da | |
parent | 12238c7d3afd751b98fe3204092c254310bf1e69 (diff) | |
download | libsoup-5f781fef6c2988e58c27da5bcc9ff03275e1edb1.tar.gz |
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.
-rw-r--r-- | libsoup/soup-message-io.c | 46 | ||||
-rw-r--r-- | 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 a2d2ec57..865f208f 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 96545ea4..3e7d7259 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); |