summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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");