summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Tytgat <joty@netsurf-browser.org>2009-08-04 23:02:23 +0000
committerJohn Tytgat <joty@netsurf-browser.org>2009-08-04 23:02:23 +0000
commit2261b616f61e6701b381d6e363e14431f321f843 (patch)
treef80512b595b5a9dbc84e25102270b23a724bd103
parent83acae8e1f41b59e32700944b996ae1e4509c07b (diff)
downloadnetsurf-2261b616f61e6701b381d6e363e14431f321f843.tar.gz
netsurf-2261b616f61e6701b381d6e363e14431f321f843.tar.bz2
- content/urldb.c(auth_data): Removed;
(prot_space_data): Added, it lives linked in the leaf host_part struct and together with its scheme and port (which defins canonical root url) and realm this defines a protection space. (path_data): Removed auth_data field and replaced by a prot_space_data pointer. (host_part::prot_space): Added linked list of protection space data structs. (urldb_get_auth_details): Given an URL fetch fetches its auth. (urldb_set_auth_details): Creates or updates the contents of a protection space to which given URL belongs. (urldb_destroy_host_tree): Delete protection data space structures using urldb_destroy_prot_space. (urldb_destroy_prot_space): Added. - content/urldb.h(urldb_get_auth_details): Added realm parameter. - content/fetchers/fetch_curl.c(fetch_curl_set_options): Update urldb_get_auth_details call (we don't know realm at this point). - content/fetchcache.c(fetchcache_callback, fetchcache_auth): At FETCH_AUTH, use realm to determine if we really don't know auth data and if so, refetch content. - content/content.h(struct content): Add content::tried_with_auth. - content/content.c(content_create): Initialize content::tried_with_auth. - riscos/401login.c(ro_gui_401login_open): Show known authentication data in dialogue so user can see what was wrong with it and correct it. Solves bug #2830829. svn path=/trunk/netsurf/; revision=9045
-rw-r--r--content/content.c1
-rw-r--r--content/content.h1
-rw-r--r--content/fetchcache.c98
-rw-r--r--content/fetchers/fetch_curl.c2
-rw-r--r--content/urldb.c183
-rw-r--r--content/urldb.h2
-rw-r--r--riscos/401login.c25
7 files changed, 241 insertions, 71 deletions
diff --git a/content/content.c b/content/content.c
index 2b4499a29..828423603 100644
--- a/content/content.c
+++ b/content/content.c
@@ -443,6 +443,7 @@ struct content * content_create(const char *url)
c->http_code = 0;
c->no_error_pages = false;
c->download = false;
+ c->tried_with_auth = false;
c->redirect_count = 0;
c->error_count = 0;
c->cache_data.req_time = 0;
diff --git a/content/content.h b/content/content.h
index 1db6122ee..db35b39a2 100644
--- a/content/content.h
+++ b/content/content.h
@@ -259,6 +259,7 @@ struct content {
bool no_error_pages; /**< Used by fetchcache(). */
bool download; /**< Used by fetchcache(). */
+ bool tried_with_auth; /**< Used by fetchcache(). */
unsigned int redirect_count; /**< Used by fetchcache(). */
/** Array of first n rendering errors or warnings. */
diff --git a/content/fetchcache.c b/content/fetchcache.c
index 71e39e4fa..3c43e1f60 100644
--- a/content/fetchcache.c
+++ b/content/fetchcache.c
@@ -1,5 +1,6 @@
/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -37,6 +38,7 @@
#include "content/content.h"
#include "content/fetchcache.h"
#include "content/fetch.h"
+#include "content/urldb.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/talloc.h"
@@ -58,6 +60,7 @@ static void fetchcache_cache_clone(struct content *c,
static void fetchcache_notmodified(struct content *c, const void *data);
static void fetchcache_redirect(struct content *c, const void *data,
unsigned long size);
+static void fetchcache_auth(struct content *c, const char *realm);
/**
@@ -516,14 +519,7 @@ void fetchcache_callback(fetch_msg msg, void *p, const void *data,
break;
case FETCH_AUTH:
- /* data -> string containing the Realm */
- LOG(("FETCH_AUTH, '%s'", (const char *)data));
- c->fetch = 0;
- msg_data.auth_realm = data;
- content_broadcast(c, CONTENT_MSG_AUTH, msg_data);
- /* set the status to ERROR so that the content is
- * destroyed in content_clean() */
- c->status = CONTENT_STATUS_ERROR;
+ fetchcache_auth(c, data);
break;
case FETCH_CERT_ERR:
@@ -1136,6 +1132,92 @@ void fetchcache_redirect(struct content *c, const void *data,
free(referer);
}
+/**
+ * Authentication callback handler
+ */
+
+void fetchcache_auth(struct content *c, const char *realm)
+{
+ char *referer;
+ const char *ref;
+ const char *auth;
+ struct content *parent;
+ bool parent_was_verifiable;
+ union content_msg_data msg_data;
+ char *headers = NULL;
+
+ /* Preconditions */
+ assert(c && realm);
+ assert(c->status == CONTENT_STATUS_TYPE_UNKNOWN);
+
+ /* Extract fetch details */
+ ref = fetch_get_referer(c->fetch);
+ parent = fetch_get_parent(c->fetch);
+ parent_was_verifiable = fetch_get_verifiable(c->fetch);
+
+ /* Clone referer -- original is destroyed in fetch_abort() */
+ referer = ref ? strdup(ref) : NULL;
+
+ fetch_abort(c->fetch);
+ c->fetch = NULL;
+
+ /* Ensure that referer cloning succeeded
+ * _must_ be after content invalidation */
+ if (ref && !referer) {
+ LOG(("Failed cloning referer"));
+
+ c->status = CONTENT_STATUS_ERROR;
+ msg_data.error = messages_get("BadRedirect");
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+
+ return;
+ }
+
+ /* Now, see if we've got some auth details */
+ auth = urldb_get_auth_details(c->url, realm);
+
+ if (auth == NULL || c->tried_with_auth) {
+ /* No authentication details or we tried what we had, so ask
+ * our client for them. */
+ c->tried_with_auth = false; /* Allow rety. */
+
+ c->status = CONTENT_STATUS_ERROR;
+ msg_data.auth_realm = realm;
+ content_broadcast(c, CONTENT_MSG_AUTH, msg_data);
+
+ return;
+ }
+ /* Flag we're retry fetching with auth data. Will be used to detect
+ * wrong auth data so that we can ask our client for better auth. */
+ c->tried_with_auth = true;
+
+ /* We have authentication details. Fetch with them. */
+ /** \todo all the useful things like headers, POST. */
+ c->fetch = fetch_start(c->url, referer,
+ fetchcache_callback, c,
+ c->no_error_pages,
+ NULL, NULL, parent_was_verifiable,
+ parent, &headers);
+ if (c->fetch == NULL) {
+ char error_message[500];
+
+ LOG(("warning: fetch_start failed"));
+ snprintf(error_message, sizeof error_message,
+ messages_get("InvalidURL"),
+ c->url);
+ if (c->no_error_pages) {
+ c->status = CONTENT_STATUS_ERROR;
+ msg_data.error = error_message;
+ content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ } else {
+ fetchcache_error_page(c, error_message);
+ }
+ }
+
+ /* Clean up */
+ free(referer);
+}
+
#ifdef TEST
#include <unistd.h>
diff --git a/content/fetchers/fetch_curl.c b/content/fetchers/fetch_curl.c
index 33425a352..8efe0d726 100644
--- a/content/fetchers/fetch_curl.c
+++ b/content/fetchers/fetch_curl.c
@@ -560,7 +560,7 @@ fetch_curl_set_options(struct curl_fetch_info *f)
SETOPT(CURLOPT_COOKIE, NULL);
}
- if ((auth = urldb_get_auth_details(f->url)) != NULL) {
+ if ((auth = urldb_get_auth_details(f->url, NULL)) != NULL) {
SETOPT(CURLOPT_HTTPAUTH, CURLAUTH_ANY);
SETOPT(CURLOPT_USERPWD, auth);
} else {
diff --git a/content/urldb.c b/content/urldb.c
index 497a7ca8b..8089e0d4e 100644
--- a/content/urldb.c
+++ b/content/urldb.c
@@ -1,5 +1,6 @@
/*
* Copyright 2006 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2009 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -132,10 +133,22 @@ struct cookie_internal_data {
struct cookie_internal_data *next; /**< Next in list */
};
-struct auth_data {
+/* A protection space is defined as a tuple canonical_root_url and realm.
+ * This structure lives as linked list element in a leaf host_part struct
+ * so we need additional scheme and port to have a canonical_root_url. */
+struct prot_space_data {
+ char *scheme; /**< URL scheme of canonical hostname of this
+ * protection space. */
+ unsigned int port; /**< Port number of canonical hostname of this
+ * protection space. When 0, it means the
+ * default port for given scheme, i.e. 80
+ * (http), 443 (https). */
char *realm; /**< Protection realm */
- char *auth; /**< Authentication details in form
+
+ char *auth; /**< Authentication details for this
+ * protection space in form
* username:password */
+ struct prot_space_data *next; /**< Next sibling */
};
struct cache_internal_data {
@@ -152,7 +165,9 @@ struct url_internal_data {
struct path_data {
char *url; /**< Full URL */
char *scheme; /**< URL scheme for data */
- unsigned int port; /**< Port number for data */
+ unsigned int port; /**< Port number for data. When 0, it means
+ * the default port for given scheme, i.e.
+ * 80 (http), 443 (https). */
char *segment; /**< Path segment for this node */
unsigned int frag_cnt; /**< Number of entries in ::fragment */
char **fragment; /**< Array of fragments */
@@ -161,7 +176,11 @@ struct path_data {
struct bitmap *thumb; /**< Thumbnail image of resource */
struct url_internal_data urld; /**< URL data for resource */
struct cache_internal_data cache; /**< Cache data for resource */
- struct auth_data auth; /**< Authentication data for resource */
+ const struct prot_space_data *prot_space; /**< Protection space
+ * to which this resource belongs too. Can be
+ * NULL when it does not belong to a protection
+ * space or when it is not known. No
+ * ownership (is with struct host_part::prot_space). */
struct cookie_internal_data *cookies; /**< Cookies associated with resource */
struct cookie_internal_data *cookies_end; /**< Last cookie in list */
@@ -183,6 +202,10 @@ struct host_part {
char *part; /**< Part of host string */
+ struct prot_space_data *prot_space; /**< Linked list of all known
+ * proctection spaces known for his host and
+ * all its schems and ports. */
+
struct host_part *next; /**< Next sibling */
struct host_part *prev; /**< Previous sibling */
struct host_part *parent; /**< Parent host part */
@@ -203,6 +226,7 @@ static void urldb_destroy_host_tree(struct host_part *root);
static void urldb_destroy_path_tree(struct path_data *root);
static void urldb_destroy_path_node_content(struct path_data *node);
static void urldb_destroy_cookie(struct cookie_internal_data *c);
+static void urldb_destroy_prot_space(struct prot_space_data *space);
static void urldb_destroy_search_tree(struct search_node *root);
/* Saving */
@@ -925,11 +949,13 @@ const char *urldb_get_url(const char *url)
* Look up authentication details in database
*
* \param url Absolute URL to search for
+ * \param realm When non-NULL, it is realm which can be used to determine
+ * the protection space when that's not been done before for given URL.
* \return Pointer to authentication details, or NULL if not found
*/
-const char *urldb_get_auth_details(const char *url)
+const char *urldb_get_auth_details(const char *url, const char *realm)
{
- struct path_data *p, *q = NULL;
+ struct path_data *p, *p_cur, *p_top;
assert(url);
@@ -940,29 +966,33 @@ const char *urldb_get_auth_details(const char *url)
if (!p)
return NULL;
- /* Check for any auth details attached to this node */
- if (p && p->auth.realm && p->auth.auth)
- return p->auth.auth;
-
- /* Now consider ancestors */
- for (; p; p = p->parent) {
- /* The parent path entry is stored hung off the
- * parent entry with an empty (not NULL) segment string.
- * We look for this here.
- */
- for (q = p->children; q; q = q->next) {
- if (q->segment[0] == '\0')
- break;
+ /* Check for any auth details attached to the path_data node or any of
+ * its parents. */
+ for (p_cur = p; p_cur != NULL; p_top = p_cur, p_cur = p_cur->parent) {
+ if (p_cur->prot_space) {
+ return p_cur->prot_space->auth;
}
-
- if (q && q->auth.realm && q->auth.auth)
- break;
}
- if (!q)
- return NULL;
+ /* Only when we have a realm (and canonical root of given URL), we can
+ * uniquely locate the protection space. */
+ if (realm != NULL) {
+ const struct host_part *h = (const struct host_part *)p_top;
+ const struct prot_space_data *space;
+
+ /* Search for a possible matching protection space. */
+ for (space = h->prot_space; space != NULL;
+ space = space->next) {
+ if (!strcmp(space->realm, realm)
+ && !strcmp(space->scheme, p->scheme)
+ && space->port == p->port) {
+ p->prot_space = space;
+ return p->prot_space->auth;
+ }
+ }
+ }
- return q->auth.auth;
+ return NULL;
}
/**
@@ -975,7 +1005,7 @@ const char *urldb_get_auth_details(const char *url)
bool urldb_get_cert_permissions(const char *url)
{
struct path_data *p;
- struct host_part *h;
+ const struct host_part *h;
assert(url);
@@ -985,8 +1015,9 @@ bool urldb_get_cert_permissions(const char *url)
for (; p && p->parent; p = p->parent)
/* do nothing */;
+ assert(p);
- h = (struct host_part *)p;
+ h = (const struct host_part *)p;
return h->permit_invalid_certs;
}
@@ -1001,48 +1032,63 @@ bool urldb_get_cert_permissions(const char *url)
void urldb_set_auth_details(const char *url, const char *realm,
const char *auth)
{
- struct path_data *p;
- char *urlt, *t1, *t2;
+ struct path_data *p, *pi;
+ struct host_part *h;
+ struct prot_space_data *space, *space_alloc;
+ char *realm_alloc, *auth_alloc, *scheme_alloc;
assert(url && realm && auth);
- urlt = strdup(url);
- if (!urlt)
- return;
-
- /* strip leafname from URL */
- t1 = strrchr(urlt, '/');
- if (t1) {
- *(t1 + 1) = '\0';
- }
-
/* add url, in case it's missing */
- urldb_add_url(urlt);
-
- p = urldb_find_url(urlt);
+ urldb_add_url(url);
- free(urlt);
+ p = urldb_find_url(url);
if (!p)
return;
- /** \todo search subtree for same realm/auth details
- * and remove them (as the lookup routine searches up the tree) */
-
- t1 = strdup(realm);
- t2 = strdup(auth);
+ /* Search for host_part */
+ for (pi = p; pi->parent != NULL; pi = pi->parent)
+ ;
+ h = (struct host_part *)pi;
- if (!t1 || !t2) {
- free(t1);
- free(t2);
- return;
+ /* Search if given URL belongs to a protection space we already know of. */
+ for (space = h->prot_space; space; space = space->next) {
+ if (!strcmp(space->realm, realm)
+ && !strcmp(space->scheme, p->scheme)
+ && space->port == p->port)
+ break;
}
- free(p->auth.realm);
- free(p->auth.auth);
+ if (space != NULL) {
+ /* Overrule existing auth. */
+ free(space->auth);
+ space->auth = strdup(auth);
+ } else {
+ /* Create a new protection space. */
+ space = space_alloc = malloc(sizeof(struct prot_space_data));
+ scheme_alloc = strdup(p->scheme);
+ realm_alloc = strdup(realm);
+ auth_alloc = strdup(auth);
+
+ if (!space_alloc || !scheme_alloc
+ || !realm_alloc || !auth_alloc) {
+ free(space_alloc);
+ free(scheme_alloc);
+ free(realm_alloc);
+ free(auth_alloc);
+ return;
+ }
- p->auth.realm = t1;
- p->auth.auth = t2;
+ space->scheme = scheme_alloc;
+ space->port = p->port;
+ space->realm = realm_alloc;
+ space->auth = auth_alloc;
+ space->next = h->prot_space;
+ h->prot_space = space;
+ }
+
+ p->prot_space = space;
}
/**
@@ -1067,6 +1113,7 @@ void urldb_set_cert_permissions(const char *url, bool permit)
for (; p && p->parent; p = p->parent)
/* do nothing */;
+ assert(p);
h = (struct host_part *)p;
@@ -3878,6 +3925,7 @@ void urldb_destroy_host_tree(struct host_part *root)
{
struct host_part *a, *b;
struct path_data *p, *q;
+ struct prot_space_data *s, *t;
/* Destroy children */
for (a = root->children; a; a = b) {
@@ -3894,6 +3942,12 @@ void urldb_destroy_host_tree(struct host_part *root)
/* Root path */
urldb_destroy_path_node_content(&root->paths);
+ /* Proctection space data */
+ for (s = root->prot_space; s; s = t) {
+ t = s->next;
+ urldb_destroy_prot_space(s);
+ }
+
/* And ourselves */
free(root->part);
free(root);
@@ -3955,8 +4009,6 @@ void urldb_destroy_path_node_content(struct path_data *node)
bitmap_destroy(node->thumb);
free(node->urld.title);
- free(node->auth.realm);
- free(node->auth.auth);
for (a = node->cookies; a; a = b) {
b = a->next;
@@ -3981,6 +4033,21 @@ void urldb_destroy_cookie(struct cookie_internal_data *c)
}
/**
+ * Destroy protection space data
+ *
+ * \param space Protection space to destroy
+ */
+void urldb_destroy_prot_space(struct prot_space_data *space)
+{
+ free(space->scheme);
+ free(space->realm);
+ free(space->auth);
+
+ free(space);
+}
+
+
+/**
* Destroy a search tree
*
* \param root Root node of tree to destroy
diff --git a/content/urldb.h b/content/urldb.h
index 0e655dbe1..f31409c41 100644
--- a/content/urldb.h
+++ b/content/urldb.h
@@ -85,7 +85,7 @@ const char *urldb_get_url(const char *url);
/* Authentication modification / lookup */
void urldb_set_auth_details(const char *url, const char *realm,
const char *auth);
-const char *urldb_get_auth_details(const char *url);
+const char *urldb_get_auth_details(const char *url, const char *realm);
/* SSL certificate permissions */
void urldb_set_cert_permissions(const char *url, bool permit);
diff --git a/riscos/401login.c b/riscos/401login.c
index ac3ebe35c..e75fe022c 100644
--- a/riscos/401login.c
+++ b/riscos/401login.c
@@ -98,6 +98,7 @@ void ro_gui_401login_open(struct browser_window *bw, const char *host,
{
struct session_401 *session;
wimp_w w;
+ const char *auth;
session = calloc(1, sizeof(struct session_401));
if (!session) {
@@ -111,10 +112,28 @@ void ro_gui_401login_open(struct browser_window *bw, const char *host,
warn_user("NoMemory", 0);
return;
}
- session->uname[0] = '\0';
- session->pwd[0] = '\0';
+ if (realm == NULL)
+ realm = "Secure Area";
+ auth = urldb_get_auth_details(session->url, realm);
+ if (auth == NULL) {
+ session->uname[0] = '\0';
+ session->pwd[0] = '\0';
+ } else {
+ const char *pwd;
+ size_t pwd_len;
+
+ pwd = strchr(auth, ':');
+ assert(pwd && pwd < auth + sizeof(session->uname));
+ memcpy(session->uname, auth, pwd - auth);
+ session->uname[pwd - auth] = '\0';
+ ++pwd;
+ pwd_len = strlen(pwd);
+ assert(pwd_len < sizeof(session->pwd));
+ memcpy(session->pwd, pwd, pwd_len);
+ session->pwd[pwd_len] = '\0';
+ }
session->host = strdup(host);
- session->realm = strdup(realm ? realm : "Secure Area");
+ session->realm = strdup(realm);
session->bwin = bw;
if ((!session->host) || (!session->realm)) {
free(session->host);