Add "authenticate" and "reauthenticate" signals. (invalidate_auth): Remove
authorDan Winship <danw@src.gnome.org>
Wed, 10 Sep 2003 21:39:06 +0000 (21:39 +0000)
committerDan Winship <danw@src.gnome.org>
Wed, 10 Sep 2003 21:39:06 +0000 (21:39 +0000)
* libsoup/soup-session.c: Add "authenticate" and "reauthenticate"
signals.
(invalidate_auth): Remove the call to soup_auth_invalidate.
(authenticate_auth): soup_auth_fn is gone. If the URI doesn't
contain authentication, then emit "authenticate" or
"reauthenticate" (depending on whether or not this is the first
time we've asked for a password for this auth).
(update_auth_internal): If the server rejects our
username/password, don't bail out immediately. Try doing a
"reauthenticate" first.

* libsoup/soup-misc.c (soup_set_authorize_callback): Gone

* libsoup/soup-auth.c (soup_auth_new_from_header_list): Remove the
"pref" arg.
(soup_auth_invalidate): Remove this; it doesn't actually do
anything useful for us.

* libsoup/soup-auth-basic.c (invalidate): Remove
* libsoup/soup-auth-digest.c: (invalidate): Remove
* libsoup/soup-auth-ntlm.c: (invalidate): Remove

* libsoup/soup-uri.c: Remove all references to "authmech".
(soup_uri_set_auth): Remove this too.

* tests/auth-test.c: Update to use the "authenticate" and
"reauthenticate" signals instead of encoding usernames and
passwords in the URIs. Add a few more test cases.

16 files changed:
ChangeLog
libsoup/soup-auth-basic.c
libsoup/soup-auth-digest.c
libsoup/soup-auth-ntlm.c
libsoup/soup-auth.c
libsoup/soup-auth.h
libsoup/soup-marshal.list
libsoup/soup-message.c
libsoup/soup-misc.c
libsoup/soup-misc.h
libsoup/soup-private.h
libsoup/soup-session.c
libsoup/soup-session.h
libsoup/soup-uri.c
libsoup/soup-uri.h
tests/auth-test.c

index ce836cc..09bc9c6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,36 @@
 2003-09-10  Dan Winship  <danw@ximian.com>
 
+       * libsoup/soup-session.c: Add "authenticate" and "reauthenticate"
+       signals.
+       (invalidate_auth): Remove the call to soup_auth_invalidate.
+       (authenticate_auth): soup_auth_fn is gone. If the URI doesn't
+       contain authentication, then emit "authenticate" or
+       "reauthenticate" (depending on whether or not this is the first
+       time we've asked for a password for this auth).
+       (update_auth_internal): If the server rejects our
+       username/password, don't bail out immediately. Try doing a
+       "reauthenticate" first.
+
+       * libsoup/soup-misc.c (soup_set_authorize_callback): Gone
+
+       * libsoup/soup-auth.c (soup_auth_new_from_header_list): Remove the
+       "pref" arg.
+       (soup_auth_invalidate): Remove this; it doesn't actually do
+       anything useful for us.
+
+       * libsoup/soup-auth-basic.c (invalidate): Remove
+       * libsoup/soup-auth-digest.c: (invalidate): Remove
+       * libsoup/soup-auth-ntlm.c: (invalidate): Remove
+
+       * libsoup/soup-uri.c: Remove all references to "authmech".
+       (soup_uri_set_auth): Remove this too.
+
+       * tests/auth-test.c: Update to use the "authenticate" and
+       "reauthenticate" signals instead of encoding usernames and
+       passwords in the URIs. Add a few more test cases.
+
+2003-09-10  Dan Winship  <danw@ximian.com>
+
        * libsoup/soup-message-private.h (SoupMessagePrivate): Remove the
        "status" field from here, since it's mostly used by SoupSession,
        which shouldn't need access to SoupMessagePrivate.
index 78bcfb2..a256fc5 100644 (file)
@@ -22,7 +22,6 @@ static void construct (SoupAuth *auth, const char *header);
 static GSList *get_protection_space (SoupAuth *auth, const SoupUri *source_uri);
 static const char *get_realm (SoupAuth *auth);
 static void authenticate (SoupAuth *auth, const char *username, const char *password);
-static gboolean invalidate (SoupAuth *auth);
 static gboolean is_authenticated (SoupAuth *auth);
 static char *get_authorization (SoupAuth *auth, SoupMessage *msg);
 
@@ -66,7 +65,6 @@ class_init (GObjectClass *object_class)
        auth_class->get_protection_space = get_protection_space;
        auth_class->get_realm = get_realm;
        auth_class->authenticate = authenticate;
-       auth_class->invalidate = invalidate;
        auth_class->is_authenticated = is_authenticated;
        auth_class->get_authorization = get_authorization;
 
@@ -135,17 +133,6 @@ authenticate (SoupAuth *auth, const char *username, const char *password)
 }
 
 static gboolean
-invalidate (SoupAuth *auth)
-{
-       SoupAuthBasic *basic = SOUP_AUTH_BASIC (auth);
-
-       g_free (basic->priv->token);
-       basic->priv->token = NULL;
-
-       return TRUE;
-}
-
-static gboolean
 is_authenticated (SoupAuth *auth)
 {
        SoupAuthBasic *basic = SOUP_AUTH_BASIC (auth);
index e8e7da7..c36cb2f 100644 (file)
@@ -26,7 +26,6 @@ static void construct (SoupAuth *auth, const char *header);
 static GSList *get_protection_space (SoupAuth *auth, const SoupUri *source_uri);
 static const char *get_realm (SoupAuth *auth);
 static void authenticate (SoupAuth *auth, const char *username, const char *password);
-static gboolean invalidate (SoupAuth *auth);
 static gboolean is_authenticated (SoupAuth *auth);
 static char *get_authorization (SoupAuth *auth, SoupMessage *msg);
 
@@ -103,7 +102,6 @@ class_init (GObjectClass *object_class)
        auth_class->get_realm = get_realm;
        auth_class->construct = construct;
        auth_class->authenticate = authenticate;
-       auth_class->invalidate = invalidate;
        auth_class->is_authenticated = is_authenticated;
        auth_class->get_authorization = get_authorization;
 
@@ -314,16 +312,6 @@ authenticate (SoupAuth *auth, const char *username, const char *password)
 }
 
 static gboolean
-invalidate (SoupAuth *auth)
-{
-       /* An invalidated Digest auth is useless. You need to get
-        * a new nonce from the server before you can start using it
-        * again.
-        */
-       return FALSE;
-}
-
-static gboolean
 is_authenticated (SoupAuth *auth)
 {
        SoupAuthDigest *digest = SOUP_AUTH_DIGEST (auth);
index 0237654..f5ed688 100644 (file)
@@ -20,7 +20,6 @@ static void construct (SoupAuth *auth, const char *header);
 static GSList *get_protection_space (SoupAuth *auth, const SoupUri *source_uri);
 static const char *get_realm (SoupAuth *auth);
 static void authenticate (SoupAuth *auth, const char *username, const char *password);
-static gboolean invalidate (SoupAuth *auth);
 static gboolean is_authenticated (SoupAuth *auth);
 static char *get_authorization (SoupAuth *auth, SoupMessage *msg);
 
@@ -76,7 +75,6 @@ class_init (GObjectClass *object_class)
        auth_class->get_protection_space = get_protection_space;
        auth_class->get_realm = get_realm;
        auth_class->authenticate = authenticate;
-       auth_class->invalidate = invalidate;
        auth_class->is_authenticated = is_authenticated;
        auth_class->get_authorization = get_authorization;
 
@@ -145,21 +143,6 @@ authenticate (SoupAuth *auth, const char *username, const char *password)
 }
 
 static gboolean
-invalidate (SoupAuth *auth)
-{
-       SoupAuthNTLM *ntlm = SOUP_AUTH_NTLM (auth);
-
-       g_free (ntlm->priv->response);
-       ntlm->priv->response = NULL;
-       g_free (ntlm->priv->header);
-       ntlm->priv->header = NULL;
-
-       ntlm->priv->authenticated = FALSE;
-
-       return TRUE;
-}
-
-static gboolean
 is_authenticated (SoupAuth *auth)
 {
        SoupAuthNTLM *ntlm = SOUP_AUTH_NTLM (auth);
index 6919cdb..65ffd7c 100644 (file)
@@ -43,7 +43,7 @@ static AuthScheme known_auth_schemes [] = {
 };
 
 SoupAuth *
-soup_auth_new_from_header_list (const GSList *vals, const char *pref)
+soup_auth_new_from_header_list (const GSList *vals)
 {
        char *header = NULL;
        AuthScheme *scheme = NULL, *iter;
@@ -55,10 +55,6 @@ soup_auth_new_from_header_list (const GSList *vals, const char *pref)
                char *tryheader = vals->data;
 
                for (iter = known_auth_schemes; iter->scheme; iter++) {
-                       if (pref &&
-                           g_strncasecmp (pref, iter->scheme,
-                                          strlen (iter->scheme)) != 0)
-                               continue;
                        if (!g_strncasecmp (tryheader, iter->scheme, 
                                            strlen (iter->scheme))) {
                                if (!scheme || 
@@ -112,14 +108,6 @@ soup_auth_get_realm (SoupAuth *auth)
 }
 
 gboolean
-soup_auth_invalidate (SoupAuth *auth)
-{
-       g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
-
-       return SOUP_AUTH_GET_CLASS (auth)->invalidate (auth);
-}
-
-gboolean
 soup_auth_is_authenticated (SoupAuth *auth)
 {
        g_return_val_if_fail (SOUP_IS_AUTH (auth), TRUE);
index 2e936a3..c385dba 100644 (file)
@@ -36,7 +36,6 @@ typedef struct {
        void         (*authenticate)         (SoupAuth      *auth,
                                              const char    *username,
                                              const char    *password);
-       gboolean     (*invalidate)           (SoupAuth      *auth);
        gboolean     (*is_authenticated)     (SoupAuth      *auth);
 
        char *       (*get_authorization)    (SoupAuth      *auth,
@@ -46,8 +45,7 @@ typedef struct {
 GType       soup_auth_get_type              (void);
 
 
-SoupAuth   *soup_auth_new_from_header_list  (const GSList  *header,
-                                            const char    *pref);
+SoupAuth   *soup_auth_new_from_header_list  (const GSList  *header);
 
 const char *soup_auth_get_scheme_name       (SoupAuth      *auth);
 const char *soup_auth_get_realm             (SoupAuth      *auth);
@@ -55,7 +53,6 @@ const char *soup_auth_get_realm             (SoupAuth      *auth);
 void        soup_auth_authenticate          (SoupAuth      *auth,
                                             const char    *username,
                                             const char    *password);
-gboolean    soup_auth_invalidate            (SoupAuth      *auth);
 gboolean    soup_auth_is_authenticated      (SoupAuth      *auth);
 
 char       *soup_auth_get_authorization     (SoupAuth      *auth, 
index 0541e0b..2469e53 100644 (file)
@@ -2,3 +2,4 @@ NONE:NONE
 NONE:INT
 NONE:OBJECT
 NONE:POINTER
+NONE:POINTER,OBJECT
index b0faf5c..65459fa 100644 (file)
@@ -31,7 +31,7 @@ enum {
        LAST_SIGNAL
 };
 
-guint signals[LAST_SIGNAL] = { 0 };
+static guint signals[LAST_SIGNAL] = { 0 };
 
 static void got_headers (SoupMessage *req);
 static void got_chunk (SoupMessage *req);
index c25950f..b5e81fb 100644 (file)
@@ -670,31 +670,6 @@ soup_get_ssl_cert_files (const gchar **cert_file, const gchar **key_file)
                *key_file = ssl_key_file;
 }
 
-SoupAuthorizeFn  soup_auth_fn = NULL;
-gpointer         soup_auth_fn_user_data = NULL;
-
-/**
- * soup_set_authorize_callback:
- * @authfn: A %SoupAuthorizeFn function to be called when authorization 
- * is needed to complete a request.
- * @user_data: A pointer to be passed @authfn.
- * 
- * Sets the authorization callback to be called when a %SoupMessage fails with a
- * 401 or 407 response, and no authorization data is present in the URI (and the
- * request is not covered by a prior successful authorization attempt).
- *
- * The callback should call %soup_uri_set_auth on the passed URI in order to try
- * the request again.
- **/
-void
-soup_set_authorize_callback (SoupAuthorizeFn authfn,
-                            gpointer        user_data)
-{
-       soup_auth_fn = authfn;
-       soup_auth_fn_user_data = user_data;
-}
-
-
 typedef struct {
        gpointer instance;
        guint    real_id, self_id;
index 6321c0f..e67d409 100644 (file)
@@ -38,16 +38,6 @@ const char        *soup_get_ssl_ca_dir       (void);
 void               soup_get_ssl_cert_files   (const gchar **cert_file,
                                              const gchar **key_file);
 
-/* Authentication callback */
-
-typedef void (*SoupAuthorizeFn) (const char    *scheme_name,
-                                SoupUri       *uri,
-                                const char    *realm,
-                                gpointer       user_data);
-
-void               soup_set_authorize_callback (SoupAuthorizeFn authfn,
-                                               gpointer        user_data);
-
 /* Base64 encoding/decoding */
 
 gchar             *soup_base64_encode          (const gchar    *text,
index af8229c..32ce8da 100644 (file)
@@ -18,9 +18,6 @@
 
 extern gboolean    soup_initialized;
 
-extern SoupAuthorizeFn soup_auth_fn;
-extern gpointer        soup_auth_fn_user_data;
-
 #ifdef HAVE_IPV6
 #define soup_sockaddr_max sockaddr_in6
 #else
index a4b2b7c..570d89c 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "soup-session.h"
 #include "soup-connection.h"
+#include "soup-marshal.h"
 #include "soup-message-queue.h"
 #include "soup-private.h"
 
@@ -55,6 +56,14 @@ static gboolean run_queue (SoupSession *session, gboolean try_pruning);
 #define PARENT_TYPE G_TYPE_OBJECT
 static GObjectClass *parent_class;
 
+enum {
+       AUTHENTICATE,
+       REAUTHENTICATE,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 static void
 init (GObject *object)
 {
@@ -96,6 +105,28 @@ class_init (GObjectClass *object_class)
 
        /* virtual method override */
        object_class->finalize = finalize;
+
+       /* signals */
+       signals[AUTHENTICATE] =
+               g_signal_new ("authenticate",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             G_STRUCT_OFFSET (SoupSessionClass, authenticate),
+                             NULL, NULL,
+                             soup_marshal_NONE__POINTER_OBJECT,
+                             G_TYPE_NONE, 2,
+                             G_TYPE_POINTER,
+                             SOUP_TYPE_MESSAGE);
+       signals[REAUTHENTICATE] =
+               g_signal_new ("reauthenticate",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             G_STRUCT_OFFSET (SoupSessionClass, reauthenticate),
+                             NULL, NULL,
+                             soup_marshal_NONE__POINTER_OBJECT,
+                             G_TYPE_NONE, 2,
+                             G_TYPE_POINTER,
+                             SOUP_TYPE_MESSAGE);
 }
 
 SOUP_MAKE_TYPE (soup_session, SoupSession, class_init, init, PARENT_TYPE)
@@ -219,11 +250,6 @@ invalidate_auth (SoupSessionHost *host, SoupAuth *auth)
        char *realm;
        gpointer key, value;
 
-       /* Try to just clean up the auth without removing it. */
-       if (soup_auth_invalidate (auth))
-               return;
-
-       /* Nope, need to remove it completely */
        realm = g_strdup_printf ("%s:%s",
                                 soup_auth_get_scheme_name (auth),
                                 soup_auth_get_realm (auth));
@@ -238,28 +264,24 @@ invalidate_auth (SoupSessionHost *host, SoupAuth *auth)
 }
 
 static gboolean
-authenticate_auth (SoupAuth *auth, SoupMessage *msg)
+authenticate_auth (SoupSession *session, SoupAuth *auth,
+                  SoupMessage *msg, gboolean prior_auth_failed)
 {
        const SoupUri *uri = soup_message_get_uri (msg);
 
-       if (!uri->user && soup_auth_fn) {
-               (*soup_auth_fn) (soup_auth_get_scheme_name (auth),
-                                (SoupUri *) uri,
-                                soup_auth_get_realm (auth), 
-                                soup_auth_fn_user_data);
+       if (uri->passwd && !prior_auth_failed) {
+               soup_auth_authenticate (auth, uri->user, uri->passwd);
+               return TRUE;
        }
 
-       if (!uri->user)
-               return FALSE;
-
-       soup_auth_authenticate (auth, uri->user, uri->passwd);
-       return TRUE;
+       g_signal_emit (session, signals[prior_auth_failed ? REAUTHENTICATE : AUTHENTICATE], 0, auth, msg);
+       return soup_auth_is_authenticated (auth);
 }
 
 static gboolean
 update_auth_internal (SoupSession *session, SoupMessage *msg,
                      const GSList *headers, gboolean proxy,
-                     gboolean prior_auth_failed)
+                     gboolean got_unauthorized)
 {
        SoupSessionHost *host;
        SoupAuth *new_auth, *prior_auth, *old_auth;
@@ -268,6 +290,7 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
        const char *path;
        char *realm;
        GSList *pspace, *p;
+       gboolean prior_auth_failed = FALSE;
 
        host = get_host_for_message (session, msg);
        g_return_val_if_fail (host != NULL, FALSE);
@@ -276,7 +299,7 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
         * there's no way we'll be able to authenticate.
         */
        msg_uri = soup_message_get_uri (msg);
-       new_auth = soup_auth_new_from_header_list (headers, msg_uri->authmech);
+       new_auth = soup_auth_new_from_header_list (headers);
        if (!new_auth)
                return FALSE;
 
@@ -286,20 +309,20 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
            G_OBJECT_TYPE (prior_auth) == G_OBJECT_TYPE (new_auth) &&
            !strcmp (soup_auth_get_realm (prior_auth),
                     soup_auth_get_realm (new_auth))) {
-               g_object_unref (new_auth);
-               if (prior_auth_failed) {
-                       /* The server didn't like the username/password
-                        * we provided before.
-                        */
-                       invalidate_auth (host, prior_auth);
-                       return FALSE;
-               } else {
-                       /* The user is trying to preauthenticate using
-                        * information we already have, so there's nothing
-                        * that needs to be done.
+               if (!got_unauthorized) {
+                       /* The user is just trying to preauthenticate
+                        * using information we already have, so
+                        * there's nothing more that needs to be done.
                         */
+                       g_object_unref (new_auth);
                        return TRUE;
                }
+
+               /* The server didn't like the username/password we
+                * provided before. Invalidate it and note this fact.
+                */
+               invalidate_auth (host, prior_auth);
+               prior_auth_failed = TRUE;
        }
 
        if (!host->auth_realms) {
@@ -338,10 +361,13 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
        } else 
                g_hash_table_insert (host->auths, realm, new_auth);
 
-       /* Try to authenticate if needed. */
-       if (!soup_auth_is_authenticated (new_auth))
-               return authenticate_auth (new_auth, 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);
+       }
 
+       /* Otherwise we're good. */
        return TRUE;
 }
 
@@ -371,7 +397,6 @@ redirect_handler (SoupMessage *msg, gpointer user_data)
 {
        SoupSession *session = user_data;
        const char *new_loc;
-       const SoupUri *old_uri;
        SoupUri *new_uri;
 
        new_loc = soup_message_get_header (msg->response_headers, "Location");
@@ -381,15 +406,6 @@ redirect_handler (SoupMessage *msg, gpointer user_data)
        if (!new_uri)
                goto INVALID_REDIRECT;
 
-       old_uri = soup_message_get_uri (msg);
-
-       /* Copy auth info from original URI. */
-       if (old_uri->user && !new_uri->user)
-               soup_uri_set_auth (new_uri,
-                                  old_uri->user,
-                                  old_uri->passwd,
-                                  old_uri->authmech);
-
        soup_message_set_uri (msg, new_uri);
        soup_uri_free (new_uri);
 
@@ -436,7 +452,7 @@ add_auth (SoupSession *session, SoupMessage *msg, gboolean proxy)
        if (!auth)
                return;
        if (!soup_auth_is_authenticated (auth) &&
-           !authenticate_auth (auth, msg))
+           !authenticate_auth (session, auth, msg, FALSE))
                return;
 
        token = soup_auth_get_authorization (auth, msg);
index 3a07b29..1871ec6 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef SOUP_SESSION_H
 #define SOUP_SESSION_H 1
 
+#include <libsoup/soup-types.h>
+#include <libsoup/soup-auth.h>
 #include <libsoup/soup-message.h>
 
 #define SOUP_TYPE_SESSION            (soup_session_get_type ())
@@ -26,6 +28,10 @@ typedef struct {
 typedef struct {
        GObjectClass parent_class;
 
+       /* signals */
+       void (*authenticate)   (SoupSession *, SoupAuth *, SoupMessage *);
+       void (*reauthenticate) (SoupSession *, SoupAuth *, SoupMessage *);
+
 } SoupSessionClass;
 
 GType soup_session_get_type (void);
index faf3ef2..3d7b7ab 100644 (file)
@@ -55,7 +55,7 @@ SoupUri *
 soup_uri_new_with_base (const SoupUri *base, const char *uri_string)
 {
        SoupUri *uri;
-       const char *end, *hash, *colon, *semi, *at, *slash, *question;
+       const char *end, *hash, *colon, *at, *slash, *question;
        const char *p;
 
        uri = g_new0 (SoupUri, 1);
@@ -107,22 +107,11 @@ soup_uri_new_with_base (const SoupUri *base, const char *uri_string)
                                colon = at;
                        }
 
-                       semi = strchr (uri_string, ';');
-                       if (semi && semi < colon &&
-                           !strncasecmp (semi, ";auth=", 6)) {
-                               uri->authmech = g_strndup (semi + 6,
-                                                          colon - semi - 6);
-                               soup_uri_decode (uri->authmech);
-                       } else {
-                               uri->authmech = NULL;
-                               semi = colon;
-                       }
-
-                       uri->user = g_strndup (uri_string, semi - uri_string);
+                       uri->user = g_strndup (uri_string, colon - uri_string);
                        soup_uri_decode (uri->user);
                        uri_string = at + 1;
                } else
-                       uri->user = uri->passwd = uri->authmech = NULL;
+                       uri->user = uri->passwd = NULL;
 
                /* Find host and port. */
                colon = strchr (uri_string, ':');
@@ -159,7 +148,6 @@ soup_uri_new_with_base (const SoupUri *base, const char *uri_string)
        else if (base && !uri->protocol) {
                uri->protocol = base->protocol;
                uri->user = g_strdup (base->user);
-               uri->authmech = g_strdup (base->authmech);
                uri->passwd = g_strdup (base->passwd);
                uri->host = g_strdup (base->host);
                uri->port = base->port;
@@ -285,10 +273,6 @@ soup_uri_to_string (const SoupUri *uri, gboolean just_path)
                g_string_append (str, "//");
                if (uri->user) {
                        append_uri_encoded (str, uri->user, ":;@/");
-                       if (uri->authmech && *uri->authmech) {
-                               g_string_append (str, ";auth=");
-                               append_uri_encoded (str, uri->authmech, ":@/");
-                       }
                        g_string_append_c (str, '@');
                }
                append_uri_encoded (str, uri->host, ":/");
@@ -328,7 +312,6 @@ soup_uri_copy (const SoupUri *uri)
        dup = g_new0 (SoupUri, 1);
        dup->protocol = uri->protocol;
        dup->user     = g_strdup (uri->user);
-       dup->authmech = g_strdup (uri->authmech);
        dup->passwd   = g_strdup (uri->passwd);
        dup->host     = g_strdup (uri->host);
        dup->port     = uri->port;
@@ -370,7 +353,6 @@ soup_uri_equal (const SoupUri *u1, const SoupUri *u2)
        if (u1->protocol != u2->protocol              ||
            u1->port     != u2->port                  ||
            !parts_equal (u1->user, u2->user)         ||
-           !parts_equal (u1->authmech, u2->authmech) ||
            !parts_equal (u1->passwd, u2->passwd)     ||
            !parts_equal (u1->host, u2->host)         ||
            !parts_equal (u1->path, u2->path)         ||
@@ -387,7 +369,6 @@ soup_uri_free (SoupUri *uri)
        g_return_if_fail (uri != NULL);
 
        g_free (uri->user);
-       g_free (uri->authmech);
        g_free (uri->passwd);
        g_free (uri->host);
        g_free (uri->path);
@@ -397,23 +378,6 @@ soup_uri_free (SoupUri *uri)
        g_free (uri);
 }
 
-void
-soup_uri_set_auth  (SoupUri    *uri, 
-                   const char *user, 
-                   const char *passwd, 
-                   const char *authmech)
-{
-       g_return_if_fail (uri != NULL);
-
-       g_free (uri->user);
-       g_free (uri->passwd);
-       g_free (uri->authmech);
-
-       uri->user = g_strdup (user);
-       uri->passwd = g_strdup (passwd);
-       uri->authmech = g_strdup (authmech);
-}
-
 /* From RFC 2396 2.4.3, the characters that should always be encoded */
 static const char uri_encoded_char[] = {
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x00 - 0x0f */
index 1afe6bc..728a221 100644 (file)
@@ -19,7 +19,6 @@ struct SoupUri {
        SoupProtocol  protocol;
 
        char         *user;
-       char         *authmech;
        char         *passwd;
 
        char         *host;
@@ -46,11 +45,6 @@ gboolean  soup_uri_equal             (const SoupUri *uri1,
 
 void      soup_uri_free              (SoupUri       *uri);
 
-void      soup_uri_set_auth          (SoupUri       *uri, 
-                                     const char    *user, 
-                                     const char    *passwd, 
-                                     const char    *authmech);
-
 char     *soup_uri_encode            (const char    *part,
                                      const char    *escape_extra);
 void      soup_uri_decode            (char          *part);
index d0d91ff..a3bb480 100644 (file)
 int errors = 0;
 
 typedef struct {
+       /* Explanation of what you should see */
        const char *explanation;
+
+       /* URL to test against */
        const char *url;
+
+       /* Provided passwords, 1 character each. ('1', '2', and '3'
+        * mean the correct passwords for "realm1", "realm2", and
+        * "realm3" respectively. '4' means "use the wrong password".)
+        * The first password (if present) will be used by
+        * authenticate(), and the second (if present) will be used by
+        * reauthenticate().
+        */
+       const char *provided;
+
+       /* Expected passwords, 1 character each. (As with the provided
+        * passwords, with the addition that '0' means "no
+        * Authorization header expected".) Used to verify that soup
+        * used the password it was supposed to at each step.
+        */
        const char *expected;
-       gboolean success;
+
+       /* What the final status code should be. */
+       guint final_status;
 } SoupAuthTest;
 
 SoupAuthTest tests[] = {
        { "No auth available, should fail",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
-         "0", FALSE },
+         "", "0", SOUP_STATUS_UNAUTHORIZED },
 
        { "Should fail with no auth, fail again with bad password, and give up",
-         "http://user4:realm4@primates.ximian.com/~danw/soup-test/Basic/realm2/index.txt",
-         "04", FALSE },
+         "http://primates.ximian.com/~danw/soup-test/Basic/realm2/index.txt",
+         "4", "04", SOUP_STATUS_UNAUTHORIZED },
 
        { "Known realm, auth provided, so should succeed immediately",
-         "http://user1:realm1@primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
-         "1", TRUE },
+         "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
+         "1", "1", SOUP_STATUS_OK },
 
        { "Now should automatically reuse previous auth",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
-         "1", TRUE },
+         "", "1", SOUP_STATUS_OK },
 
        { "Subdir should also automatically reuse auth",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm1/subdir/index.txt",
-         "1", TRUE },
+         "", "1", SOUP_STATUS_OK },
 
        { "Subdir should retry last auth, but will fail this time",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/index.txt",
-         "1", FALSE },
+         "", "1", SOUP_STATUS_UNAUTHORIZED },
 
        { "Now should use provided auth on first try",
-         "http://user2:realm2@primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/index.txt",
-         "2", TRUE },
+         "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/index.txt",
+         "2", "2", SOUP_STATUS_OK },
 
        { "Reusing last auth. Should succeed on first try",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/index.txt",
-         "2", TRUE },
+         "", "2", SOUP_STATUS_OK },
 
        { "Reuse will fail, but 2nd try will succeed because it's a known realm",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/realm1/index.txt",
-         "21", TRUE },
+         "", "21", SOUP_STATUS_OK },
 
        { "Should succeed on first try. (Known realm with cached password)",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm2/index.txt",
-         "2", TRUE },
+         "", "2", SOUP_STATUS_OK },
 
-       { "Fail once, then use password",
-         "http://user3:realm3@primates.ximian.com/~danw/soup-test/Basic/realm3/index.txt",
-         "03", TRUE },
+       { "Fail once, then use typoed password, then use right password",
+         "http://primates.ximian.com/~danw/soup-test/Basic/realm3/index.txt",
+         "43", "043", SOUP_STATUS_OK },
 
 
        { "No auth available, should fail",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
-         "0", FALSE },
+         "", "0", SOUP_STATUS_UNAUTHORIZED },
 
        { "Should fail with no auth, fail again with bad password, and give up",
-         "http://user4:realm4@primates.ximian.com/~danw/soup-test/Digest/realm2/index.txt",
-         "04", FALSE },
+         "http://primates.ximian.com/~danw/soup-test/Digest/realm2/index.txt",
+         "4", "04", SOUP_STATUS_UNAUTHORIZED },
 
        { "Known realm, auth provided, so should succeed immediately",
-         "http://user1:realm1@primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
-         "1", TRUE },
+         "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
+         "1", "1", SOUP_STATUS_OK },
 
        { "Now should automatically reuse previous auth",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
-         "1", TRUE },
+         "", "1", SOUP_STATUS_OK },
 
        { "Subdir should also automatically reuse auth",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm1/subdir/index.txt",
-         "1", TRUE },
+         "", "1", SOUP_STATUS_OK },
 
        { "Subdir should retry last auth, but will fail this time",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/index.txt",
-         "1", FALSE },
+         "", "1", SOUP_STATUS_UNAUTHORIZED },
 
        { "Now should use provided auth on first try",
-         "http://user2:realm2@primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/index.txt",
-         "2", TRUE },
+         "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/index.txt",
+         "2", "2", SOUP_STATUS_OK },
 
        { "Reusing last auth. Should succeed on first try",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/index.txt",
-         "2", TRUE },
+         "", "2", SOUP_STATUS_OK },
 
        { "Should succeed on first try because of earlier domain directive",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/realm1/index.txt",
-         "1", TRUE },
+         "", "1", SOUP_STATUS_OK },
 
        { "Should succeed on first try. (Known realm with cached password)",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm2/index.txt",
-         "2", TRUE },
+         "", "2", SOUP_STATUS_OK },
 
