Only set up a tunnel if the destination protocol is HTTPS.
authorJoe Shaw <joe@ximian.com>
Tue, 16 Dec 2003 17:33:00 +0000 (17:33 +0000)
committerJoe Shaw <joeshaw@src.gnome.org>
Tue, 16 Dec 2003 17:33:00 +0000 (17:33 +0000)
2003-12-16  Joe Shaw  <joe@ximian.com>

* libsoup/soup-connection.c (socket_connect_result,
soup_connection_connect_sync): Only set up a tunnel if the
destination protocol is HTTPS.

* libsoup/soup-message.c (class_init): Add a default handler for
wrote_body.
(wrote_body): Run the SOUP_HANDLER_POST_REQUEST handlers here.
(soup_message_cancel): Don't set the status to
SOUP_STATUS_CANCELLED and call soup_message_finished() if the
status is already SOUP_MESSAGE_STATUS_FINISHED.

* libsoup/soup-session.c (set_property): Don't cancel the session
if the proxy URI set as a property isn't different from the old
one.
(get_host_for_message): Refactor some code so that we can easily
get the right SoupSessionHost for proxies as well as from the
message.
(authenticate_auth): Take a gboolean proxy parameter.  Check it to
see which URI (message URI or proxy URI) to use for
authentication.  Add a long comment about lack of clarity in RFC
2617 with respect to proxies and protection spaces.

ChangeLog
libsoup/soup-connection.c
libsoup/soup-message.c
libsoup/soup-message.h
libsoup/soup-session.c

index 9b5a56e..6b6979e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2003-12-16  Joe Shaw  <joe@ximian.com>
+
+       * libsoup/soup-connection.c (socket_connect_result,
+       soup_connection_connect_sync): Only set up a tunnel if the
+       destination protocol is HTTPS.
+
+       * libsoup/soup-message.c (class_init): Add a default handler for
+       wrote_body.
+       (wrote_body): Run the SOUP_HANDLER_POST_REQUEST handlers here.
+       (soup_message_cancel): Don't set the status to
+       SOUP_STATUS_CANCELLED and call soup_message_finished() if the
+       status is already SOUP_MESSAGE_STATUS_FINISHED.
+
+       * libsoup/soup-session.c (set_property): Don't cancel the session
+       if the proxy URI set as a property isn't different from the old
+       one.
+       (get_host_for_message): Refactor some code so that we can easily
+       get the right SoupSessionHost for proxies as well as from the
+       message.
+       (authenticate_auth): Take a gboolean proxy parameter.  Check it to
+       see which URI (message URI or proxy URI) to use for
+       authentication.  Add a long comment about lack of clarity in RFC
+       2617 with respect to proxies and protection spaces.
+
 2003-12-15  Dan Winship  <danw@ximian.com>
 
        * libsoup/soup-socket.h (soup_socket_read, soup_socket_read_until,
index 6352580..c37f813 100644 (file)
@@ -335,11 +335,14 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
        }
 
        /* See if we need to tunnel */
-       if (conn->priv->proxy_uri && conn->priv->origin_uri) {
+       if (conn->priv->proxy_uri &&
+           conn->priv->origin_uri &&
+           conn->priv->origin_uri->protocol == SOUP_PROTOCOL_HTTPS) {
                SoupMessage *connect_msg;
 
                connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
                                                         conn->priv->origin_uri);
+
                g_signal_connect (connect_msg, "finished",
                                  G_CALLBACK (tunnel_connect_finished), conn);
 
@@ -414,7 +417,10 @@ soup_connection_connect_sync (SoupConnection *conn)
                }
        }
 
