summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2019-10-29 22:29:22 +0000
committerVincent Sanders <vince@kyllikki.org>2019-10-29 22:29:22 +0000
commit76eac192272acf77763d0c619cd78118650748cf (patch)
tree255a4a10b6e39e2c8f3c91afd0a16e85cddc2a3d
parent1176ce427113face73c48c4b2e4e5a810577b355 (diff)
downloadnetsurf-76eac192272acf77763d0c619cd78118650748cf.tar.gz
netsurf-76eac192272acf77763d0c619cd78118650748cf.tar.bz2
add internal query page for request timeouts
-rw-r--r--content/fetchers/about.c153
-rw-r--r--desktop/browser_window.c131
-rw-r--r--resources/FatMessages9
-rw-r--r--resources/internal.css38
-rw-r--r--utils/corestringlist.h2
5 files changed, 309 insertions, 24 deletions
diff --git a/content/fetchers/about.c b/content/fetchers/about.c
index df514108c..d8a5fa793 100644
--- a/content/fetchers/about.c
+++ b/content/fetchers/about.c
@@ -90,6 +90,11 @@ static const char *authentication_description_fallback = "The site %s is request
static const char *privacy_description_fallback = "A privacy error occurred while communicating with %s this may be a site configuration error or an attempt to steal private information (passwords, messages or credit cards)";
/**
+ * timeout query description if messages fails to retrieve usable text
+ */
+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.";
+
+/**
* issue fetch callbacks with locking
*/
static inline bool
@@ -939,15 +944,18 @@ fetch_about_query_auth_handler_aborted:
/**
- * generate the description of the privacy query
+ * generate a query description
*/
-static nserror get_privacy_description(struct nsurl *url, char **out_str)
+static nserror
+get_query_description(struct nsurl *url,
+ const char *key,
+ const char *fallback,
+ char **out_str)
{
nserror res;
char *url_s;
size_t url_l;
char *str = NULL;
- const char *key = "PrivacyDescription";
/* get the host in question */
res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
@@ -967,10 +975,10 @@ static nserror get_privacy_description(struct nsurl *url, char **out_str)
* fall back to basic english.
*/
int slen;
- slen = snprintf(str, 0, privacy_description_fallback, url_s) + 1;
+ slen = snprintf(str, 0, fallback, url_s) + 1;
str = malloc(slen);
if (str != NULL) {
- snprintf(str, slen, privacy_description_fallback, url_s);
+ snprintf(str, slen, fallback, url_s);
}
}
@@ -1049,7 +1057,10 @@ static bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx)
goto fetch_about_query_ssl_handler_aborted;
}
- res = get_privacy_description(siteurl, &description);
+ res = get_query_description(siteurl,
+ "PrivacyDescription",
+ privacy_description_fallback,
+ &description);
if (res == NSERROR_OK) {
res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
free(description);
@@ -1105,6 +1116,129 @@ fetch_about_query_ssl_handler_aborted:
}
+/**
+ * Handler to generate about scheme timeout query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_query_timeout_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_timeout_handler_aborted;
+ }
+
+ title = messages_get("TimeoutTitle");
+ res = ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body id =\"timeout\">\n"
+ "<h1>%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ res = get_query_description(siteurl,
+ "TimeoutDescription",
+ timeout_description_fallback,
+ &description);
+ if (res == NSERROR_OK) {
+ res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+ }
+ res = ssenddataf(ctx, "<div><p>%s</p></div>", reason);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<div id=\"buttons\">"
+ "<input type=\"submit\" id=\"back\" name=\"back\" "
+ "value=\"%s\" class=\"default-action\">"
+ "<input type=\"submit\" id=\"retry\" name=\"retry\" "
+ "value=\"%s\">"
+ "</div>",
+ messages_get("Backtoprevious"),
+ messages_get("TryAgain"));
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ url_s = strdup("");
+ }
+ res = ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
+ url_s);
+ free(url_s);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ res = ssenddataf(ctx, "</form></body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ nsurl_unref(siteurl);
+
+ return true;
+
+fetch_about_query_timeout_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);
@@ -1211,6 +1345,13 @@ struct about_handlers about_handler_list[] = {
NULL,
fetch_about_query_privacy_handler,
true
+ },
+ {
+ "query/timeout",
+ SLEN("query/timeout"),
+ NULL,
+ fetch_about_query_timeout_handler,
+ true
}
};
diff --git a/desktop/browser_window.c b/desktop/browser_window.c
index a6b77b08b..5f7c2cc4b 100644
--- a/desktop/browser_window.c
+++ b/desktop/browser_window.c
@@ -1182,6 +1182,41 @@ browser_window__handle_bad_certs(struct browser_window *bw,
/**
+ * Handle a timeout during a fetch
+ */
+static nserror
+browser_window__handle_timeout(struct browser_window *bw, nsurl *url)
+{
+ struct browser_fetch_parameters params;
+ nserror err;
+
+ memset(&params, 0, sizeof(params));
+
+ params.url = nsurl_ref(corestring_nsurl_about_query_timeout);
+ 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;
+ }
+
+ /* Now we issue the fetch */
+ bw->internal_nav = true;
+ err = browser_window__navigate_internal(bw, &params);
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ out:
+ browser_window__free_fetch_parameters(&params);
+ return err;
+}
+
+
+/**
* Handle errors during content fetch
*/
static nserror
@@ -1208,6 +1243,9 @@ browser_window__handle_error(struct browser_window *bw,
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);
@@ -1239,6 +1277,9 @@ browser_window__handle_error(struct browser_window *bw,
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:
break;
}
@@ -2368,6 +2409,8 @@ is_internal_navigate_url(nsurl *url)
is_internal = true;
} else if (path == corestring_lwc_query_ssl) {
is_internal = true;
+ } else if (path == corestring_lwc_query_timeout) {
+ is_internal = true;
}
}
lwc_string_unref(path);
@@ -3338,12 +3381,16 @@ browser_window_navigate(struct browser_window *bw,
return error;
}
+
+/**
+ * Internal navigation handler for normal fetches
+ */
static nserror
-browser_window__navigate_internal_real(struct browser_window *bw,
- struct browser_fetch_parameters *params)
+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);
+ bool fetch_is_post;
llcache_post_data post;
hlcache_child_context child;
nserror res;
@@ -3351,6 +3398,8 @@ browser_window__navigate_internal_real(struct browser_window *bw,
NSLOG(netsurf, INFO, "Loading '%s'", nsurl_access(params->url));
+ fetch_is_post = (params->post_urlenc != NULL || params->post_multipart != NULL);
+
/* Clear SSL info for load */
bw->loading_ssl_info.num = 0;
@@ -3424,6 +3473,7 @@ browser_window__navigate_internal_real(struct browser_window *bw,
return res;
}
+
/**
* Internal navigation handler for the authentication query handler
*
@@ -3431,8 +3481,8 @@ browser_window__navigate_internal_real(struct browser_window *bw,
* 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)
+navigate_internal_query_auth(struct browser_window *bw,
+ struct browser_fetch_parameters *params)
{
char *userpass = NULL;
const char *username, *password, *realm, *siteurl;
@@ -3447,7 +3497,7 @@ browser_window__navigate_internal_query_auth(struct browser_window *bw,
if (!(is_login || is_cancel)) {
/* This is a request, so pass it on */
- return browser_window__navigate_internal_real(bw, params);
+ return navigate_internal_real(bw, params);
}
if (is_cancel) {
@@ -3497,7 +3547,7 @@ browser_window__navigate_internal_query_auth(struct browser_window *bw,
/* Finally navigate to the original loading parameters */
bw->internal_nav = false;
- return browser_window__navigate_internal_real(bw, &bw->loading_parameters);
+ return navigate_internal_real(bw, &bw->loading_parameters);
}
@@ -3508,8 +3558,8 @@ browser_window__navigate_internal_query_auth(struct browser_window *bw,
* then we deal with that, otherwise we pass it on to the about: handler
*/
static nserror
-browser_window__navigate_internal_query_ssl(struct browser_window *bw,
- struct browser_fetch_parameters *params)
+navigate_internal_query_ssl(struct browser_window *bw,
+ struct browser_fetch_parameters *params)
{
bool is_proceed = false, is_back = false;
@@ -3520,23 +3570,64 @@ browser_window__navigate_internal_query_ssl(struct browser_window *bw,
if (!(is_proceed || is_back)) {
/* This is a request, so pass it on */
- return browser_window__navigate_internal_real(bw, params);
+ return navigate_internal_real(bw, params);
}
return browser_window__handle_ssl_query_response(is_proceed, bw);
}
+/**
+ * Internal navigation handler for the timeout 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_timeout(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
+ *
+ * Here we determine if we're navigating to an internal query URI and
+ * if so, what we need to do about it.
+ *
+ * \note these check must match those in is_internal_navigate_url()
+ *
+ * If we're not, then we just move on to the real navigate.
+ */
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);
@@ -3550,18 +3641,22 @@ browser_window__navigate_internal(struct browser_window *bw,
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);
+ return navigate_internal_query_auth(bw, params);
}
if (path == corestring_lwc_query_ssl) {
lwc_string_unref(path);
- return browser_window__navigate_internal_query_ssl(bw, params);
+ return navigate_internal_query_ssl(bw, params);
+ }
+ if (path == corestring_lwc_query_timeout) {
+ lwc_string_unref(path);
+ return navigate_internal_query_timeout(bw, params);
}
lwc_string_unref(path);
/* Fall through to a normal about: fetch */
normal_fetch:
- return browser_window__navigate_internal_real(bw, params);
+ return navigate_internal_real(bw, params);
}
diff --git a/resources/FatMessages b/resources/FatMessages
index d1ecd9dd1..aa2d7a2d1 100644
--- a/resources/FatMessages
+++ b/resources/FatMessages
@@ -1087,6 +1087,15 @@ en.all.SSLCertErrRevoked:The certificate has been revoked by the issuer.
en.all.SSLCertErrHostnameMismatch:The certificate is for a different host than the server
+# Timeout error interface
+# =======================
+#
+en.all.TimeoutTitle:Connection timed out
+en.all.TimeoutDescription: A connection to %s could not be established. The site may be temporarily unavailable or too busy to respond.
+en.all.Backtoprevious: Back
+en.all.TryAgain: Try Again
+
+
# SSL certificate viewer
# ======================
#
diff --git a/resources/internal.css b/resources/internal.css
index e43d18309..14b47cfa9 100644
--- a/resources/internal.css
+++ b/resources/internal.css
@@ -343,3 +343,41 @@ body#privacy div#buttons {
body#privacy div#buttons input#back {
margin-right: 1em;
}
+
+/*
+ * timeout query styling
+ */
+
+body#timeout {
+ max-width: 45em;
+}
+
+body#timeout 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#timeout 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#timeout form div + div {
+ margin-top: 1em;
+}
+
+body#timeout div#buttons {
+ text-align: right;
+ margin-right: 1em;
+}
+
+body#timeout div#buttons input#back {
+ margin-right: 1em;
+}
diff --git a/utils/corestringlist.h b/utils/corestringlist.h
index f0d39c605..e7516b18a 100644
--- a/utils/corestringlist.h
+++ b/utils/corestringlist.h
@@ -148,6 +148,7 @@ CORESTRING_LWC_VALUE(no_cache, "no-cache");
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");
/* mime types */
CORESTRING_LWC_VALUE(multipart_form_data, "multipart/form-data");
@@ -360,6 +361,7 @@ CORESTRING_DOM_VALUE(html_namespace, "http://www.w3.org/1999/xhtml");
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");
#undef CORESTRING_LWC_STRING
#undef CORESTRING_DOM_STRING