From 4b0c3f0efef2239dd5d62a9e73eeec4037c056a4 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Oct 2019 18:56:38 +0000 Subject: [PATCH] add internal query handler for fetch errors Any errors from the fetch which are not already handled are reported with an internal query page instead of a modal dialog. This is much less invasive for the user and much more in keeping with how this is handled by other browsers. The handler is similar to the timeout handler but the functionality is kept separate as it is intended timeout handling be extended in future. --- content/fetchers/about.c | 136 +++++++++++++++++++++++++++++++++++++++ desktop/browser_window.c | 119 ++++++++++++++++++++++++++-------- resources/FatMessages | 7 ++ resources/internal.css | 38 +++++++++++ utils/corestringlist.h | 2 + 5 files changed, 275 insertions(+), 27 deletions(-) diff --git a/content/fetchers/about.c b/content/fetchers/about.c index d8a5fa793..e98c6ec35 100644 --- a/content/fetchers/about.c +++ b/content/fetchers/about.c @@ -94,6 +94,11 @@ static const char *privacy_description_fallback = "A privacy error occurred whil */ static const char *timeout_description_fallback = "A connection to %s could not be established. The site may be temporarily unavailable or too busy to respond."; +/** + * fetcherror query description if messages fails to retrieve usable text + */ +static const char *fetcherror_description_fallback = "An error occoured when connecting to %s"; + /** * issue fetch callbacks with locking */ @@ -1239,6 +1244,130 @@ fetch_about_query_timeout_handler_aborted: } +/** + * Handler to generate about scheme fetch error query page + * + * \param ctx The fetcher context. + * \return true if handled false if aborted. + */ +static bool +fetch_about_query_fetcherror_handler(struct fetch_about_context *ctx) +{ + nserror res; + char *url_s; + size_t url_l; + const char *reason = ""; + const char *title; + struct nsurl *siteurl = NULL; + char *description = NULL; + const struct fetch_multipart_data *curmd; /* mutipart data iterator */ + + /* extract parameters from multipart post data */ + curmd = ctx->multipart; + while (curmd != NULL) { + if (strcmp(curmd->name, "siteurl") == 0) { + res = nsurl_create(curmd->value, &siteurl); + if (res != NSERROR_OK) { + return fetch_about_srverror(ctx); + } + } else if (strcmp(curmd->name, "reason") == 0) { + reason = curmd->value; + } + curmd = curmd->next; + } + + if (siteurl == NULL) { + return fetch_about_srverror(ctx); + } + + /* content is going to return ok */ + fetch_set_http_code(ctx->fetchh, 200); + + /* content type */ + if (fetch_about_send_header(ctx, "Content-Type: text/html; charset=utf-8")) { + goto fetch_about_query_fetcherror_handler_aborted; + } + + title = messages_get("FetchErrorTitle"); + res = ssenddataf(ctx, + "\n\n" + "%s\n" + "\n" + "\n" + "\n" + "

%s

\n", + title, title); + if (res != NSERROR_OK) { + goto fetch_about_query_fetcherror_handler_aborted; + } + + res = ssenddataf(ctx, + "
"); + if (res != NSERROR_OK) { + goto fetch_about_query_fetcherror_handler_aborted; + } + + res = get_query_description(siteurl, + "FetchErrorDescription", + fetcherror_description_fallback, + &description); + if (res == NSERROR_OK) { + res = ssenddataf(ctx, "

%s

", description); + free(description); + if (res != NSERROR_OK) { + goto fetch_about_query_fetcherror_handler_aborted; + } + } + res = ssenddataf(ctx, "

%s

