[libsoup/carlosgc/authenticate: 5/9] Move authenticate signal from SoupSession to SoupMessage




commit 8a918ee3cd75def6f9c1a6bdcb1008e99684ec6b
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Mon Oct 26 10:20:01 2020 +0100

    Move authenticate signal from SoupSession to SoupMessage
    
    In case of tunneling the authenticate signal is emitted in the original
    message, since the tunneling message is an internal implementation
    detail. The authenticate signal is now true handled, and SoupAuthManager
    automatically pauses and unpauses the message when handled
    asynchronously. soup_auth_cancel() has been added to complete an async
    authentication when no credentials are provided.

 docs/reference/libsoup-3.0-sections.txt |   2 +
 libsoup/auth/soup-auth-manager.c        |  37 +++-
 libsoup/auth/soup-auth.c                | 100 ++++++++++
 libsoup/auth/soup-auth.h                |   8 +
 libsoup/soup-message-private.h          |   3 +
 libsoup/soup-message.c                  |  46 +++++
 libsoup/soup-message.h                  |   3 +
 libsoup/soup-session-private.h          |   2 +
 libsoup/soup-session.c                  |  72 +++-----
 tests/auth-test.c                       | 311 +++++++++++++++++---------------
 tests/misc-test.c                       |  18 +-
 tests/ntlm-test.c                       |  85 +++++----
 tests/proxy-test.c                      |  33 ++--
 tests/pull-api-test.c                   |  21 ++-
 14 files changed, 478 insertions(+), 263 deletions(-)
---
diff --git a/docs/reference/libsoup-3.0-sections.txt b/docs/reference/libsoup-3.0-sections.txt
index d50ec834..f89ac3b7 100644
--- a/docs/reference/libsoup-3.0-sections.txt
+++ b/docs/reference/libsoup-3.0-sections.txt
@@ -457,6 +457,8 @@ soup_auth_authenticate
 soup_auth_can_authenticate
 soup_auth_is_authenticated
 soup_auth_is_ready
+soup_auth_cancel
+soup_auth_is_cancelled
 <SUBSECTION>
 soup_auth_get_authorization
 soup_auth_get_protection_space
diff --git a/libsoup/auth/soup-auth-manager.c b/libsoup/auth/soup-auth-manager.c
index 86f249d4..2af4a0b5 100644
--- a/libsoup/auth/soup-auth-manager.c
+++ b/libsoup/auth/soup-auth-manager.c
@@ -507,6 +507,21 @@ lookup_proxy_auth (SoupAuthManagerPrivate *priv, SoupMessage *msg)
        return priv->proxy_auth;
 }
 
+static void
+async_auth_finished (SoupAuth    *auth,
+                    GParamSpec  *pspec,
+                    SoupMessage *msg)
+{
+       SoupSession *session;
+
+       session = g_object_steal_data (G_OBJECT (msg), "auth-msg-session");
+       if (!session)
+               return;
+
+       soup_session_unpause_message (session, msg);
+       g_object_unref (session);
+}
+
 static void
 authenticate_auth (SoupAuthManager *manager, SoupAuth *auth,
                   SoupMessage *msg, gboolean prior_auth_failed,
@@ -533,8 +548,24 @@ authenticate_auth (SoupAuthManager *manager, SoupAuth *auth,
                soup_uri_set_password (uri, NULL);
                soup_uri_set_user (uri, NULL);
        } else if (!soup_auth_is_authenticated (auth) && can_interact) {
-               g_signal_emit (manager, signals[AUTHENTICATE], 0,
-                              msg, auth, prior_auth_failed);
+               SoupMessage *original_msg;
+               gboolean handled;
+
+               original_msg = soup_session_get_original_message_for_authentication (priv->session,
+                                                                                    msg);
+               handled = soup_message_authenticate (original_msg, auth, prior_auth_failed);
+               if (handled && !soup_auth_is_authenticated (auth)) {
+                       soup_session_pause_message (priv->session, msg);
+                       g_object_set_data_full (G_OBJECT (msg), "auth-msg-session",
+                                               g_object_ref (priv->session),
+                                               g_object_unref);
+                       g_signal_connect_object (auth, "notify::is-authenticated",
+                                                G_CALLBACK (async_auth_finished),
+                                                msg, 0);
+                       g_signal_connect_object (auth, "notify::is-cancelled",
+                                                G_CALLBACK (async_auth_finished),
+                                                msg, 0);
+               }
        }
 }
 
@@ -578,7 +609,7 @@ record_auth_for_uri (SoupAuthManagerPrivate *priv, SoupURI *uri,
         * since the old one might already be authenticated.)
         */
        old_auth = g_hash_table_lookup (host->auths, auth_info);
