[libsoup/wip/proxy-connect: 9/9] soup-session: add soup_session_proxy_connect* functions
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/wip/proxy-connect: 9/9] soup-session: add soup_session_proxy_connect* functions
- Date: Sat, 7 Jun 2014 16:04:05 +0000 (UTC)
commit 3fb733a9938e1dd843316db4ed23d5c96800f662
Author: Dan Winship <danw gnome org>
Date: Sat Mar 15 09:12:31 2014 -0400
soup-session: add soup_session_proxy_connect* functions
Add functions to connect to a remote host, possibly via an HTTP proxy.
Based on a patch from Dirkjan Ochtman.
https://bugzilla.gnome.org/show_bug.cgi?id=721343
libsoup/libsoup-2.4.sym | 3 +
libsoup/soup-connection.c | 11 ++
libsoup/soup-connection.h | 1 +
libsoup/soup-message-queue.h | 3 +-
libsoup/soup-session.c | 244 ++++++++++++++++++++++++++++++++++++------
libsoup/soup-session.h | 18 +++
6 files changed, 244 insertions(+), 36 deletions(-)
---
diff --git a/libsoup/libsoup-2.4.sym b/libsoup/libsoup-2.4.sym
index d1b8388..b53b5c0 100644
--- a/libsoup/libsoup-2.4.sym
+++ b/libsoup/libsoup-2.4.sym
@@ -374,6 +374,9 @@ soup_session_async_get_type
soup_session_async_new
soup_session_async_new_with_options
soup_session_cancel_message
+soup_session_proxy_connect
+soup_session_proxy_connect_async
+soup_session_proxy_connect_finish
soup_session_feature_add_feature
soup_session_feature_attach
soup_session_feature_detach
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 48df8e3..fcdc1cf 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -526,6 +526,17 @@ soup_connection_is_tunnelled (SoupConnection *conn)
}
gboolean
+soup_connection_is_ssl (SoupConnection *conn)
+{
+ SoupConnectionPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
+ priv = SOUP_CONNECTION_GET_PRIVATE (conn);
+
+ return priv->ssl;
+}
+
+gboolean
soup_connection_start_ssl_sync (SoupConnection *conn,
GCancellable *cancellable,
GError **error)
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 8df6112..bc4dcfa 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -68,6 +68,7 @@ SoupURI *soup_connection_get_remote_uri (SoupConnection *conn);
SoupURI *soup_connection_get_proxy_uri (SoupConnection *conn);
gboolean soup_connection_is_via_proxy (SoupConnection *conn);
gboolean soup_connection_is_tunnelled (SoupConnection *conn);
+gboolean soup_connection_is_ssl (SoupConnection *conn);
SoupConnectionState soup_connection_get_state (SoupConnection *conn);
void soup_connection_set_state (SoupConnection *conn,
diff --git a/libsoup/soup-message-queue.h b/libsoup/soup-message-queue.h
index d2dfda4..a9bfa07 100644
--- a/libsoup/soup-message-queue.h
+++ b/libsoup/soup-message-queue.h
@@ -49,7 +49,8 @@ struct _SoupMessageQueueItem {
guint io_started : 1;
guint async : 1;
guint priority : 3;
- guint resend_count : 25;
+ guint proxy_connect : 1;
+ guint resend_count : 24;
SoupMessageQueueItemState state;
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 04d311e..45b7da6 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -9,6 +9,7 @@
#include <config.h>
#endif
+#include <stdlib.h>
#include <glib/gi18n-lib.h>
#include "soup-session.h"
@@ -1637,7 +1638,11 @@ tunnel_complete (SoupMessageQueueItem *tunnel_item,
soup_session_set_item_status (session, item, status, error);
}
- item->state = SOUP_MESSAGE_READY;
+ if (item->proxy_connect)
+ item->state = SOUP_MESSAGE_FINISHING;
+ else
+ item->state = SOUP_MESSAGE_READY;
+
if (item->async)
soup_session_kick_queue (session);
soup_message_queue_item_unref (item);
@@ -1685,6 +1690,11 @@ tunnel_message_completed (SoupMessage *msg, gboolean io_complete, gpointer user_
return;
}
+ if (!soup_connection_is_ssl (item->conn)) {
+ tunnel_complete (tunnel_item, status, NULL);
+ return;
+ }
+
if (tunnel_item->async) {
soup_connection_start_ssl_async (item->conn, item->cancellable,
tunnel_handshake_complete,
@@ -1773,6 +1783,49 @@ connect_async_complete (GObject *object,
/* requires conn_lock */
static SoupConnection *
+new_connection_for_host (SoupSession *session,
+ SoupSessionHost *host)
+{
+ SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
+ SoupConnection *conn;
+
+ ensure_socket_props (session);
+ conn = g_object_new (SOUP_TYPE_CONNECTION,
+ SOUP_CONNECTION_REMOTE_URI, host->uri,
+ SOUP_CONNECTION_SSL_FALLBACK, host->ssl_fallback,
+ SOUP_CONNECTION_SOCKET_PROPERTIES, priv->socket_props,
+ NULL);
+
+ g_signal_connect (conn, "disconnected",
+ G_CALLBACK (connection_disconnected),
+ session);
+ g_signal_connect (conn, "notify::state",
+ G_CALLBACK (connection_state_changed),
+ session);
+
+ /* This is a debugging-related signal, and so can ignore the
+ * usual rule about not emitting signals while holding
+ * conn_lock.
+ */
+ g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
+
+ g_hash_table_insert (priv->conns, conn, host);
+
+ priv->num_conns++;
+ host->num_conns++;
+ host->connections = g_slist_prepend (host->connections, conn);
+
+ if (host->keep_alive_src) {
+ g_source_destroy (host->keep_alive_src);
+ g_source_unref (host->keep_alive_src);
+ host->keep_alive_src = NULL;
+ }
+
+ return conn;
+}
+
+/* requires conn_lock */
+static SoupConnection *
get_connection_for_host (SoupSession *session,
SoupMessageQueueItem *item,
SoupSessionHost *host,
@@ -1819,39 +1872,7 @@ get_connection_for_host (SoupSession *session,
return NULL;
}
- ensure_socket_props (session);
- conn = g_object_new (SOUP_TYPE_CONNECTION,
- SOUP_CONNECTION_REMOTE_URI, host->uri,
- SOUP_CONNECTION_SSL_FALLBACK, host->ssl_fallback,
- SOUP_CONNECTION_SOCKET_PROPERTIES, priv->socket_props,
- NULL);
-
- g_signal_connect (conn, "disconnected",
- G_CALLBACK (connection_disconnected),
- session);
- g_signal_connect (conn, "notify::state",
- G_CALLBACK (connection_state_changed),
- session);
-
- /* This is a debugging-related signal, and so can ignore the
- * usual rule about not emitting signals while holding
- * conn_lock.
- */
- g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
-
- g_hash_table_insert (priv->conns, conn, host);
-
- priv->num_conns++;
- host->num_conns++;
- host->connections = g_slist_prepend (host->connections, conn);
-
- if (host->keep_alive_src) {
- g_source_destroy (host->keep_alive_src);
- g_source_unref (host->keep_alive_src);
- host->keep_alive_src = NULL;
- }
-
- return conn;
+ return new_connection_for_host (session, host);
}
static gboolean
@@ -1943,7 +1964,13 @@ soup_session_process_queue_item (SoupSession *session,
break;
case SOUP_MESSAGE_CONNECTED:
- if (soup_connection_is_tunnelled (item->conn))
+ if (item->proxy_connect) {
+ if (soup_connection_is_via_proxy (item->conn))
+ tunnel_connect (item);
+ else
+ item->state = SOUP_MESSAGE_FINISHING;
+ break;
+ } else if (soup_connection_is_tunnelled (item->conn))
tunnel_connect (item);
else
item->state = SOUP_MESSAGE_READY;
@@ -4628,3 +4655,150 @@ soup_request_error_quark (void)
error = g_quark_from_static_string ("soup_request_error_quark");
return error;
}
+
+/**
+ * soup_session_proxy_connect:
+ * @session: a #SoupSession
+ * @host: the host to connect to
+ * @port: the port on @hostname to connect to
+ * @cancellable: a #GCancellable
+ * @error: return location for a #GError, or %NULL
+ *
+ * Opens a connection to @host and @port. If @session is not
+ * configured to use an HTTP proxy for @host, then this is more or
+ * less equivalent to g_socket_client_connect_to_host().
+ *
+ * However, if an HTTP proxy is required to connect to @host, then
+ * this will connect to that proxy and then send a CONNECT request to
+ * create a tunnel to @host.
+ *
+ * Return value: a #GIOStream to the destination, or %NULL on error.
+ *
+ * Since: 2.48
+ */
+GIOStream *
+soup_session_proxy_connect (SoupSession *session,
+ const char *host,
+ guint port,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return NULL;
+}
+
+static void
+proxy_connect_async_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
+ SoupMessageQueueItem *item = user_data;
+ SoupSocket *sock;
+ SoupSessionHost *host;
+ GIOStream *iostream;
+ GError *error;
+ SoupConnection *conn;
+
+ conn = item->conn;
+ item->conn = NULL;
+ error = (!conn && item->error) ? g_error_copy (item->error) : NULL;
+ soup_session_set_item_connection (session, item, NULL);
+
+ if (!conn) {
+ g_task_return_error (item->task, error);
+ return;
+ }
+
+ g_mutex_lock (&priv->conn_lock);
+ host = get_host_for_message (session, item->msg);
+ g_hash_table_remove (priv->conns, conn);
+ drop_connection (session, host, conn);
+ g_mutex_unlock (&priv->conn_lock);
+
+ sock = soup_connection_get_socket (conn);
+ g_object_set (G_OBJECT (sock),
+ SOUP_SOCKET_CLOSE_ON_DISPOSE, FALSE,
+ NULL);
+ iostream = soup_socket_get_connection (sock);
+ g_object_ref (iostream);
+ g_object_unref (conn);
+
+ g_task_return_pointer (item->task, iostream, g_object_unref);
+}
+
+/**
+ * soup_session_proxy_connect_async:
+ * @session: a #SoupSession
+ * @host: the host to connect to
+ * @port: the port on @hostname to connect to
+ * @cancellable: a #GCancellable
+ * @callback: a callback to call when the connection is established
+ * @user_data: data for @callback
+ *
+ * Asynchronously begins connecting to @host and @port. If @session is
+ * not configured to use an HTTP proxy for @host, then this is more or
+ * less equivalent to g_socket_client_connect_to_host_async().
+ *
+ * However, if an HTTP proxy is required to connect to @host, then
+ * this will connect to that proxy and then send a CONNECT request to
+ * create a tunnel to @host.
+ *
+ * Since: 2.48
+ */
+void
+soup_session_proxy_connect_async (SoupSession *session,
+ const char *host,
+ guint port,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SoupSessionPrivate *priv;
+ SoupMessage *msg;
+ SoupMessageQueueItem *item;
+ char *uri;
+
+ g_return_if_fail (SOUP_IS_SESSION (session));
+ g_return_if_fail (!SOUP_IS_SESSION_SYNC (session));
+
+ priv = SOUP_SESSION_GET_PRIVATE (session);
+ g_return_if_fail (priv->use_thread_context == TRUE);
+
+ uri = g_strdup_printf ("http://%s:%u", host, port);
+ msg = soup_message_new (SOUP_METHOD_HEAD, uri);
+ g_free (uri);
+ item = soup_session_append_queue_item (session, msg, TRUE, TRUE,
+ NULL, NULL);
+ item->callback = proxy_connect_async_cb;
+ item->callback_data = item;
+ soup_message_queue_item_ref (item);
+
+ item->new_api = TRUE;
+ item->proxy_connect = TRUE;
+ item->task = g_task_new (session, NULL, callback, user_data);
+ g_task_set_task_data (item->task, item, (GDestroyNotify) soup_message_queue_item_unref);
+ soup_session_kick_queue (session);
+}
+
+/**
+ * soup_session_proxy_connect_finish:
+ * @session: a #SoupSession
+ * @result: the #GAsyncResult from the connect operation
+ * @error: return location for a #GError, or %NULL
+ *
+ * Retrieves the result of a soup_session_proxy_connect_async()
+ * operation.
+ *
+ * Return value: a #GIOStream to the destination, or %NULL on error.
+ *
+ * Since: 2.48
+ */
+GIOStream *
+soup_session_proxy_connect_finish (SoupSession *session,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, session), NULL);
+
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index eed392d..402e784 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -206,6 +206,24 @@ typedef enum {
SOUP_REQUEST_ERROR_ENCODING
} SoupRequestError;
+SOUP_AVAILABLE_IN_2_48
+GIOStream *soup_session_proxy_connect (SoupSession *session,
+ const char *host,
+ guint port,
+ GCancellable *cancellable,
+ GError **error);
+SOUP_AVAILABLE_IN_2_48
+void soup_session_proxy_connect_async (SoupSession *session,
+ const char *host,
+ guint port,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+SOUP_AVAILABLE_IN_2_48
+GIOStream *soup_session_proxy_connect_finish (SoupSession *session,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#endif /* SOUP_SESSION_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]