-       if (conn->priv->proxy_uri && conn->priv->origin_uri) {
+       /* See if we need to tunnel */
+       if (conn->priv->proxy_uri &&
+           conn->priv->origin_uri &&
+           conn->priv->origin_uri->protocol == SOUP_PROTOCOL_HTTPS) {
                SoupMessage *connect_msg;
 
                connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
index 5bdf885..fe6edf8 100644 (file)
@@ -36,6 +36,7 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
+static void wrote_body (SoupMessage *req);
 static void got_headers (SoupMessage *req);
 static void got_chunk (SoupMessage *req);
 static void got_body (SoupMessage *req);
@@ -100,6 +101,7 @@ class_init (GObjectClass *object_class)
        parent_class = g_type_class_ref (PARENT_TYPE);
 
        /* virtual method definition */
+       message_class->wrote_body   = wrote_body;
        message_class->got_headers  = got_headers;
        message_class->got_chunk    = got_chunk;
        message_class->got_body     = got_body;
@@ -319,6 +321,14 @@ soup_message_wrote_chunk (SoupMessage *msg)
        g_signal_emit (msg, signals[WROTE_CHUNK], 0);
 }
 
+static void
+wrote_body (SoupMessage *req)
+{
+       g_object_ref (req);
+       soup_message_run_handlers (req, SOUP_HANDLER_POST_REQUEST);
+       g_object_unref (req);
+}
+
 void
 soup_message_wrote_body (SoupMessage *msg)
 {
@@ -397,7 +407,6 @@ soup_message_finished (SoupMessage *msg)
        g_signal_emit (msg, signals[FINISHED], 0);
 }
 
-
 /**
  * soup_message_cancel:
  * @msg: a #SoupMessage currently being processed.
@@ -409,8 +418,10 @@ soup_message_finished (SoupMessage *msg)
 void
 soup_message_cancel (SoupMessage *msg)
 {
-       soup_message_set_status (msg, SOUP_STATUS_CANCELLED);
-       soup_message_finished (msg);
+       if (msg->status != SOUP_MESSAGE_STATUS_FINISHED) {
+               soup_message_set_status (msg, SOUP_STATUS_CANCELLED);
+               soup_message_finished (msg);
+       }
 }
 
 static gboolean
@@ -577,7 +588,7 @@ soup_message_get_flags (SoupMessage *msg)
 }
 
 void
-soup_message_set_http_version  (SoupMessage *msg, SoupHttpVersion version)
+soup_message_set_http_version (SoupMessage *msg, SoupHttpVersion version)
 {
        g_return_if_fail (SOUP_IS_MESSAGE (msg));
 
index d030a47..89a1753 100644 (file)
@@ -189,7 +189,8 @@ guint          soup_message_get_flags           (SoupMessage        *msg);
  * Handler Registration 
  */
 typedef enum {
-       SOUP_HANDLER_PRE_BODY = 1,
+       SOUP_HANDLER_POST_REQUEST = 1,
+       SOUP_HANDLER_PRE_BODY,
        SOUP_HANDLER_BODY_CHUNK,
        SOUP_HANDLER_POST_BODY
 } SoupHandlerPhase;
index 98a92e3..bc4d79c 100644 (file)
@@ -241,22 +241,43 @@ soup_session_new_with_options (const char *optname1, ...)
        return session;
 }
 
