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