-       { "Fail once, then use password",
-         "http://user3:realm3@primates.ximian.com/~danw/soup-test/Digest/realm3/index.txt",
-         "03", TRUE },
+       { "Fail once, then use typoed password, then use right password",
+         "http://primates.ximian.com/~danw/soup-test/Digest/realm3/index.txt",
+         "43", "043", SOUP_STATUS_OK },
 
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
-         "1", TRUE },
+         "", "1", SOUP_STATUS_OK },
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/index.txt",
-         "2", TRUE },
+         "", "2", SOUP_STATUS_OK },
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/realm1/index.txt",
-         "1", TRUE },
+         "", "1", SOUP_STATUS_OK },
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm2/index.txt",
-         "2", TRUE },
+         "", "2", SOUP_STATUS_OK },
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Basic/realm3/index.txt",
-         "3", TRUE },
+         "", "3", SOUP_STATUS_OK },
 
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
-         "1", TRUE },
+         "", "1", SOUP_STATUS_OK },
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/index.txt",
-         "2", TRUE },
+         "", "2", SOUP_STATUS_OK },
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/realm1/index.txt",
-         "1", TRUE },
+         "", "1", SOUP_STATUS_OK },
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm2/index.txt",
-         "2", TRUE },
+         "", "2", SOUP_STATUS_OK },
 
        { "Make sure we haven't forgotten anything",
          "http://primates.ximian.com/~danw/soup-test/Digest/realm3/index.txt",
-         "3", TRUE }
+         "", "3", SOUP_STATUS_OK },
+
+       { "Now the server will reject the formerly-good password",
+         "http://primates.ximian.com/~danw/soup-test/Basic/realm1/not/index.txt",
+         "1" /* should not be used */, "1", SOUP_STATUS_UNAUTHORIZED },
+
+       { "Make sure we've forgotten it",
+         "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
+         "", "0", SOUP_STATUS_UNAUTHORIZED },
+
+       { "Likewise, reject the formerly-good Digest password",
+         "http://primates.ximian.com/~danw/soup-test/Digest/realm1/not/index.txt",
+         "1" /* should not be used */, "1", SOUP_STATUS_UNAUTHORIZED },
+
+       { "Make sure we've forgotten it",
+         "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
+         "", "0", SOUP_STATUS_UNAUTHORIZED }
 };
 int ntests = sizeof (tests) / sizeof (tests[0]);
 
