diff options
-rw-r--r-- | content/fetch.c | 54 | ||||
-rw-r--r-- | content/fetch.h | 24 | ||||
-rw-r--r-- | content/llcache.c | 2 | ||||
-rw-r--r-- | desktop/browser_private.h | 2 | ||||
-rw-r--r-- | desktop/browser_window.c | 491 | ||||
-rw-r--r-- | desktop/gui_factory.c | 14 | ||||
-rw-r--r-- | desktop/netsurf.c | 200 | ||||
-rw-r--r-- | frontends/amiga/gui.c | 1 | ||||
-rw-r--r-- | frontends/atari/gui.c | 1 | ||||
-rw-r--r-- | frontends/beos/gui.cpp | 2 | ||||
-rw-r--r-- | frontends/gtk/gui.c | 1 | ||||
-rw-r--r-- | frontends/monkey/401login.c | 20 | ||||
-rw-r--r-- | frontends/monkey/401login.h | 4 | ||||
-rw-r--r-- | frontends/riscos/gui.c | 1 | ||||
-rw-r--r-- | frontends/windows/main.c | 1 | ||||
-rw-r--r-- | include/netsurf/browser_window.h | 5 | ||||
-rw-r--r-- | include/netsurf/misc.h | 34 | ||||
-rw-r--r-- | utils/corestringlist.h | 1 |
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(¶ms, 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", ¶ms.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(¶ms.post_multipart, + "siteurl", + nsurl_access(url)); + if (err != NSERROR_OK) { + goto out; + } + + err = fetch_multipart_data_new_kv(¶ms.post_multipart, + "realm", + realm); + if (err != NSERROR_OK) { + goto out; + } + + err = fetch_multipart_data_new_kv(¶ms.post_multipart, + "username", + username); + if (err != NSERROR_OK) { + goto out; + } + + err = fetch_multipart_data_new_kv(¶ms.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, ¶ms); + + 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(¶ms); + 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(¶ms, 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 = ¶ms; + } else { + /* At this point, we're navigating, so store the fetch parameters */ + browser_window__free_fetch_parameters(&bw->loading_parameters); + memcpy(&bw->loading_parameters, ¶ms, sizeof(params)); + memset(¶ms, 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(¶ms); + } + 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"); |