+static gboolean
+safe_uri_equal (const SoupUri *a, const SoupUri *b)
+{
+       if (!a && !b)
+               return TRUE;
+
+       if (a && !b || b && !a)
+               return FALSE;
+
+       return soup_uri_equal (a, b);
+}
+
 static void
 set_property (GObject *object, guint prop_id,
              const GValue *value, GParamSpec *pspec)
 {
        SoupSession *session = SOUP_SESSION (object);
        gpointer pval;
+       gboolean need_abort = FALSE;
 
        switch (prop_id) {
        case PROP_PROXY_URI:
+               pval = g_value_get_pointer (value);
+
+               if (!safe_uri_equal (session->priv->proxy_uri, pval))
+                       need_abort = TRUE;
+
                if (session->priv->proxy_uri)
                        soup_uri_free (session->priv->proxy_uri);
-               pval = g_value_get_pointer (value);
+
                session->priv->proxy_uri = pval ? soup_uri_copy (pval) : NULL;
 
-               soup_session_abort (session);
-               cleanup_hosts (session);
+               if (need_abort) {
+                       soup_session_abort (session);
+                       cleanup_hosts (session);
+               }
+
                break;
        case PROP_MAX_CONNS:
                session->priv->max_conns = g_value_get_int (value);
@@ -330,6 +351,23 @@ host_uri_equal (gconstpointer v1, gconstpointer v2)
 }
 
 static SoupSessionHost *
+soup_session_host_new (SoupSession *session, const SoupUri *source_uri)
+{
+       SoupSessionHost *host;
+
+       host = g_new0 (SoupSessionHost, 1);
+       host->root_uri = soup_uri_copy_root (source_uri);
+
+       if (host->root_uri->protocol == SOUP_PROTOCOL_HTTPS &&
+           !session->priv->ssl_creds) {
+               session->priv->ssl_creds =
+                       soup_ssl_get_client_credentials (session->priv->ssl_ca_file);
+       }
+
+       return host;
+}
+
+static SoupSessionHost *
 get_host_for_message (SoupSession *session, SoupMessage *msg)
 {
        SoupSessionHost *host;
@@ -339,20 +377,25 @@ get_host_for_message (SoupSession *session, SoupMessage *msg)
        if (host)
                return host;
 
-       host = g_new0 (SoupSessionHost, 1);
-       host->root_uri = soup_uri_copy_root (source);
+       host = soup_session_host_new (session, source);
 
        g_hash_table_insert (session->priv->hosts, host->root_uri, host);
 
-       if (host->root_uri->protocol == SOUP_PROTOCOL_HTTPS &&
-           !session->priv->ssl_creds) {
-               session->priv->ssl_creds =
-                       soup_ssl_get_client_credentials (session->priv->ssl_ca_file);
-       }
-
        return host;
 }
 
+static SoupSessionHost *
+get_proxy_host (SoupSession *session)
+{
+       if (session->priv->proxy_host)
+               return session->priv->proxy_host;
+
+       session->priv->proxy_host =
+               soup_session_host_new (session, session->priv->proxy_uri);
+
+       return session->priv->proxy_host;
+}
+
 static void
 free_realm (gpointer path, gpointer scheme_realm, gpointer data)
 {
@@ -399,7 +442,7 @@ lookup_auth (SoupSession *session, SoupMessage *msg, gboolean proxy)
        const char *realm, *const_path;
 
        if (proxy) {
-               host = session->priv->proxy_host;
+               host = get_proxy_host (session);
                const_path = "/";
        } else {
                host = get_host_for_message (session, msg);
@@ -450,11 +493,17 @@ invalidate_auth (SoupSessionHost *host, SoupAuth *auth)
 
 static gboolean
 authenticate_auth (SoupSession *session, SoupAuth *auth,
-                  SoupMessage *msg, gboolean prior_auth_failed)
+                  SoupMessage *msg, gboolean prior_auth_failed,
+                  gboolean proxy)
 {
-       const SoupUri *uri = soup_message_get_uri (msg);
+       const SoupUri *uri;
        char *username = NULL, *password = NULL;
 
+       if (proxy)
+               uri = session->priv->proxy_uri;
+       else
+               uri = soup_message_get_uri (msg);
+
        if (uri->passwd && !prior_auth_failed) {
                soup_auth_authenticate (auth, uri->user, uri->passwd);
                return TRUE;
@@ -490,7 +539,11 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
        GSList *pspace, *p;
        gboolean prior_auth_failed = FALSE;
 
-       host = get_host_for_message (session, msg);
+       if (proxy)
+               host = get_proxy_host (session);
+       else
+               host = get_host_for_message (session, msg);
+
        g_return_val_if_fail (host != NULL, FALSE);
 
        /* Try to construct a new auth from the headers; if we can't,
@@ -532,7 +585,20 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
        realm = g_strdup_printf ("%s:%s",
                                 soup_auth_get_scheme_name (new_auth),
                                 soup_auth_get_realm (new_auth));
-       pspace = soup_auth_get_protection_space (new_auth, msg_uri);
+
+       /* 
+        * RFC 2617 is somewhat unclear about the scope of protection
+        * spaces with regard to proxies.  The only mention of it is
+        * as an aside in section 3.2.1, where it is defining the fields
+        * of a Digest challenge and says that the protection space is
+        * always the entire proxy.  Is this the case for all authentication
+        * schemes or just Digest?  Who knows, but we're assuming all.
+        */
+       if (proxy)
+               pspace = g_slist_prepend (NULL, g_strdup (""));
+       else
+               pspace = soup_auth_get_protection_space (new_auth, msg_uri);
+
        for (p = pspace; p; p = p->next) {
                path = p->data;
                if (g_hash_table_lookup_extended (host->auth_realms, path,
@@ -561,8 +627,8 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
 
        /* If we need to authenticate, try to do it. */
        if (!soup_auth_is_authenticated (new_auth)) {
-               return authenticate_auth (session, new_auth,
-                                         msg, prior_auth_failed);
+               return authenticate_auth (session, new_auth, msg,
+                                         prior_auth_failed, proxy);
        }
 
        /* Otherwise we're good. */
@@ -679,7 +745,7 @@ add_auth (SoupSession *session, SoupMessage *msg, gboolean proxy)
        if (!auth)
                return;
        if (!soup_auth_is_authenticated (auth) &&
-           !authenticate_auth (session, auth, msg, FALSE))
+           !authenticate_auth (session, auth, msg, FALSE, proxy))
                return;
 
        token = soup_auth_get_authorization (auth, msg);
@@ -945,10 +1011,12 @@ soup_session_queue_message (SoupSession *session, SoupMessage *req,
 
        g_signal_connect (req, "finished",
                          G_CALLBACK (request_finished), session);
+
        if (callback) {
                g_signal_connect (req, "finished",
                                  G_CALLBACK (callback), user_data);
        }
+
        g_signal_connect_after (req, "finished",
                                G_CALLBACK (final_finished), session);