@@ -184,6 +220,8 @@ identify_auth (SoupMessage *msg)
                        num = 0;
        }
 
+       g_assert (num >= 0 && num <= 4);
+
        return num;
 }
 
@@ -211,6 +249,32 @@ handler (SoupMessage *msg, gpointer data)
        }
 }
 
+static void
+authenticate (SoupSession *session, SoupAuth *auth, SoupMessage *msg, gpointer data)
+{
+       char user[6], password[7];
+       int *i = data;
+
+       if (tests[*i].provided[0]) {
+               sprintf (user, "user%c", tests[*i].provided[0]);
+               sprintf (password, "realm%c", tests[*i].provided[0]);
+               soup_auth_authenticate (auth, user, password);
+       }
+}
+
+static void
+reauthenticate (SoupSession *session, SoupAuth *auth, SoupMessage *msg, gpointer data)
+{
+       char user[6], password[7];
+       int *i = data;
+
+       if (tests[*i].provided[0] && tests[*i].provided[1]) {
+               sprintf (user, "user%c", tests[*i].provided[1]);
+               sprintf (password, "realm%c", tests[*i].provided[1]);
+               soup_auth_authenticate (auth, user, password);
+       }
+}
+
 int
 main (int argc, char **argv)
 {
@@ -220,7 +284,12 @@ main (int argc, char **argv)
        int i;
 
        g_type_init ();
+
        session = soup_session_new_default ();
+       g_signal_connect (session, "authenticate",
+                         G_CALLBACK (authenticate), &i);
+       g_signal_connect (session, "reauthenticate",
+                         G_CALLBACK (reauthenticate), &i);
 
        for (i = 0; i < ntests; i++) {
                printf ("Test %d: %s\n", i + 1, tests[i].explanation);
@@ -245,6 +314,7 @@ main (int argc, char **argv)
                    msg->status_code != SOUP_STATUS_OK) {
                        printf ("  %d %s !\n", msg->status_code,
                                msg->reason_phrase);
+                       errors++;
                }
                if (*expected) {
                        printf ("  expected %d more round(s)\n",
@@ -253,12 +323,8 @@ main (int argc, char **argv)
                }
                g_free (expected);
 
-               if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) !=
-                   tests[i].success) {
-                       printf ("  expected %s\n",
-                               tests[i].success ? "success" : "failure");
-                       errors++;
-               }
+               if (msg->status_code != tests[i].final_status)
+                       printf ("  expected %d\n", tests[i].final_status);
 
                printf ("\n");