", reason); + if (res != NSERROR_OK) { + goto fetch_about_query_fetcherror_handler_aborted; + } + + res = ssenddataf(ctx, + "
" + "" + "" + "
", + messages_get("Backtoprevious"), + messages_get("TryAgain")); + if (res != NSERROR_OK) { + goto fetch_about_query_fetcherror_handler_aborted; + } + + res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l); + if (res != NSERROR_OK) { + url_s = strdup(""); + } + res = ssenddataf(ctx, + "", + url_s); + free(url_s); + if (res != NSERROR_OK) { + goto fetch_about_query_fetcherror_handler_aborted; + } + + res = ssenddataf(ctx, "
\n\n"); + if (res != NSERROR_OK) { + goto fetch_about_query_fetcherror_handler_aborted; + } + + fetch_about_send_finished(ctx); + + nsurl_unref(siteurl); + + return true; + +fetch_about_query_fetcherror_handler_aborted: + nsurl_unref(siteurl); + + return false; +} + + /* Forward declaration because this handler requires the handler table. */ static bool fetch_about_about_handler(struct fetch_about_context *ctx); @@ -1352,6 +1481,13 @@ struct about_handlers about_handler_list[] = { NULL, fetch_about_query_timeout_handler, true + }, + { + "query/fetcherror", + SLEN("query/fetcherror"), + NULL, + fetch_about_query_fetcherror_handler, + true } }; diff --git a/desktop/browser_window.c b/desktop/browser_window.c index 5f7c2cc4b..807393ed1 100644 --- a/desktop/browser_window.c +++ b/desktop/browser_window.c @@ -1216,6 +1216,50 @@ browser_window__handle_timeout(struct browser_window *bw, nsurl *url) } +/** + * Handle non specific errors during a fetch + */ +static nserror +browser_window__handle_fetcherror(struct browser_window *bw, + const char *reason, + nsurl *url) +{ + struct browser_fetch_parameters params; + nserror err; + + memset(¶ms, 0, sizeof(params)); + + params.url = nsurl_ref(corestring_nsurl_about_query_fetcherror); + 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, + "reason", + reason); + 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; + } + + out: + browser_window__free_fetch_parameters(¶ms); + return err; +} + + /** * Handle errors during content fetch */ @@ -1226,39 +1270,14 @@ browser_window__handle_error(struct browser_window *bw, { const char *message = event->data.errordata.errormsg; nserror code = event->data.errordata.errorcode; - bool do_warning = true; nserror res; nsurl *url = hlcache_handle_get_url(c); /* Unexpected OK? */ assert(code != NSERROR_OK); - switch (code) { - case NSERROR_BAD_AUTH: - do_warning = false; - break; - case NSERROR_BAD_CERTS: - do_warning = false; - break; - case NSERROR_BAD_REDIRECT: - /* The message is already filled out */ - break; - case NSERROR_TIMEOUT: - do_warning = false; - break; - default: - if (message == NULL) { - message = messages_get_errorcode(code); - } - break; - } - - if (do_warning) { - browser_window_set_status(bw, message); - /* Only warn the user about errors in top-level windows */ - if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) { - guit->misc->warning(message, NULL); - } + if (message == NULL) { + message = messages_get_errorcode(code); } if (c == bw->loading_content) { @@ -1274,13 +1293,17 @@ browser_window__handle_error(struct browser_window *bw, case NSERROR_BAD_AUTH: res = browser_window__handle_login(bw, message, url); break; + case NSERROR_BAD_CERTS: res = browser_window__handle_bad_certs(bw, url); break; + case NSERROR_TIMEOUT: res = browser_window__handle_timeout(bw, url); break; + default: + res = browser_window__handle_fetcherror(bw, message, url); break; } @@ -2411,6 +2434,8 @@ is_internal_navigate_url(nsurl *url) is_internal = true; } else if (path == corestring_lwc_query_timeout) { is_internal = true; + } else if (path == corestring_lwc_query_fetcherror) { + is_internal = true; } } lwc_string_unref(path); @@ -3613,6 +3638,42 @@ navigate_internal_query_timeout(struct browser_window *bw, } +/** + * Internal navigation handler for the fetch error query page. + * + * 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 +navigate_internal_query_fetcherror(struct browser_window *bw, + struct browser_fetch_parameters *params) +{ + bool is_retry = false, is_back = false; + + NSLOG(netsurf, INFO, "bw:%p params:%p", bw, params); + + assert(params->post_multipart != NULL); + + is_retry = fetch_multipart_data_find(params->post_multipart, "retry") != NULL; + is_back = fetch_multipart_data_find(params->post_multipart, "back") != NULL; + + if (is_back) { + /* do a rough-and-ready nav to the old 'current' + * parameters, with any post data stripped away + */ + return browser_window__reload_current_parameters(bw); + } + + if (is_retry) { + /* Finally navigate to the original loading parameters */ + bw->internal_nav = false; + return navigate_internal_real(bw, &bw->loading_parameters); + } + + return navigate_internal_real(bw, params); +} + + /** * dispatch to internal query handlers or normal navigation * @@ -3651,6 +3712,10 @@ browser_window__navigate_internal(struct browser_window *bw, lwc_string_unref(path); return navigate_internal_query_timeout(bw, params); } + if (path == corestring_lwc_query_fetcherror) { + lwc_string_unref(path); + return navigate_internal_query_fetcherror(bw, params); + } lwc_string_unref(path); /* Fall through to a normal about: fetch */ diff --git a/resources/FatMessages b/resources/FatMessages index aa2d7a2d1..06d61c942 100644 --- a/resources/FatMessages +++ b/resources/FatMessages @@ -1096,6 +1096,13 @@ en.all.Backtoprevious: Back en.all.TryAgain: Try Again +# Fetch error interface +# ======================= +# +en.all.FetchErrorTitle:Error occured fetching page +en.all.FetchErrorDescription:An error occoured when connecting to %s + + # SSL certificate viewer # ====================== # diff --git a/resources/internal.css b/resources/internal.css index 14b47cfa9..ded56ee0b 100644 --- a/resources/internal.css +++ b/resources/internal.css @@ -381,3 +381,41 @@ body#timeout div#buttons { body#timeout div#buttons input#back { margin-right: 1em; } + +/* + * fetch error query styling + */ + +body#fetcherror { + max-width: 45em; +} + +body#fetcherror h1 { + padding: 0.8em 0.4em 0.5em 0.4em; + border-bottom: 0.1em solid #444; + margin: 0 0 1.3em 0; + background: #c55; + color: white; +} + +body#fetcherror form { + /* Just to center the form on the page */ + margin: 0 auto; + /* To see the outline of the form */ + padding: 1em; + border: 1px solid #CCC; + border-radius: 1em; +} + +body#fetcherror form div + div { + margin-top: 1em; +} + +body#fetcherror div#buttons { + text-align: right; + margin-right: 1em; +} + +body#fetcherror div#buttons input#back { + margin-right: 1em; +} diff --git a/utils/corestringlist.h b/utils/corestringlist.h index e7516b18a..b1095458b 100644 --- a/utils/corestringlist.h +++ b/utils/corestringlist.h @@ -149,6 +149,7 @@ CORESTRING_LWC_VALUE(no_store, "no-store"); CORESTRING_LWC_VALUE(query_auth, "query/auth"); CORESTRING_LWC_VALUE(query_ssl, "query/ssl"); CORESTRING_LWC_VALUE(query_timeout, "query/timeout"); +CORESTRING_LWC_VALUE(query_fetcherror, "query/fetcherror"); /* mime types */ CORESTRING_LWC_VALUE(multipart_form_data, "multipart/form-data"); @@ -362,6 +363,7 @@ CORESTRING_NSURL(about_blank, "about:blank"); CORESTRING_NSURL(about_query_ssl, "about:query/ssl"); CORESTRING_NSURL(about_query_auth, "about:query/auth"); CORESTRING_NSURL(about_query_timeout, "about:query/timeout"); +CORESTRING_NSURL(about_query_fetcherror, "about:query/fetcherror"); #undef CORESTRING_LWC_STRING #undef CORESTRING_DOM_STRING