summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2010-12-07 15:12:08 +0100
committerDan Winship <danw@gnome.org>2010-12-07 15:12:08 +0100
commit5f781fef6c2988e58c27da5bcc9ff03275e1edb1 (patch)
treedeb954938222067a90fd2a6ca18d1545a88d01da
parent12238c7d3afd751b98fe3204092c254310bf1e69 (diff)
downloadlibsoup-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.c46
-rw-r--r--libsoup/soup-socket.c39
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);