summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2019-08-06 11:25:11 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2019-08-06 11:26:47 +0100
commit8469f4cc8e62e80a3165a1d4f13b62b5b4a04720 (patch)
tree707b46c3cf0b373b53adf8c54d290e4c546ebb2c
parent9c9c26a308995c22210c90e3772e86f49a1948b9 (diff)
downloadnetsurf-8469f4cc8e62e80a3165a1d4f13b62b5b4a04720.tar.gz
netsurf-8469f4cc8e62e80a3165a1d4f13b62b5b4a04720.tar.bz2
Reimplement handling of BAD_AUTH inside browser_window
We now handle authentication requests via an `about:` page which presents a nice form built into the browser window. In order to do this, we add internal navigation as a concept to the browser window and we strip the 401login support from all frontends except monkey. The 401login callback is now intended for password safe type support rather than an immediately interactive prompt. Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
-rw-r--r--content/fetch.c54
-rw-r--r--content/fetch.h24
-rw-r--r--content/llcache.c2
-rw-r--r--desktop/browser_private.h2
-rw-r--r--desktop/browser_window.c491
-rw-r--r--desktop/gui_factory.c14
-rw-r--r--desktop/netsurf.c200
-rw-r--r--frontends/amiga/gui.c1
-rw-r--r--frontends/atari/gui.c1
-rw-r--r--frontends/beos/gui.cpp2
-rw-r--r--frontends/gtk/gui.c1
-rw-r--r--frontends/monkey/401login.c20
-rw-r--r--frontends/monkey/401login.h4
-rw-r--r--frontends/riscos/gui.c1
-rw-r--r--frontends/windows/main.c1
-rw-r--r--include/netsurf/browser_window.h5
-rw-r--r--include/netsurf/misc.h34
-rw-r--r--utils/corestringlist.h1
18 files changed, 568 insertions, 290 deletions
diff --git a/content/fetch.c b/content/fetch.c
index 766502941..2ac86a812 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -712,6 +712,23 @@ fetch_multipart_data_clone(const struct fetch_multipart_data *list)
return result;
}
+
+/* exported interface documented in content/fetch.h */
+const char *
+fetch_multipart_data_find(const struct fetch_multipart_data *list,
+ const char *name)
+{
+ while (list != NULL) {
+ if (strcmp(list->name, name) == 0) {
+ return list->value;
+ }
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+
/* exported interface documented in content/fetch.h */
void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
{
@@ -730,6 +747,43 @@ void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
}
}
+
+/* exported interface documented in content/fetch.h */
+nserror
+fetch_multipart_data_new_kv(struct fetch_multipart_data **list,
+ const char *name,
+ const char *value)
+{
+ struct fetch_multipart_data *newdata;
+
+ assert(list);
+
+ newdata = calloc(sizeof(*newdata), 1);
+
+ if (newdata == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ newdata->name = strdup(name);
+ if (newdata->name == NULL) {
+ free(newdata);
+ return NSERROR_NOMEM;
+ }
+
+ newdata->value = strdup(value);
+ if (newdata->value == NULL) {
+ free(newdata->name);
+ free(newdata);
+ return NSERROR_NOMEM;
+ }
+
+ newdata->next = *list;
+ *list = newdata;
+
+ return NSERROR_OK;
+}
+
+
/* exported interface documented in content/fetch.h */
void
fetch_send_callback(const fetch_msg *msg, struct fetch *fetch)
diff --git a/content/fetch.h b/content/fetch.h
index 174e07bf6..7c02fb0d7 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -185,6 +185,30 @@ void fetch_multipart_data_destroy(struct fetch_multipart_data *list);
struct fetch_multipart_data *fetch_multipart_data_clone(const struct fetch_multipart_data *list);
/**
+ * Find an entry in a fetch_multipart_data
+ *
+ * \param list Pointer to the multipart list
+ * \param name The name to look for in the list
+ * \return The value found, or NULL if not present
+ */
+const char *fetch_multipart_data_find(const struct fetch_multipart_data *list,
+ const char *name);
+
+/**
+ * Create an entry for a fetch_multipart_data
+ *
+ * If an entry exists of the same name, it will *NOT* be overwritten
+ *
+ * \param list Pointer to the pointer to the current multipart list
+ * \param name The name of the entry to create
+ * \param value The value of the entry to create
+ * \return The result of the attempt
+ */
+nserror fetch_multipart_data_new_kv(struct fetch_multipart_data **list,
+ const char *name,
+ const char *value);
+
+/**
* send message to fetch
*/
void fetch_send_callback(const fetch_msg *msg, struct fetch *fetch);
diff --git a/content/llcache.c b/content/llcache.c
index 07533f15e..f209fabf0 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -2290,7 +2290,7 @@ static nserror llcache_fetch_auth(llcache_object *object, const char *realm)
event.type = LLCACHE_EVENT_ERROR;
/** \todo More appropriate error message */
event.data.error.code = NSERROR_BAD_AUTH;
- event.data.error.msg = messages_get("FetchFailed");
+ event.data.error.msg = realm;
error = llcache_send_event_to_users(object, &event);
} else {
diff --git a/desktop/browser_private.h b/desktop/browser_private.h
index 8838436fb..0995561f6 100644
--- a/desktop/browser_private.h
+++ b/desktop/browser_private.h
@@ -167,6 +167,8 @@ struct browser_window {
bool throbbing;
/** Add loading_content to the window history when it loads. */
bool history_add;
+ /** Internal navigation, do not update URL etc */
+ bool internal_nav;
/** Fragment identifier for current_content. */
lwc_string *frag_id;
diff --git a/desktop/browser_window.c b/desktop/browser_window.c
index 78f1cc2fd..911d7abde 100644
--- a/desktop/browser_window.c
+++ b/desktop/browser_window.c
@@ -92,6 +92,33 @@ static nserror browser_window__navigate_internal(
/**
+ * Close and destroy all child browser window.
+ *
+ * \param bw browser window
+ */
+static void browser_window_destroy_children(struct browser_window *bw)
+{
+ int i;
+
+ if (bw->children) {
+ for (i = 0; i < (bw->rows * bw->cols); i++)
+ browser_window_destroy_internal(&bw->children[i]);
+ free(bw->children);
+ bw->children = NULL;
+ bw->rows = 0;
+ bw->cols = 0;
+ }
+ if (bw->iframes) {
+ for (i = 0; i < bw->iframe_count; i++)
+ browser_window_destroy_internal(&bw->iframes[i]);
+ free(bw->iframes);
+ bw->iframes = NULL;
+ bw->iframe_count = 0;
+ }
+}
+
+
+/**
* Free the stored fetch parameters
*
* \param bw The browser window
@@ -679,14 +706,16 @@ static nserror browser_window_content_ready(struct browser_window *bw)
bw->current_content = bw->loading_content;
bw->loading_content = NULL;
- /* Transfer the fetch parameters */
- browser_window__free_fetch_parameters(&bw->current_parameters);
- bw->current_parameters = bw->loading_parameters;
- memset(&bw->loading_parameters, 0, sizeof(bw->loading_parameters));
+ if (!bw->internal_nav) {
+ /* Transfer the fetch parameters */
+ browser_window__free_fetch_parameters(&bw->current_parameters);
+ bw->current_parameters = bw->loading_parameters;
+ memset(&bw->loading_parameters, 0, sizeof(bw->loading_parameters));
+ /* Transfer the SSL info */
+ bw->current_ssl_info = bw->loading_ssl_info;
+ bw->loading_ssl_info.num = 0;
+ }
- /* Transfer the SSL info */
- bw->current_ssl_info = bw->loading_ssl_info;
- bw->loading_ssl_info.num = 0;
/* Format the new content to the correct dimensions */
browser_window_get_dimensions(bw, &width, &height);
@@ -800,7 +829,9 @@ browser_window_content_done(struct browser_window *bw)
}
browser_window_history_update(bw, bw->current_content);
- hotlist_update_url(hlcache_handle_get_url(bw->current_content));
+ if (!bw->internal_nav) {
+ hotlist_update_url(hlcache_handle_get_url(bw->current_content));
+ }
if (bw->refresh_interval != -1) {
guit->misc->schedule(bw->refresh_interval * 10,
@@ -810,12 +841,8 @@ browser_window_content_done(struct browser_window *bw)
return NSERROR_OK;
}
-/* Cheeky import for now */
-nserror netsurf__handle_login(const char * realm, nsurl *url,
- browser_window_query_callback cb, void *cbpw);
-
/**
- * Handle query responses from authentication or SSL requests
+ * Handle query responses from SSL requests
*/
static nserror
browser_window__handle_query_response(bool proceed, void *pw)
@@ -837,6 +864,215 @@ browser_window__handle_query_response(bool proceed, void *pw)
return res;
}
+/**
+ * Unpack a "username:password" to components.
+ *
+ * \param[in] userpass The input string to split.
+ * \param[in] username_out Returns username on success. Owned by caller.
+ * \param[out] password_out Returns password on success. Owned by caller.
+ * \return NSERROR_OK, or appropriate error code.
+ */
+static nserror
+browser_window__unpack_userpass(const char *userpass,
+ char **username_out,
+ char **password_out)
+{
+ const char *tmp;
+ char *username;
+ char *password;
+ size_t len;
+
+ if (userpass == NULL) {
+ username = malloc(1);
+ password = malloc(1);
+ if (username == NULL || password == NULL) {
+ free(username);
+ free(password);
+ return NSERROR_NOMEM;
+ }
+ username[0] = '\0';
+ password[0] = '\0';
+
+ *username_out = username;
+ *password_out = password;
+ return NSERROR_OK;
+ }
+
+ tmp = strchr(userpass, ':');
+ if (tmp == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ } else {
+ size_t len2;
+ len = tmp - userpass;
+ len2 = strlen(++tmp);
+
+ username = malloc(len + 1);
+ password = malloc(len2 + 1);
+ if (username == NULL || password == NULL) {
+ free(username);
+ free(password);
+ return NSERROR_NOMEM;
+ }
+ memcpy(username, userpass, len);
+ username[len] = '\0';
+ memcpy(password, tmp, len2 + 1);
+ }
+
+ *username_out = username;
+ *password_out = password;
+ return NSERROR_OK;
+}
+
+/**
+ * Build a "username:password" from components.
+ *
+ * \param[in] username The username component.
+ * \param[in] password The password component.
+ * \param[out] userpass_out Returns combined string on success.
+ * Owned by caller.
+ * \return NSERROR_OK, or appropriate error code.
+ */
+static nserror
+browser_window__build_userpass(const char *username,
+ const char *password,
+ char **userpass_out)
+{
+ char *userpass;
+ size_t len;
+
+ len = strlen(username) + 1 + strlen(password) + 1;
+
+ userpass = malloc(len);
+ if (userpass == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(userpass, len, "%s:%s", username, password);
+
+ *userpass_out = userpass;
+ return NSERROR_OK;
+}
+
+/**
+ * Handle a response from the UI when prompted for credentials
+ */
+static nserror
+browser_window__handle_userpass_response(nsurl *url,
+ const char *realm,
+ const char *username,
+ const char *password,
+ void *pw)
+{
+ struct browser_window *bw = (struct browser_window *)pw;
+ char *userpass;
+ nserror err;
+
+ err = browser_window__build_userpass(username, password, &userpass);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ urldb_set_auth_details(url, realm, userpass);
+
+ free(userpass);
+
+ /**
+ * \todo QUERY - Eventually this should fill out the form *NOT* nav
+ * to the original location
+ */
+ /* Finally navigate to the original loading parameters */
+ if (bw->loading_content != NULL) {
+ /* We had a loading content (maybe auth page?) */
+ browser_window_stop(bw);
+ browser_window_remove_caret(bw, false);
+ browser_window_destroy_children(bw);
+ }
+ bw->internal_nav = false;
+ return browser_window__navigate_internal(bw, &bw->loading_parameters);
+}
+
+/**
+ * Handle login request (BAD_AUTH) during fetch
+ *
+ */
+static nserror
+browser_window__handle_login(struct browser_window *bw,
+ const char *realm,
+ nsurl *url) {
+ char *username = NULL, *password = NULL;
+ nserror err = NSERROR_OK;
+ struct browser_fetch_parameters params;
+
+ memset(&params, 0, sizeof(params));
+
+ /* Step one, retrieve what we have */
+ err = browser_window__unpack_userpass(
+ urldb_get_auth_details(url, realm),
+ &username, &password);
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ /* Step two, construct our fetch parameters */
+ err = nsurl_create("about:query/auth", &params.url);
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+ params.referrer = nsurl_ref(url);
+ params.flags = BW_NAVIGATE_HISTORY | BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL;
+
+ err = fetch_multipart_data_new_kv(&params.post_multipart,
+ "siteurl",
+ nsurl_access(url));
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ err = fetch_multipart_data_new_kv(&params.post_multipart,
+ "realm",
+ realm);
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ err = fetch_multipart_data_new_kv(&params.post_multipart,
+ "username",
+ username);
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ err = fetch_multipart_data_new_kv(&params.post_multipart,
+ "password",
+ password);
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ /* Now we issue the fetch */
+ bw->internal_nav = true;
+ err = browser_window__navigate_internal(bw, &params);
+
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ err = guit->misc->login(url, realm, username, password,
+ browser_window__handle_userpass_response, bw);
+
+ if (err == NSERROR_NOT_IMPLEMENTED) {
+ err = NSERROR_OK;
+ }
+out:
+ if (username != NULL) {
+ free(username);
+ }
+ if (password != NULL) {
+ free(password);
+ }
+ browser_window__free_fetch_parameters(&params);
+ return err;
+}
/**
* Handle errors during content fetch
@@ -891,9 +1127,7 @@ browser_window__handle_error(struct browser_window *bw,
switch (code) {
case NSERROR_BAD_AUTH:
- res = netsurf__handle_login(message, url,
- browser_window__handle_query_response,
- bw);
+ res = browser_window__handle_login(bw, message, url);
break;
case NSERROR_BAD_CERTS:
res = guit->misc->cert_verify(url,
@@ -1235,33 +1469,6 @@ browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw)
/**
- * Close and destroy all child browser window.
- *
- * \param bw browser window
- */
-static void browser_window_destroy_children(struct browser_window *bw)
-{
- int i;
-
- if (bw->children) {
- for (i = 0; i < (bw->rows * bw->cols); i++)
- browser_window_destroy_internal(&bw->children[i]);
- free(bw->children);
- bw->children = NULL;
- bw->rows = 0;
- bw->cols = 0;
- }
- if (bw->iframes) {
- for (i = 0; i < bw->iframe_count; i++)
- browser_window_destroy_internal(&bw->iframes[i]);
- free(bw->iframes);
- bw->iframes = NULL;
- bw->iframe_count = 0;
- }
-}
-
-
-/**
* internal scheduled reformat callback.
*
* scheduled reformat callback to allow reformats from unthreaded context.
@@ -2717,12 +2924,23 @@ nserror browser_window_refresh_url_bar(struct browser_window *bw)
ret = browser_window_refresh_url_bar_internal(bw,
corestring_nsurl_about_blank);
} else if (bw->frag_id == NULL) {
- ret = browser_window_refresh_url_bar_internal(bw,
- hlcache_handle_get_url(bw->current_content));
+ nsurl *url;
+ if (bw->internal_nav) {
+ url = bw->loading_parameters.url;
+ } else {
+ url = hlcache_handle_get_url(bw->current_content);
+ }
+ ret = browser_window_refresh_url_bar_internal(bw, url);
} else {
/* Combine URL and Fragment */
+ nsurl *url;
+ if (bw->internal_nav) {
+ url = bw->loading_parameters.url;
+ } else {
+ url = hlcache_handle_get_url(bw->current_content);
+ }
ret = nsurl_refragment(
- hlcache_handle_get_url(bw->current_content),
+ url,
bw->frag_id, &display_url);
if (ret == NSERROR_OK) {
ret = browser_window_refresh_url_bar_internal(bw,
@@ -2752,12 +2970,38 @@ browser_window_navigate(struct browser_window *bw,
llcache_post_data post;
hlcache_child_context child;
nserror error;
+ bool is_internal = false;
+ struct browser_fetch_parameters params, *pass_params = NULL;
+ lwc_string *scheme, *path;
assert(bw);
assert(url);
NSLOG(netsurf, INFO, "bw %p, url %s", bw, nsurl_access(url));
+ /* Check if this is an internal navigation URL, if so, we do not
+ * do certain things during the load
+ */
+ scheme = nsurl_get_component(url, NSURL_SCHEME);
+ path = nsurl_get_component(url, NSURL_PATH);
+ if (scheme == corestring_lwc_about) {
+ if (path == corestring_lwc_query_auth) {
+ is_internal = true;
+ }
+ }
+ lwc_string_unref(scheme);
+ lwc_string_unref(path);
+
+ if (is_internal &&
+ !(flags & BW_NAVIGATE_INTERNAL)) {
+ /* Internal navigation detected, but flag not set, only allow
+ * this is there's a fetch multipart
+ */
+ if (post_multipart == NULL) {
+ return NSERROR_NEED_DATA;
+ }
+ }
+
/* If we're navigating and we have a history entry and a content
* then update the history entry before we navigate to save our
* current state. However since history navigation pre-moves
@@ -2768,6 +3012,7 @@ browser_window_navigate(struct browser_window *bw,
if (bw->current_content != NULL &&
bw->history != NULL &&
bw->history->current != NULL &&
+ !is_internal &&
!(flags & BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE)) {
browser_window_history_update(bw, bw->current_content);
}
@@ -2872,31 +3117,43 @@ browser_window_navigate(struct browser_window *bw,
browser_window_remove_caret(bw, false);
browser_window_destroy_children(bw);
- /* At this point, we're navigating, so store the fetch parameters */
- browser_window__free_fetch_parameters(&bw->loading_parameters);
+ /* Set up the fetch parameters */
+ memset(&params, 0, sizeof(params));
- bw->loading_parameters.url = nsurl_ref(url);
+ params.url = nsurl_ref(url);
if (referrer != NULL) {
- bw->loading_parameters.referrer = nsurl_ref(referrer);
+ params.referrer = nsurl_ref(referrer);
}
- bw->loading_parameters.flags = flags;
+ params.flags = flags;
if (post_urlenc != NULL) {
- bw->loading_parameters.post_urlenc = strdup(post_urlenc);
+ params.post_urlenc = strdup(post_urlenc);
}
if (post_multipart != NULL) {
- bw->loading_parameters.post_multipart = fetch_multipart_data_clone(post_multipart);
+ params.post_multipart = fetch_multipart_data_clone(post_multipart);
}
if (parent != NULL) {
- bw->loading_parameters.parent_charset = strdup(child.charset);
- bw->loading_parameters.parent_quirks = child.quirks;
+ params.parent_charset = strdup(child.charset);
+ params.parent_quirks = child.quirks;
}
- error = browser_window__navigate_internal(bw, &bw->loading_parameters);
+ bw->internal_nav = is_internal;
+
+ if (is_internal) {
+ pass_params = &params;
+ } else {
+ /* At this point, we're navigating, so store the fetch parameters */
+ browser_window__free_fetch_parameters(&bw->loading_parameters);
+ memcpy(&bw->loading_parameters, &params, sizeof(params));
+ memset(&params, 0, sizeof(params));
+ pass_params = &bw->loading_parameters;
+ }
+
+ error = browser_window__navigate_internal(bw, pass_params);
nsurl_unref(url);
@@ -2904,12 +3161,16 @@ browser_window_navigate(struct browser_window *bw,
nsurl_unref(referrer);
}
+ if (is_internal) {
+ browser_window__free_fetch_parameters(&params);
+ }
+
return error;
}
-nserror
-browser_window__navigate_internal(struct browser_window *bw,
- struct browser_fetch_parameters *params)
+static nserror
+browser_window__navigate_internal_real(struct browser_window *bw,
+ struct browser_fetch_parameters *params)
{
uint32_t fetch_flags = 0;
bool fetch_is_post = (params->post_urlenc != NULL || params->post_multipart != NULL);
@@ -2985,6 +3246,118 @@ browser_window__navigate_internal(struct browser_window *bw,
return error;
}
+/**
+ * Internal navigation handler for the authentication query handler
+ *
+ * If the parameters indicate we're processing a *response* from the handler
+ * then we deal with that, otherwise we pass it on to the about: handler
+ */
+static nserror
+browser_window__navigate_internal_query_auth(struct browser_window *bw,
+ struct browser_fetch_parameters *params)
+{
+ char *userpass = NULL;
+ const char *username, *password, *realm, *siteurl;
+ nsurl *sitensurl;
+ nserror res;
+ bool is_login = false, is_cancel = false;
+
+ assert(params->post_multipart != NULL);
+
+ is_login = fetch_multipart_data_find(params->post_multipart, "login") != NULL;
+ is_cancel = fetch_multipart_data_find(params->post_multipart, "cancel") != NULL;
+
+ if (!(is_login || is_cancel)) {
+ /* This is a request, so pass it on */
+ return browser_window__navigate_internal_real(bw, params);
+ }
+
+ if (is_cancel) {
+ /* We're processing a cancel, do a rough-and-ready nav to
+ * about:blank
+ */
+ browser_window__free_fetch_parameters(&bw->loading_parameters);
+ res = nsurl_create("about:blank", &bw->loading_parameters.url);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ bw->loading_parameters.flags = BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL;
+ bw->internal_nav = true;
+ return browser_window__navigate_internal(bw, &bw->loading_parameters);
+ }
+
+ /* We're processing a "login" attempt from the form */
+
+ /* Retrieve the data */
+ username = fetch_multipart_data_find(params->post_multipart, "username");
+ password = fetch_multipart_data_find(params->post_multipart, "password");
+ realm = fetch_multipart_data_find(params->post_multipart, "realm");
+ siteurl = fetch_multipart_data_find(params->post_multipart, "siteurl");
+
+ if (username == NULL || password == NULL ||
+ realm == NULL || siteurl == NULL) {
+ /* Bad inputs, simply fail */
+ return NSERROR_INVALID;
+ }
+
+ /* Parse the URL */
+ res = nsurl_create(siteurl, &sitensurl);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* Construct the username/password */
+ res = browser_window__build_userpass(username, password, &userpass);
+ if (res != NSERROR_OK) {
+ nsurl_unref(sitensurl);
+ return res;
+ }
+
+ /* And let urldb know */
+ urldb_set_auth_details(sitensurl, realm, userpass);
+
+ /* Clean up */
+ free(userpass);
+ nsurl_unref(sitensurl);
+
+ /* Finally navigate to the original loading parameters */
+ return browser_window__navigate_internal_real(bw, &bw->loading_parameters);
+}
+
+
+nserror
+browser_window__navigate_internal(struct browser_window *bw,
+ struct browser_fetch_parameters *params)
+{
+ lwc_string *scheme, *path;
+ /* Here we determine if we're navigating to an internal query URI
+ * and if so, what we need to do about it.
+ *
+ * If we're not, then we just move on to the real navigate.
+ */
+
+ /* All our special URIs are in the about: scheme */
+ scheme = nsurl_get_component(params->url, NSURL_SCHEME);
+ if (scheme != corestring_lwc_about) {
+ lwc_string_unref(scheme);
+ goto normal_fetch;
+ }
+ lwc_string_unref(scheme);
+
+ /* Is it the auth query handler? */
+ path = nsurl_get_component(params->url, NSURL_PATH);
+ if (path == corestring_lwc_query_auth) {
+ lwc_string_unref(path);
+ return browser_window__navigate_internal_query_auth(bw, params);
+ }
+ lwc_string_unref(path);
+
+ /* Fall through to a normal about: fetch */
+
+normal_fetch:
+ return browser_window__navigate_internal_real(bw, params);
+}
+
/* Exported interface, documented in netsurf/browser_window.h */
bool browser_window_up_available(struct browser_window *bw)
diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c
index 5628caad5..bd8d35bc5 100644
--- a/desktop/gui_factory.c
+++ b/desktop/gui_factory.c
@@ -691,12 +691,14 @@ static nserror gui_default_cert_verify(nsurl *url,
return NSERROR_NOT_IMPLEMENTED;
}
-static nserror gui_default_401login_open(nsurl *url, const char *realm,
- const char *username, const char *password,
- nserror (*cb)(const char *username,
- const char *password,
- void *pw),
- void *cbpw)
+static nserror gui_default_401login_open(
+ nsurl *url, const char *realm,
+ const char *username, const char *password,
+ nserror (*cb)(nsurl *url, const char * realm,
+ const char *username,
+ const char *password,
+ void *pw),
+ void *cbpw)
{
return NSERROR_NOT_IMPLEMENTED;
}
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 706ca7be0..0928442dc 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -98,206 +98,6 @@ static void netsurf_lwc_iterator(lwc_string *str, void *pw)
(int)lwc_string_length(str), lwc_string_data(str));
}
-/**
- * Build a "username:password" from components.
- *
- * \param[in] username The username component.
- * \param[in] password The password component.
- * \param[out] userpass_out Returns combined string on success.
- * Owned by caller.
- * \return NSERROR_OK, or appropriate error code.
- */
-static nserror netsurf__build_userpass(
- const char *username,
- const char *password,
- char **userpass_out)
-{
- char *userpass;
- size_t len;
-
- len = strlen(username) + 1 + strlen(password) + 1;
-
- userpass = malloc(len);
- if (userpass == NULL) {
- return NSERROR_NOMEM;
- }
-
- snprintf(userpass, len, "%s:%s", username, password);
-
- *userpass_out = userpass;
- return NSERROR_OK;
-}
-
-/**
- * Unpack a "username:password" to components.
- *
- * \param[in] userpass The input string to split.
- * \param[in] username_out Returns username on success. Owned by caller.
- * \param[out] password_out Returns password on success. Owned by caller.
- * \return NSERROR_OK, or appropriate error code.
- */
-static nserror netsurf__unpack_userpass(
- const char *userpass,
- char **username_out,
- char **password_out)
-{
- const char *tmp;
- char *username;
- char *password;
- size_t len;
-
- if (userpass == NULL) {
- username = malloc(1);
- password = malloc(1);
- if (username == NULL || password == NULL) {
- free(username);
- free(password);
- return NSERROR_NOMEM;
- }
- username[0] = '\0';
- password[0] = '\0';
-
- *username_out = username;
- *password_out = password;
- return NSERROR_OK;
- }
-
- tmp = strchr(userpass, ':');
- if (tmp == NULL) {
- return NSERROR_BAD_PARAMETER;
- } else {
- size_t len2;
- len = tmp - userpass;
- len2 = strlen(++tmp);
-
- username = malloc(len + 1);
- password = malloc(len2 + 1);
- if (username == NULL || password == NULL) {
- free(username);
- free(password);
- return NSERROR_NOMEM;
- }
- memcpy(username, userpass, len);
- username[len] = '\0';
- memcpy(password, tmp, len2 + 1);
- }
-
- *username_out = username;
- *password_out = password;
- return NSERROR_OK;
-}
-
-/**
- * Contect for login callbacks to front ends.
- */
-struct auth_data {
- char *realm;
- nsurl *url;
-
- browser_window_query_callback cb;
- void *pw;
-};
-
-/**
- * Callback function passed to front ends for handling logins.
- *
- * \param[in] username The username.
- * \param[in] password The password.
- * \param[in] cbpw Our context.
- * \return NSERROR_OK, or appropriate error code.
- */
-static nserror netsurf__handle_login_response(
- const char *username,
- const char *password,
- void *cbpw)
-{
- struct auth_data *ctx = cbpw;
- bool proceed = false;
- nserror err;
-
- if (username != NULL && password != NULL) {
- char *userpass;
-
- err = netsurf__build_userpass(username, password, &userpass);
- if (err != NSERROR_OK) {
- return err;
- }
-
- urldb_set_auth_details(ctx->url, ctx->realm, userpass);
- free(userpass);
- proceed = true;
- }
-
- err = ctx->cb(proceed, ctx->pw);
- nsurl_unref(ctx->url);
- free(ctx->realm);
- free(ctx);
- return err;
-}
-
-/* Cheeky */
-nserror netsurf__handle_login(const char * realm, nsurl *url,
- browser_window_query_callback cb, void *cbpw);
-/**
- * Helper for getting front end to handle logins.
- *
- * \param[in] query Query descriptor
- * \param[in] pw Private data
- * \param[in] cb Continuation callback
- * \param[in] cbpw Private data for continuation
- * \return NSERROR_OK, or appropriate error code.
- */
-nserror netsurf__handle_login(const char * realm, nsurl *url,
- browser_window_query_callback cb, void *cbpw)
-{
- struct auth_data *ctx;
- char *username;
- char *password;
- nserror err;
-
- NSLOG(llcache, INFO, "HTTP Auth for: %s: %s",
- realm, nsurl_access(url));
-
- ctx = malloc(sizeof(*ctx));
- if (ctx == NULL) {
- return NSERROR_NOMEM;
- }
-
- ctx->realm = strdup(realm);
- if (ctx->realm == NULL) {
- free(ctx);
- return NSERROR_NOMEM;
- }
- ctx->url = nsurl_ref(url);
- ctx->cb = cb;
- ctx->pw = cbpw;
-
- err = netsurf__unpack_userpass(
- urldb_get_auth_details(ctx->url, ctx->realm),
- &username, &password);
- if (err != NSERROR_OK) {
- nsurl_unref(ctx->url);
- free(ctx->realm);
- free(ctx);
- return err;
- }
-
- err = guit->misc->login(ctx->url, ctx->realm, username, password,
- netsurf__handle_login_response, ctx);
- free(username);
- free(password);
- if (err != NSERROR_OK) {
- ctx->cb(false, ctx->pw);
- nsurl_unref(ctx->url);
- free(ctx->realm);
- free(ctx);
- return err;
- }
-
- return NSERROR_OK;
-}
-
-
/* exported interface documented in netsurf/netsurf.h */
nserror netsurf_init(const char *store_path)
{
diff --git a/frontends/amiga/gui.c b/frontends/amiga/gui.c
index 54273ee54..af9322e53 100644
--- a/frontends/amiga/gui.c
+++ b/frontends/amiga/gui.c
@@ -6087,7 +6087,6 @@ static struct gui_misc_table amiga_misc_table = {
.quit = gui_quit,
.launch_url = gui_launch_url,
.cert_verify = ami_cert_verify,
- .login = gui_401login_open,
};
/** Normal entry point from OS */
diff --git a/frontends/atari/gui.c b/frontends/atari/gui.c
index 5e2fd6102..cce4e13ee 100644
--- a/frontends/atari/gui.c
+++ b/frontends/atari/gui.c
@@ -1108,7 +1108,6 @@ static struct gui_misc_table atari_misc_table = {
.quit = gui_quit,
.cert_verify = gui_cert_verify,
- .login = gui_401login_open,
};
/* #define WITH_DBG_LOGFILE 1 */
diff --git a/frontends/beos/gui.cpp b/frontends/beos/gui.cpp
index f5bb5824e..b738d105d 100644
--- a/frontends/beos/gui.cpp
+++ b/frontends/beos/gui.cpp
@@ -997,7 +997,7 @@ static struct gui_misc_table beos_misc_table = {
gui_quit,
gui_launch_url,
NULL, //cert_verify
- gui_401login_open,
+ NULL, //401login
NULL, // pdf_password (if we have Haru support)
};
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index ee7e3365b..740543b44 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -1073,7 +1073,6 @@ static struct gui_misc_table nsgtk_misc_table = {
.quit = gui_quit,
.launch_url = gui_launch_url,
.cert_verify = gtk_cert_verify,
- .login = gui_401login_open,
.pdf_password = nsgtk_pdf_password,
};
diff --git a/frontends/monkey/401login.c b/frontends/monkey/401login.c
index b9e75bf8f..1629425f6 100644
--- a/frontends/monkey/401login.c
+++ b/frontends/monkey/401login.c
@@ -30,10 +30,12 @@
struct monkey401 {
struct monkey401 *r_next, *r_prev;
uint32_t num;
- nserror (*cb)(const char *, const char *, void *);
+ nserror (*cb)(struct nsurl*, const char *, const char *, const char *, void *);
void *cbpw;
char *username;
char *password;
+ char *realm;
+ struct nsurl *url;
};
static struct monkey401 *m401_ring = NULL;
@@ -45,7 +47,9 @@ gui_401login_open(struct nsurl *url,
const char *realm,
const char *username,
const char *password,
- nserror (*cb)(const char *username,
+ nserror (*cb)(struct nsurl *url,
+ const char *realm,
+ const char *username,
const char *password,
void *pw),
void *cbpw)
@@ -56,6 +60,12 @@ gui_401login_open(struct nsurl *url,
if (m401_ctx == NULL) {
return NSERROR_NOMEM;
}
+ m401_ctx->realm = strdup(realm);
+ if (m401_ctx->realm == NULL) {
+ free(m401_ctx);
+ return NSERROR_NOMEM;
+ }
+ m401_ctx->url = nsurl_ref(url);
m401_ctx->cb = cb;
m401_ctx->cbpw = cbpw;
m401_ctx->num = m401_ctr++;
@@ -102,6 +112,8 @@ static void free_login_context(struct monkey401 *m401_ctx) {
if (m401_ctx->password != NULL) {
free(m401_ctx->password);
}
+ free(m401_ctx->realm);
+ nsurl_unref(m401_ctx->url);
free(m401_ctx);
}
@@ -121,7 +133,7 @@ monkey_login_handle_go(int argc, char **argv)
return;
}
- m401_ctx->cb(m401_ctx->username, m401_ctx->password, m401_ctx->cbpw);
+ m401_ctx->cb(m401_ctx->url, m401_ctx->realm, m401_ctx->username, m401_ctx->password, m401_ctx->cbpw);
free_login_context(m401_ctx);
}
@@ -142,8 +154,6 @@ monkey_login_handle_destroy(int argc, char **argv)
return;
}
- m401_ctx->cb(NULL, NULL, m401_ctx->cbpw);
-
free_login_context(m401_ctx);
}
diff --git a/frontends/monkey/401login.h b/frontends/monkey/401login.h
index 9ebe46a62..45a2a1b52 100644
--- a/frontends/monkey/401login.h
+++ b/frontends/monkey/401login.h
@@ -27,7 +27,9 @@ nserror gui_401login_open(struct nsurl *url,
const char *realm,
const char *username,
const char *password,
- nserror (*cb)(const char *username,
+ nserror (*cb)(struct nsurl *url,
+ const char *realm,
+ const char *username,
const char *password,
void *pw),
void *cbpw);
diff --git a/frontends/riscos/gui.c b/frontends/riscos/gui.c
index 93bad1638..ef215487d 100644
--- a/frontends/riscos/gui.c
+++ b/frontends/riscos/gui.c
@@ -2432,7 +2432,6 @@ static struct gui_misc_table riscos_misc_table = {
.quit = gui_quit,
.launch_url = gui_launch_url,
.cert_verify = gui_cert_verify,
- .login = gui_401login_open,
};
diff --git a/frontends/windows/main.c b/frontends/windows/main.c
index 6592e1626..bae7815ae 100644
--- a/frontends/windows/main.c
+++ b/frontends/windows/main.c
@@ -314,7 +314,6 @@ static struct gui_misc_table win32_misc_table = {
.warning = win32_warning,
.cert_verify = nsw32_cert_verify,
- .login = nsw32_401login,
};
/**
diff --git a/include/netsurf/browser_window.h b/include/netsurf/browser_window.h
index d21af2629..0b140521f 100644
--- a/include/netsurf/browser_window.h
+++ b/include/netsurf/browser_window.h
@@ -120,7 +120,10 @@ enum browser_window_nav_flags {
BW_NAVIGATE_UNVERIFIABLE = (1 << 2),
/** suppress initial history updates (used by back/fwd/etc) */
- BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE = (1 << 3)
+ BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE = (1 << 3),
+
+ /** Internal navigation (set only by core features using such) */
+ BW_NAVIGATE_INTERNAL = (1 << 4)
};
/**
diff --git a/include/netsurf/misc.h b/include/netsurf/misc.h
index cd86cf644..ac58cf302 100644
--- a/include/netsurf/misc.h
+++ b/include/netsurf/misc.h
@@ -98,19 +98,29 @@ struct gui_misc_table {
void *cbpw);
/**
- * Prompt user for login
+ * Retrieve username/password for a given url+realm if there is one
+ * stored in a frontend-specific way (e.g. gnome-keyring)
*
- * To cancel a login, clients should call the `cb` callback passing
- * NULL for username, and password. Otherwise, for logins, username
- * and password should both be non-NULL. Pass "" if the empty string
+ * To respond, call the callback with the url, realm, username,
+ * and password. Pass "" if the empty string
* is required.
*
- * If the front end returns NSERROR_OK for this function, they must,
+ * To keep hold of the url, remember to nsurl_ref() it, and to keep
+ * the realm, you will need to strdup() it.
+ *
+ * If the front end returns NSERROR_OK for this function, they may,
* at some future time, call the `cb` with `cbpw` callback exactly once.
*
- * If ther front end returns other than NSERROR_OK, they should not
+ * If the front end returns other than NSERROR_OK, they should not
* call the `cb` callback.
*
+ * The callback should not be called immediately upon receipt of this
+ * call as the browser window may not be reentered.
+ *
+ * **NOTE** The lifetime of the cbpw is not well defined. In general
+ * do not use the cb if *any* browser window has navigated or been
+ * destroyed.
+ *
* \param url The URL being verified.
* \param realm The authorization realm.
* \param username Any current username (or empty string).
@@ -120,11 +130,13 @@ struct gui_misc_table {
* \return NSERROR_OK on sucess else error and cb never called
*/
nserror (*login)(struct nsurl *url, const char *realm,
- const char *username, const char *password,
- nserror (*cb)(const char *username,
- const char *password,
- void *pw),
- void *cbpw);
+ const char *username, const char *password,
+ nserror (*cb)(struct nsurl *url,
+ const char *realm,
+ const char *username,
+ const char *password,
+ void *pw),
+ void *cbpw);
/**
* Prompt the user for a password for a PDF.
diff --git a/utils/corestringlist.h b/utils/corestringlist.h
index 4261f4d07..e6530c506 100644
--- a/utils/corestringlist.h
+++ b/utils/corestringlist.h
@@ -146,6 +146,7 @@ CORESTRING_LWC_VALUE(slash_, "/");
CORESTRING_LWC_VALUE(max_age, "max-age");
CORESTRING_LWC_VALUE(no_cache, "no-cache");
CORESTRING_LWC_VALUE(no_store, "no-store");
+CORESTRING_LWC_VALUE(query_auth, "query/auth");
/* mime types */
CORESTRING_LWC_VALUE(multipart_form_data, "multipart/form-data");