diff options
author | Dan Winship <danw@gnome.org> | 2013-07-04 11:35:29 -0400 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2013-10-19 20:33:38 -0400 |
commit | 88103312ffac176b8ffeb159bd75fc3bbe2c452e (patch) | |
tree | a9702a746bd4d7b67d6cc743492c51c0ebd9cb5f | |
parent | caa68752e295d48a3d1d9c6e5334f6c17a576000 (diff) | |
download | libsoup-88103312ffac176b8ffeb159bd75fc3bbe2c452e.tar.gz |
SoupSocket: make handshaking methods gio-like
and update SoupConnection to use them
-rw-r--r-- | libsoup/soup-connection.c | 150 | ||||
-rw-r--r-- | libsoup/soup-misc-private.h | 18 | ||||
-rw-r--r-- | libsoup/soup-socket.c | 155 |
3 files changed, 170 insertions, 153 deletions
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c index 00fe72b9..f8b6cef7 100644 --- a/libsoup/soup-connection.c +++ b/libsoup/soup-connection.c @@ -451,12 +451,12 @@ typedef struct { } SoupConnectionAsyncConnectData; static void -socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data) +socket_connect_finished (SoupConnectionAsyncConnectData *data, guint status) { - SoupConnectionAsyncConnectData *data = user_data; SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn); - g_signal_handler_disconnect (socket, data->event_id); + if (priv->socket) + g_signal_handler_disconnect (priv->socket, data->event_id); if (SOUP_STATUS_IS_SUCCESSFUL (status)) { if (priv->ssl && !priv->proxy_uri) { @@ -473,9 +473,6 @@ socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data) soup_connection_set_state (data->conn, SOUP_CONNECTION_IN_USE); priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT; start_idle_timer (data->conn); - } else if (status == SOUP_STATUS_TLS_FAILED) { - priv->ssl_fallback = TRUE; - status = SOUP_STATUS_TRY_AGAIN; } if (data->callback) { @@ -489,6 +486,31 @@ socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data) g_slice_free (SoupConnectionAsyncConnectData, data); } + +static void +socket_handshake_complete (GObject *object, GAsyncResult *result, gpointer user_data) +{ + SoupConnectionAsyncConnectData *data = user_data; + SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn); + GError *error = NULL; + guint status; + + if (priv->async_context && !priv->use_thread_context) + g_main_context_pop_thread_default (priv->async_context); + + if (soup_socket_handshake_finish (priv->socket, result, &error)) + status = SOUP_STATUS_OK; + else if (!priv->ssl_fallback && + g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) { + priv->ssl_fallback = TRUE; + status = SOUP_STATUS_TRY_AGAIN; + } else + status = SOUP_STATUS_SSL_FAILED; + g_clear_error (&error); + + socket_connect_finished (data, status); +} + static void socket_connect_result (SoupSocket *sock, guint status, gpointer user_data) { @@ -496,26 +518,26 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data) SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn); if (!SOUP_STATUS_IS_SUCCESSFUL (status)) { - socket_connect_finished (sock, status, data); + socket_connect_finished (data, status); return; } priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket); if (priv->ssl && !priv->proxy_uri) { - if (soup_socket_start_ssl (sock, data->cancellable)) { - soup_connection_event (data->conn, - G_SOCKET_CLIENT_TLS_HANDSHAKING, - NULL); - soup_socket_handshake_async (sock, data->cancellable, - socket_connect_finished, data); - return; - } - - status = SOUP_STATUS_SSL_FAILED; + soup_connection_event (data->conn, + G_SOCKET_CLIENT_TLS_HANDSHAKING, + NULL); + + if (priv->async_context && !priv->use_thread_context) + g_main_context_push_thread_default (priv->async_context); + soup_socket_handshake_async (sock, priv->remote_uri->host, + data->cancellable, + socket_handshake_complete, data); + return; } - socket_connect_finished (sock, status, data); + socket_connect_finished (data, status); } void @@ -601,22 +623,25 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable) priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket); if (priv->ssl && !priv->proxy_uri) { - if (!soup_socket_start_ssl (priv->socket, cancellable)) - status = SOUP_STATUS_SSL_FAILED; - else { + GError *error = NULL; + + soup_connection_event (conn, + G_SOCKET_CLIENT_TLS_HANDSHAKING, + NULL); + if (soup_socket_handshake_sync (priv->socket, + priv->remote_uri->host, + cancellable, &error)) { soup_connection_event (conn, - G_SOCKET_CLIENT_TLS_HANDSHAKING, + G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL); - status = soup_socket_handshake_sync (priv->socket, cancellable); - if (status == SOUP_STATUS_OK) { - soup_connection_event (conn, - G_SOCKET_CLIENT_TLS_HANDSHAKED, - NULL); - } else if (status == SOUP_STATUS_TLS_FAILED) { - priv->ssl_fallback = TRUE; - status = SOUP_STATUS_TRY_AGAIN; - } - } + status = SOUP_STATUS_OK; + } else if (!priv->ssl_fallback && + g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) { + priv->ssl_fallback = TRUE; + status = SOUP_STATUS_TRY_AGAIN; + } else + status = SOUP_STATUS_SSL_FAILED; + g_clear_error (&error); } if (SOUP_STATUS_IS_SUCCESSFUL (status)) { @@ -656,21 +681,19 @@ soup_connection_start_ssl_sync (SoupConnection *conn, { SoupConnectionPrivate *priv; guint status; + GError *error = NULL; g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE); priv = SOUP_CONNECTION_GET_PRIVATE (conn); - if (!soup_socket_start_proxy_ssl (priv->socket, - priv->remote_uri->host, - cancellable)) - return SOUP_STATUS_SSL_FAILED; - soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL); - status = soup_socket_handshake_sync (priv->socket, cancellable); - if (status == SOUP_STATUS_OK) { + if (soup_socket_handshake_sync (priv->socket, priv->remote_uri->host, + cancellable, &error)) { soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL); soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL); - } else if (status == SOUP_STATUS_TLS_FAILED) { + status = SOUP_STATUS_OK; + } else if (!priv->ssl_fallback && + g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) { priv->ssl_fallback = TRUE; status = SOUP_STATUS_TRY_AGAIN; } @@ -679,33 +702,33 @@ soup_connection_start_ssl_sync (SoupConnection *conn, } static void -start_ssl_completed (SoupSocket *socket, guint status, gpointer user_data) +start_ssl_completed (GObject *object, GAsyncResult *result, gpointer user_data) { SoupConnectionAsyncConnectData *data = user_data; SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn); + guint status; + GError *error = NULL; - if (status == SOUP_STATUS_OK) { + if (priv->async_context && !priv->use_thread_context) + g_main_context_pop_thread_default (priv->async_context); + + if (soup_socket_handshake_finish (priv->socket, result, &error)) { soup_connection_event (data->conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL); soup_connection_event (data->conn, G_SOCKET_CLIENT_COMPLETE, NULL); - } else if (status == SOUP_STATUS_TLS_FAILED) { + status = SOUP_STATUS_OK; + } else if (!priv->ssl_fallback && + g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) { priv->ssl_fallback = TRUE; status = SOUP_STATUS_TRY_AGAIN; - } + } else + status = SOUP_STATUS_SSL_FAILED; + g_clear_error (&error); data->callback (data->conn, status, data->callback_data); g_object_unref (data->conn); g_slice_free (SoupConnectionAsyncConnectData, data); } -static gboolean -idle_start_ssl_completed (gpointer user_data) -{ - SoupConnectionAsyncConnectData *data = user_data; - - start_ssl_completed (NULL, SOUP_STATUS_SSL_FAILED, data); - return FALSE; -} - void soup_connection_start_ssl_async (SoupConnection *conn, GCancellable *cancellable, @@ -714,7 +737,6 @@ soup_connection_start_ssl_async (SoupConnection *conn, { SoupConnectionPrivate *priv; SoupConnectionAsyncConnectData *data; - GMainContext *async_context; g_return_if_fail (SOUP_IS_CONNECTION (conn)); priv = SOUP_CONNECTION_GET_PRIVATE (conn); @@ -724,22 +746,12 @@ soup_connection_start_ssl_async (SoupConnection *conn, data->callback = callback; data->callback_data = user_data; - if (priv->use_thread_context) - async_context = g_main_context_get_thread_default (); - else - async_context = priv->async_context; - - if (!soup_socket_start_proxy_ssl (priv->socket, - priv->remote_uri->host, - cancellable)) { - soup_add_completion (async_context, - idle_start_ssl_completed, data); - return; - } - soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL); - soup_socket_handshake_async (priv->socket, cancellable, - start_ssl_completed, data); + + if (priv->async_context && !priv->use_thread_context) + g_main_context_push_thread_default (priv->async_context); + soup_socket_handshake_async (priv->socket, priv->remote_uri->host, + cancellable, start_ssl_completed, data); } /** diff --git a/libsoup/soup-misc-private.h b/libsoup/soup-misc-private.h index 7ea2cdea..948470ff 100644 --- a/libsoup/soup-misc-private.h +++ b/libsoup/soup-misc-private.h @@ -16,12 +16,18 @@ char *soup_uri_to_string_internal (SoupURI *uri, gboolean just_path_and_query, gboolean soup_uri_is_http (SoupURI *uri, char **aliases); gboolean soup_uri_is_https (SoupURI *uri, char **aliases); -guint soup_socket_handshake_sync (SoupSocket *sock, - GCancellable *cancellable); -void soup_socket_handshake_async (SoupSocket *sock, - GCancellable *cancellable, - SoupSocketCallback callback, - gpointer user_data); +gboolean soup_socket_handshake_sync (SoupSocket *sock, + const char *host, + GCancellable *cancellable, + GError **error); +void soup_socket_handshake_async (SoupSocket *sock, + const char *host, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean soup_socket_handshake_finish (SoupSocket *sock, + GAsyncResult *result, + GError **error); GSocket *soup_socket_get_gsocket (SoupSocket *sock); GIOStream *soup_socket_get_connection (SoupSocket *sock); diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c index baa9290c..9caf0d2c 100644 --- a/libsoup/soup-socket.c +++ b/libsoup/soup-socket.c @@ -1035,37 +1035,11 @@ soup_socket_accept_certificate (GTlsConnection *conn, GTlsCertificate *cert, return TRUE; } -/** - * soup_socket_start_ssl: - * @sock: the socket - * @cancellable: a #GCancellable - * - * Starts using SSL on @socket. - * - * Return value: success or failure - **/ -gboolean -soup_socket_start_ssl (SoupSocket *sock, GCancellable *cancellable) -{ - SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); - - return soup_socket_start_proxy_ssl (sock, soup_address_get_name (priv->remote_addr), cancellable); -} - -/** - * soup_socket_start_proxy_ssl: - * @sock: the socket - * @ssl_host: hostname of the SSL server - * @cancellable: a #GCancellable - * - * Starts using SSL on @socket, expecting to find a host named - * @ssl_host. - * - * Return value: success or failure - **/ -gboolean -soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host, - GCancellable *cancellable) +static gboolean +soup_socket_setup_ssl (SoupSocket *sock, + const char *ssl_host, + GCancellable *cancellable, + GError **error) { SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); GTlsBackend *backend = g_tls_backend_get_default (); @@ -1073,7 +1047,7 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host, if (G_IS_TLS_CONNECTION (priv->conn)) return TRUE; - if (g_cancellable_is_cancelled (cancellable)) + if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; priv->ssl = TRUE; @@ -1084,7 +1058,7 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host, identity = g_network_address_new (ssl_host, 0); conn = g_initable_new (g_tls_backend_get_client_connection_type (backend), - NULL, NULL, + cancellable, error, "base-io-stream", priv->conn, "server-identity", identity, "database", priv->ssl_creds, @@ -1108,7 +1082,7 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host, GTlsServerConnection *conn; conn = g_initable_new (g_tls_backend_get_server_connection_type (backend), - NULL, NULL, + cancellable, error, "base-io-stream", priv->conn, "certificate", priv->ssl_creds, "use-system-certdb", FALSE, @@ -1133,76 +1107,101 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host, return TRUE; } + +/** + * soup_socket_start_ssl: + * @sock: the socket + * @cancellable: a #GCancellable + * + * Starts using SSL on @socket. + * + * Return value: success or failure + **/ +gboolean +soup_socket_start_ssl (SoupSocket *sock, GCancellable *cancellable) +{ + SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); + + return soup_socket_setup_ssl (sock, soup_address_get_name (priv->remote_addr), + cancellable, NULL); +} -guint +/** + * soup_socket_start_proxy_ssl: + * @sock: the socket + * @ssl_host: hostname of the SSL server + * @cancellable: a #GCancellable + * + * Starts using SSL on @socket, expecting to find a host named + * @ssl_host. + * + * Return value: success or failure + **/ +gboolean +soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host, + GCancellable *cancellable) +{ + return soup_socket_setup_ssl (sock, ssl_host, cancellable, NULL); +} + +gboolean soup_socket_handshake_sync (SoupSocket *sock, - GCancellable *cancellable) + const char *ssl_host, + GCancellable *cancellable, + GError **error) { SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); - GError *error = NULL; - priv->ssl = TRUE; - if (g_tls_connection_handshake (G_TLS_CONNECTION (priv->conn), - cancellable, &error)) - return SOUP_STATUS_OK; - else if (!priv->ssl_fallback && - g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) { - g_error_free (error); - return SOUP_STATUS_TLS_FAILED; - } else { - g_error_free (error); - return SOUP_STATUS_SSL_FAILED; - } + if (!soup_socket_setup_ssl (sock, ssl_host, cancellable, error)) + return FALSE; + + return g_tls_connection_handshake (G_TLS_CONNECTION (priv->conn), + cancellable, error); } static void handshake_async_ready (GObject *source, GAsyncResult *result, gpointer user_data) { - SoupSocketAsyncConnectData *data = user_data; - SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (data->sock); + GTask *task = user_data; GError *error = NULL; - guint status; - - if (priv->async_context && !priv->use_thread_context) - g_main_context_pop_thread_default (priv->async_context); if (g_tls_connection_handshake_finish (G_TLS_CONNECTION (source), result, &error)) - status = SOUP_STATUS_OK; - else if (!priv->ssl_fallback && - g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) - status = SOUP_STATUS_TLS_FAILED; + g_task_return_boolean (task, TRUE); else - status = SOUP_STATUS_SSL_FAILED; - g_clear_error (&error); - - data->callback (data->sock, status, data->user_data); - g_object_unref (data->sock); - g_slice_free (SoupSocketAsyncConnectData, data); + g_task_return_error (task, error); } void -soup_socket_handshake_async (SoupSocket *sock, - GCancellable *cancellable, - SoupSocketCallback callback, - gpointer user_data) +soup_socket_handshake_async (SoupSocket *sock, + const char *ssl_host, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); - SoupSocketAsyncConnectData *data; + GTask *task; + GError *error = NULL; - priv->ssl = TRUE; + task = g_task_new (sock, cancellable, callback, user_data); - data = g_slice_new (SoupSocketAsyncConnectData); - data->sock = g_object_ref (sock); - data->callback = callback; - data->user_data = user_data; + if (!soup_socket_setup_ssl (sock, ssl_host, cancellable, &error)) { + g_task_return_error (task, error); + return; + } - if (priv->async_context && !priv->use_thread_context) - g_main_context_push_thread_default (priv->async_context); g_tls_connection_handshake_async (G_TLS_CONNECTION (priv->conn), G_PRIORITY_DEFAULT, cancellable, handshake_async_ready, - data); + task); +} + +gboolean +soup_socket_handshake_finish (SoupSocket *sock, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (result), error); } /** |