-       if (old_auth && (old_auth != auth || !prior_auth_failed)) {
+       if (old_auth && (old_auth != auth || !prior_auth_failed) && !soup_auth_is_cancelled (old_auth)) {
                g_free (auth_info);
                return old_auth;
        } else {
diff --git a/libsoup/auth/soup-auth.c b/libsoup/auth/soup-auth.c
index 881ed9f9..62d0a677 100644
--- a/libsoup/auth/soup-auth.c
+++ b/libsoup/auth/soup-auth.c
@@ -38,6 +38,7 @@ typedef struct {
         char *realm;
        char *host;
        gboolean proxy;
+       gboolean cancelled;
 } SoupAuthPrivate;
 
 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (SoupAuth, soup_auth, G_TYPE_OBJECT)
@@ -50,6 +51,7 @@ enum {
        PROP_HOST,
        PROP_IS_FOR_PROXY,
        PROP_IS_AUTHENTICATED,
+       PROP_IS_CANCELLED,
 
        LAST_PROP
 };
@@ -59,6 +61,18 @@ soup_auth_init (SoupAuth *auth)
 {
 }
 
+static void
+soup_auth_dispose (GObject *object)
+{
+       SoupAuth *auth = SOUP_AUTH (object);
+       SoupAuthPrivate *priv = soup_auth_get_instance_private (auth);
+
+       if (!priv->cancelled && !soup_auth_is_authenticated (auth))
+               soup_auth_cancel (auth);
+
+       G_OBJECT_CLASS (soup_auth_parent_class)->dispose (object);
+}
+
 static void
 soup_auth_finalize (GObject *object)
 {
@@ -119,6 +133,8 @@ soup_auth_get_property (GObject *object, guint prop_id,
        case PROP_IS_AUTHENTICATED:
                g_value_set_boolean (value, soup_auth_is_authenticated (auth));
                break;
+       case PROP_IS_CANCELLED:
+               g_value_set_boolean (value, priv->cancelled);
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -138,6 +154,7 @@ soup_auth_class_init (SoupAuthClass *auth_class)
 
        auth_class->can_authenticate = auth_can_authenticate;
 
+       object_class->dispose = soup_auth_dispose;
        object_class->finalize     = soup_auth_finalize;
        object_class->set_property = soup_auth_set_property;
        object_class->get_property = soup_auth_get_property;
@@ -208,6 +225,20 @@ soup_auth_class_init (SoupAuthClass *auth_class)
                                      FALSE,
                                      G_PARAM_READABLE |
                                      G_PARAM_STATIC_STRINGS));
+       /**
+        * SoupAuth:is-cancelled:
+        *
+        * An alias for the #SoupAuth:is-cancelled property.
+        * (Whether or not the auth has been cancelled.)
+        **/
+       g_object_class_install_property (
+               object_class, PROP_IS_CANCELLED,
+               g_param_spec_boolean ("is-cancelled",
+                                     "Cancelled",
+                                     "Whether or not the auth is cancelled",
+                                     FALSE,
+                                     G_PARAM_READABLE |
+                                     G_PARAM_STATIC_STRINGS));
 }
 
 /**
@@ -289,6 +320,9 @@ soup_auth_update (SoupAuth *auth, SoupMessage *msg, const char *auth_header)
        g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
        g_return_val_if_fail (auth_header != NULL, FALSE);
 
+       if (priv->cancelled)
+               return FALSE;
+
        scheme = soup_auth_get_scheme_name (auth);
        if (g_ascii_strncasecmp (auth_header, scheme, strlen (scheme)) != 0)
                return FALSE;
@@ -323,18 +357,47 @@ soup_auth_update (SoupAuth *auth, SoupMessage *msg, const char *auth_header)
 void
 soup_auth_authenticate (SoupAuth *auth, const char *username, const char *password)
 {
+       SoupAuthPrivate *priv;
        gboolean was_authenticated;
 
        g_return_if_fail (SOUP_IS_AUTH (auth));
        g_return_if_fail (username != NULL);
        g_return_if_fail (password != NULL);
 
+       priv = soup_auth_get_instance_private (auth);
+       if (priv->cancelled)
+               return;
+
        was_authenticated = soup_auth_is_authenticated (auth);
        SOUP_AUTH_GET_CLASS (auth)->authenticate (auth, username, password);
        if (was_authenticated != soup_auth_is_authenticated (auth))
                g_object_notify (G_OBJECT (auth), "is-authenticated");
 }
 
+/**
+ * soup_auth_cancel:
+ * @auth: a #SoupAuth
+ *
+ * Call this on an auth to cancel it. You need to cancel an auth to complete
+ * an asynchronous authenticate operation when no credentials are provided
+ * (soup_auth_authenticate() is not called).
+ * The #SoupAuth will be cancelled on dispose if it hans't been authenticated.
+ */
+void
+soup_auth_cancel (SoupAuth *auth)
+{
+       SoupAuthPrivate *priv;
+
+       g_return_if_fail (SOUP_IS_AUTH (auth));
+
+       priv = soup_auth_get_instance_private (auth);
+       if (priv->cancelled)
+               return;
+
+       priv->cancelled = TRUE;
+       g_object_notify (G_OBJECT (auth), "is-cancelled");
+}
+
 /**
  * soup_auth_is_for_proxy:
  * @auth: a #SoupAuth
@@ -447,11 +510,36 @@ soup_auth_get_info (SoupAuth *auth)
 gboolean
 soup_auth_is_authenticated (SoupAuth *auth)
 {
+       SoupAuthPrivate *priv;
+
        g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
 
+       priv = soup_auth_get_instance_private (auth);
+       if (priv->cancelled)
+               return FALSE;
+
        return SOUP_AUTH_GET_CLASS (auth)->is_authenticated (auth);
 }
 
+/**
+ * soup_auth_is_cancelled:
+ * @auth: a #SoupAuth
+ *
+ * Tests if @auth has been cancelled
+ *
+ * Returns: %TRUE if @auth has been cancelled
+ */
+gboolean
+soup_auth_is_cancelled (SoupAuth *auth)
+{
+       SoupAuthPrivate *priv;
+
+       g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
+
+       priv = soup_auth_get_instance_private (auth);
+       return priv->cancelled;
+}
+
 /**
  * soup_auth_get_authorization:
  * @auth: a #SoupAuth
@@ -490,9 +578,15 @@ gboolean
 soup_auth_is_ready (SoupAuth    *auth,
                    SoupMessage *msg)
 {
+       SoupAuthPrivate *priv;
+
        g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
        g_return_val_if_fail (SOUP_IS_MESSAGE (msg), TRUE);
 
+       priv = soup_auth_get_instance_private (auth);
+       if (priv->cancelled)
+               return FALSE;
+
        if (SOUP_AUTH_GET_CLASS (auth)->is_ready)
                return SOUP_AUTH_GET_CLASS (auth)->is_ready (auth, msg);
        else
@@ -513,8 +607,14 @@ soup_auth_is_ready (SoupAuth    *auth,
 gboolean
 soup_auth_can_authenticate (SoupAuth *auth)
 {
+       SoupAuthPrivate *priv;
+
        g_return_val_if_fail (SOUP_IS_AUTH (auth), FALSE);
 
+       priv = soup_auth_get_instance_private (auth);
+       if (priv->cancelled)
+               return FALSE;
+
        return SOUP_AUTH_GET_CLASS (auth)->can_authenticate (auth);
 }
 
diff --git a/libsoup/auth/soup-auth.h b/libsoup/auth/soup-auth.h
index ab3f2519..284aa3da 100644
--- a/libsoup/auth/soup-auth.h
+++ b/libsoup/auth/soup-auth.h
@@ -67,8 +67,16 @@ SOUP_AVAILABLE_IN_2_4
 void        soup_auth_authenticate          (SoupAuth      *auth,
                                             const char    *username,
                                             const char    *password);
+
+SOUP_AVAILABLE_IN_ALL
+void        soup_auth_cancel                (SoupAuth      *auth);
+
 SOUP_AVAILABLE_IN_2_4
 gboolean    soup_auth_is_authenticated      (SoupAuth      *auth);
+
+SOUP_AVAILABLE_IN_ALL
+gboolean    soup_auth_is_cancelled          (SoupAuth      *auth);
+
 SOUP_AVAILABLE_IN_2_42
 gboolean    soup_auth_is_ready              (SoupAuth      *auth,
                                             SoupMessage   *msg);
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index 5ff12512..47068bac 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -130,6 +130,9 @@ void soup_message_content_sniffed   (SoupMessage *msg,
 void soup_message_starting          (SoupMessage *msg);
 void soup_message_restarted         (SoupMessage *msg);
 void soup_message_finished          (SoupMessage *msg);
+gboolean soup_message_authenticate  (SoupMessage *msg,
+                                    SoupAuth    *auth,
+                                    gboolean     retrying);
 
 gboolean soup_message_disables_feature (SoupMessage *msg,
                                        gpointer     feature);
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 39c0fc1a..6eae152d 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -73,6 +73,7 @@ enum {
        RESTARTED,
        FINISHED,
 
+       AUTHENTICATE,
        NETWORK_EVENT,
 
        LAST_SIGNAL
@@ -482,6 +483,40 @@ soup_message_class_init (SoupMessageClass *message_class)
                              NULL,
                              G_TYPE_NONE, 0);
 
+       /**
+        * SoupMessage::authenticate:
+        * @msg: the message
+        * @auth: the #SoupAuth to authenticate
+        * @retrying: %TRUE if this is the second (or later) attempt
+        *
+        * Emitted when the message requires authentication. If
+        * credentials are available call soup_auth_authenticate() on
+        * @auth. If these credentials fail, the signal will be
+        * emitted again, with @retrying set to %TRUE, which will
+        * continue until you return without calling
+        * soup_auth_authenticate() on @auth.
+        *
+        * Note that this may be emitted before @msg's body has been
+        * fully read.
+        *
+        * You can authenticate @auth asynchronously by calling g_object_ref()
+        * on @auth and returning %TRUE. The operation will complete once
+        * either soup_auth_authenticate() or soup_auth_cancel() are called.
+        *
+        * Returns: %TRUE to stop other handlers from being invoked
+        *    or %FALSE to propagate the event further.
+        **/
+       signals[AUTHENTICATE] =
+               g_signal_new ("authenticate",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (SoupMessageClass, authenticate),
+                             g_signal_accumulator_true_handled, NULL,
+                             NULL,
+                             G_TYPE_BOOLEAN, 2,
+                             SOUP_TYPE_AUTH,
+                             G_TYPE_BOOLEAN);
+
        /**
         * SoupMessage::network-event:
         * @msg: the message
@@ -866,6 +901,17 @@ soup_message_network_event (SoupMessage         *msg,
                       event, connection);
 }
 
+gboolean
+soup_message_authenticate (SoupMessage *msg,
+                          SoupAuth    *auth,
+                          gboolean     retrying)
+{
+       gboolean handled;
+       g_signal_emit (msg, signals[AUTHENTICATE], 0,
+                      auth, retrying, &handled);
+       return handled;
+}
+
 static void
 header_handler_free (gpointer header_name, GClosure *closure)
 {
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index dca2c301..57bf79dd 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -46,6 +46,9 @@ typedef struct {
        void     (*restarted)           (SoupMessage *msg);
        void     (*finished)            (SoupMessage *msg);
        void     (*starting)            (SoupMessage *msg);
+       void     (*authenticate)        (SoupMessage *msg,
+                                        SoupAuth    *auth,
+                                        gboolean     retrying);
 
        /* Padding for future expansion */
        void (*_libsoup_reserved1) (void);
diff --git a/libsoup/soup-session-private.h b/libsoup/soup-session-private.h
index 57ce3fd1..d641c69b 100644
--- a/libsoup/soup-session-private.h
+++ b/libsoup/soup-session-private.h
@@ -15,6 +15,8 @@ SoupURI *soup_session_get_message_proxy_uri (SoupSession *session,
                                             SoupMessage *msg);
 void     soup_session_requeue_message       (SoupSession *session,
                                             SoupMessage *msg);
+SoupMessage *soup_session_get_original_message_for_authentication (SoupSession *session,
+                                                                  SoupMessage *msg);
 
 G_END_DECLS
 
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index b7394ed8..b2a94bb2 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -138,10 +138,6 @@ static void connection_disconnected (SoupConnection *conn, gpointer user_data);
 static void drop_connection (SoupSession *session, SoupSessionHost *host,
                             SoupConnection *conn);
 
-static void auth_manager_authenticate (SoupAuthManager *manager,
-                                      SoupMessage *msg, SoupAuth *auth,
-                                      gboolean retrying, gpointer user_data);
-
 static void async_run_queue (SoupSession *session);
 
 static void async_send_request_running (SoupSession *session, SoupMessageQueueItem *item);
@@ -166,7 +162,6 @@ G_DEFINE_TYPE_WITH_PRIVATE (SoupSession, soup_session, G_TYPE_OBJECT)
 enum {
        REQUEST_QUEUED,
        REQUEST_UNQUEUED,
-       AUTHENTICATE,
        LAST_SIGNAL
 };
 
@@ -244,8 +239,6 @@ soup_session_init (SoupSession *session)
        priv->features_cache = g_hash_table_new (NULL, NULL);
 
        auth_manager = g_object_new (SOUP_TYPE_AUTH_MANAGER, NULL);
-       g_signal_connect (auth_manager, "authenticate",
-                         G_CALLBACK (auth_manager_authenticate), session);
        soup_session_feature_add_feature (SOUP_SESSION_FEATURE (auth_manager),
                                          SOUP_TYPE_AUTH_BASIC);
        soup_session_feature_add_feature (SOUP_SESSION_FEATURE (auth_manager),
@@ -774,14 +767,6 @@ free_host (SoupSessionHost *host)
        g_slice_free (SoupSessionHost, host);
 }
 
-static void
-auth_manager_authenticate (SoupAuthManager *manager, SoupMessage *msg,
-                          SoupAuth *auth, gboolean retrying,
-                          gpointer session)
-{
-       g_signal_emit (session, signals[AUTHENTICATE], 0, msg, auth, retrying);
-}
-
 #define SOUP_SESSION_WOULD_REDIRECT_AS_GET(session, msg) \
        ((msg)->status_code == SOUP_STATUS_SEE_OTHER || \
         ((msg)->status_code == SOUP_STATUS_FOUND && \
@@ -2435,41 +2420,6 @@ soup_session_class_init (SoupSessionClass *session_class)
                              G_TYPE_NONE, 1,
                              SOUP_TYPE_MESSAGE);
 
-       /**
-        * SoupSession::authenticate:
-        * @session: the session
-        * @msg: the #SoupMessage being sent
-        * @auth: the #SoupAuth to authenticate
-        * @retrying: %TRUE if this is the second (or later) attempt
-        *
-        * Emitted when the session requires authentication. If
-        * credentials are available call soup_auth_authenticate() on
-        * @auth. If these credentials fail, the signal will be
-        * emitted again, with @retrying set to %TRUE, which will
-        * continue until you return without calling
-        * soup_auth_authenticate() on @auth.
-        *
-        * Note that this may be emitted before @msg's body has been
-        * fully read.
-        *
-        * If you call soup_session_pause_message() on @msg before
-        * returning, then you can authenticate @auth asynchronously
-        * (as long as you g_object_ref() it to make sure it doesn't
-        * get destroyed), and then unpause @msg when you are ready
-        * for it to continue.
-        **/
-       signals[AUTHENTICATE] =
-               g_signal_new ("authenticate",
-                             G_OBJECT_CLASS_TYPE (object_class),
-                             G_SIGNAL_RUN_FIRST,
-                             0,
-                             NULL, NULL,
-                             NULL,
-                             G_TYPE_NONE, 3,
-                             SOUP_TYPE_MESSAGE,
-                             SOUP_TYPE_AUTH,
-                             G_TYPE_BOOLEAN);
-
        /* properties */
        /**
         * SoupSession:proxy-resolver:
@@ -4233,3 +4183,25 @@ soup_session_get_message_proxy_uri (SoupSession *session,
        soup_message_queue_item_unref (item);
        return uri;
 }
+
+SoupMessage *
+soup_session_get_original_message_for_authentication (SoupSession *session,
+                                                     SoupMessage *msg)
+{
+       SoupSessionPrivate *priv = soup_session_get_instance_private (session);
+       SoupMessageQueueItem *item;
+       SoupMessage *original_msg;
+
+       item = soup_message_queue_lookup (priv->queue, msg);
+       if (!item)
+                return msg;
+
+       if (msg->method != SOUP_METHOD_CONNECT) {
+               soup_message_queue_item_unref (item);
+               return msg;
+       }
+
+       original_msg = item->related ? item->related->msg : msg;
+       soup_message_queue_item_unref (item);
+       return original_msg;
+}
diff --git a/tests/auth-test.c b/tests/auth-test.c
index 2b10b310..01280d26 100644
--- a/tests/auth-test.c
+++ b/tests/auth-test.c
@@ -213,19 +213,20 @@ handler (SoupMessage *msg, gpointer data)
        }
 }
 
-static void
-authenticate (SoupSession *session, SoupMessage *msg,
-             SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+authenticate (SoupMessage  *msg,
+             SoupAuth     *auth,
+             gboolean      retrying,
+             SoupAuthTest *test)
 {
-       SoupAuthTest *test = data;
        char *username, *password;
        char num;
 
        if (!test->provided[0])
-               return;
+               return FALSE;
        if (retrying) {
                if (!test->provided[1])
-                       return;
+                       return FALSE;
                num = test->provided[1];
        } else
                num = test->provided[0];
@@ -235,6 +236,8 @@ authenticate (SoupSession *session, SoupMessage *msg,
        soup_auth_authenticate (auth, username, password);
        g_free (username);
        g_free (password);
+
+       return TRUE;
 }
 
 static void
@@ -250,16 +253,17 @@ bug271540_sent (SoupMessage *msg, gpointer data)
                          "sent unauthenticated message %d after authenticating", n);
 }
 
-static void
-bug271540_authenticate (SoupSession *session, SoupMessage *msg,
-                       SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+bug271540_authenticate (SoupMessage *msg,
+                       SoupAuth    *auth,
+                       gboolean     retrying,
+                       gboolean    *authenticated)
 {
        int n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (msg), "#"));
-       gboolean *authenticated = data;
 
        if (strcmp (soup_auth_get_scheme_name (auth), "Basic") != 0 ||
            strcmp (soup_auth_get_realm (auth), "realm1") != 0)
-               return;
+               return FALSE;
 
        if (!*authenticated) {
                debug_printf (1, "    authenticating message %d\n", n);
@@ -269,6 +273,8 @@ bug271540_authenticate (SoupSession *session, SoupMessage *msg,
                soup_test_assert (!*authenticated,
                                  "asked to authenticate message %d after authenticating", n);
        }
+
+       return TRUE;
 }
 
 static void
@@ -299,13 +305,12 @@ do_pipelined_auth_test (void)
        session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
 
        authenticated = FALSE;
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (bug271540_authenticate), &authenticated);
-
        uri = g_strconcat (base_uri, "Basic/realm1/", NULL);
        for (i = 0; i < 10; i++) {
                msg = soup_message_new (SOUP_METHOD_GET, uri);
                g_object_set_data (G_OBJECT (msg), "#", GINT_TO_POINTER (i + 1));
+               g_signal_connect (msg, "authenticate",
+                                 G_CALLBACK (bug271540_authenticate), &authenticated);
                g_signal_connect (msg, "wrote_headers",
                                  G_CALLBACK (bug271540_sent), &authenticated);
 
@@ -393,18 +398,21 @@ do_pipelined_auth_test (void)
  *
  */
 
-static void
-digest_nonce_authenticate (SoupSession *session, SoupMessage *msg,
-                          SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+digest_nonce_authenticate (SoupMessage *msg,
+                          SoupAuth    *auth,
+                          gboolean     retrying)
 {
        if (retrying)
-               return;
+               return FALSE;
 
        if (strcmp (soup_auth_get_scheme_name (auth), "Digest") != 0 ||
            strcmp (soup_auth_get_realm (auth), "realm1") != 0)
-               return;
+               return FALSE;
 
        soup_auth_authenticate (auth, "user1", "realm1");
+
+       return TRUE;
 }
 
 static void
@@ -429,7 +437,7 @@ do_digest_nonce_test (SoupSession *session,
                soup_message_set_flags (msg, flags | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE);
        }
        if (expect_signal) {
-               g_signal_connect (session, "authenticate",
+               g_signal_connect (msg, "authenticate",
                                  G_CALLBACK (digest_nonce_authenticate),
                                  NULL);
        }
@@ -486,11 +494,12 @@ do_digest_expiration_test (void)
  * succeed.
  */
 
-static void
-async_authenticate (SoupSession *session, SoupMessage *msg,
-                   SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+async_authenticate (SoupMessage *msg,
+                   SoupAuth    *auth,
+                   gboolean     retrying,
+                   SoupAuth   **saved_auth)
 {
-       SoupAuth **saved_auth = data;
        int id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (msg), "id"));
 
        debug_printf (2, "  async_authenticate msg%d\n", id);
@@ -501,13 +510,14 @@ async_authenticate (SoupSession *session, SoupMessage *msg,
         */
        if (msg->status_code != SOUP_STATUS_UNAUTHORIZED) {
                debug_printf (2, "    (ignoring)\n");
-               return;
+               return FALSE;
        }
 
-       soup_session_pause_message (session, msg);
        if (saved_auth)
                *saved_auth = g_object_ref (auth);
        g_main_loop_quit (loop);
+
+       return TRUE;
 }
 
 static void
@@ -524,33 +534,36 @@ async_finished (SoupMessage *msg,
                g_main_loop_quit (loop);
 }
 
-static void
-async_authenticate_assert_once (SoupSession *session, SoupMessage *msg,
-                                SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+async_authenticate_assert_once (SoupMessage *msg,
+                                SoupAuth    *auth,
+                               gboolean     retrying,
+                               gboolean    *been_here)
 {
-       gboolean *been_here = data;
-
        debug_printf (2, "  async_authenticate_assert_once\n");
 
        soup_test_assert (!*been_here,
                          "async_authenticate_assert_once called twice");
        *been_here = TRUE;
+
+       return FALSE;
 }
 
-static void
-async_authenticate_assert_once_and_stop (SoupSession *session, SoupMessage *msg,
-                                        SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+async_authenticate_assert_once_and_stop (SoupMessage *msg,
+                                        SoupAuth    *auth,
+                                        gboolean     retrying,
+                                        SoupAuth   **saved_auth)
 {
-       gboolean *been_here = data;
-
        debug_printf (2, "  async_authenticate_assert_once_and_stop\n");
 
-       soup_test_assert (!*been_here,
+       soup_test_assert (!*saved_auth,
                          "async_authenticate_assert_once called twice");
-       *been_here = TRUE;
+       *saved_auth = g_object_ref (auth);
 
-       soup_session_pause_message (session, msg);
        g_main_loop_quit (loop);
+
+       return TRUE;
 }
 
 static void
@@ -558,7 +571,6 @@ do_async_auth_good_password_test (void)
 {
        SoupSession *session;
        SoupMessage *msg1, *msg2, *msg3, msg2_bak;
-       guint auth_id;
        char *uri;
        SoupAuth *auth = NULL;
        int remaining;
@@ -572,14 +584,13 @@ do_async_auth_good_password_test (void)
 
        msg1 = soup_message_new ("GET", uri);
        g_object_set_data (G_OBJECT (msg1), "id", GINT_TO_POINTER (1));
-       auth_id = g_signal_connect (session, "authenticate",
+       g_signal_connect (msg1, "authenticate",
                                    G_CALLBACK (async_authenticate), &auth);
        remaining++;
        g_signal_connect (msg1, "finished",
                          G_CALLBACK (async_finished), &remaining);
        soup_session_send_async (session, msg1, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
        g_main_loop_run (loop);
-       g_signal_handler_disconnect (session, auth_id);
 
        /* async_authenticate will pause msg1 and quit loop */
 
@@ -598,14 +609,13 @@ do_async_auth_good_password_test (void)
 
        msg3 = soup_message_new ("GET", uri);
        g_object_set_data (G_OBJECT (msg3), "id", GINT_TO_POINTER (3));
-       auth_id = g_signal_connect (session, "authenticate",
-                                   G_CALLBACK (async_authenticate), NULL);
+       g_signal_connect (msg3, "authenticate",
+                         G_CALLBACK (async_authenticate), NULL);
        remaining++;
        g_signal_connect (msg3, "finished",
                          G_CALLBACK (async_finished), &remaining);
        soup_session_send_async (session, msg3, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
        g_main_loop_run (loop);
-       g_signal_handler_disconnect (session, auth_id);
 
        /* async_authenticate will pause msg3 and quit loop */
 
@@ -613,8 +623,6 @@ do_async_auth_good_password_test (void)
        if (auth) {
                soup_auth_authenticate (auth, "user1", "realm1");
                g_object_unref (auth);
-               soup_session_unpause_message (session, msg1);
-               soup_session_unpause_message (session, msg3);
 
                g_main_loop_run (loop);
 
@@ -658,28 +666,25 @@ do_async_auth_bad_password_test (void)
        session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
        uri = g_strconcat (base_uri, "Basic/realm1/", NULL);
        remaining = 0;
-       auth = NULL;
 
        msg = soup_message_new ("GET", uri);
        g_object_set_data (G_OBJECT (msg), "id", GINT_TO_POINTER (1));
-       auth_id = g_signal_connect (session, "authenticate",
+       auth_id = g_signal_connect (msg, "authenticate",
                                    G_CALLBACK (async_authenticate), &auth);
        remaining++;
        g_signal_connect (msg, "finished",
                          G_CALLBACK (async_finished), &remaining);
        soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
        g_main_loop_run (loop);
-       g_signal_handler_disconnect (session, auth_id);
+       g_signal_handler_disconnect (msg, auth_id);
        soup_auth_authenticate (auth, "user1", "wrong");
        g_object_unref (auth);
-       soup_session_unpause_message (session, msg);
 
        been_there = FALSE;
-       auth_id = g_signal_connect (session, "authenticate",
-                                   G_CALLBACK (async_authenticate_assert_once),
-                                   &been_there);
+       g_signal_connect (msg, "authenticate",
+                         G_CALLBACK (async_authenticate_assert_once),
+                         &been_there);
        g_main_loop_run (loop);
-       g_signal_handler_disconnect (session, auth_id);
 
        soup_test_assert (been_there,
                          "authenticate not emitted");
@@ -696,10 +701,9 @@ do_async_auth_no_password_test (void)
 {
        SoupSession *session;
        SoupMessage *msg;
-       guint auth_id;
        char *uri;
        int remaining;
-       gboolean been_there;
+       SoupAuth *auth = NULL;
 
        /* Test that giving no password doesn't cause multiple
         * authenticate signals the second time.
@@ -717,34 +721,32 @@ do_async_auth_no_password_test (void)
         */
        msg = soup_message_new ("GET", uri);
        g_object_set_data (G_OBJECT (msg), "id", GINT_TO_POINTER (1));
-       auth_id = g_signal_connect (session, "authenticate",
-                                   G_CALLBACK (async_authenticate), NULL);
+       g_signal_connect (msg, "authenticate",
+                         G_CALLBACK (async_authenticate), &auth);
        remaining++;
        g_signal_connect (msg, "finished",
                          G_CALLBACK (async_finished), &remaining);
        soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
        g_main_loop_run (loop);
-       g_signal_handler_disconnect (session, auth_id);
-       soup_session_unpause_message (session, msg);
+       soup_auth_cancel (auth);
+       g_clear_object (&auth);
        g_main_loop_run (loop);
        g_object_unref(msg);
 
        /* Now send a second message */
        msg = soup_message_new ("GET", uri);
        g_object_set_data (G_OBJECT (msg), "id", GINT_TO_POINTER (2));
-       been_there = FALSE;
-       auth_id = g_signal_connect (session, "authenticate",
-                                   G_CALLBACK (async_authenticate_assert_once_and_stop),
-                                   &been_there);
+       g_signal_connect (msg, "authenticate",
+                         G_CALLBACK (async_authenticate_assert_once_and_stop),
+                         &auth);
        remaining++;
        g_signal_connect (msg, "finished",
                          G_CALLBACK (async_finished), &remaining);
        soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
        g_main_loop_run (loop);
-       soup_session_unpause_message (session, msg);
-
+       soup_auth_cancel (auth);
        g_main_loop_run (loop);
-       g_signal_handler_disconnect (session, auth_id);
+       g_object_unref (auth);
 
        soup_test_session_abort_unref (session);
        g_object_unref (msg);
@@ -761,11 +763,12 @@ typedef struct {
        } round[2];
 } SelectAuthData;
 
-static void
-select_auth_authenticate (SoupSession *session, SoupMessage *msg,
-                         SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+select_auth_authenticate (SoupMessage    *msg,
+                         SoupAuth       *auth,
+                         gboolean        retrying,
+                         SelectAuthData *sad)
 {
-       SelectAuthData *sad = data;
        const char *header, *basic, *digest;
        int round = retrying ? 1 : 0;
 
@@ -784,8 +787,13 @@ select_auth_authenticate (SoupSession *session, SoupMessage *msg,
                sad->round[round].headers = "Digest";
 
        sad->round[round].response = soup_auth_get_scheme_name (auth);
-       if (sad->password && !retrying)
+       if (sad->password && !retrying) {
                soup_auth_authenticate (auth, "user", sad->password);
+
+               return TRUE;
+       }
+
+       return FALSE;
 }
 
 static void
@@ -803,12 +811,11 @@ select_auth_test_one (SoupURI *uri,
        if (disable_digest)
                soup_session_remove_feature_by_type (session, SOUP_TYPE_AUTH_DIGEST);
 
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (select_auth_authenticate), &sad);
-       memset (&sad, 0, sizeof (sad));
-       sad.password = password;
-
        msg = soup_message_new_from_uri ("GET", uri);
+       g_signal_connect (msg, "authenticate",
+                          G_CALLBACK (select_auth_authenticate), &sad);
+        memset (&sad, 0, sizeof (sad));
+        sad.password = password;
        soup_test_session_send_message (session, msg);
 
        soup_test_assert (strcmp (sad.round[0].headers, first_headers) == 0,
@@ -1013,21 +1020,21 @@ auth_close_idle_authenticate (gpointer user_data)
        AuthCloseData *acd = user_data;
 
        soup_auth_authenticate (acd->auth, "user", "good-basic");
-       soup_session_unpause_message (acd->session, acd->msg);
 
        g_object_unref (acd->auth);
        return FALSE;
 }
 
-static void
-auth_close_authenticate (SoupSession *session, SoupMessage *msg,
-                        SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+auth_close_authenticate (SoupMessage   *msg,
+                        SoupAuth      *auth,
+                        gboolean       retrying,
+                        AuthCloseData *acd)
 {
-       AuthCloseData *acd = data;
-
-       soup_session_pause_message (session, msg);
        acd->auth = g_object_ref (auth);
        g_idle_add (auth_close_idle_authenticate, acd);
+
+       return TRUE;
 }
 
 static void
@@ -1058,10 +1065,9 @@ do_auth_close_test (void)
                          G_CALLBACK (auth_close_request_started), NULL);
 
        acd.session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
-       g_signal_connect (acd.session, "authenticate",
-                         G_CALLBACK (auth_close_authenticate), &acd);
-
        acd.msg = soup_message_new_from_uri ("GET", uri);
+       g_signal_connect (acd.msg, "authenticate",
+                         G_CALLBACK (auth_close_authenticate), &acd);
        soup_uri_free (uri);
        body = soup_test_session_async_send (acd.session, acd.msg);
 
@@ -1080,11 +1086,14 @@ infinite_cancel (gpointer session)
        return FALSE;
 }
 
-static void
-infinite_authenticate (SoupSession *session, SoupMessage *msg,
-                      SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+infinite_authenticate (SoupMessage *msg,
+                      SoupAuth    *auth,
+                      gboolean     retrying)
 {
        soup_auth_authenticate (auth, "user", "bad");
+
+       return TRUE;
 }
 
 static void
@@ -1098,11 +1107,10 @@ do_infinite_auth_test (void)
        SOUP_TEST_SKIP_IF_NO_APACHE;
 
        session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (infinite_authenticate), NULL);
-
        uri = g_strconcat (base_uri, "Basic/realm1/", NULL);
        msg = soup_message_new ("GET", uri);
+       g_signal_connect (msg, "authenticate",
+                          G_CALLBACK (infinite_authenticate), NULL);
        g_free (uri);
 
        timeout = g_timeout_add (500, infinite_cancel, session);
@@ -1137,15 +1145,20 @@ disappear_request_read (SoupServer        *server,
                soup_message_headers_remove (response_headers, "WWW-Authenticate");
 }
 
-static void
-disappear_authenticate (SoupSession *session, SoupMessage *msg,
-                       SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+disappear_authenticate (SoupMessage *msg,
+                       SoupAuth    *auth,
+                       gboolean     retrying,
+                       int         *counter)
 {
-       int *counter = data;
-
        (*counter)++;
-       if (!retrying)
+       if (!retrying) {
                soup_auth_authenticate (auth, "user", "bad");
+
+               return TRUE;
+       }
+
+       return FALSE;
 }
 
 static void
@@ -1179,10 +1192,10 @@ do_disappearing_auth_test (void)
        session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
 
        counter = 0;
-       g_signal_connect (session, "authenticate",
+       msg = soup_message_new_from_uri ("GET", uri);
+       g_signal_connect (msg, "authenticate",
                          G_CALLBACK (disappear_authenticate), &counter);
 
-       msg = soup_message_new_from_uri ("GET", uri);
        body = soup_test_session_async_send (session, msg);
 
        soup_test_assert (counter <= 2,
@@ -1242,7 +1255,6 @@ do_batch_tests (gconstpointer data)
        SoupMessage *msg;
        char *expected, *uristr;
        SoupURI *base;
-       guint signal;
        int i;
 
        SOUP_TEST_SKIP_IF_NO_APACHE;
@@ -1283,11 +1295,10 @@ do_batch_tests (gconstpointer data)
                        msg, "got_headers", SOUP_STATUS_OK,
                        G_CALLBACK (handler), expected);
 
-               signal = g_signal_connect (session, "authenticate",
-                                          G_CALLBACK (authenticate),
-                                          (gpointer)&current_tests[i]);
+               g_signal_connect (msg, "authenticate",
+                                 G_CALLBACK (authenticate),
+                                 (gpointer)&current_tests[i]);
                soup_test_session_send_message (session, msg);
-               g_signal_handler_disconnect (session, signal);
 
                soup_test_assert_message_status (msg, current_tests[i].final_status);
                soup_test_assert (!*expected,
@@ -1385,15 +1396,18 @@ do_message_do_not_use_auth_cache_test (void)
        soup_test_session_abort_unref (session);
 }
 
-static void
-async_no_auth_cache_authenticate (SoupSession *session, SoupMessage *msg,
-                                 SoupAuth *auth, gboolean retrying, SoupAuth **auth_out)
+static gboolean
+async_no_auth_cache_authenticate (SoupMessage *msg,
+                                 SoupAuth    *auth,
+                                 gboolean     retrying,
+                                 SoupAuth   **auth_out)
 {
        debug_printf (1, "  async_no_auth_cache_authenticate\n");
 
-       soup_session_pause_message (session, msg);
        *auth_out = g_object_ref (auth);
        g_main_loop_quit (loop);
+
+       return TRUE;
 }
 
 static void
@@ -1421,7 +1435,7 @@ do_async_message_do_not_use_auth_cache_test (void)
 
        msg = soup_message_new ("GET", uri);
        g_free (uri);
-       g_signal_connect (session, "authenticate",
+       g_signal_connect (msg, "authenticate",
                          G_CALLBACK (async_no_auth_cache_authenticate), &auth);
        flags = soup_message_get_flags (msg);
        soup_message_set_flags (msg, flags | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE);
@@ -1436,7 +1450,6 @@ do_async_message_do_not_use_auth_cache_test (void)
        soup_auth_authenticate (auth, "user1", "realm1");
        g_object_unref (auth);
 
-       soup_session_unpause_message (session, msg);
        g_main_loop_run (loop);
 
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
@@ -1446,19 +1459,22 @@ do_async_message_do_not_use_auth_cache_test (void)
        g_main_loop_unref (loop);
 }
 
-static void
-has_authorization_header_authenticate (SoupSession *session, SoupMessage *msg,
-                                      SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+has_authorization_header_authenticate (SoupMessage *msg,
+                                      SoupAuth    *auth,
+                                      gboolean     retrying,
+                                      SoupAuth   **saved_auth)
 {
-       SoupAuth **saved_auth = data;
-
        soup_auth_authenticate (auth, "user1", "realm1");
        *saved_auth = g_object_ref (auth);
+
+       return TRUE;
 }
 
 static void
-has_authorization_header_authenticate_assert (SoupSession *session, SoupMessage *msg,
-                                             SoupAuth *auth, gboolean retrying, gpointer data)
+has_authorization_header_authenticate_assert (SoupMessage *msg,
+                                             SoupAuth    *auth,
+                                             gboolean     retrying)
 {
        soup_test_assert (FALSE, "authenticate emitted unexpectedly");
 }
@@ -1471,7 +1487,6 @@ do_message_has_authorization_header_test (void)
        SoupAuthManager *manager;
        SoupAuth *auth = NULL;
        char *token;
-       guint auth_id;
        char *uri;
 
        g_test_bug ("775882");
@@ -1482,7 +1497,7 @@ do_message_has_authorization_header_test (void)
        uri = g_strconcat (base_uri, "Digest/realm1/", NULL);
 
        msg = soup_message_new ("GET", uri);
-       auth_id = g_signal_connect (session, "authenticate",
+       g_signal_connect (msg, "authenticate",
                          G_CALLBACK (has_authorization_header_authenticate), &auth);
        soup_test_session_send_message (session, msg);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
@@ -1490,16 +1505,15 @@ do_message_has_authorization_header_test (void)
        token = soup_auth_get_authorization (auth, msg);
        g_object_unref (auth);
        g_object_unref (msg);
-       g_signal_handler_disconnect (session, auth_id);
 
        manager = SOUP_AUTH_MANAGER (soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER));
        soup_auth_manager_clear_cached_credentials (manager);
 
        msg = soup_message_new ("GET", uri);
        soup_message_headers_replace (msg->request_headers, "Authorization", token);
-       auth_id = g_signal_connect (session, "authenticate",
-                                   G_CALLBACK (has_authorization_header_authenticate_assert),
-                                   NULL);
+       g_signal_connect (msg, "authenticate",
+                         G_CALLBACK (has_authorization_header_authenticate_assert),
+                         NULL);
        soup_test_session_send_message (session, msg);
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_object_unref (msg);
@@ -1513,24 +1527,32 @@ do_message_has_authorization_header_test (void)
        soup_test_assert_message_status (msg, SOUP_STATUS_OK);
        g_object_unref (msg);
        g_free (token);
-       g_signal_handler_disconnect (session, auth_id);
 
        g_free (uri);
        soup_test_session_abort_unref (session);
 }
 
-static void
-cancel_after_retry_authenticate (SoupSession  *session,
-                                 SoupMessage  *msg,
-                                 SoupAuth     *auth,
-                                 gboolean      retrying,
-                                 GCancellable *cancellable)
+typedef struct {
+       SoupSession *session;
+       GCancellable *cancellable;
+} CancelAfterRetryData;
+
+static gboolean
+cancel_after_retry_authenticate (SoupMessage          *msg,
+                                 SoupAuth             *auth,
+                                 gboolean              retrying,
+                                 CancelAfterRetryData *data)
 {
         if (retrying) {
-                soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
-                g_cancellable_cancel (cancellable);
-        } else
-                soup_auth_authenticate (auth, "user1", "wrong");
+                soup_session_cancel_message (data->session, msg, SOUP_STATUS_CANCELLED);
+                g_cancellable_cancel (data->cancellable);
+
+               return FALSE;
+       }
+
+       soup_auth_authenticate (auth, "user1", "wrong");
+
+       return TRUE;
 }
 
 static void
@@ -1554,27 +1576,28 @@ do_cancel_after_retry_test (void)
         SoupSession *session;
         SoupMessage *msg;
         char *uri;
-        GCancellable *cancellable;
+       CancelAfterRetryData data;
         GMainLoop *loop;
 
         SOUP_TEST_SKIP_IF_NO_APACHE;
 
         session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
-        cancellable = g_cancellable_new ();
-        g_signal_connect (session, "authenticate",
-                          G_CALLBACK (cancel_after_retry_authenticate),
-                          cancellable);
+       data.session = session;
+        data.cancellable = g_cancellable_new ();
 
         loop = g_main_loop_new (NULL, FALSE);
 
         uri = g_strconcat (base_uri, "Digest/realm1/", NULL);
         msg = soup_message_new ("GET", uri);
-        soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, cancellable,
+       g_signal_connect (msg, "authenticate",
+                          G_CALLBACK (cancel_after_retry_authenticate),
+                          &data);
+        soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, data.cancellable,
                                 (GAsyncReadyCallback)request_send_cb, loop);
         g_main_loop_run (loop);
 
         g_object_unref (msg);
-        g_object_unref (cancellable);
+        g_object_unref (data.cancellable);
         g_free (uri);
         soup_test_session_abort_unref (session);
 }
diff --git a/tests/misc-test.c b/tests/misc-test.c
index f270cadf..8bc2c3da 100644
--- a/tests/misc-test.c
+++ b/tests/misc-test.c
@@ -254,7 +254,7 @@ do_callback_unref_test (void)
        /* Otherwise, if we haven't crashed, we're ok. */
 }
 
-/* SoupSession should clean up all signal handlers on a message after
+/* SoupSession should clean up all internal signal handlers on a message after
  * it is finished, allowing the message to be reused if desired.
  */
 static void
@@ -264,6 +264,9 @@ ensure_no_signal_handlers (SoupMessage *msg, guint *signal_ids, guint n_signal_i
        guint id;
 
        for (i = 0; i < n_signal_ids; i++) {
+               if (strcmp (g_signal_name (signal_ids[i]), "authenticate") == 0)
+                       continue;
+
                id = g_signal_handler_find (msg, G_SIGNAL_MATCH_ID, signal_ids[i],
                                            0, NULL, NULL, NULL);
                soup_test_assert (id == 0,
@@ -272,15 +275,18 @@ ensure_no_signal_handlers (SoupMessage *msg, guint *signal_ids, guint n_signal_i
        }
 }
 
-static void
-reuse_test_authenticate (SoupSession *session, SoupMessage *msg,
-                        SoupAuth *auth, gboolean retrying)
+static gboolean
+reuse_test_authenticate (SoupMessage *msg,
+                        SoupAuth    *auth,
+                        gboolean     retrying)
 {
        /* Get it wrong the first time, then succeed */
        if (!retrying)
                soup_auth_authenticate (auth, "user", "wrong password");
        else
                soup_auth_authenticate (auth, "user", "password");
+
+       return TRUE;
 }
 
 static void
@@ -296,11 +302,11 @@ do_msg_reuse_test (void)
        signal_ids = g_signal_list_ids (SOUP_TYPE_MESSAGE, &n_signal_ids);
 
        session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (reuse_test_authenticate), NULL);
 
        debug_printf (1, "  First message\n");
        msg = soup_message_new_from_uri ("GET", base_uri);
+       g_signal_connect (msg, "authenticate",
+                          G_CALLBACK (reuse_test_authenticate), NULL);
        soup_test_session_async_send (session, msg);
        ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
 
diff --git a/tests/ntlm-test.c b/tests/ntlm-test.c
index d56c54bf..dfbf0d90 100644
--- a/tests/ntlm-test.c
+++ b/tests/ntlm-test.c
@@ -207,15 +207,21 @@ teardown_server (TestServer *ts,
 
 static gboolean authenticated_ntlm = FALSE;
 
-static void
-authenticate (SoupSession *session, SoupMessage *msg,
-             SoupAuth *auth, gboolean retrying, gpointer user)
+static gboolean
+authenticate (SoupMessage *msg,
+             SoupAuth    *auth,
+             gboolean    retrying,
+             gpointer    user)
 {
        if (!retrying) {
                soup_auth_authenticate (auth, user, "password");
                if (g_str_equal (soup_auth_get_scheme_name (auth), "NTLM"))
                        authenticated_ntlm = TRUE;
+
+               return TRUE;
        }
+
+       return FALSE;
 }
 
 typedef struct {
@@ -311,10 +317,15 @@ response_check (SoupMessage *msg, gpointer user_data)
 }
 
 static void
-do_message (SoupSession *session, SoupURI *base_uri, const char *path,
-           gboolean get_ntlm_prompt, gboolean do_ntlm,
-           gboolean get_basic_prompt, gboolean do_basic,
-           guint status_code)
+do_message (SoupSession *session,
+           SoupURI     *base_uri,
+           const char  *path,
+           const char  *user,
+           gboolean     get_ntlm_prompt,
+           gboolean     do_ntlm,
+           gboolean     get_basic_prompt,
+           gboolean     do_basic,
+           guint        status_code)
 {
        SoupURI *uri;
        SoupMessage *msg;
@@ -325,6 +336,11 @@ do_message (SoupSession *session, SoupURI *base_uri, const char *path,
        msg = soup_message_new_from_uri ("GET", uri);
        soup_uri_free (uri);
 
+       if (user) {
+               g_signal_connect (msg, "authenticate",
+                                 G_CALLBACK (authenticate),
+                                 (gpointer)user);
+       }
        g_signal_connect (msg, "got_headers",
                          G_CALLBACK (prompt_check), &state);
        g_signal_connect (msg, "got_headers",
@@ -409,12 +425,9 @@ do_ntlm_round (SoupURI *base_uri, gboolean use_ntlm,
 
        session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
 
-       if (user) {
-               g_signal_connect (session, "authenticate",
-                                 G_CALLBACK (authenticate), (char *)user);
-               if (use_ntlm && !use_builtin_ntlm)
-                       g_setenv ("NTLMUSER", user, TRUE);
-       }
+       if (user && use_ntlm && !use_builtin_ntlm)
+               g_setenv ("NTLMUSER", user, TRUE);
+
        if (use_ntlm) {
                SoupAuthManager *auth_manager;
                SoupAuth *ntlm;
@@ -432,7 +445,7 @@ do_ntlm_round (SoupURI *base_uri, gboolean use_ntlm,
         * asking.
         */
        authenticated_ntlm = FALSE;
-       do_message (session, base_uri, "/noauth/",
+       do_message (session, base_uri, "/noauth/", user,
                    FALSE, use_ntlm,
                    FALSE, FALSE,
                    SOUP_STATUS_OK);
@@ -448,7 +461,7 @@ do_ntlm_round (SoupURI *base_uri, gboolean use_ntlm,
         * previous step, then we'll just immediately get a 401 here.
         * So in no case will we see the client try to do_ntlm.
         */
-       do_message (session, base_uri, "/alice/",
+       do_message (session, base_uri, "/alice/", user,
                    !alice_via_ntlm, FALSE,
                    !alice_via_ntlm, alice_via_basic,
                    alice ? SOUP_STATUS_OK :
@@ -461,14 +474,14 @@ do_ntlm_round (SoupURI *base_uri, gboolean use_ntlm,
         * to send auth without it being requested, so also won't get
         * prompts. But Bob/nobody will.
         */
-       do_message (session, base_uri, "/alice/404",
+       do_message (session, base_uri, "/alice/404", user,
                    !alice, bob_via_ntlm,
                    !alice, alice_via_basic,
                    alice ? SOUP_STATUS_NOT_FOUND :
                    SOUP_STATUS_UNAUTHORIZED);
 
        /* 4. Should be exactly the same as #3, except the status code */
-       do_message (session, base_uri, "/alice/",
+       do_message (session, base_uri, "/alice/", user,
                    !alice, bob_via_ntlm,
                    !alice, alice_via_basic,
                    alice ? SOUP_STATUS_OK :
@@ -480,7 +493,7 @@ do_ntlm_round (SoupURI *base_uri, gboolean use_ntlm,
         * (and fail). Bob-via-NTLM will try to do NTLM right away and
         * succeed.
         */
-       do_message (session, base_uri, "/bob/",
+       do_message (session, base_uri, "/bob/", user,
                    !bob_via_ntlm, bob_via_ntlm,
                    !bob_via_ntlm, alice_via_basic,
                    bob ? SOUP_STATUS_OK :
@@ -492,7 +505,7 @@ do_ntlm_round (SoupURI *base_uri, gboolean use_ntlm,
         * still knows about this path, so will try Basic right away
         * and succeed.
         */
-       do_message (session, base_uri, "/alice/",
+       do_message (session, base_uri, "/alice/", user,
                    !alice_via_ntlm, alice_via_ntlm,
                    !alice_via_ntlm, alice_via_basic,
                    alice ? SOUP_STATUS_OK :
@@ -502,7 +515,7 @@ do_ntlm_round (SoupURI *base_uri, gboolean use_ntlm,
         * Since Bob-via-NTLM is unauthenticated at this point, he'll try
         * NTLM before realizing that the server doesn't support it.
         */
-       do_message (session, base_uri, "/basic/",
+       do_message (session, base_uri, "/basic/", user,
                    FALSE, bob_via_ntlm,
                    TRUE, user != NULL,
                    user != NULL ? SOUP_STATUS_OK :
@@ -513,7 +526,7 @@ do_ntlm_round (SoupURI *base_uri, gboolean use_ntlm,
         * previous NTLM connections will have been closed by the 401
         * from /basic). Non-NTLM users will be prompted for either.
         */
-       do_message (session, base_uri, "/either/",
+       do_message (session, base_uri, "/either/", user,
                    !use_ntlm, use_ntlm,
                    !use_ntlm, !use_ntlm && user != NULL,
                    user != NULL ? SOUP_STATUS_OK :
@@ -617,23 +630,30 @@ do_ntlm_test (TestServer *ts,
        do_ntlm_round (ts->uri, test->conn_uses_ntlm, test->user, use_builtin_ntlm);
 }
 
-static void
-retry_test_authenticate (SoupSession *session, SoupMessage *msg,
-                        SoupAuth *auth, gboolean retrying,
-                        gpointer user_data)
+static gboolean
+retry_test_authenticate (SoupMessage *msg,
+                        SoupAuth    *auth,
+                        gboolean     retrying,
+                        gboolean    *retried)
 {
-       gboolean *retried = user_data;
-
        if (!retrying) {
                /* server_callback doesn't actually verify the password,
                 * only the username. So we pass an incorrect username
                 * rather than an incorrect password.
                 */
                soup_auth_authenticate (auth, "wrong", "password");
-       } else if (!*retried) {
+
+               return TRUE;
+       }
+
+       if (!*retried) {
                soup_auth_authenticate (auth, "alice", "password");
                *retried = TRUE;
+
+               return TRUE;
        }
+
+       return FALSE;
 }
 
 static void
@@ -655,11 +675,11 @@ do_retrying_test (TestServer *ts,
        session = soup_test_session_new (SOUP_TYPE_SESSION,
                                         "add-feature-by-type", SOUP_TYPE_AUTH_NTLM,
                                         NULL);
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (retry_test_authenticate), &retried);
 
        uri = soup_uri_new_with_base (ts->uri, "/alice");
        msg = soup_message_new_from_uri ("GET", uri);
+       g_signal_connect (msg, "authenticate",
+                         G_CALLBACK (retry_test_authenticate), &retried);
        soup_uri_free (uri);
 
        body = soup_test_session_send (session, msg, NULL, NULL);
@@ -677,12 +697,11 @@ do_retrying_test (TestServer *ts,
        session = soup_test_session_new (SOUP_TYPE_SESSION,
                                         "add-feature-by-type", SOUP_TYPE_AUTH_NTLM,
                                         NULL);
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (retry_test_authenticate), &retried);
        retried = FALSE;
-
        uri = soup_uri_new_with_base (ts->uri, "/bob");
        msg = soup_message_new_from_uri ("GET", uri);
+       g_signal_connect (msg, "authenticate",
+                         G_CALLBACK (retry_test_authenticate), &retried);
        soup_uri_free (uri);
 
        body = soup_test_session_send (session, msg, NULL, NULL);
diff --git a/tests/proxy-test.c b/tests/proxy-test.c
index f28cb3c5..f1824235 100644
--- a/tests/proxy-test.c
+++ b/tests/proxy-test.c
@@ -41,24 +41,18 @@ static const char *proxy_names[] = {
 static GProxyResolver *proxy_resolvers[3];
 static const char *ignore_hosts[] = { "localhost", NULL };
 
-static void
-authenticate (SoupSession *session, SoupMessage *msg,
-             SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+authenticate (SoupMessage *msg,
+             SoupAuth    *auth,
+             gboolean     retrying)
 {
-       if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
-               soup_test_assert (!soup_auth_is_for_proxy (auth),
-                                 "got proxy auth object for 401");
-       } else if (msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED) {
-               soup_test_assert (soup_auth_is_for_proxy (auth),
-                                 "got regular auth object for 407");
-       } else {
-               soup_test_assert (FALSE,
-                                 "got authenticate signal with status %d\n",
-                                 msg->status_code);
+       if (!retrying) {
+               soup_auth_authenticate (auth, "user1", "realm1");
+
+               return TRUE;
        }
 
-       if (!retrying)
-               soup_auth_authenticate (auth, "user1", "realm1");
+       return FALSE;
 }
 
 static void
@@ -97,8 +91,6 @@ test_url (const char *url, int proxy, guint expected, gboolean close)
                                         "proxy-resolver", proxy_resolvers[proxy],
                                         "ssl-strict", FALSE,
                                         NULL);
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (authenticate), NULL);
 
        msg = soup_message_new (SOUP_METHOD_GET, url);
        if (!msg) {
@@ -106,6 +98,9 @@ test_url (const char *url, int proxy, guint expected, gboolean close)
                exit (1);
        }
 
+       g_signal_connect (msg, "authenticate",
+                          G_CALLBACK (authenticate), NULL);
+
        if (close) {
                /* FIXME g_test_bug ("611663") */
                g_signal_connect (msg, "starting",
@@ -250,6 +245,8 @@ do_proxy_auth_request (const char *url, SoupSession *session, gboolean do_read)
        GError *error = NULL;
 
        msg = soup_message_new ("GET", url);
+       g_signal_connect (msg, "authenticate",
+                         G_CALLBACK (authenticate), NULL);
 
        stream = soup_test_request_send (session, msg, NULL, 0, &error);
        g_assert_no_error (error);
@@ -299,8 +296,6 @@ do_proxy_auth_cache_test (void)
                                         "proxy-resolver", proxy_resolvers[AUTH_PROXY],
                                         "add-feature", cache,
                                         NULL);
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (authenticate), NULL);
 
        url = g_strconcat (HTTP_SERVER, "/Basic/realm1/", NULL);
 
diff --git a/tests/pull-api-test.c b/tests/pull-api-test.c
index edb4726d..24c4f8e1 100644
--- a/tests/pull-api-test.c
+++ b/tests/pull-api-test.c
@@ -4,12 +4,18 @@
 
 static GBytes *correct_response;
 
-static void
-authenticate (SoupSession *session, SoupMessage *msg,
-             SoupAuth *auth, gboolean retrying, gpointer data)
+static gboolean
+authenticate (SoupMessage *msg,
+             SoupAuth    *auth,
+             gboolean     retrying)
 {
-       if (!retrying)
+       if (!retrying) {
                soup_auth_authenticate (auth, "user2", "realm2");
+
+               return TRUE;
+       }
+
+       return FALSE;
 }
 
 #ifdef HAVE_APACHE
@@ -97,6 +103,9 @@ do_fully_async_test (SoupSession *session,
        ad.read_so_far = 0;
        ad.expected_status = expected_status;
 
+       g_signal_connect (msg, "authenticate",
+                         G_CALLBACK (authenticate), NULL);
+
        /* Connect to "got_headers", from which we'll decide where to
         * go next.
         */
@@ -192,8 +201,6 @@ do_fast_async_test (gconstpointer data)
        SOUP_TEST_SKIP_IF_NO_APACHE;
 
        session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (authenticate), NULL);
        do_fully_async_test (session, base_uri, "/",
                             TRUE, SOUP_STATUS_OK);
        do_fully_async_test (session, base_uri, "/Basic/realm1/",
@@ -212,8 +219,6 @@ do_slow_async_test (gconstpointer data)
        SOUP_TEST_SKIP_IF_NO_APACHE;
 
        session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
-       g_signal_connect (session, "authenticate",
-                         G_CALLBACK (authenticate), NULL);
        do_fully_async_test (session, base_uri, "/",
                             FALSE, SOUP_STATUS_OK);
        do_fully_async_test (session, base_uri, "/Basic/realm1/",


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]