netsurf: branch master updated. release/3.10-61-g44225f1
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/44225f1b34eb1d393a74c...
...commit http://git.netsurf-browser.org/netsurf.git/commit/44225f1b34eb1d393a74cc4...
...tree http://git.netsurf-browser.org/netsurf.git/tree/44225f1b34eb1d393a74cc44d...
The branch, master has been updated
via 44225f1b34eb1d393a74cc44dcfc32d102205ef6 (commit)
via 7e459699931f39739348c75f743b5627e01338b0 (commit)
via f0b7955d3d31ca825ff0717e2cf4d087fc925226 (commit)
via 746affa7821662be32df3e2bdff4e52ad8dde270 (commit)
via b1844cbf2a997ccf999286472ffc4d2c4bf79c1e (commit)
via ff3b948ac0ee0142535bea9a6ebde57b7056c2eb (commit)
via 86ecde9a473deffdbb023317074a46c124477ca2 (commit)
via da7904554c476f4e8451cc54f6f3de882c2f03b6 (commit)
via dd541886fe8899353f45842534c168e42b1ef9a0 (commit)
via 4cbc8f16b65571364828bf12a54c9094b25513f6 (commit)
via 5207ecf3083fdf9e28fbc775426e415ff4a08f5d (commit)
via c74509cdf58fb2473290fcacb8b1cc885b53df87 (commit)
from 7997182cc0748ce449e29460b0534aed8013b6e8 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=44225f1b34eb1d393a7...
commit 44225f1b34eb1d393a74cc44dcfc32d102205ef6
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out about scheme handler for nscolours css
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index da27109..10c9a6a 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -7,6 +7,7 @@ S_FETCHER_ABOUT := \
choices.c \
config.c \
imagecache.c \
+ nscolours.c \
query.c \
query_auth.c \
query_fetcherror.c \
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index bb9d682..fe9eba7 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -26,27 +26,24 @@
* information from the browser from a known, fixed URL.
*/
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
+#include <stdbool.h>
+#include <stddef.h>
#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
#include "netsurf/inttypes.h"
-#include "netsurf/plot_style.h"
-#include "utils/log.h"
+#include "utils/errors.h"
+#include "utils/nsurl.h"
#include "utils/corestrings.h"
-#include "utils/nscolour.h"
-#include "utils/nsoption.h"
#include "utils/utils.h"
-#include "utils/messages.h"
#include "utils/ring.h"
#include "content/fetch.h"
#include "content/fetchers.h"
-#include "desktop/system_colour.h"
-
#include "private.h"
#include "about.h"
#include "blank.h"
@@ -54,6 +51,7 @@
#include "config.h"
#include "choices.h"
#include "imagecache.h"
+#include "nscolours.h"
#include "query.h"
#include "query_auth.h"
#include "query_fetcherror.h"
@@ -299,51 +297,6 @@ static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
/**
- * Handler to generate the nscolours stylesheet
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_nscolours_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- const char *stylesheet;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, 200);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/css; charset=utf-8")) {
- goto aborted;
- }
-
- res = nscolour_get_stylesheet(&stylesheet);
- if (res != NSERROR_OK) {
- goto aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "html {\n"
- "\tbackground-color: #%06x;\n"
- "}\n"
- "%s",
- colour_rb_swap(nscolours[NSCOLOUR_WIN_ODD_BG]),
- stylesheet);
- if (res != NSERROR_OK) {
- goto aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-aborted:
-
- return false;
-}
-
-
-/**
* Handler to generate about scheme logo page
*
* \param ctx The fetcher context.
diff --git a/content/fetchers/about/nscolours.c b/content/fetchers/about/nscolours.c
new file mode 100644
index 0000000..bd7a5ed
--- /dev/null
+++ b/content/fetchers/about/nscolours.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "netsurf/plot_style.h"
+
+#include "utils/errors.h"
+#include "utils/nscolour.h"
+
+#include "private.h"
+#include "nscolours.h"
+
+/**
+ * Handler to generate the nscolours stylesheet
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_nscolours_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ const char *stylesheet;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/css; charset=utf-8")) {
+ goto aborted;
+ }
+
+ res = nscolour_get_stylesheet(&stylesheet);
+ if (res != NSERROR_OK) {
+ goto aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "html {\n"
+ "\tbackground-color: #%06x;\n"
+ "}\n"
+ "%s",
+ colour_rb_swap(nscolours[NSCOLOUR_WIN_ODD_BG]),
+ stylesheet);
+ if (res != NSERROR_OK) {
+ goto aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+aborted:
+
+ return false;
+}
diff --git a/content/fetchers/about/nscolours.h b/content/fetchers/about/nscolours.h
new file mode 100644
index 0000000..a602e4d
--- /dev/null
+++ b/content/fetchers/about/nscolours.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme nscolours handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_NSCOLOURS_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_NSCOLOURS_H
+
+/**
+ * Handler to generate the nscolours stylesheet
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_nscolours_handler(struct fetch_about_context *ctx);
+
+#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=7e459699931f3973934...
commit 7e459699931f39739348c75f743b5627e01338b0
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out about scheme query fetcherror handler
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index 5291418..da27109 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -9,6 +9,7 @@ S_FETCHER_ABOUT := \
imagecache.c \
query.c \
query_auth.c \
+ query_fetcherror.c \
query_privacy.c \
query_timeout.c \
testament.c
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index d1547ae..bb9d682 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -56,6 +56,7 @@
#include "imagecache.h"
#include "query.h"
#include "query_auth.h"
+#include "query_fetcherror.h"
#include "query_privacy.h"
#include "query_timeout.h"
#include "atestament.h"
@@ -386,131 +387,6 @@ static bool fetch_about_welcome_handler(struct fetch_about_context *ctx)
}
-
-
-/**
- * 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 = fetch_about_ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>%s</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"fetcherror\">\n"
- "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<form method=\"post\""
- " enctype=\"multipart/form-data\">");
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
-
- res = get_query_description(siteurl,
- "FetchErrorDescription",
- &description);
- if (res == NSERROR_OK) {
- res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
- }
- res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", reason);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
-
- res = fetch_about_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_fetcherror_handler_aborted;
- }
-
- res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
- if (res != NSERROR_OK) {
- url_s = strdup("");
- }
- res = fetch_about_ssenddataf(ctx,
- "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
- url_s);
- free(url_s);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\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);
diff --git a/content/fetchers/about/query_fetcherror.c b/content/fetchers/about/query_fetcherror.c
new file mode 100644
index 0000000..010a597
--- /dev/null
+++ b/content/fetchers/about/query_fetcherror.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/messages.h"
+#include "content/fetch.h"
+
+#include "private.h"
+#include "query.h"
+#include "query_fetcherror.h"
+
+/**
+ * Handler to generate about scheme fetch error query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+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 = fetch_about_get_multipart(ctx);
+ 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_about_set_http_code(ctx, 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 = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"fetcherror\">\n"
+ "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = get_query_description(siteurl,
+ "FetchErrorDescription",
+ &description);
+ if (res == NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+ }
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", reason);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = fetch_about_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_fetcherror_handler_aborted;
+ }
+
+ res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ url_s = strdup("");
+ }
+ res = fetch_about_ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
+ url_s);
+ free(url_s);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\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;
+}
diff --git a/content/fetchers/about/query_fetcherror.h b/content/fetchers/about/query_fetcherror.h
new file mode 100644
index 0000000..85d972f
--- /dev/null
+++ b/content/fetchers/about/query_fetcherror.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme query fetch error handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_FETCHERROR_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_FETCHERROR_H
+
+/**
+ * Handler to generate about scheme fetch error query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_query_fetcherror_handler(struct fetch_about_context *ctx);
+
+#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=f0b7955d3d31ca825ff...
commit f0b7955d3d31ca825ff0717e2cf4d087fc925226
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out about scheme query timeout page
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index ea6a2d4..5291418 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -10,6 +10,7 @@ S_FETCHER_ABOUT := \
query.c \
query_auth.c \
query_privacy.c \
+ query_timeout.c \
testament.c
# The following files depend on the testament
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index 9f1b3e9..d1547ae 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -57,6 +57,7 @@
#include "query.h"
#include "query_auth.h"
#include "query_privacy.h"
+#include "query_timeout.h"
#include "atestament.h"
typedef bool (*fetch_about_handler)(struct fetch_about_context *);
@@ -385,126 +386,6 @@ static bool fetch_about_welcome_handler(struct fetch_about_context *ctx)
}
-/**
- * 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 = fetch_about_ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>%s</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"timeout\">\n"
- "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_timeout_handler_aborted;
- }
-
- res = fetch_about_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",
- &description);
- if (res == NSERROR_OK) {
- res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_timeout_handler_aborted;
- }
- }
- res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", reason);
- if (res != NSERROR_OK) {
- goto fetch_about_query_timeout_handler_aborted;
- }
-
- res = fetch_about_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 = fetch_about_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 = fetch_about_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;
-}
/**
diff --git a/content/fetchers/about/query_timeout.c b/content/fetchers/about/query_timeout.c
new file mode 100644
index 0000000..5c014bc
--- /dev/null
+++ b/content/fetchers/about/query_timeout.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query timeout page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/messages.h"
+#include "content/fetch.h"
+
+#include "private.h"
+#include "query.h"
+#include "query_timeout.h"
+
+/**
+ * Handler to generate about scheme timeout query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+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 = fetch_about_get_multipart(ctx);
+ 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_about_set_http_code(ctx, 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 = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"timeout\">\n"
+ "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ res = fetch_about_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",
+ &description);
+ if (res == NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+ }
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", reason);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ res = fetch_about_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 = fetch_about_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 = fetch_about_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;
+}
diff --git a/content/fetchers/about/query_timeout.h b/content/fetchers/about/query_timeout.h
new file mode 100644
index 0000000..a64757f
--- /dev/null
+++ b/content/fetchers/about/query_timeout.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme query timeout handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_TIMEOUT_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_TIMEOUT_H
+
+/**
+ * Handler to generate about scheme timeout query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_query_timeout_handler(struct fetch_about_context *ctx);
+
+#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=746affa7821662be32d...
commit 746affa7821662be32df3e2bdff4e52ad8dde270
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out about scheme query auth handler
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index 4b3df3e..ea6a2d4 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -8,6 +8,7 @@ S_FETCHER_ABOUT := \
config.c \
imagecache.c \
query.c \
+ query_auth.c \
query_privacy.c \
testament.c
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index 38ad575..9f1b3e9 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -48,13 +48,14 @@
#include "desktop/system_colour.h"
#include "private.h"
-#include "query.h"
#include "about.h"
#include "blank.h"
#include "certificate.h"
#include "config.h"
#include "choices.h"
#include "imagecache.h"
+#include "query.h"
+#include "query_auth.h"
#include "query_privacy.h"
#include "atestament.h"
@@ -385,219 +386,6 @@ static bool fetch_about_welcome_handler(struct fetch_about_context *ctx)
/**
- * generate the description of the login query
- */
-static nserror
-get_authentication_description(struct nsurl *url,
- const char *realm,
- const char *username,
- const char *password,
- char **out_str)
-{
- nserror res;
- char *url_s;
- size_t url_l;
- char *str = NULL;
- const char *key;
-
- res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
- if (res != NSERROR_OK) {
- return res;
- }
-
- if ((*username == 0) && (*password == 0)) {
- key = "LoginDescription";
- } else {
- key = "LoginAgain";
- }
-
- str = messages_get_buff(key, url_s, realm);
- if (str != NULL) {
- NSLOG(netsurf, INFO,
- "key:%s url:%s realm:%s str:%s",
- key, url_s, realm, str);
- *out_str = str;
- } else {
- res = NSERROR_NOMEM;
- }
-
- free(url_s);
-
- return res;
-}
-
-
-
-
-/**
- * Handler to generate about scheme authentication query page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- char *url_s;
- size_t url_l;
- const char *realm = "";
- const char *username = "";
- const char *password = "";
- const char *title;
- char *description = NULL;
- struct nsurl *siteurl = 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, "realm") == 0) {
- realm = curmd->value;
- } else if (strcmp(curmd->name, "username") == 0) {
- username = curmd->value;
- } else if (strcmp(curmd->name, "password") == 0) {
- password = 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_auth_handler_aborted;
- }
-
- title = messages_get("LoginTitle");
- res = fetch_about_ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>%s</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"authentication\">\n"
- "<h1 class=\"ns-border\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<form method=\"post\""
- " enctype=\"multipart/form-data\">");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = get_authentication_description(siteurl,
- realm,
- username,
- password,
- &description);
- if (res == NSERROR_OK) {
- res = fetch_about_ssenddataf(ctx, "<p>%s</p>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
- }
-
- res = fetch_about_ssenddataf(ctx, "<table>");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<tr>"
- "<th><label for=\"name\">%s:</label></th>"
- "<td><input type=\"text\" id=\"username\" "
- "name=\"username\" value=\"%s\"></td>"
- "</tr>",
- messages_get("Username"), username);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<tr>"
- "<th><label for=\"password\">%s:</label></th>"
- "<td><input type=\"password\" id=\"password\" "
- "name=\"password\" value=\"%s\"></td>"
- "</tr>",
- messages_get("Password"), password);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx, "</table>");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<div id=\"buttons\">"
- "<input type=\"submit\" id=\"login\" name=\"login\" "
- "value=\"%s\" class=\"default-action\">"
- "<input type=\"submit\" id=\"cancel\" name=\"cancel\" "
- "value=\"%s\">"
- "</div>",
- messages_get("Login"),
- messages_get("Cancel"));
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
- if (res != NSERROR_OK) {
- url_s = strdup("");
- }
- res = fetch_about_ssenddataf(ctx,
- "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
- url_s);
- free(url_s);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<input type=\"hidden\" name=\"realm\" value=\"%s\">",
- realm);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- nsurl_unref(siteurl);
-
- return true;
-
-fetch_about_query_auth_handler_aborted:
-
- nsurl_unref(siteurl);
-
- return false;
-}
-
-
-
-
-/**
* Handler to generate about scheme timeout query page
*
* \param ctx The fetcher context.
diff --git a/content/fetchers/about/query_auth.c b/content/fetchers/about/query_auth.c
new file mode 100644
index 0000000..1ed2e80
--- /dev/null
+++ b/content/fetchers/about/query_auth.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "content/fetch.h"
+
+#include "private.h"
+#include "query_auth.h"
+
+
+/**
+ * generate the description of the login query
+ */
+static nserror
+get_authentication_description(struct nsurl *url,
+ const char *realm,
+ const char *username,
+ const char *password,
+ char **out_str)
+{
+ nserror res;
+ char *url_s;
+ size_t url_l;
+ char *str = NULL;
+ const char *key;
+
+ res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if ((*username == 0) && (*password == 0)) {
+ key = "LoginDescription";
+ } else {
+ key = "LoginAgain";
+ }
+
+ str = messages_get_buff(key, url_s, realm);
+ if (str != NULL) {
+ NSLOG(netsurf, INFO,
+ "key:%s url:%s realm:%s str:%s",
+ key, url_s, realm, str);
+ *out_str = str;
+ } else {
+ res = NSERROR_NOMEM;
+ }
+
+ free(url_s);
+
+ return res;
+}
+
+
+/**
+ * Handler to generate about scheme authentication query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ char *url_s;
+ size_t url_l;
+ const char *realm = "";
+ const char *username = "";
+ const char *password = "";
+ const char *title;
+ char *description = NULL;
+ struct nsurl *siteurl = NULL;
+ const struct fetch_multipart_data *curmd; /* mutipart data iterator */
+
+ /* extract parameters from multipart post data */
+ curmd = fetch_about_get_multipart(ctx);
+ 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, "realm") == 0) {
+ realm = curmd->value;
+ } else if (strcmp(curmd->name, "username") == 0) {
+ username = curmd->value;
+ } else if (strcmp(curmd->name, "password") == 0) {
+ password = curmd->value;
+ }
+ curmd = curmd->next;
+ }
+
+ if (siteurl == NULL) {
+ return fetch_about_srverror(ctx);
+ }
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html; charset=utf-8")) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ title = messages_get("LoginTitle");
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"authentication\">\n"
+ "<h1 class=\"ns-border\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = get_authentication_description(siteurl,
+ realm,
+ username,
+ password,
+ &description);
+ if (res == NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<p>%s</p>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx, "<table>");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<tr>"
+ "<th><label for=\"name\">%s:</label></th>"
+ "<td><input type=\"text\" id=\"username\" "
+ "name=\"username\" value=\"%s\"></td>"
+ "</tr>",
+ messages_get("Username"), username);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<tr>"
+ "<th><label for=\"password\">%s:</label></th>"
+ "<td><input type=\"password\" id=\"password\" "
+ "name=\"password\" value=\"%s\"></td>"
+ "</tr>",
+ messages_get("Password"), password);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</table>");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<div id=\"buttons\">"
+ "<input type=\"submit\" id=\"login\" name=\"login\" "
+ "value=\"%s\" class=\"default-action\">"
+ "<input type=\"submit\" id=\"cancel\" name=\"cancel\" "
+ "value=\"%s\">"
+ "</div>",
+ messages_get("Login"),
+ messages_get("Cancel"));
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ url_s = strdup("");
+ }
+ res = fetch_about_ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
+ url_s);
+ free(url_s);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"realm\" value=\"%s\">",
+ realm);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ nsurl_unref(siteurl);
+
+ return true;
+
+fetch_about_query_auth_handler_aborted:
+
+ nsurl_unref(siteurl);
+
+ return false;
+}
diff --git a/content/fetchers/about/query_auth.h b/content/fetchers/about/query_auth.h
new file mode 100644
index 0000000..1c7f658
--- /dev/null
+++ b/content/fetchers/about/query_auth.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme query auth handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_AUTH_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_AUTH_H
+
+/**
+ * Handler to generate about scheme query auth page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_query_auth_handler(struct fetch_about_context *ctx);
+
+#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=b1844cbf2a997ccf999...
commit b1844cbf2a997ccf999286472ffc4d2c4bf79c1e
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out about scheme query private handler
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index 52eaece..4b3df3e 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -7,6 +7,8 @@ S_FETCHER_ABOUT := \
choices.c \
config.c \
imagecache.c \
+ query.c \
+ query_privacy.c \
testament.c
# The following files depend on the testament
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index 1bc382b..38ad575 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -48,13 +48,15 @@
#include "desktop/system_colour.h"
#include "private.h"
+#include "query.h"
+#include "about.h"
#include "blank.h"
#include "certificate.h"
-#include "imagecache.h"
-#include "atestament.h"
#include "config.h"
#include "choices.h"
-#include "about.h"
+#include "imagecache.h"
+#include "query_privacy.h"
+#include "atestament.h"
typedef bool (*fetch_about_handler)(struct fetch_about_context *);
@@ -219,13 +221,16 @@ nsurl *fetch_about_get_url(struct fetch_about_context *ctx)
}
-/**
- * Generate a 500 server error respnse
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_srverror(struct fetch_about_context *ctx)
+/* exported interface documented in about/private.h */
+const struct fetch_multipart_data *
+fetch_about_get_multipart(struct fetch_about_context *ctx)
+{
+ return ctx->multipart;
+}
+
+
+/* exported interface documented in about/private.h */
+bool fetch_about_srverror(struct fetch_about_context *ctx)
{
nserror res;
@@ -422,37 +427,6 @@ get_authentication_description(struct nsurl *url,
}
-/**
- * generate a generic query description
- */
-static nserror
-get_query_description(struct nsurl *url,
- const char *key,
- char **out_str)
-{
- nserror res;
- char *url_s;
- size_t url_l;
- char *str = NULL;
-
- /* get the host in question */
- res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
- if (res != NSERROR_OK) {
- return res;
- }
-
- /* obtain the description with the url substituted */
- str = messages_get_buff(key, url_s);
- if (str == NULL) {
- res = NSERROR_NOMEM;
- } else {
- *out_str = str;
- }
-
- free(url_s);
-
- return res;
-}
/**
@@ -621,142 +595,6 @@ fetch_about_query_auth_handler_aborted:
}
-/**
- * Handler to generate about scheme privacy query page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_query_privacy_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 char *chainurl = 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;
- } else if (strcmp(curmd->name, "chainurl") == 0) {
- chainurl = 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_ssl_handler_aborted;
- }
-
- title = messages_get("PrivacyTitle");
- res = fetch_about_ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>%s</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"privacy\">\n"
- "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<form method=\"post\""
- " enctype=\"multipart/form-data\">");
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- res = get_query_description(siteurl,
- "PrivacyDescription",
- &description);
- if (res == NSERROR_OK) {
- res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
- }
-
- if (chainurl == NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<div><p>%s</p></div>"
- "<div><p>%s</p></div>",
- reason,
- messages_get("ViewCertificatesNotPossible"));
- } else {
- res = fetch_about_ssenddataf(ctx,
- "<div><p>%s</p></div>"
- "<div><p><a href=\"%s\" target=\"_blank\">%s</a></p></div>",
- reason,
- chainurl,
- messages_get("ViewCertificates"));
- }
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
- res = fetch_about_ssenddataf(ctx,
- "<div id=\"buttons\">"
- "<input type=\"submit\" id=\"back\" name=\"back\" "
- "value=\"%s\" class=\"default-action\">"
- "<input type=\"submit\" id=\"proceed\" name=\"proceed\" "
- "value=\"%s\">"
- "</div>",
- messages_get("Backtosafety"),
- messages_get("Proceed"));
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
- if (res != NSERROR_OK) {
- url_s = strdup("");
- }
- res = fetch_about_ssenddataf(ctx,
- "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
- url_s);
- free(url_s);
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- nsurl_unref(siteurl);
-
- return true;
-
-fetch_about_query_ssl_handler_aborted:
- nsurl_unref(siteurl);
-
- return false;
-}
/**
diff --git a/content/fetchers/about/private.h b/content/fetchers/about/private.h
index 808a91e..fcf9b19 100644
--- a/content/fetchers/about/private.h
+++ b/content/fetchers/about/private.h
@@ -25,6 +25,7 @@
#define NETSURF_CONTENT_FETCHERS_ABOUT_PRIVATE_H
struct fetch_about_context;
+struct fetch_multipart_data;
/**
* set http response code on about response
@@ -43,8 +44,7 @@ bool fetch_about_send_header(struct fetch_about_context *ctx, const char *fmt, .
/**
* send data on the about response
*/
-nserror
-fetch_about_senddata(struct fetch_about_context *ctx, const uint8_t *data, size_t data_len);
+nserror fetch_about_senddata(struct fetch_about_context *ctx, const uint8_t *data, size_t data_len);
/**
* send formatted data on the about response
@@ -57,7 +57,21 @@ nserror fetch_about_ssenddataf(struct fetch_about_context *ctx, const char *fmt,
bool fetch_about_send_finished(struct fetch_about_context *ctx);
/**
+ * Generate a 500 server error respnse
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_srverror(struct fetch_about_context *ctx);
+
+/**
+ * get the fetch url
*/
struct nsurl *fetch_about_get_url(struct fetch_about_context *ctx);
+/**
+ * get multipart fetch data
+ */
+const struct fetch_multipart_data *fetch_about_get_multipart(struct fetch_about_context *ctx);
+
#endif
diff --git a/content/fetchers/about/query.c b/content/fetchers/about/query.c
new file mode 100644
index 0000000..7c4e9f4
--- /dev/null
+++ b/content/fetchers/about/query.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/nsurl.h"
+#include "utils/messages.h"
+
+#include "query.h"
+
+/* exported interface documented in about/query.h */
+nserror
+get_query_description(struct nsurl *url,
+ const char *key,
+ char **out_str)
+{
+ nserror res;
+ char *url_s;
+ size_t url_l;
+ char *str = NULL;
+
+ /* get the host in question */
+ res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* obtain the description with the url substituted */
+ str = messages_get_buff(key, url_s);
+ if (str == NULL) {
+ res = NSERROR_NOMEM;
+ } else {
+ *out_str = str;
+ }
+
+ free(url_s);
+
+ return res;
+}
diff --git a/content/fetchers/about/query.h b/content/fetchers/about/query.h
new file mode 100644
index 0000000..889a9ec
--- /dev/null
+++ b/content/fetchers/about/query.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme query handlers support interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_H
+
+/**
+ * generate a generic query description
+ *
+ * \param url The site url
+ * \param key message key
+ * \param out_str pointer to buffer with output
+ */
+nserror get_query_description(struct nsurl *url, const char *key, char **out_str);
+
+#endif
diff --git a/content/fetchers/about/query_privacy.c b/content/fetchers/about/query_privacy.c
new file mode 100644
index 0000000..030672b
--- /dev/null
+++ b/content/fetchers/about/query_privacy.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/messages.h"
+#include "content/fetch.h"
+
+#include "private.h"
+#include "query.h"
+#include "query_privacy.h"
+
+/**
+ * Handler to generate about scheme privacy query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_query_privacy_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 char *chainurl = NULL;
+ const struct fetch_multipart_data *curmd; /* mutipart data iterator */
+
+ /* extract parameters from multipart post data */
+ curmd = fetch_about_get_multipart(ctx);
+ 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;
+ } else if (strcmp(curmd->name, "chainurl") == 0) {
+ chainurl = curmd->value;
+ }
+ curmd = curmd->next;
+ }
+
+ if (siteurl == NULL) {
+ return fetch_about_srverror(ctx);
+ }
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html; charset=utf-8")) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ title = messages_get("PrivacyTitle");
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"privacy\">\n"
+ "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = get_query_description(siteurl,
+ "PrivacyDescription",
+ &description);
+ if (res == NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+ }
+
+ if (chainurl == NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<div><p>%s</p></div>"
+ "<div><p>%s</p></div>",
+ reason,
+ messages_get("ViewCertificatesNotPossible"));
+ } else {
+ res = fetch_about_ssenddataf(ctx,
+ "<div><p>%s</p></div>"
+ "<div><p><a href=\"%s\" target=\"_blank\">%s</a></p></div>",
+ reason,
+ chainurl,
+ messages_get("ViewCertificates"));
+ }
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+ res = fetch_about_ssenddataf(ctx,
+ "<div id=\"buttons\">"
+ "<input type=\"submit\" id=\"back\" name=\"back\" "
+ "value=\"%s\" class=\"default-action\">"
+ "<input type=\"submit\" id=\"proceed\" name=\"proceed\" "
+ "value=\"%s\">"
+ "</div>",
+ messages_get("Backtosafety"),
+ messages_get("Proceed"));
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ url_s = strdup("");
+ }
+ res = fetch_about_ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
+ url_s);
+ free(url_s);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ nsurl_unref(siteurl);
+
+ return true;
+
+fetch_about_query_ssl_handler_aborted:
+ nsurl_unref(siteurl);
+
+ return false;
+}
diff --git a/content/fetchers/about/query_privacy.h b/content/fetchers/about/query_privacy.h
new file mode 100644
index 0000000..38ddbe8
--- /dev/null
+++ b/content/fetchers/about/query_privacy.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme query privacy handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_PRIVACY_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_PRIVACY_H
+
+/**
+ * Handler to generate about scheme query privacy page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx);
+
+#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=ff3b948ac0ee0142535...
commit ff3b948ac0ee0142535bea9a6ebde57b7056c2eb
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out choices about scheme handler
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index 700ac39..52eaece 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -4,6 +4,7 @@ S_FETCHER_ABOUT := \
about.c \
blank.c \
certificate.c \
+ choices.c \
config.c \
imagecache.c \
testament.c
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index e41e6c8..1bc382b 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -53,6 +53,7 @@
#include "imagecache.h"
#include "atestament.h"
#include "config.h"
+#include "choices.h"
#include "about.h"
typedef bool (*fetch_about_handler)(struct fetch_about_context *);
@@ -289,8 +290,6 @@ static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
}
-
-
/**
* Handler to generate the nscolours stylesheet
*
@@ -337,71 +336,6 @@ aborted:
/**
- * Generate the text of a Choices file which represents the current
- * in use options.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_choices_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- char buffer[1024];
- int code = 200;
- int slen;
- unsigned int opt_loop = 0;
- int res = 0;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, code);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
- goto fetch_about_choices_handler_aborted;
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
-
- slen = snprintf(buffer, sizeof buffer,
- "# Automatically generated current NetSurf browser Choices\n");
-
- do {
- res = nsoption_snoptionf(buffer + slen,
- sizeof buffer - slen,
- opt_loop,
- "%k:%v\n");
- if (res <= 0)
- break; /* last option */
-
- if (res >= (int) (sizeof buffer - slen)) {
- /* last entry would not fit in buffer, submit buffer */
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_choices_handler_aborted;
- slen = 0;
- } else {
- /* normal addition */
- slen += res;
- opt_loop++;
- }
- } while (res > 0);
-
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_choices_handler_aborted;
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_choices_handler_aborted:
- return false;
-}
-
-
-
-
-/**
* Handler to generate about scheme logo page
*
* \param ctx The fetcher context.
diff --git a/content/fetchers/about/choices.c b/content/fetchers/about/choices.c
new file mode 100644
index 0000000..a95502e
--- /dev/null
+++ b/content/fetchers/about/choices.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme blank page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include "netsurf/types.h"
+#include "utils/errors.h"
+#include "utils/nsoption.h"
+
+#include "private.h"
+#include "choices.h"
+
+/**
+ * Generate the text of a Choices file which represents the current
+ * in use options.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_choices_handler(struct fetch_about_context *ctx)
+{
+ char buffer[1024];
+ int code = 200;
+ int slen;
+ unsigned int opt_loop = 0;
+ int res = 0;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
+ goto fetch_about_choices_handler_aborted;
+
+ slen = snprintf(buffer, sizeof buffer,
+ "# Automatically generated current NetSurf browser Choices\n");
+
+ do {
+ res = nsoption_snoptionf(buffer + slen,
+ sizeof buffer - slen,
+ opt_loop,
+ "%k:%v\n");
+ if (res <= 0)
+ break; /* last option */
+
+ if (res >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_choices_handler_aborted;
+ }
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += res;
+ opt_loop++;
+ }
+ } while (res > 0);
+
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_choices_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_choices_handler_aborted:
+ return false;
+}
diff --git a/content/fetchers/about/choices.h b/content/fetchers/about/choices.h
new file mode 100644
index 0000000..0548f5b
--- /dev/null
+++ b/content/fetchers/about/choices.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme choices handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_CHOICES_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_CHOICES_H
+
+/**
+ * Handler to generate about scheme choices page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_choices_handler(struct fetch_about_context *ctx);
+
+#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=86ecde9a473deffdbb0...
commit 86ecde9a473deffdbb023317074a46c124477ca2
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out about handler config handler
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index 142c533..700ac39 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -1,6 +1,12 @@
# about fetcher sources
-S_FETCHER_ABOUT := about.c imagecache.c blank.c certificate.c testament.c
+S_FETCHER_ABOUT := \
+ about.c \
+ blank.c \
+ certificate.c \
+ config.c \
+ imagecache.c \
+ testament.c
# The following files depend on the testament
content/fetchers/about/testament.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index 117bd66..e41e6c8 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -52,6 +52,7 @@
#include "certificate.h"
#include "imagecache.h"
#include "atestament.h"
+#include "config.h"
#include "about.h"
typedef bool (*fetch_about_handler)(struct fetch_about_context *);
@@ -288,106 +289,6 @@ static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
}
-/**
- * Handler to generate about scheme config page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_config_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- char buffer[1024];
- int slen = 0;
- unsigned int opt_loop = 0;
- int elen = 0; /* entry length */
- nserror res;
- bool even = false;
-
- /* 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")) {
- goto fetch_about_config_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>NetSurf Browser Config</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body "
- "id =\"configlist\" "
- "class=\"ns-even-bg ns-even-fg ns-border\" "
- "style=\"overflow: hidden;\">\n"
- "<h1 class=\"ns-border\">NetSurf Browser Config</h1>\n"
- "<table class=\"config\">\n"
- "<tr><th>Option</th>"
- "<th>Type</th>"
- "<th>Provenance</th>"
- "<th>Setting</th></tr>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_config_handler_aborted;
- }
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
-
- do {
- if (even) {
- elen = nsoption_snoptionf(buffer + slen,
- sizeof buffer - slen,
- opt_loop,
- "<tr class=\"ns-even-bg\">"
- "<th class=\"ns-border\">%k</th>"
- "<td class=\"ns-border\">%t</td>"
- "<td class=\"ns-border\">%p</td>"
- "<td class=\"ns-border\">%V</td>"
- "</tr>\n");
- } else {
- elen = nsoption_snoptionf(buffer + slen,
- sizeof buffer - slen,
- opt_loop,
- "<tr class=\"ns-odd-bg\">"
- "<th class=\"ns-border\">%k</th>"
- "<td class=\"ns-border\">%t</td>"
- "<td class=\"ns-border\">%p</td>"
- "<td class=\"ns-border\">%V</td>"
- "</tr>\n");
- }
- if (elen <= 0)
- break; /* last option */
-
- if (elen >= (int) (sizeof buffer - slen)) {
- /* last entry would not fit in buffer, submit buffer */
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_config_handler_aborted;
- slen = 0;
- } else {
- /* normal addition */
- slen += elen;
- opt_loop++;
- even = !even;
- }
- } while (elen > 0);
-
- slen += snprintf(buffer + slen, sizeof buffer - slen,
- "</table>\n</body>\n</html>\n");
-
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_config_handler_aborted;
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_config_handler_aborted:
- return false;
-}
/**
diff --git a/content/fetchers/about/config.c b/content/fetchers/about/config.c
new file mode 100644
index 0000000..a18af95
--- /dev/null
+++ b/content/fetchers/about/config.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme blank page
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "netsurf/types.h"
+#include "utils/errors.h"
+#include "utils/nsoption.h"
+
+#include "private.h"
+#include "config.h"
+
+/**
+ * Handler to generate about scheme config page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_config_handler(struct fetch_about_context *ctx)
+{
+ char buffer[1024];
+ int slen = 0;
+ unsigned int opt_loop = 0;
+ int elen = 0; /* entry length */
+ nserror res;
+ bool even = false;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html")) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>NetSurf Browser Config</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body "
+ "id =\"configlist\" "
+ "class=\"ns-even-bg ns-even-fg ns-border\" "
+ "style=\"overflow: hidden;\">\n"
+ "<h1 class=\"ns-border\">NetSurf Browser Config</h1>\n"
+ "<table class=\"config\">\n"
+ "<tr><th>Option</th>"
+ "<th>Type</th>"
+ "<th>Provenance</th>"
+ "<th>Setting</th></tr>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+
+ do {
+ if (even) {
+ elen = nsoption_snoptionf(buffer + slen,
+ sizeof buffer - slen,
+ opt_loop,
+ "<tr class=\"ns-even-bg\">"
+ "<th class=\"ns-border\">%k</th>"
+ "<td class=\"ns-border\">%t</td>"
+ "<td class=\"ns-border\">%p</td>"
+ "<td class=\"ns-border\">%V</td>"
+ "</tr>\n");
+ } else {
+ elen = nsoption_snoptionf(buffer + slen,
+ sizeof buffer - slen,
+ opt_loop,
+ "<tr class=\"ns-odd-bg\">"
+ "<th class=\"ns-border\">%k</th>"
+ "<td class=\"ns-border\">%t</td>"
+ "<td class=\"ns-border\">%p</td>"
+ "<td class=\"ns-border\">%V</td>"
+ "</tr>\n");
+ }
+ if (elen <= 0)
+ break; /* last option */
+
+ if (elen >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += elen;
+ opt_loop++;
+ even = !even;
+ }
+ } while (elen > 0);
+
+ slen += snprintf(buffer + slen, sizeof buffer - slen,
+ "</table>\n</body>\n</html>\n");
+
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_config_handler_aborted:
+ return false;
+}
diff --git a/content/fetchers/about/config.h b/content/fetchers/about/config.h
new file mode 100644
index 0000000..efef239
--- /dev/null
+++ b/content/fetchers/about/config.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme config handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_CONFIG_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_CONFIG_H
+
+/**
+ * Handler to generate about scheme config page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_config_handler(struct fetch_about_context *ctx);
+
+#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=da7904554c476f4e845...
commit da7904554c476f4e8451cc54f6f3de882c2f03b6
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out about scheme testament handler
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index cca22d3..142c533 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -1,6 +1,6 @@
# about fetcher sources
-S_FETCHER_ABOUT := about.c imagecache.c blank.c certificate.c
+S_FETCHER_ABOUT := about.c imagecache.c blank.c certificate.c testament.c
# The following files depend on the testament
-content/fetchers/about/about.c: testament $(OBJROOT)/testament.h
+content/fetchers/about/testament.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index 2ef470b..117bd66 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -35,7 +35,6 @@
#include "netsurf/plot_style.h"
#include "utils/log.h"
-#include "testament.h"
#include "utils/corestrings.h"
#include "utils/nscolour.h"
#include "utils/nsoption.h"
@@ -52,6 +51,7 @@
#include "blank.h"
#include "certificate.h"
#include "imagecache.h"
+#include "atestament.h"
#include "about.h"
typedef bool (*fetch_about_handler)(struct fetch_about_context *);
@@ -216,6 +216,7 @@ nsurl *fetch_about_get_url(struct fetch_about_context *ctx)
return ctx->url;
}
+
/**
* Generate a 500 server error respnse
*
@@ -243,8 +244,6 @@ static bool fetch_about_srverror(struct fetch_about_context *ctx)
}
-
-
/**
* Handler to generate about scheme credits page.
*
@@ -289,9 +288,6 @@ static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
}
-
-
-
/**
* Handler to generate about scheme config page
*
@@ -502,102 +498,6 @@ fetch_about_choices_handler_aborted:
}
-typedef struct {
- const char *leaf;
- const char *modtype;
-} modification_t;
-
-/**
- * Generate the text of an svn testament which represents the current
- * build-tree status
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_testament_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- static modification_t modifications[] = WT_MODIFICATIONS;
- int modidx; /* midification index */
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, 200);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
- goto fetch_about_testament_handler_aborted;
-
- res = fetch_about_ssenddataf(ctx,
- "# Automatically generated by NetSurf build system\n\n");
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
-#if defined(WT_BRANCHISTRUNK) || defined(WT_BRANCHISMASTER)
- "# This is a *DEVELOPMENT* build from the main line.\n\n"
-#elif defined(WT_BRANCHISTAG) && (WT_MODIFIED == 0)
- "# This is a tagged build of NetSurf\n"
-#ifdef WT_TAGIS
- "# The tag used was '" WT_TAGIS "'\n\n"
-#else
- "\n"
-#endif
-#elif defined(WT_NO_SVN) || defined(WT_NO_GIT)
- "# This NetSurf was built outside of our revision "
- "control environment.\n"
- "# This testament is therefore not very useful.\n\n"
-#else
- "# This NetSurf was built from a branch (" WT_BRANCHPATH ").\n\n"
-#endif
-#if defined(CI_BUILD)
- "# This build carries the CI build number '" CI_BUILD "'\n\n"
-#endif
- );
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "Built by %s (%s) from %s at revision %s on %s\n\n",
- GECOS, USERNAME, WT_BRANCHPATH, WT_REVID, WT_COMPILEDATE);
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- res = fetch_about_ssenddataf(ctx, "Built on %s in %s\n\n", WT_HOSTNAME, WT_ROOT);
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- if (WT_MODIFIED > 0) {
- res = fetch_about_ssenddataf(ctx,
- "Working tree has %d modification%s\n\n",
- WT_MODIFIED, WT_MODIFIED == 1 ? "" : "s");
- } else {
- res = fetch_about_ssenddataf(ctx, "Working tree is not modified.\n");
- }
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- for (modidx = 0; modidx < WT_MODIFIED; ++modidx) {
- res = fetch_about_ssenddataf(ctx,
- " %s %s\n",
- modifications[modidx].modtype,
- modifications[modidx].leaf);
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_testament_handler_aborted:
- return false;
-}
/**
diff --git a/content/fetchers/about/atestament.h b/content/fetchers/about/atestament.h
new file mode 100644
index 0000000..1851e8f
--- /dev/null
+++ b/content/fetchers/about/atestament.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme testament handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_TESTAMENT_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_TESTAMENT_H
+
+/**
+ * Handler to generate about scheme testament page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_testament_handler(struct fetch_about_context *ctx);
+
+#endif
diff --git a/content/fetchers/about/testament.c b/content/fetchers/about/testament.c
new file mode 100644
index 0000000..ae992ec
--- /dev/null
+++ b/content/fetchers/about/testament.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme testament page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "utils/errors.h"
+#include "netsurf/inttypes.h"
+#include "testament.h"
+
+#include "private.h"
+#include "atestament.h"
+
+typedef struct {
+ const char *leaf;
+ const char *modtype;
+} modification_t;
+
+/**
+ * Generate the text of an svn testament which represents the current
+ * build-tree status
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_testament_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ static modification_t modifications[] = WT_MODIFICATIONS;
+ int modidx; /* midification index */
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
+ goto fetch_about_testament_handler_aborted;
+
+ res = fetch_about_ssenddataf(ctx,
+ "# Automatically generated by NetSurf build system\n\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+#if defined(WT_BRANCHISTRUNK) || defined(WT_BRANCHISMASTER)
+ "# This is a *DEVELOPMENT* build from the main line.\n\n"
+#elif defined(WT_BRANCHISTAG) && (WT_MODIFIED == 0)
+ "# This is a tagged build of NetSurf\n"
+#ifdef WT_TAGIS
+ "# The tag used was '" WT_TAGIS "'\n\n"
+#else
+ "\n"
+#endif
+#elif defined(WT_NO_SVN) || defined(WT_NO_GIT)
+ "# This NetSurf was built outside of our revision "
+ "control environment.\n"
+ "# This testament is therefore not very useful.\n\n"
+#else
+ "# This NetSurf was built from a branch (" WT_BRANCHPATH ").\n\n"
+#endif
+#if defined(CI_BUILD)
+ "# This build carries the CI build number '" CI_BUILD "'\n\n"
+#endif
+ );
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "Built by %s (%s) from %s at revision %s on %s\n\n",
+ GECOS, USERNAME, WT_BRANCHPATH, WT_REVID, WT_COMPILEDATE);
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "Built on %s in %s\n\n", WT_HOSTNAME, WT_ROOT);
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ if (WT_MODIFIED > 0) {
+ res = fetch_about_ssenddataf(ctx,
+ "Working tree has %d modification%s\n\n",
+ WT_MODIFIED, WT_MODIFIED == 1 ? "" : "s");
+ } else {
+ res = fetch_about_ssenddataf(ctx, "Working tree is not modified.\n");
+ }
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ for (modidx = 0; modidx < WT_MODIFIED; ++modidx) {
+ res = fetch_about_ssenddataf(ctx,
+ " %s %s\n",
+ modifications[modidx].modtype,
+ modifications[modidx].leaf);
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_testament_handler_aborted:
+ return false;
+}
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=dd541886fe8899353f4...
commit dd541886fe8899353f45842534c168e42b1ef9a0
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out about scheme certificate viewer generator
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index 5b45022..cca22d3 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -1,6 +1,6 @@
# about fetcher sources
-S_FETCHER_ABOUT := about.c imagecache.c blank.c
+S_FETCHER_ABOUT := about.c imagecache.c blank.c certificate.c
# The following files depend on the testament
content/fetchers/about/about.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index 0448a0e..2ef470b 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -50,6 +50,7 @@
#include "private.h"
#include "blank.h"
+#include "certificate.h"
#include "imagecache.h"
#include "about.h"
@@ -209,6 +210,12 @@ fetch_about_ssenddataf(struct fetch_about_context *ctx, const char *fmt, ...)
}
+/* exported interface documented in about/private.h */
+nsurl *fetch_about_get_url(struct fetch_about_context *ctx)
+{
+ return ctx->url;
+}
+
/**
* Generate a 500 server error respnse
*
@@ -283,1158 +290,6 @@ static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
-/**
- * certificate name parameters
- */
-struct ns_cert_name {
- char *common_name;
- char *organisation;
- char *organisation_unit;
- char *locality;
- char *province;
- char *country;
-};
-
-/**
- * Certificate public key parameters
- */
-struct ns_cert_pkey {
- char *algor;
- int size;
- char *modulus;
- char *exponent;
- char *curve;
- char *public;
-};
-
-/**
- * Certificate subject alternative name
- */
-struct ns_cert_san {
- struct ns_cert_san *next;
- char *name;
-};
-
-/**
- * certificate information for certificate chain
- */
-struct ns_cert_info {
- struct ns_cert_name subject_name; /**< Subject details */
- struct ns_cert_name issuer_name; /**< Issuer details */
- struct ns_cert_pkey public_key; /**< public key details */
- long version; /**< Certificate version */
- char *not_before; /**< Valid from date */
- char *not_after; /**< Valid to date */
- int sig_type; /**< Signature type */
- char *sig_algor; /**< Signature Algorithm */
- char *serialnum; /**< Serial number */
- char *sha1fingerprint; /**< fingerprint shar1 encoded */
- char *sha256fingerprint; /**< fingerprint shar256 encoded */
- struct ns_cert_san *san; /**< subject alternative names */
- ssl_cert_err err; /**< Whatever is wrong with this certificate */
-};
-
-/**
- * free all resources associated with a certificate information structure
- */
-static nserror free_ns_cert_info(struct ns_cert_info *cinfo)
-{
- struct ns_cert_san *san;
-
- free(cinfo->subject_name.common_name);
- free(cinfo->subject_name.organisation);
- free(cinfo->subject_name.organisation_unit);
- free(cinfo->subject_name.locality);
- free(cinfo->subject_name.province);
- free(cinfo->subject_name.country);
- free(cinfo->issuer_name.common_name);
- free(cinfo->issuer_name.organisation);
- free(cinfo->issuer_name.organisation_unit);
- free(cinfo->issuer_name.locality);
- free(cinfo->issuer_name.province);
- free(cinfo->issuer_name.country);
- free(cinfo->public_key.algor);
- free(cinfo->public_key.modulus);
- free(cinfo->public_key.exponent);
- free(cinfo->public_key.curve);
- free(cinfo->public_key.public);
- free(cinfo->not_before);
- free(cinfo->not_after);
- free(cinfo->sig_algor);
- free(cinfo->serialnum);
-
- /* free san list avoiding use after free */
- san = cinfo->san;
- while (san != NULL) {
- struct ns_cert_san *next;
- next = san->next;
- free(san);
- san = next;
- }
-
- free(cinfo);
-
- return NSERROR_OK;
-}
-
-#ifdef WITH_OPENSSL
-
-#include <openssl/ssl.h>
-#include <openssl/x509v3.h>
-
-/* OpenSSL 1.0.x, 1.0.2, 1.1.0 and 1.1.1 API all changed
- * LibreSSL declares its OpenSSL version as 2.1 but only supports 1.0.x API
- */
-#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL))
-/* 1.0.x */
-
-#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1000200fL))
-/* pre 1.0.2 */
-static int ns_X509_get_signature_nid(X509 *cert)
-{
- return OBJ_obj2nid(cert->cert_info->key->algor->algorithm);
-}
-#else
-#define ns_X509_get_signature_nid X509_get_signature_nid
-#endif
-
-static const unsigned char *ns_ASN1_STRING_get0_data(ASN1_STRING *asn1str)
-{
- return (const unsigned char *)ASN1_STRING_data(asn1str);
-}
-
-static const BIGNUM *ns_RSA_get0_n(const RSA *d)
-{
- return d->n;
-}
-
-static const BIGNUM *ns_RSA_get0_e(const RSA *d)
-{
- return d->e;
-}
-
-static int ns_RSA_bits(const RSA *rsa)
-{
- return RSA_size(rsa) * 8;
-}
-
-static int ns_DSA_bits(const DSA *dsa)
-{
- return DSA_size(dsa) * 8;
-}
-
-static int ns_DH_bits(const DH *dh)
-{
- return DH_size(dh) * 8;
-}
-
-#elif (OPENSSL_VERSION_NUMBER < 0x1010100fL)
-/* 1.1.0 */
-#define ns_X509_get_signature_nid X509_get_signature_nid
-#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
-
-static const BIGNUM *ns_RSA_get0_n(const RSA *r)
-{
- const BIGNUM *n;
- const BIGNUM *e;
- const BIGNUM *d;
- RSA_get0_key(r, &n, &e, &d);
- return n;
-}
-
-static const BIGNUM *ns_RSA_get0_e(const RSA *r)
-{
- const BIGNUM *n;
- const BIGNUM *e;
- const BIGNUM *d;
- RSA_get0_key(r, &n, &e, &d);
- return e;
-}
-
-#define ns_RSA_bits RSA_bits
-#define ns_DSA_bits DSA_bits
-#define ns_DH_bits DH_bits
-
-#else
-/* 1.1.1 and later */
-#define ns_X509_get_signature_nid X509_get_signature_nid
-#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
-#define ns_RSA_get0_n RSA_get0_n
-#define ns_RSA_get0_e RSA_get0_e
-#define ns_RSA_bits RSA_bits
-#define ns_DSA_bits DSA_bits
-#define ns_DH_bits DH_bits
-#endif
-
-/**
- * extract certificate name information
- *
- * \param xname The X509 name to convert. The reference is borrowed so is not freeed
- * \param iname The info structure to recive the extracted parameters.
- * \return NSERROR_OK on success else error code
- */
-static nserror
-xname_to_info(X509_NAME *xname, struct ns_cert_name *iname)
-{
- int entryidx;
- int entrycnt;
- X509_NAME_ENTRY *entry; /* current name entry */
- ASN1_STRING *value;
- const unsigned char *value_str;
- ASN1_OBJECT *name;
- int name_nid;
- char **field;
-
- entrycnt = X509_NAME_entry_count(xname);
-
- for (entryidx = 0; entryidx < entrycnt; entryidx++) {
- entry = X509_NAME_get_entry(xname, entryidx);
- name = X509_NAME_ENTRY_get_object(entry);
- name_nid = OBJ_obj2nid(name);
- value = X509_NAME_ENTRY_get_data(entry);
- value_str = ns_ASN1_STRING_get0_data(value);
- switch (name_nid) {
- case NID_commonName:
- field = &iname->common_name;
- break;
- case NID_countryName:
- field = &iname->country;
- break;
- case NID_localityName:
- field = &iname->locality;
- break;
- case NID_stateOrProvinceName:
- field = &iname->province;
- break;
- case NID_organizationName:
- field = &iname->organisation;
- break;
- case NID_organizationalUnitName:
- field = &iname->organisation_unit;
- break;
- default :
- field = NULL;
- break;
- }
- if (field != NULL) {
- *field = strdup((const char *)value_str);
- NSLOG(netsurf, DEEPDEBUG,
- "NID:%d value: %s", name_nid, *field);
- } else {
- NSLOG(netsurf, DEEPDEBUG, "NID:%d", name_nid);
- }
- }
-
- /*
- * ensure the common name is set to something, this being
- * missing means the certificate is broken but this should be
- * robust in the face of bad data
- */
- if (iname->common_name == NULL) {
- iname->common_name = strdup("Unknown");
- }
-
- return NSERROR_OK;
-}
-
-
-/**
- * duplicate a hex formatted string inserting the colons
- *
- * \todo only uses html entity as separator because netsurfs line breaking
- * fails otherwise.
- */
-static char *hexdup(const char *hex)
-{
- int hexlen;
- char *dst;
- char *out;
- int cn = 0;
-
- hexlen = strlen(hex);
- /* allow space fox XXYY to XX:YY: */
- dst = malloc(((hexlen * 7) + 6) / 2);
-
- if (dst != NULL) {
- for (out = dst; *hex != 0; hex++) {
- if (cn == 2) {
- cn = 0;
- *out++ = '&';
- *out++ = '#';
- *out++ = '5';
- *out++ = '8';
- *out++ = ';';
- }
- *out++ = *hex;
- cn++;
- }
- *out = 0;
- }
- return dst;
-}
-
-
-/**
- * create a hex formatted string inserting the colons from binary data
- *
- * \todo only uses html entity as separator because netsurfs line breaking
- * fails otherwise.
- */
-static char *bindup(unsigned char *bin, unsigned int binlen)
-{
- char *dst;
- char *out;
- unsigned int idx;
- const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
-
- /* allow space fox XY to expand to XX:YY: */
- dst = malloc(binlen * 7);
-
- if (dst != NULL) {
- out = dst;
- for (idx = 0; idx < binlen; idx++) {
- *out++ = hex[(bin[idx] & 0xf0) >> 4];
- *out++ = hex[bin[idx] & 0xf];
-
- *out++ = '&';
- *out++ = '#';
- *out++ = '5';
- *out++ = '8';
- *out++ = ';';
- }
- out -= 5;
- *out = 0;
- }
- return dst;
-}
-
-
-/**
- * extract RSA key information to info structure
- *
- * \param rsa The RSA key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-rsa_to_info(RSA *rsa, struct ns_cert_pkey *ikey)
-{
- char *tmp;
-
- if (rsa == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("RSA");
-
- ikey->size = ns_RSA_bits(rsa);
-
- tmp = BN_bn2hex(ns_RSA_get0_n(rsa));
- if (tmp != NULL) {
- ikey->modulus = hexdup(tmp);
- OPENSSL_free(tmp);
- }
-
- tmp = BN_bn2dec(ns_RSA_get0_e(rsa));
- if (tmp != NULL) {
- ikey->exponent = strdup(tmp);
- OPENSSL_free(tmp);
- }
-
- RSA_free(rsa);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract DSA key information to info structure
- *
- * \param dsa The RSA key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-dsa_to_info(DSA *dsa, struct ns_cert_pkey *ikey)
-{
- if (dsa == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("DSA");
-
- ikey->size = ns_DSA_bits(dsa);
-
- DSA_free(dsa);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract DH key information to info structure
- *
- * \param dsa The RSA key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-dh_to_info(DH *dh, struct ns_cert_pkey *ikey)
-{
- if (dh == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("Diffie Hellman");
-
- ikey->size = ns_DH_bits(dh);
-
- DH_free(dh);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract EC key information to info structure
- *
- * \param ec The EC key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-ec_to_info(EC_KEY *ec, struct ns_cert_pkey *ikey)
-{
- const EC_GROUP *ecgroup;
- const EC_POINT *ecpoint;
- BN_CTX *bnctx;
- char *ecpoint_hex;
-
- if (ec == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("Elliptic Curve");
-
- ecgroup = EC_KEY_get0_group(ec);
-
- if (ecgroup != NULL) {
- ikey->size = EC_GROUP_get_degree(ecgroup);
-
- ikey->curve = strdup(OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)));
-
- ecpoint = EC_KEY_get0_public_key(ec);
- if (ecpoint != NULL) {
- bnctx = BN_CTX_new();
- ecpoint_hex = EC_POINT_point2hex(ecgroup,
- ecpoint,
- POINT_CONVERSION_UNCOMPRESSED,
- bnctx);
- ikey->public = hexdup(ecpoint_hex);
- OPENSSL_free(ecpoint_hex);
- BN_CTX_free(bnctx);
- }
- }
- EC_KEY_free(ec);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract public key information to info structure
- *
- * \param pkey the public key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-pkey_to_info(EVP_PKEY *pkey, struct ns_cert_pkey *ikey)
-{
- nserror res;
-
- if (pkey == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- switch (EVP_PKEY_base_id(pkey)) {
- case EVP_PKEY_RSA:
- res = rsa_to_info(EVP_PKEY_get1_RSA(pkey), ikey);
- break;
-
- case EVP_PKEY_DSA:
- res = dsa_to_info(EVP_PKEY_get1_DSA(pkey), ikey);
- break;
-
- case EVP_PKEY_DH:
- res = dh_to_info(EVP_PKEY_get1_DH(pkey), ikey);
- break;
-
- case EVP_PKEY_EC:
- res = ec_to_info(EVP_PKEY_get1_EC_KEY(pkey), ikey);
- break;
-
- default:
- res = NSERROR_NOT_IMPLEMENTED;
- break;
- }
-
- EVP_PKEY_free(pkey);
-
- return res;
-}
-
-static nserror san_to_info(X509 *cert, struct ns_cert_san **prev_next)
-{
- int idx;
- int san_names_nb = -1;
- const GENERAL_NAME *current_name;
- const unsigned char *dns_name;
- struct ns_cert_san *isan;
-
- STACK_OF(GENERAL_NAME) *san_names = NULL;
-
- san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
- if (san_names == NULL) {
- return NSERROR_OK;
- }
-
- san_names_nb = sk_GENERAL_NAME_num(san_names);
-
- /* Check each name within the extension */
- for (idx = 0; idx < san_names_nb; idx++) {
- current_name = sk_GENERAL_NAME_value(san_names, idx);
-
- if (current_name->type == GEN_DNS) {
- /* extract DNS name into info structure */
- dns_name = ns_ASN1_STRING_get0_data(current_name->d.dNSName);
-
- isan = malloc(sizeof(struct ns_cert_san));
- if (isan != NULL) {
- isan->name = strdup((const char *)dns_name);
- isan->next = NULL;
- *prev_next = isan;
- prev_next = &isan->next;
- }
- }
- }
-
- /* AmiSSL can't cope with the "correct" mechanism of freeing
- * the GENERAL_NAME stack, which is:
- * sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
- * So instead we do this open-coded loop which does the same:
- */
- for (idx = 0; idx < san_names_nb; idx++) {
- GENERAL_NAME *entry = sk_GENERAL_NAME_pop(san_names);
- GENERAL_NAME_free(entry);
- }
- sk_GENERAL_NAME_free(san_names);
-
- return NSERROR_OK;
-}
-
-static nserror
-der_to_certinfo(const uint8_t *der,
- size_t der_length,
- struct ns_cert_info *info)
-{
- BIO *mem;
- BUF_MEM *buf;
- const ASN1_INTEGER *asn1_num;
- BIGNUM *bignum;
- X509 *cert; /**< Pointer to certificate */
-
- if (der == NULL) {
- return NSERROR_OK;
- }
-
- cert = d2i_X509(NULL, &der, der_length);
- if (cert == NULL) {
- return NSERROR_INVALID;
- }
-
- /*
- * get certificate version
- *
- * \note this is defined by standards (X.509 et al) to be one
- * less than the certificate version.
- */
- info->version = X509_get_version(cert) + 1;
-
- /* not before date */
- mem = BIO_new(BIO_s_mem());
- ASN1_TIME_print(mem, X509_get_notBefore(cert));
- BIO_get_mem_ptr(mem, &buf);
- (void) BIO_set_close(mem, BIO_NOCLOSE);
- BIO_free(mem);
- info->not_before = calloc(1, buf->length + 1);
- if (info->not_before != NULL) {
- memcpy(info->not_before, buf->data, (unsigned)buf->length);
- }
- BUF_MEM_free(buf);
-
- /* not after date */
- mem = BIO_new(BIO_s_mem());
- ASN1_TIME_print(mem,
- X509_get_notAfter(cert));
- BIO_get_mem_ptr(mem, &buf);
- (void) BIO_set_close(mem, BIO_NOCLOSE);
- BIO_free(mem);
- info->not_after = calloc(1, buf->length + 1);
- if (info->not_after != NULL) {
- memcpy(info->not_after, buf->data, (unsigned)buf->length);
- }
- BUF_MEM_free(buf);
-
- /* signature type */
- info->sig_type = X509_get_signature_type(cert);
-
- /* signature algorithm */
- int pkey_nid = ns_X509_get_signature_nid(cert);
- if (pkey_nid != NID_undef) {
- const char* sslbuf = OBJ_nid2ln(pkey_nid);
- if (sslbuf != NULL) {
- info->sig_algor = strdup(sslbuf);
- }
- }
-
- /* serial number */
- asn1_num = X509_get_serialNumber(cert);
- if (asn1_num != NULL) {
- bignum = ASN1_INTEGER_to_BN(asn1_num, NULL);
- if (bignum != NULL) {
- char *tmp = BN_bn2hex(bignum);
- if (tmp != NULL) {
- info->serialnum = hexdup(tmp);
- OPENSSL_free(tmp);
- }
- BN_free(bignum);
- bignum = NULL;
- }
- }
-
- /* fingerprints */
- const EVP_MD *digest;
- unsigned int dig_len;
- unsigned char *buff;
- int rc;
-
- digest = EVP_sha1();
- buff = malloc(EVP_MD_size(digest));
- if (buff != NULL) {
- rc = X509_digest(cert, digest, buff, &dig_len);
- if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
- info->sha1fingerprint = bindup(buff, dig_len);
- }
- free(buff);
- }
-
- digest = EVP_sha256();
- buff = malloc(EVP_MD_size(digest));
- if (buff != NULL) {
- rc = X509_digest(cert, digest, buff, &dig_len);
- if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
- info->sha256fingerprint = bindup(buff, dig_len);
- }
- free(buff);
- }
-
- /* subject alternative names */
- san_to_info(cert, &info->san);
-
- /* issuer name */
- xname_to_info(X509_get_issuer_name(cert), &info->issuer_name);
-
- /* subject */
- xname_to_info(X509_get_subject_name(cert), &info->subject_name);
-
- /* public key */
- pkey_to_info(X509_get_pubkey(cert), &info->public_key);
-
- X509_free(cert);
-
- return NSERROR_OK;
-}
-
-/* copy certificate data */
-static nserror
-convert_chain_to_cert_info(const struct cert_chain *chain,
- struct ns_cert_info **cert_info_out)
-{
- struct ns_cert_info *certs;
- size_t depth;
- nserror res;
-
- certs = calloc(chain->depth, sizeof(struct ns_cert_info));
- if (certs == NULL) {
- return NSERROR_NOMEM;
- }
-
- for (depth = 0; depth < chain->depth;depth++) {
- res = der_to_certinfo(chain->certs[depth].der,
- chain->certs[depth].der_length,
- certs + depth);
- if (res != NSERROR_OK) {
- free(certs);
- return res;
- }
- certs[depth].err = chain->certs[depth].err;
- }
-
- *cert_info_out = certs;
- return NSERROR_OK;
-}
-
-#else
-static nserror
-convert_chain_to_cert_info(const struct cert_chain *chain,
- struct ns_cert_info **cert_info_out)
-{
- return NSERROR_NOT_IMPLEMENTED;
-}
-#endif
-
-
-static nserror
-format_certificate_name(struct fetch_about_context *ctx,
- struct ns_cert_name *cert_name)
-{
- nserror res;
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Common Name</th><td>%s</td></tr>\n",
- cert_name->common_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_name->organisation != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Organisation</th><td>%s</td></tr>\n",
- cert_name->organisation);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->organisation_unit != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Organisation Unit</th><td>%s</td></tr>\n",
- cert_name->organisation_unit);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->locality != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Locality</th><td>%s</td></tr>\n",
- cert_name->locality);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->province != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Privince</th><td>%s</td></tr>\n",
- cert_name->province);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->country != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Country</th><td>%s</td></tr>\n",
- cert_name->country);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- return res;
-}
-
-/**
- * output formatted certificate subject alternate names
- */
-static nserror
-format_certificate_san(struct fetch_about_context *ctx,
- struct ns_cert_san *san)
-{
- nserror res;
-
- if (san == NULL) {
- return NSERROR_OK;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Alternative Names</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- while (san != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>DNS Name</th><td>%s</td></tr>\n",
- san->name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- san = san->next;
- }
-
- res = fetch_about_ssenddataf(ctx, "</table>\n");
-
- return res;
-
-}
-
-
-static nserror
-format_certificate_public_key(struct fetch_about_context *ctx,
- struct ns_cert_pkey *public_key)
-{
- nserror res;
-
- if (public_key->algor == NULL) {
- /* skip the table if no algorithm name */
- return NSERROR_OK;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Public Key</th><td><hr></td></tr>\n"
- "<tr><th>Algorithm</th><td>%s</td></tr>\n"
- "<tr><th>Key Size</th><td>%d</td></tr>\n",
- public_key->algor,
- public_key->size);
- if (res != NSERROR_OK) {
- return res;
- }
-
-
- if (public_key->exponent != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Exponent</th><td>%s</td></tr>\n",
- public_key->exponent);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (public_key->modulus != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Modulus</th><td class=\"data\">%s</td></tr>\n",
- public_key->modulus);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (public_key->curve != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Curve</th><td>%s</td></tr>\n",
- public_key->curve);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (public_key->public != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Public Value</th><td>%s</td></tr>\n",
- public_key->public);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = fetch_about_ssenddataf(ctx, "</table>\n");
-
- return res;
-}
-
-static nserror
-format_certificate_fingerprint(struct fetch_about_context *ctx,
- struct ns_cert_info *cert_info)
-{
- nserror res;
-
- if ((cert_info->sha1fingerprint == NULL) &&
- (cert_info->sha256fingerprint == NULL)) {
- /* skip the table if no fingerprints */
- return NSERROR_OK;
- }
-
-
- res = fetch_about_ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Fingerprints</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_info->sha256fingerprint != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>SHA-256</th><td class=\"data\">%s</td></tr>\n",
- cert_info->sha256fingerprint);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_info->sha1fingerprint != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>SHA-1</th><td class=\"data\">%s</td></tr>\n",
- cert_info->sha1fingerprint);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = fetch_about_ssenddataf(ctx, "</table>\n");
-
- return res;
-}
-
-static nserror
-format_certificate(struct fetch_about_context *ctx,
- struct ns_cert_info *cert_info,
- size_t depth)
-{
- nserror res;
-
- res = fetch_about_ssenddataf(ctx,
- "<h2 id=\"%"PRIsizet"\" class=\"ns-border\">%s</h2>\n",
- depth, cert_info->subject_name.common_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_info->err != SSL_CERT_ERR_OK) {
- res = fetch_about_ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr class=\"ns-even-fg-bad\">"
- "<th>Fault</th>"
- "<td>%s</td>"
- "</tr>"
- "</table>\n",
- messages_get_sslcode(cert_info->err));
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Issued To</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_name(ctx, &cert_info->subject_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "</table>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Issued By</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_name(ctx, &cert_info->issuer_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "</table>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Validity</th><td><hr></td></tr>\n"
- "<tr><th>Valid From</th><td>%s</td></tr>\n"
- "<tr><th>Valid Until</th><td>%s</td></tr>\n"
- "</table>\n",
- cert_info->not_before,
- cert_info->not_after);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_san(ctx, cert_info->san);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_public_key(ctx, &cert_info->public_key);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Miscellaneous</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_info->serialnum != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Serial Number</th><td>%s</td></tr>\n",
- cert_info->serialnum);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_info->sig_algor != NULL) {
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Signature Algorithm</th>"
- "<td>%s</td></tr>\n",
- cert_info->sig_algor);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = fetch_about_ssenddataf(ctx,
- "<tr><th>Version</th><td>%ld</td></tr>\n"
- "</table>\n",
- cert_info->version);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_fingerprint(ctx, cert_info);
- if (res != NSERROR_OK) {
- return res;
- }
-
- return res;
-}
-
-/**
- * Handler to generate about:certificate page.
- *
- * Shows details of a certificate chain
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
-{
- int code = 200;
- nserror res;
- struct cert_chain *chain = NULL;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, code);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/html"))
- goto fetch_about_certificate_handler_aborted;
-
- /* page head */
- res = fetch_about_ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>NetSurf Browser Certificate Viewer</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body id=\"certificate\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
- "<h1 class=\"ns-border\">Certificate</h1>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
-
- res = cert_chain_from_query(ctx->url, &chain);
- if (res != NSERROR_OK) {
- res = fetch_about_ssenddataf(ctx, "<p>Could not process that</p>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
- } else {
- struct ns_cert_info *cert_info;
- res = convert_chain_to_cert_info(chain, &cert_info);
- if (res == NSERROR_OK) {
- size_t depth;
- res = fetch_about_ssenddataf(ctx, "<ul>\n");
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- for (depth = 0; depth < chain->depth; depth++) {
- res = fetch_about_ssenddataf(ctx, "<li><a href=\"#%"PRIsizet"\">%s</a></li>\n",
- depth, (cert_info + depth)
- ->subject_name
- .common_name);
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- }
-
- res = fetch_about_ssenddataf(ctx, "</ul>\n");
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- for (depth = 0; depth < chain->depth; depth++) {
- res = format_certificate(ctx, cert_info + depth,
- depth);
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- }
- free_ns_cert_info(cert_info);
-
- } else {
- res = fetch_about_ssenddataf(ctx,
- "<p>Invalid certificate data</p>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
- }
- }
-
-
- /* page footer */
- res = fetch_about_ssenddataf(ctx, "</body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- cert_chain_free(chain);
-
- return true;
-
-fetch_about_certificate_handler_aborted:
- cert_chain_free(chain);
- return false;
-}
/**
diff --git a/content/fetchers/about/certificate.c b/content/fetchers/about/certificate.c
new file mode 100644
index 0000000..0d0d6f5
--- /dev/null
+++ b/content/fetchers/about/certificate.c
@@ -0,0 +1,1189 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme certificate page
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "netsurf/inttypes.h"
+#include "netsurf/ssl_certs.h"
+
+#include "private.h"
+#include "certificate.h"
+
+/**
+ * certificate name parameters
+ */
+struct ns_cert_name {
+ char *common_name;
+ char *organisation;
+ char *organisation_unit;
+ char *locality;
+ char *province;
+ char *country;
+};
+
+/**
+ * Certificate public key parameters
+ */
+struct ns_cert_pkey {
+ char *algor;
+ int size;
+ char *modulus;
+ char *exponent;
+ char *curve;
+ char *public;
+};
+
+/**
+ * Certificate subject alternative name
+ */
+struct ns_cert_san {
+ struct ns_cert_san *next;
+ char *name;
+};
+
+/**
+ * certificate information for certificate chain
+ */
+struct ns_cert_info {
+ struct ns_cert_name subject_name; /**< Subject details */
+ struct ns_cert_name issuer_name; /**< Issuer details */
+ struct ns_cert_pkey public_key; /**< public key details */
+ long version; /**< Certificate version */
+ char *not_before; /**< Valid from date */
+ char *not_after; /**< Valid to date */
+ int sig_type; /**< Signature type */
+ char *sig_algor; /**< Signature Algorithm */
+ char *serialnum; /**< Serial number */
+ char *sha1fingerprint; /**< fingerprint shar1 encoded */
+ char *sha256fingerprint; /**< fingerprint shar256 encoded */
+ struct ns_cert_san *san; /**< subject alternative names */
+ ssl_cert_err err; /**< Whatever is wrong with this certificate */
+};
+
+/**
+ * free all resources associated with a certificate information structure
+ */
+static nserror free_ns_cert_info(struct ns_cert_info *cinfo)
+{
+ struct ns_cert_san *san;
+
+ free(cinfo->subject_name.common_name);
+ free(cinfo->subject_name.organisation);
+ free(cinfo->subject_name.organisation_unit);
+ free(cinfo->subject_name.locality);
+ free(cinfo->subject_name.province);
+ free(cinfo->subject_name.country);
+ free(cinfo->issuer_name.common_name);
+ free(cinfo->issuer_name.organisation);
+ free(cinfo->issuer_name.organisation_unit);
+ free(cinfo->issuer_name.locality);
+ free(cinfo->issuer_name.province);
+ free(cinfo->issuer_name.country);
+ free(cinfo->public_key.algor);
+ free(cinfo->public_key.modulus);
+ free(cinfo->public_key.exponent);
+ free(cinfo->public_key.curve);
+ free(cinfo->public_key.public);
+ free(cinfo->not_before);
+ free(cinfo->not_after);
+ free(cinfo->sig_algor);
+ free(cinfo->serialnum);
+
+ /* free san list avoiding use after free */
+ san = cinfo->san;
+ while (san != NULL) {
+ struct ns_cert_san *next;
+ next = san->next;
+ free(san);
+ san = next;
+ }
+
+ free(cinfo);
+
+ return NSERROR_OK;
+}
+
+#ifdef WITH_OPENSSL
+
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+
+/* OpenSSL 1.0.x, 1.0.2, 1.1.0 and 1.1.1 API all changed
+ * LibreSSL declares its OpenSSL version as 2.1 but only supports 1.0.x API
+ */
+#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL))
+/* 1.0.x */
+
+#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1000200fL))
+/* pre 1.0.2 */
+static int ns_X509_get_signature_nid(X509 *cert)
+{
+ return OBJ_obj2nid(cert->cert_info->key->algor->algorithm);
+}
+#else
+#define ns_X509_get_signature_nid X509_get_signature_nid
+#endif
+
+static const unsigned char *ns_ASN1_STRING_get0_data(ASN1_STRING *asn1str)
+{
+ return (const unsigned char *)ASN1_STRING_data(asn1str);
+}
+
+static const BIGNUM *ns_RSA_get0_n(const RSA *d)
+{
+ return d->n;
+}
+
+static const BIGNUM *ns_RSA_get0_e(const RSA *d)
+{
+ return d->e;
+}
+
+static int ns_RSA_bits(const RSA *rsa)
+{
+ return RSA_size(rsa) * 8;
+}
+
+static int ns_DSA_bits(const DSA *dsa)
+{
+ return DSA_size(dsa) * 8;
+}
+
+static int ns_DH_bits(const DH *dh)
+{
+ return DH_size(dh) * 8;
+}
+
+#elif (OPENSSL_VERSION_NUMBER < 0x1010100fL)
+/* 1.1.0 */
+#define ns_X509_get_signature_nid X509_get_signature_nid
+#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
+
+static const BIGNUM *ns_RSA_get0_n(const RSA *r)
+{
+ const BIGNUM *n;
+ const BIGNUM *e;
+ const BIGNUM *d;
+ RSA_get0_key(r, &n, &e, &d);
+ return n;
+}
+
+static const BIGNUM *ns_RSA_get0_e(const RSA *r)
+{
+ const BIGNUM *n;
+ const BIGNUM *e;
+ const BIGNUM *d;
+ RSA_get0_key(r, &n, &e, &d);
+ return e;
+}
+
+#define ns_RSA_bits RSA_bits
+#define ns_DSA_bits DSA_bits
+#define ns_DH_bits DH_bits
+
+#else
+/* 1.1.1 and later */
+#define ns_X509_get_signature_nid X509_get_signature_nid
+#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
+#define ns_RSA_get0_n RSA_get0_n
+#define ns_RSA_get0_e RSA_get0_e
+#define ns_RSA_bits RSA_bits
+#define ns_DSA_bits DSA_bits
+#define ns_DH_bits DH_bits
+#endif
+
+/**
+ * extract certificate name information
+ *
+ * \param xname The X509 name to convert. The reference is borrowed so is not freeed
+ * \param iname The info structure to recive the extracted parameters.
+ * \return NSERROR_OK on success else error code
+ */
+static nserror
+xname_to_info(X509_NAME *xname, struct ns_cert_name *iname)
+{
+ int entryidx;
+ int entrycnt;
+ X509_NAME_ENTRY *entry; /* current name entry */
+ ASN1_STRING *value;
+ const unsigned char *value_str;
+ ASN1_OBJECT *name;
+ int name_nid;
+ char **field;
+
+ entrycnt = X509_NAME_entry_count(xname);
+
+ for (entryidx = 0; entryidx < entrycnt; entryidx++) {
+ entry = X509_NAME_get_entry(xname, entryidx);
+ name = X509_NAME_ENTRY_get_object(entry);
+ name_nid = OBJ_obj2nid(name);
+ value = X509_NAME_ENTRY_get_data(entry);
+ value_str = ns_ASN1_STRING_get0_data(value);
+ switch (name_nid) {
+ case NID_commonName:
+ field = &iname->common_name;
+ break;
+ case NID_countryName:
+ field = &iname->country;
+ break;
+ case NID_localityName:
+ field = &iname->locality;
+ break;
+ case NID_stateOrProvinceName:
+ field = &iname->province;
+ break;
+ case NID_organizationName:
+ field = &iname->organisation;
+ break;
+ case NID_organizationalUnitName:
+ field = &iname->organisation_unit;
+ break;
+ default :
+ field = NULL;
+ break;
+ }
+ if (field != NULL) {
+ *field = strdup((const char *)value_str);
+ NSLOG(netsurf, DEEPDEBUG,
+ "NID:%d value: %s", name_nid, *field);
+ } else {
+ NSLOG(netsurf, DEEPDEBUG, "NID:%d", name_nid);
+ }
+ }
+
+ /*
+ * ensure the common name is set to something, this being
+ * missing means the certificate is broken but this should be
+ * robust in the face of bad data
+ */
+ if (iname->common_name == NULL) {
+ iname->common_name = strdup("Unknown");
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * duplicate a hex formatted string inserting the colons
+ *
+ * \todo only uses html entity as separator because netsurfs line breaking
+ * fails otherwise.
+ */
+static char *hexdup(const char *hex)
+{
+ int hexlen;
+ char *dst;
+ char *out;
+ int cn = 0;
+
+ hexlen = strlen(hex);
+ /* allow space fox XXYY to XX:YY: */
+ dst = malloc(((hexlen * 7) + 6) / 2);
+
+ if (dst != NULL) {
+ for (out = dst; *hex != 0; hex++) {
+ if (cn == 2) {
+ cn = 0;
+ *out++ = '&';
+ *out++ = '#';
+ *out++ = '5';
+ *out++ = '8';
+ *out++ = ';';
+ }
+ *out++ = *hex;
+ cn++;
+ }
+ *out = 0;
+ }
+ return dst;
+}
+
+
+/**
+ * create a hex formatted string inserting the colons from binary data
+ *
+ * \todo only uses html entity as separator because netsurfs line breaking
+ * fails otherwise.
+ */
+static char *bindup(unsigned char *bin, unsigned int binlen)
+{
+ char *dst;
+ char *out;
+ unsigned int idx;
+ const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ /* allow space fox XY to expand to XX:YY: */
+ dst = malloc(binlen * 7);
+
+ if (dst != NULL) {
+ out = dst;
+ for (idx = 0; idx < binlen; idx++) {
+ *out++ = hex[(bin[idx] & 0xf0) >> 4];
+ *out++ = hex[bin[idx] & 0xf];
+
+ *out++ = '&';
+ *out++ = '#';
+ *out++ = '5';
+ *out++ = '8';
+ *out++ = ';';
+ }
+ out -= 5;
+ *out = 0;
+ }
+ return dst;
+}
+
+
+/**
+ * extract RSA key information to info structure
+ *
+ * \param rsa The RSA key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+rsa_to_info(RSA *rsa, struct ns_cert_pkey *ikey)
+{
+ char *tmp;
+
+ if (rsa == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("RSA");
+
+ ikey->size = ns_RSA_bits(rsa);
+
+ tmp = BN_bn2hex(ns_RSA_get0_n(rsa));
+ if (tmp != NULL) {
+ ikey->modulus = hexdup(tmp);
+ OPENSSL_free(tmp);
+ }
+
+ tmp = BN_bn2dec(ns_RSA_get0_e(rsa));
+ if (tmp != NULL) {
+ ikey->exponent = strdup(tmp);
+ OPENSSL_free(tmp);
+ }
+
+ RSA_free(rsa);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract DSA key information to info structure
+ *
+ * \param dsa The RSA key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+dsa_to_info(DSA *dsa, struct ns_cert_pkey *ikey)
+{
+ if (dsa == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("DSA");
+
+ ikey->size = ns_DSA_bits(dsa);
+
+ DSA_free(dsa);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract DH key information to info structure
+ *
+ * \param dsa The RSA key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+dh_to_info(DH *dh, struct ns_cert_pkey *ikey)
+{
+ if (dh == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("Diffie Hellman");
+
+ ikey->size = ns_DH_bits(dh);
+
+ DH_free(dh);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract EC key information to info structure
+ *
+ * \param ec The EC key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+ec_to_info(EC_KEY *ec, struct ns_cert_pkey *ikey)
+{
+ const EC_GROUP *ecgroup;
+ const EC_POINT *ecpoint;
+ BN_CTX *bnctx;
+ char *ecpoint_hex;
+
+ if (ec == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("Elliptic Curve");
+
+ ecgroup = EC_KEY_get0_group(ec);
+
+ if (ecgroup != NULL) {
+ ikey->size = EC_GROUP_get_degree(ecgroup);
+
+ ikey->curve = strdup(OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)));
+
+ ecpoint = EC_KEY_get0_public_key(ec);
+ if (ecpoint != NULL) {
+ bnctx = BN_CTX_new();
+ ecpoint_hex = EC_POINT_point2hex(ecgroup,
+ ecpoint,
+ POINT_CONVERSION_UNCOMPRESSED,
+ bnctx);
+ ikey->public = hexdup(ecpoint_hex);
+ OPENSSL_free(ecpoint_hex);
+ BN_CTX_free(bnctx);
+ }
+ }
+ EC_KEY_free(ec);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract public key information to info structure
+ *
+ * \param pkey the public key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+pkey_to_info(EVP_PKEY *pkey, struct ns_cert_pkey *ikey)
+{
+ nserror res;
+
+ if (pkey == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ switch (EVP_PKEY_base_id(pkey)) {
+ case EVP_PKEY_RSA:
+ res = rsa_to_info(EVP_PKEY_get1_RSA(pkey), ikey);
+ break;
+
+ case EVP_PKEY_DSA:
+ res = dsa_to_info(EVP_PKEY_get1_DSA(pkey), ikey);
+ break;
+
+ case EVP_PKEY_DH:
+ res = dh_to_info(EVP_PKEY_get1_DH(pkey), ikey);
+ break;
+
+ case EVP_PKEY_EC:
+ res = ec_to_info(EVP_PKEY_get1_EC_KEY(pkey), ikey);
+ break;
+
+ default:
+ res = NSERROR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ EVP_PKEY_free(pkey);
+
+ return res;
+}
+
+static nserror san_to_info(X509 *cert, struct ns_cert_san **prev_next)
+{
+ int idx;
+ int san_names_nb = -1;
+ const GENERAL_NAME *current_name;
+ const unsigned char *dns_name;
+ struct ns_cert_san *isan;
+
+ STACK_OF(GENERAL_NAME) *san_names = NULL;
+
+ san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+ if (san_names == NULL) {
+ return NSERROR_OK;
+ }
+
+ san_names_nb = sk_GENERAL_NAME_num(san_names);
+
+ /* Check each name within the extension */
+ for (idx = 0; idx < san_names_nb; idx++) {
+ current_name = sk_GENERAL_NAME_value(san_names, idx);
+
+ if (current_name->type == GEN_DNS) {
+ /* extract DNS name into info structure */
+ dns_name = ns_ASN1_STRING_get0_data(current_name->d.dNSName);
+
+ isan = malloc(sizeof(struct ns_cert_san));
+ if (isan != NULL) {
+ isan->name = strdup((const char *)dns_name);
+ isan->next = NULL;
+ *prev_next = isan;
+ prev_next = &isan->next;
+ }
+ }
+ }
+
+ /* AmiSSL can't cope with the "correct" mechanism of freeing
+ * the GENERAL_NAME stack, which is:
+ * sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+ * So instead we do this open-coded loop which does the same:
+ */
+ for (idx = 0; idx < san_names_nb; idx++) {
+ GENERAL_NAME *entry = sk_GENERAL_NAME_pop(san_names);
+ GENERAL_NAME_free(entry);
+ }
+ sk_GENERAL_NAME_free(san_names);
+
+ return NSERROR_OK;
+}
+
+static nserror
+der_to_certinfo(const uint8_t *der,
+ size_t der_length,
+ struct ns_cert_info *info)
+{
+ BIO *mem;
+ BUF_MEM *buf;
+ const ASN1_INTEGER *asn1_num;
+ BIGNUM *bignum;
+ X509 *cert; /**< Pointer to certificate */
+
+ if (der == NULL) {
+ return NSERROR_OK;
+ }
+
+ cert = d2i_X509(NULL, &der, der_length);
+ if (cert == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ /*
+ * get certificate version
+ *
+ * \note this is defined by standards (X.509 et al) to be one
+ * less than the certificate version.
+ */
+ info->version = X509_get_version(cert) + 1;
+
+ /* not before date */
+ mem = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(mem, X509_get_notBefore(cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ info->not_before = calloc(1, buf->length + 1);
+ if (info->not_before != NULL) {
+ memcpy(info->not_before, buf->data, (unsigned)buf->length);
+ }
+ BUF_MEM_free(buf);
+
+ /* not after date */
+ mem = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(mem,
+ X509_get_notAfter(cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ info->not_after = calloc(1, buf->length + 1);
+ if (info->not_after != NULL) {
+ memcpy(info->not_after, buf->data, (unsigned)buf->length);
+ }
+ BUF_MEM_free(buf);
+
+ /* signature type */
+ info->sig_type = X509_get_signature_type(cert);
+
+ /* signature algorithm */
+ int pkey_nid = ns_X509_get_signature_nid(cert);
+ if (pkey_nid != NID_undef) {
+ const char* sslbuf = OBJ_nid2ln(pkey_nid);
+ if (sslbuf != NULL) {
+ info->sig_algor = strdup(sslbuf);
+ }
+ }
+
+ /* serial number */
+ asn1_num = X509_get_serialNumber(cert);
+ if (asn1_num != NULL) {
+ bignum = ASN1_INTEGER_to_BN(asn1_num, NULL);
+ if (bignum != NULL) {
+ char *tmp = BN_bn2hex(bignum);
+ if (tmp != NULL) {
+ info->serialnum = hexdup(tmp);
+ OPENSSL_free(tmp);
+ }
+ BN_free(bignum);
+ bignum = NULL;
+ }
+ }
+
+ /* fingerprints */
+ const EVP_MD *digest;
+ unsigned int dig_len;
+ unsigned char *buff;
+ int rc;
+
+ digest = EVP_sha1();
+ buff = malloc(EVP_MD_size(digest));
+ if (buff != NULL) {
+ rc = X509_digest(cert, digest, buff, &dig_len);
+ if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
+ info->sha1fingerprint = bindup(buff, dig_len);
+ }
+ free(buff);
+ }
+
+ digest = EVP_sha256();
+ buff = malloc(EVP_MD_size(digest));
+ if (buff != NULL) {
+ rc = X509_digest(cert, digest, buff, &dig_len);
+ if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
+ info->sha256fingerprint = bindup(buff, dig_len);
+ }
+ free(buff);
+ }
+
+ /* subject alternative names */
+ san_to_info(cert, &info->san);
+
+ /* issuer name */
+ xname_to_info(X509_get_issuer_name(cert), &info->issuer_name);
+
+ /* subject */
+ xname_to_info(X509_get_subject_name(cert), &info->subject_name);
+
+ /* public key */
+ pkey_to_info(X509_get_pubkey(cert), &info->public_key);
+
+ X509_free(cert);
+
+ return NSERROR_OK;
+}
+
+/* copy certificate data */
+static nserror
+convert_chain_to_cert_info(const struct cert_chain *chain,
+ struct ns_cert_info **cert_info_out)
+{
+ struct ns_cert_info *certs;
+ size_t depth;
+ nserror res;
+
+ certs = calloc(chain->depth, sizeof(struct ns_cert_info));
+ if (certs == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ for (depth = 0; depth < chain->depth;depth++) {
+ res = der_to_certinfo(chain->certs[depth].der,
+ chain->certs[depth].der_length,
+ certs + depth);
+ if (res != NSERROR_OK) {
+ free(certs);
+ return res;
+ }
+ certs[depth].err = chain->certs[depth].err;
+ }
+
+ *cert_info_out = certs;
+ return NSERROR_OK;
+}
+
+#else
+static nserror
+convert_chain_to_cert_info(const struct cert_chain *chain,
+ struct ns_cert_info **cert_info_out)
+{
+ return NSERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+
+static nserror
+format_certificate_name(struct fetch_about_context *ctx,
+ struct ns_cert_name *cert_name)
+{
+ nserror res;
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Common Name</th><td>%s</td></tr>\n",
+ cert_name->common_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_name->organisation != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Organisation</th><td>%s</td></tr>\n",
+ cert_name->organisation);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->organisation_unit != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Organisation Unit</th><td>%s</td></tr>\n",
+ cert_name->organisation_unit);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->locality != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Locality</th><td>%s</td></tr>\n",
+ cert_name->locality);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->province != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Privince</th><td>%s</td></tr>\n",
+ cert_name->province);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->country != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Country</th><td>%s</td></tr>\n",
+ cert_name->country);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ return res;
+}
+
+/**
+ * output formatted certificate subject alternate names
+ */
+static nserror
+format_certificate_san(struct fetch_about_context *ctx,
+ struct ns_cert_san *san)
+{
+ nserror res;
+
+ if (san == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Alternative Names</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ while (san != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>DNS Name</th><td>%s</td></tr>\n",
+ san->name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ san = san->next;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</table>\n");
+
+ return res;
+
+}
+
+
+static nserror
+format_certificate_public_key(struct fetch_about_context *ctx,
+ struct ns_cert_pkey *public_key)
+{
+ nserror res;
+
+ if (public_key->algor == NULL) {
+ /* skip the table if no algorithm name */
+ return NSERROR_OK;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Public Key</th><td><hr></td></tr>\n"
+ "<tr><th>Algorithm</th><td>%s</td></tr>\n"
+ "<tr><th>Key Size</th><td>%d</td></tr>\n",
+ public_key->algor,
+ public_key->size);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+
+ if (public_key->exponent != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Exponent</th><td>%s</td></tr>\n",
+ public_key->exponent);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (public_key->modulus != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Modulus</th><td class=\"data\">%s</td></tr>\n",
+ public_key->modulus);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (public_key->curve != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Curve</th><td>%s</td></tr>\n",
+ public_key->curve);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (public_key->public != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Public Value</th><td>%s</td></tr>\n",
+ public_key->public);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</table>\n");
+
+ return res;
+}
+
+static nserror
+format_certificate_fingerprint(struct fetch_about_context *ctx,
+ struct ns_cert_info *cert_info)
+{
+ nserror res;
+
+ if ((cert_info->sha1fingerprint == NULL) &&
+ (cert_info->sha256fingerprint == NULL)) {
+ /* skip the table if no fingerprints */
+ return NSERROR_OK;
+ }
+
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Fingerprints</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_info->sha256fingerprint != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>SHA-256</th><td class=\"data\">%s</td></tr>\n",
+ cert_info->sha256fingerprint);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_info->sha1fingerprint != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>SHA-1</th><td class=\"data\">%s</td></tr>\n",
+ cert_info->sha1fingerprint);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</table>\n");
+
+ return res;
+}
+
+static nserror
+format_certificate(struct fetch_about_context *ctx,
+ struct ns_cert_info *cert_info,
+ size_t depth)
+{
+ nserror res;
+
+ res = fetch_about_ssenddataf(ctx,
+ "<h2 id=\"%"PRIsizet"\" class=\"ns-border\">%s</h2>\n",
+ depth, cert_info->subject_name.common_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_info->err != SSL_CERT_ERR_OK) {
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr class=\"ns-even-fg-bad\">"
+ "<th>Fault</th>"
+ "<td>%s</td>"
+ "</tr>"
+ "</table>\n",
+ messages_get_sslcode(cert_info->err));
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Issued To</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_name(ctx, &cert_info->subject_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "</table>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Issued By</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_name(ctx, &cert_info->issuer_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "</table>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Validity</th><td><hr></td></tr>\n"
+ "<tr><th>Valid From</th><td>%s</td></tr>\n"
+ "<tr><th>Valid Until</th><td>%s</td></tr>\n"
+ "</table>\n",
+ cert_info->not_before,
+ cert_info->not_after);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_san(ctx, cert_info->san);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_public_key(ctx, &cert_info->public_key);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Miscellaneous</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_info->serialnum != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Serial Number</th><td>%s</td></tr>\n",
+ cert_info->serialnum);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_info->sig_algor != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Signature Algorithm</th>"
+ "<td>%s</td></tr>\n",
+ cert_info->sig_algor);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Version</th><td>%ld</td></tr>\n"
+ "</table>\n",
+ cert_info->version);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_fingerprint(ctx, cert_info);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ return res;
+}
+
+/**
+ * Handler to generate about:certificate page.
+ *
+ * Shows details of a certificate chain
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
+{
+ int code = 200;
+ nserror res;
+ struct cert_chain *chain = NULL;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_about_certificate_handler_aborted;
+
+ /* page head */
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>NetSurf Browser Certificate Viewer</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body id=\"certificate\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
+ "<h1 class=\"ns-border\">Certificate</h1>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ res = cert_chain_from_query(fetch_about_get_url(ctx), &chain);
+ if (res != NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<p>Could not process that</p>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+ } else {
+ struct ns_cert_info *cert_info;
+ res = convert_chain_to_cert_info(chain, &cert_info);
+ if (res == NSERROR_OK) {
+ size_t depth;
+ res = fetch_about_ssenddataf(ctx, "<ul>\n");
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ for (depth = 0; depth < chain->depth; depth++) {
+ res = fetch_about_ssenddataf(ctx, "<li><a href=\"#%"PRIsizet"\">%s</a></li>\n",
+ depth, (cert_info + depth)
+ ->subject_name
+ .common_name);
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</ul>\n");
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ for (depth = 0; depth < chain->depth; depth++) {
+ res = format_certificate(ctx, cert_info + depth,
+ depth);
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ }
+ free_ns_cert_info(cert_info);
+
+ } else {
+ res = fetch_about_ssenddataf(ctx,
+ "<p>Invalid certificate data</p>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+ }
+ }
+
+
+ /* page footer */
+ res = fetch_about_ssenddataf(ctx, "</body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ cert_chain_free(chain);
+
+ return true;
+
+fetch_about_certificate_handler_aborted:
+ cert_chain_free(chain);
+ return false;
+}
diff --git a/content/fetchers/about/certificate.h b/content/fetchers/about/certificate.h
new file mode 100644
index 0000000..80ac068
--- /dev/null
+++ b/content/fetchers/about/certificate.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme certificate handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_CERTIFICATE_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_CERTIFICATE_H
+
+/**
+ * Handler to generate about scheme certificate page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_certificate_handler(struct fetch_about_context *ctx);
+
+#endif
diff --git a/content/fetchers/about/private.h b/content/fetchers/about/private.h
index d877ac5..808a91e 100644
--- a/content/fetchers/about/private.h
+++ b/content/fetchers/about/private.h
@@ -56,4 +56,8 @@ nserror fetch_about_ssenddataf(struct fetch_about_context *ctx, const char *fmt,
*/
bool fetch_about_send_finished(struct fetch_about_context *ctx);
+/**
+ */
+struct nsurl *fetch_about_get_url(struct fetch_about_context *ctx);
+
#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=4cbc8f16b6557136482...
commit 4cbc8f16b65571364828bf12a54c9094b25513f6
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out blank handler for about scheme
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index 3a96d03..5b45022 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -1,6 +1,6 @@
# about fetcher sources
-S_FETCHER_ABOUT := about.c imagecache.c
+S_FETCHER_ABOUT := about.c imagecache.c blank.c
# The following files depend on the testament
content/fetchers/about/about.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index 3e645cd..0448a0e 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -49,6 +49,7 @@
#include "desktop/system_colour.h"
#include "private.h"
+#include "blank.h"
#include "imagecache.h"
#include "about.h"
@@ -235,40 +236,6 @@ static bool fetch_about_srverror(struct fetch_about_context *ctx)
}
-/**
- * Handler to generate about scheme cache page.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_blank_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- const char buffer[2] = { ' ', '\0' };
-
- /* 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"))
- goto fetch_about_blank_handler_aborted;
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
- msg.data.header_or_data.len = strlen(buffer);
-
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_blank_handler_aborted;
-
- msg.type = FETCH_FINISHED;
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-
-fetch_about_blank_handler_aborted:
- return false;
-}
/**
diff --git a/content/fetchers/about/blank.c b/content/fetchers/about/blank.c
new file mode 100644
index 0000000..b7ba52e
--- /dev/null
+++ b/content/fetchers/about/blank.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme blank page
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "netsurf/types.h"
+#include "utils/errors.h"
+
+#include "private.h"
+#include "blank.h"
+
+/**
+ * Handler to generate about scheme cache page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_blank_handler(struct fetch_about_context *ctx)
+{
+ const char buffer[2] = { ' ', '\0' };
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_about_blank_handler_aborted;
+
+ fetch_about_senddata(ctx, (const uint8_t *) buffer, strlen(buffer));
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_blank_handler_aborted:
+ return false;
+}
diff --git a/content/fetchers/about/blank.h b/content/fetchers/about/blank.h
new file mode 100644
index 0000000..09dcc1f
--- /dev/null
+++ b/content/fetchers/about/blank.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme blank handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_BLANK_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_BLANK_H
+
+/**
+ * Handler to generate about scheme blank page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_blank_handler(struct fetch_about_context *ctx);
+
+#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=5207ecf3083fdf9e28f...
commit 5207ecf3083fdf9e28fbc775426e415ff4a08f5d
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
split out the about scheme imagecache page generator
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
index 88786ec..3a96d03 100644
--- a/content/fetchers/about/Makefile
+++ b/content/fetchers/about/Makefile
@@ -1,6 +1,6 @@
# about fetcher sources
-S_FETCHER_ABOUT := about.c
+S_FETCHER_ABOUT := about.c imagecache.c
# The following files depend on the testament
content/fetchers/about/about.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
index e2fbd4d..3e645cd 100644
--- a/content/fetchers/about/about.c
+++ b/content/fetchers/about/about.c
@@ -45,14 +45,13 @@
#include "content/fetch.h"
#include "content/fetchers.h"
-#include "image/image_cache.h"
#include "desktop/system_colour.h"
+#include "private.h"
+#include "imagecache.h"
#include "about.h"
-struct fetch_about_context;
-
typedef bool (*fetch_about_handler)(struct fetch_about_context *);
/**
@@ -87,10 +86,11 @@ struct about_handlers {
};
+
/**
* issue fetch callbacks with locking
*/
-static inline bool
+static bool
fetch_about_send_callback(const fetch_msg *msg, struct fetch_about_context *ctx)
{
ctx->locked = true;
@@ -100,7 +100,8 @@ fetch_about_send_callback(const fetch_msg *msg, struct fetch_about_context *ctx)
return ctx->aborted;
}
-static inline bool
+/* exported interface documented in about/private.h */
+bool
fetch_about_send_finished(struct fetch_about_context *ctx)
{
fetch_msg msg;
@@ -108,7 +109,16 @@ fetch_about_send_finished(struct fetch_about_context *ctx)
return fetch_about_send_callback(&msg, ctx);
}
-static bool
+/* exported interface documented in about/private.h */
+bool fetch_about_set_http_code(struct fetch_about_context *ctx, long code)
+{
+ fetch_set_http_code(ctx->fetchh, code);
+
+ return ctx->aborted;
+}
+
+/* exported interface documented in about/private.h */
+bool
fetch_about_send_header(struct fetch_about_context *ctx, const char *fmt, ...)
{
char header[64];
@@ -128,10 +138,26 @@ fetch_about_send_header(struct fetch_about_context *ctx, const char *fmt, ...)
return fetch_about_send_callback(&msg, ctx);
}
-/**
- * send formatted data on a fetch
- */
-static nserror ssenddataf(struct fetch_about_context *ctx, const char *fmt, ...)
+/* exported interface documented in about/private.h */
+nserror
+fetch_about_senddata(struct fetch_about_context *ctx, const uint8_t *data, size_t data_len)
+{
+ fetch_msg msg;
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = data;
+ msg.data.header_or_data.len = data_len;
+
+ if (fetch_about_send_callback(&msg, ctx)) {
+ return NSERROR_INVALID;
+ }
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in about/private.h */
+nserror
+fetch_about_ssenddataf(struct fetch_about_context *ctx, const char *fmt, ...)
{
char buffer[1024];
char *dbuff;
@@ -198,7 +224,7 @@ static bool fetch_about_srverror(struct fetch_about_context *ctx)
if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
return false;
- res = ssenddataf(ctx, "Server error 500");
+ res = fetch_about_ssenddataf(ctx, "Server error 500");
if (res != NSERROR_OK) {
return false;
}
@@ -289,153 +315,6 @@ static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
}
-/**
- * Handler to generate about:imagecache page.
- *
- * Shows details of current image cache.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- char buffer[2048]; /* output buffer */
- int code = 200;
- int slen;
- unsigned int cent_loop = 0;
- int elen = 0; /* entry length */
- nserror res;
- bool even = false;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, code);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/html"))
- goto fetch_about_imagecache_handler_aborted;
-
- /* page head */
- res = ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>Image Cache Status</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body id =\"cachelist\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
- "<h1 class=\"ns-border\">Image Cache Status</h1>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_imagecache_handler_aborted;
- }
-
- /* image cache summary */
- slen = image_cache_snsummaryf(buffer, sizeof(buffer),
- "<p>Configured limit of %a hysteresis of %b</p>\n"
- "<p>Total bitmap size in use %c (in %d)</p>\n"
- "<p>Age %es</p>\n"
- "<p>Peak size %f (in %g)</p>\n"
- "<p>Peak image count %h (size %i)</p>\n"
- "<p>Cache total/hit/miss/fail (counts) %j/%k/%l/%m "
- "(%pj%%/%pk%%/%pl%%/%pm%%)</p>\n"
- "<p>Cache total/hit/miss/fail (size) %n/%o/%q/%r "
- "(%pn%%/%po%%/%pq%%/%pr%%)</p>\n"
- "<p>Total images never rendered: %s "
- "(includes %t that were converted)</p>\n"
- "<p>Total number of excessive conversions: %u "
- "(from %v images converted more than once)"
- "</p>\n"
- "<p>Bitmap of size %w had most (%x) conversions</p>\n"
- "<h2 class=\"ns-border\">Current contents</h2>\n");
- if (slen >= (int) (sizeof(buffer))) {
- goto fetch_about_imagecache_handler_aborted; /* overflow */
- }
-
- /* send image cache summary */
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx)) {
- goto fetch_about_imagecache_handler_aborted;
- }
-
- /* image cache entry table */
- res = ssenddataf(ctx, "<p class=\"imagecachelist\">\n"
- "<strong>"
- "<span>Entry</span>"
- "<span>Content Key</span>"
- "<span>Redraw Count</span>"
- "<span>Conversion Count</span>"
- "<span>Last Redraw</span>"
- "<span>Bitmap Age</span>"
- "<span>Bitmap Size</span>"
- "<span>Source</span>"
- "</strong>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_imagecache_handler_aborted;
- }
-
- slen = 0;
- do {
- if (even) {
- elen = image_cache_snentryf(buffer + slen,
- sizeof buffer - slen,
- cent_loop,
- "<a href=\"%U\">"
- "<span class=\"ns-border\">%e</span>"
- "<span class=\"ns-border\">%k</span>"
- "<span class=\"ns-border\">%r</span>"
- "<span class=\"ns-border\">%c</span>"
- "<span class=\"ns-border\">%a</span>"
- "<span class=\"ns-border\">%g</span>"
- "<span class=\"ns-border\">%s</span>"
- "<span class=\"ns-border\">%o</span>"
- "</a>\n");
- } else {
- elen = image_cache_snentryf(buffer + slen,
- sizeof buffer - slen,
- cent_loop,
- "<a class=\"ns-odd-bg\" href=\"%U\">"
- "<span class=\"ns-border\">%e</span>"
- "<span class=\"ns-border\">%k</span>"
- "<span class=\"ns-border\">%r</span>"
- "<span class=\"ns-border\">%c</span>"
- "<span class=\"ns-border\">%a</span>"
- "<span class=\"ns-border\">%g</span>"
- "<span class=\"ns-border\">%s</span>"
- "<span class=\"ns-border\">%o</span>"
- "</a>\n");
- }
- if (elen <= 0)
- break; /* last option */
-
- if (elen >= (int) (sizeof buffer - slen)) {
- /* last entry would not fit in buffer, submit buffer */
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_imagecache_handler_aborted;
- slen = 0;
- } else {
- /* normal addition */
- slen += elen;
- cent_loop++;
- even = !even;
- }
- } while (elen > 0);
-
- slen += snprintf(buffer + slen, sizeof buffer - slen,
- "</p>\n</body>\n</html>\n");
-
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_imagecache_handler_aborted;
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_imagecache_handler_aborted:
- return false;
-}
/**
* certificate name parameters
@@ -1155,7 +1034,7 @@ format_certificate_name(struct fetch_about_context *ctx,
struct ns_cert_name *cert_name)
{
nserror res;
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Common Name</th><td>%s</td></tr>\n",
cert_name->common_name);
if (res != NSERROR_OK) {
@@ -1163,7 +1042,7 @@ format_certificate_name(struct fetch_about_context *ctx,
}
if (cert_name->organisation != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Organisation</th><td>%s</td></tr>\n",
cert_name->organisation);
if (res != NSERROR_OK) {
@@ -1172,7 +1051,7 @@ format_certificate_name(struct fetch_about_context *ctx,
}
if (cert_name->organisation_unit != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Organisation Unit</th><td>%s</td></tr>\n",
cert_name->organisation_unit);
if (res != NSERROR_OK) {
@@ -1181,7 +1060,7 @@ format_certificate_name(struct fetch_about_context *ctx,
}
if (cert_name->locality != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Locality</th><td>%s</td></tr>\n",
cert_name->locality);
if (res != NSERROR_OK) {
@@ -1190,7 +1069,7 @@ format_certificate_name(struct fetch_about_context *ctx,
}
if (cert_name->province != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Privince</th><td>%s</td></tr>\n",
cert_name->province);
if (res != NSERROR_OK) {
@@ -1199,7 +1078,7 @@ format_certificate_name(struct fetch_about_context *ctx,
}
if (cert_name->country != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Country</th><td>%s</td></tr>\n",
cert_name->country);
if (res != NSERROR_OK) {
@@ -1223,7 +1102,7 @@ format_certificate_san(struct fetch_about_context *ctx,
return NSERROR_OK;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<table class=\"info\">\n"
"<tr><th>Alternative Names</th><td><hr></td></tr>\n");
if (res != NSERROR_OK) {
@@ -1231,7 +1110,7 @@ format_certificate_san(struct fetch_about_context *ctx,
}
while (san != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>DNS Name</th><td>%s</td></tr>\n",
san->name);
if (res != NSERROR_OK) {
@@ -1241,7 +1120,7 @@ format_certificate_san(struct fetch_about_context *ctx,
san = san->next;
}
- res = ssenddataf(ctx, "</table>\n");
+ res = fetch_about_ssenddataf(ctx, "</table>\n");
return res;
@@ -1259,7 +1138,7 @@ format_certificate_public_key(struct fetch_about_context *ctx,
return NSERROR_OK;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<table class=\"info\">\n"
"<tr><th>Public Key</th><td><hr></td></tr>\n"
"<tr><th>Algorithm</th><td>%s</td></tr>\n"
@@ -1272,7 +1151,7 @@ format_certificate_public_key(struct fetch_about_context *ctx,
if (public_key->exponent != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Exponent</th><td>%s</td></tr>\n",
public_key->exponent);
if (res != NSERROR_OK) {
@@ -1281,7 +1160,7 @@ format_certificate_public_key(struct fetch_about_context *ctx,
}
if (public_key->modulus != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Modulus</th><td class=\"data\">%s</td></tr>\n",
public_key->modulus);
if (res != NSERROR_OK) {
@@ -1290,7 +1169,7 @@ format_certificate_public_key(struct fetch_about_context *ctx,
}
if (public_key->curve != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Curve</th><td>%s</td></tr>\n",
public_key->curve);
if (res != NSERROR_OK) {
@@ -1299,7 +1178,7 @@ format_certificate_public_key(struct fetch_about_context *ctx,
}
if (public_key->public != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Public Value</th><td>%s</td></tr>\n",
public_key->public);
if (res != NSERROR_OK) {
@@ -1307,7 +1186,7 @@ format_certificate_public_key(struct fetch_about_context *ctx,
}
}
- res = ssenddataf(ctx, "</table>\n");
+ res = fetch_about_ssenddataf(ctx, "</table>\n");
return res;
}
@@ -1325,7 +1204,7 @@ format_certificate_fingerprint(struct fetch_about_context *ctx,
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<table class=\"info\">\n"
"<tr><th>Fingerprints</th><td><hr></td></tr>\n");
if (res != NSERROR_OK) {
@@ -1333,7 +1212,7 @@ format_certificate_fingerprint(struct fetch_about_context *ctx,
}
if (cert_info->sha256fingerprint != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>SHA-256</th><td class=\"data\">%s</td></tr>\n",
cert_info->sha256fingerprint);
if (res != NSERROR_OK) {
@@ -1342,7 +1221,7 @@ format_certificate_fingerprint(struct fetch_about_context *ctx,
}
if (cert_info->sha1fingerprint != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>SHA-1</th><td class=\"data\">%s</td></tr>\n",
cert_info->sha1fingerprint);
if (res != NSERROR_OK) {
@@ -1350,7 +1229,7 @@ format_certificate_fingerprint(struct fetch_about_context *ctx,
}
}
- res = ssenddataf(ctx, "</table>\n");
+ res = fetch_about_ssenddataf(ctx, "</table>\n");
return res;
}
@@ -1362,7 +1241,7 @@ format_certificate(struct fetch_about_context *ctx,
{
nserror res;
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<h2 id=\"%"PRIsizet"\" class=\"ns-border\">%s</h2>\n",
depth, cert_info->subject_name.common_name);
if (res != NSERROR_OK) {
@@ -1370,7 +1249,7 @@ format_certificate(struct fetch_about_context *ctx,
}
if (cert_info->err != SSL_CERT_ERR_OK) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<table class=\"info\">\n"
"<tr class=\"ns-even-fg-bad\">"
"<th>Fault</th>"
@@ -1383,7 +1262,7 @@ format_certificate(struct fetch_about_context *ctx,
}
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<table class=\"info\">\n"
"<tr><th>Issued To</th><td><hr></td></tr>\n");
if (res != NSERROR_OK) {
@@ -1395,13 +1274,13 @@ format_certificate(struct fetch_about_context *ctx,
return res;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"</table>\n");
if (res != NSERROR_OK) {
return res;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<table class=\"info\">\n"
"<tr><th>Issued By</th><td><hr></td></tr>\n");
if (res != NSERROR_OK) {
@@ -1413,13 +1292,13 @@ format_certificate(struct fetch_about_context *ctx,
return res;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"</table>\n");
if (res != NSERROR_OK) {
return res;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<table class=\"info\">\n"
"<tr><th>Validity</th><td><hr></td></tr>\n"
"<tr><th>Valid From</th><td>%s</td></tr>\n"
@@ -1441,7 +1320,7 @@ format_certificate(struct fetch_about_context *ctx,
return res;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<table class=\"info\">\n"
"<tr><th>Miscellaneous</th><td><hr></td></tr>\n");
if (res != NSERROR_OK) {
@@ -1449,7 +1328,7 @@ format_certificate(struct fetch_about_context *ctx,
}
if (cert_info->serialnum != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Serial Number</th><td>%s</td></tr>\n",
cert_info->serialnum);
if (res != NSERROR_OK) {
@@ -1458,7 +1337,7 @@ format_certificate(struct fetch_about_context *ctx,
}
if (cert_info->sig_algor != NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Signature Algorithm</th>"
"<td>%s</td></tr>\n",
cert_info->sig_algor);
@@ -1467,7 +1346,7 @@ format_certificate(struct fetch_about_context *ctx,
}
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr><th>Version</th><td>%ld</td></tr>\n"
"</table>\n",
cert_info->version);
@@ -1505,7 +1384,7 @@ static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
goto fetch_about_certificate_handler_aborted;
/* page head */
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<html>\n<head>\n"
"<title>NetSurf Browser Certificate Viewer</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
@@ -1519,7 +1398,7 @@ static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
res = cert_chain_from_query(ctx->url, &chain);
if (res != NSERROR_OK) {
- res = ssenddataf(ctx, "<p>Could not process that</p>\n");
+ res = fetch_about_ssenddataf(ctx, "<p>Could not process that</p>\n");
if (res != NSERROR_OK) {
goto fetch_about_certificate_handler_aborted;
}
@@ -1528,14 +1407,14 @@ static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
res = convert_chain_to_cert_info(chain, &cert_info);
if (res == NSERROR_OK) {
size_t depth;
- res = ssenddataf(ctx, "<ul>\n");
+ res = fetch_about_ssenddataf(ctx, "<ul>\n");
if (res != NSERROR_OK) {
free_ns_cert_info(cert_info);
goto fetch_about_certificate_handler_aborted;
}
for (depth = 0; depth < chain->depth; depth++) {
- res = ssenddataf(ctx, "<li><a href=\"#%"PRIsizet"\">%s</a></li>\n",
+ res = fetch_about_ssenddataf(ctx, "<li><a href=\"#%"PRIsizet"\">%s</a></li>\n",
depth, (cert_info + depth)
->subject_name
.common_name);
@@ -1546,7 +1425,7 @@ static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
}
- res = ssenddataf(ctx, "</ul>\n");
+ res = fetch_about_ssenddataf(ctx, "</ul>\n");
if (res != NSERROR_OK) {
free_ns_cert_info(cert_info);
goto fetch_about_certificate_handler_aborted;
@@ -1564,7 +1443,7 @@ static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
free_ns_cert_info(cert_info);
} else {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<p>Invalid certificate data</p>\n");
if (res != NSERROR_OK) {
goto fetch_about_certificate_handler_aborted;
@@ -1574,7 +1453,7 @@ static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
/* page footer */
- res = ssenddataf(ctx, "</body>\n</html>\n");
+ res = fetch_about_ssenddataf(ctx, "</body>\n</html>\n");
if (res != NSERROR_OK) {
goto fetch_about_certificate_handler_aborted;
}
@@ -1615,7 +1494,7 @@ static bool fetch_about_config_handler(struct fetch_about_context *ctx)
goto fetch_about_config_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<html>\n<head>\n"
"<title>NetSurf Browser Config</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
@@ -1717,7 +1596,7 @@ static bool fetch_about_nscolours_handler(struct fetch_about_context *ctx)
goto aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"html {\n"
"\tbackground-color: #%06x;\n"
"}\n"
@@ -1826,13 +1705,13 @@ static bool fetch_about_testament_handler(struct fetch_about_context *ctx)
if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
goto fetch_about_testament_handler_aborted;
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"# Automatically generated by NetSurf build system\n\n");
if (res != NSERROR_OK) {
goto fetch_about_testament_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
#if defined(WT_BRANCHISTRUNK) || defined(WT_BRANCHISMASTER)
"# This is a *DEVELOPMENT* build from the main line.\n\n"
#elif defined(WT_BRANCHISTAG) && (WT_MODIFIED == 0)
@@ -1857,31 +1736,31 @@ static bool fetch_about_testament_handler(struct fetch_about_context *ctx)
goto fetch_about_testament_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"Built by %s (%s) from %s at revision %s on %s\n\n",
GECOS, USERNAME, WT_BRANCHPATH, WT_REVID, WT_COMPILEDATE);
if (res != NSERROR_OK) {
goto fetch_about_testament_handler_aborted;
}
- res = ssenddataf(ctx, "Built on %s in %s\n\n", WT_HOSTNAME, WT_ROOT);
+ res = fetch_about_ssenddataf(ctx, "Built on %s in %s\n\n", WT_HOSTNAME, WT_ROOT);
if (res != NSERROR_OK) {
goto fetch_about_testament_handler_aborted;
}
if (WT_MODIFIED > 0) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"Working tree has %d modification%s\n\n",
WT_MODIFIED, WT_MODIFIED == 1 ? "" : "s");
} else {
- res = ssenddataf(ctx, "Working tree is not modified.\n");
+ res = fetch_about_ssenddataf(ctx, "Working tree is not modified.\n");
}
if (res != NSERROR_OK) {
goto fetch_about_testament_handler_aborted;
}
for (modidx = 0; modidx < WT_MODIFIED; ++modidx) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
" %s %s\n",
modifications[modidx].modtype,
modifications[modidx].leaf);
@@ -2069,7 +1948,7 @@ static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
}
title = messages_get("LoginTitle");
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<html>\n<head>\n"
"<title>%s</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
@@ -2082,7 +1961,7 @@ static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
goto fetch_about_query_auth_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<form method=\"post\""
" enctype=\"multipart/form-data\">");
if (res != NSERROR_OK) {
@@ -2095,19 +1974,19 @@ static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
password,
&description);
if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<p>%s</p>", description);
+ res = fetch_about_ssenddataf(ctx, "<p>%s</p>", description);
free(description);
if (res != NSERROR_OK) {
goto fetch_about_query_auth_handler_aborted;
}
}
- res = ssenddataf(ctx, "<table>");
+ res = fetch_about_ssenddataf(ctx, "<table>");
if (res != NSERROR_OK) {
goto fetch_about_query_auth_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr>"
"<th><label for=\"name\">%s:</label></th>"
"<td><input type=\"text\" id=\"username\" "
@@ -2118,7 +1997,7 @@ static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
goto fetch_about_query_auth_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<tr>"
"<th><label for=\"password\">%s:</label></th>"
"<td><input type=\"password\" id=\"password\" "
@@ -2129,12 +2008,12 @@ static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
goto fetch_about_query_auth_handler_aborted;
}
- res = ssenddataf(ctx, "</table>");
+ res = fetch_about_ssenddataf(ctx, "</table>");
if (res != NSERROR_OK) {
goto fetch_about_query_auth_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<div id=\"buttons\">"
"<input type=\"submit\" id=\"login\" name=\"login\" "
"value=\"%s\" class=\"default-action\">"
@@ -2151,7 +2030,7 @@ static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
if (res != NSERROR_OK) {
url_s = strdup("");
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
url_s);
free(url_s);
@@ -2159,14 +2038,14 @@ static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
goto fetch_about_query_auth_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<input type=\"hidden\" name=\"realm\" value=\"%s\">",
realm);
if (res != NSERROR_OK) {
goto fetch_about_query_auth_handler_aborted;
}
- res = ssenddataf(ctx, "</form></body>\n</html>\n");
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
if (res != NSERROR_OK) {
goto fetch_about_query_auth_handler_aborted;
}
@@ -2232,7 +2111,7 @@ static bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx)
}
title = messages_get("PrivacyTitle");
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<html>\n<head>\n"
"<title>%s</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
@@ -2245,7 +2124,7 @@ static bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx)
goto fetch_about_query_ssl_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<form method=\"post\""
" enctype=\"multipart/form-data\">");
if (res != NSERROR_OK) {
@@ -2256,7 +2135,7 @@ static bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx)
"PrivacyDescription",
&description);
if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
free(description);
if (res != NSERROR_OK) {
goto fetch_about_query_ssl_handler_aborted;
@@ -2264,13 +2143,13 @@ static bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx)
}
if (chainurl == NULL) {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<div><p>%s</p></div>"
"<div><p>%s</p></div>",
reason,
messages_get("ViewCertificatesNotPossible"));
} else {
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<div><p>%s</p></div>"
"<div><p><a href=\"%s\" target=\"_blank\">%s</a></p></div>",
reason,
@@ -2280,7 +2159,7 @@ static bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx)
if (res != NSERROR_OK) {
goto fetch_about_query_ssl_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<div id=\"buttons\">"
"<input type=\"submit\" id=\"back\" name=\"back\" "
"value=\"%s\" class=\"default-action\">"
@@ -2297,7 +2176,7 @@ static bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx)
if (res != NSERROR_OK) {
url_s = strdup("");
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
url_s);
free(url_s);
@@ -2305,7 +2184,7 @@ static bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx)
goto fetch_about_query_ssl_handler_aborted;
}
- res = ssenddataf(ctx, "</form></body>\n</html>\n");
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
if (res != NSERROR_OK) {
goto fetch_about_query_ssl_handler_aborted;
}
@@ -2367,7 +2246,7 @@ static bool fetch_about_query_timeout_handler(struct fetch_about_context *ctx)
}
title = messages_get("TimeoutTitle");
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<html>\n<head>\n"
"<title>%s</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
@@ -2380,7 +2259,7 @@ static bool fetch_about_query_timeout_handler(struct fetch_about_context *ctx)
goto fetch_about_query_timeout_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<form method=\"post\""
" enctype=\"multipart/form-data\">");
if (res != NSERROR_OK) {
@@ -2391,18 +2270,18 @@ static bool fetch_about_query_timeout_handler(struct fetch_about_context *ctx)
"TimeoutDescription",
&description);
if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ res = fetch_about_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);
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", reason);
if (res != NSERROR_OK) {
goto fetch_about_query_timeout_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<div id=\"buttons\">"
"<input type=\"submit\" id=\"back\" name=\"back\" "
"value=\"%s\" class=\"default-action\">"
@@ -2419,7 +2298,7 @@ static bool fetch_about_query_timeout_handler(struct fetch_about_context *ctx)
if (res != NSERROR_OK) {
url_s = strdup("");
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
url_s);
free(url_s);
@@ -2427,7 +2306,7 @@ static bool fetch_about_query_timeout_handler(struct fetch_about_context *ctx)
goto fetch_about_query_timeout_handler_aborted;
}
- res = ssenddataf(ctx, "</form></body>\n</html>\n");
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
if (res != NSERROR_OK) {
goto fetch_about_query_timeout_handler_aborted;
}
@@ -2490,7 +2369,7 @@ fetch_about_query_fetcherror_handler(struct fetch_about_context *ctx)
}
title = messages_get("FetchErrorTitle");
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<html>\n<head>\n"
"<title>%s</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
@@ -2503,7 +2382,7 @@ fetch_about_query_fetcherror_handler(struct fetch_about_context *ctx)
goto fetch_about_query_fetcherror_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<form method=\"post\""
" enctype=\"multipart/form-data\">");
if (res != NSERROR_OK) {
@@ -2514,18 +2393,18 @@ fetch_about_query_fetcherror_handler(struct fetch_about_context *ctx)
"FetchErrorDescription",
&description);
if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
free(description);
if (res != NSERROR_OK) {
goto fetch_about_query_fetcherror_handler_aborted;
}
}
- res = ssenddataf(ctx, "<div><p>%s</p></div>", reason);
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", reason);
if (res != NSERROR_OK) {
goto fetch_about_query_fetcherror_handler_aborted;
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<div id=\"buttons\">"
"<input type=\"submit\" id=\"back\" name=\"back\" "
"value=\"%s\" class=\"default-action\">"
@@ -2542,7 +2421,7 @@ fetch_about_query_fetcherror_handler(struct fetch_about_context *ctx)
if (res != NSERROR_OK) {
url_s = strdup("");
}
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
url_s);
free(url_s);
@@ -2550,7 +2429,7 @@ fetch_about_query_fetcherror_handler(struct fetch_about_context *ctx)
goto fetch_about_query_fetcherror_handler_aborted;
}
- res = ssenddataf(ctx, "</form></body>\n</html>\n");
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
if (res != NSERROR_OK) {
goto fetch_about_query_fetcherror_handler_aborted;
}
@@ -2720,7 +2599,7 @@ static bool fetch_about_about_handler(struct fetch_about_context *ctx)
if (fetch_about_send_header(ctx, "Content-Type: text/html"))
goto fetch_about_config_handler_aborted;
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<html>\n<head>\n"
"<title>List of NetSurf pages</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
@@ -2739,7 +2618,7 @@ static bool fetch_about_about_handler(struct fetch_about_context *ctx)
if (about_handler_list[abt_loop].hidden)
continue;
- res = ssenddataf(ctx,
+ res = fetch_about_ssenddataf(ctx,
"<li><a href=\"about:%s\">about:%s</a></li>\n",
about_handler_list[abt_loop].name,
about_handler_list[abt_loop].name);
@@ -2748,7 +2627,7 @@ static bool fetch_about_about_handler(struct fetch_about_context *ctx)
}
}
- res = ssenddataf(ctx, "</ul>\n</body>\n</html>\n");
+ res = fetch_about_ssenddataf(ctx, "</ul>\n</body>\n</html>\n");
if (res != NSERROR_OK) {
goto fetch_about_config_handler_aborted;
}
@@ -2774,7 +2653,7 @@ fetch_about_404_handler(struct fetch_about_context *ctx)
return false;
}
- res = ssenddataf(ctx, "Unknown page: %s", nsurl_access(ctx->url));
+ res = fetch_about_ssenddataf(ctx, "Unknown page: %s", nsurl_access(ctx->url));
if (res != NSERROR_OK) {
return false;
}
diff --git a/content/fetchers/about/about.h b/content/fetchers/about/about.h
index 944f84a..bf63797 100644
--- a/content/fetchers/about/about.h
+++ b/content/fetchers/about/about.h
@@ -16,12 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * about: URL method handler
+/**
+ * \file
+ * about scheme URL method handler
*/
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_ABOUT_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_ABOUT_H
/**
* Register about scheme handler.
diff --git a/content/fetchers/about/imagecache.c b/content/fetchers/about/imagecache.c
new file mode 100644
index 0000000..5e2abcb
--- /dev/null
+++ b/content/fetchers/about/imagecache.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme imagecache page
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "netsurf/types.h"
+
+#include "image/image_cache.h"
+
+#include "private.h"
+#include "imagecache.h"
+
+/* exported interface documented in about/imagecache.h */
+bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
+{
+ char buffer[2048]; /* output buffer */
+ int code = 200;
+ int slen;
+ unsigned int cent_loop = 0;
+ int elen = 0; /* entry length */
+ nserror res;
+ bool even = false;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_about_imagecache_handler_aborted;
+
+ /* page head */
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>Image Cache Status</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body id =\"cachelist\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
+ "<h1 class=\"ns-border\">Image Cache Status</h1>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ /* image cache summary */
+ slen = image_cache_snsummaryf(buffer, sizeof(buffer),
+ "<p>Configured limit of %a hysteresis of %b</p>\n"
+ "<p>Total bitmap size in use %c (in %d)</p>\n"
+ "<p>Age %es</p>\n"
+ "<p>Peak size %f (in %g)</p>\n"
+ "<p>Peak image count %h (size %i)</p>\n"
+ "<p>Cache total/hit/miss/fail (counts) %j/%k/%l/%m "
+ "(%pj%%/%pk%%/%pl%%/%pm%%)</p>\n"
+ "<p>Cache total/hit/miss/fail (size) %n/%o/%q/%r "
+ "(%pn%%/%po%%/%pq%%/%pr%%)</p>\n"
+ "<p>Total images never rendered: %s "
+ "(includes %t that were converted)</p>\n"
+ "<p>Total number of excessive conversions: %u "
+ "(from %v images converted more than once)"
+ "</p>\n"
+ "<p>Bitmap of size %w had most (%x) conversions</p>\n"
+ "<h2 class=\"ns-border\">Current contents</h2>\n");
+ if (slen >= (int) (sizeof(buffer))) {
+ goto fetch_about_imagecache_handler_aborted; /* overflow */
+ }
+
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ /* image cache entry table */
+ res = fetch_about_ssenddataf(ctx, "<p class=\"imagecachelist\">\n"
+ "<strong>"
+ "<span>Entry</span>"
+ "<span>Content Key</span>"
+ "<span>Redraw Count</span>"
+ "<span>Conversion Count</span>"
+ "<span>Last Redraw</span>"
+ "<span>Bitmap Age</span>"
+ "<span>Bitmap Size</span>"
+ "<span>Source</span>"
+ "</strong>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ slen = 0;
+ do {
+ if (even) {
+ elen = image_cache_snentryf(buffer + slen,
+ sizeof buffer - slen,
+ cent_loop,
+ "<a href=\"%U\">"
+ "<span class=\"ns-border\">%e</span>"
+ "<span class=\"ns-border\">%k</span>"
+ "<span class=\"ns-border\">%r</span>"
+ "<span class=\"ns-border\">%c</span>"
+ "<span class=\"ns-border\">%a</span>"
+ "<span class=\"ns-border\">%g</span>"
+ "<span class=\"ns-border\">%s</span>"
+ "<span class=\"ns-border\">%o</span>"
+ "</a>\n");
+ } else {
+ elen = image_cache_snentryf(buffer + slen,
+ sizeof buffer - slen,
+ cent_loop,
+ "<a class=\"ns-odd-bg\" href=\"%U\">"
+ "<span class=\"ns-border\">%e</span>"
+ "<span class=\"ns-border\">%k</span>"
+ "<span class=\"ns-border\">%r</span>"
+ "<span class=\"ns-border\">%c</span>"
+ "<span class=\"ns-border\">%a</span>"
+ "<span class=\"ns-border\">%g</span>"
+ "<span class=\"ns-border\">%s</span>"
+ "<span class=\"ns-border\">%o</span>"
+ "</a>\n");
+ }
+ if (elen <= 0)
+ break; /* last option */
+
+ if (elen >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ res = fetch_about_senddata(ctx,
+ (const uint8_t *)buffer,
+ slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += elen;
+ cent_loop++;
+ even = !even;
+ }
+ } while (elen > 0);
+
+ slen += snprintf(buffer + slen, sizeof buffer - slen,
+ "</p>\n</body>\n</html>\n");
+
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_imagecache_handler_aborted:
+ return false;
+}
diff --git a/content/fetchers/about/imagecache.h b/content/fetchers/about/imagecache.h
new file mode 100644
index 0000000..d1419ce
--- /dev/null
+++ b/content/fetchers/about/imagecache.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * about scheme imagecache handler interface
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_IMAGECACHE_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_IMAGECACHE_H
+
+/**
+ * Handler to generate about scheme imagecache page.
+ *
+ * Shows details of current image cache.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_imagecache_handler(struct fetch_about_context *ctx);
+
+#endif
diff --git a/content/fetchers/about/private.h b/content/fetchers/about/private.h
new file mode 100644
index 0000000..d877ac5
--- /dev/null
+++ b/content/fetchers/about/private.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Private interfaces for the about scheme fetcher.
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_PRIVATE_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_PRIVATE_H
+
+struct fetch_about_context;
+
+/**
+ * set http response code on about response
+ */
+bool fetch_about_set_http_code(struct fetch_about_context *ctx, long code);
+
+/**
+ * Send a header on the about response
+ *
+ * \param ctx The about fetch context
+ * \param fmt The format specifier of the header
+ * \return true if the fetch has been aborted else false
+ */
+bool fetch_about_send_header(struct fetch_about_context *ctx, const char *fmt, ...);
+
+/**
+ * send data on the about response
+ */
+nserror
+fetch_about_senddata(struct fetch_about_context *ctx, const uint8_t *data, size_t data_len);
+
+/**
+ * send formatted data on the about response
+ */
+nserror fetch_about_ssenddataf(struct fetch_about_context *ctx, const char *fmt, ...);
+
+/**
+ * complete the about fetch response
+ */
+bool fetch_about_send_finished(struct fetch_about_context *ctx);
+
+#endif
diff --git a/content/handlers/image/image_cache.h b/content/handlers/image/image_cache.h
index 955306e..1c2d621 100644
--- a/content/handlers/image/image_cache.h
+++ b/content/handlers/image/image_cache.h
@@ -40,6 +40,7 @@
#include "utils/errors.h"
#include "netsurf/content_type.h"
+struct content;
struct content_redraw_data;
struct redraw_context;
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=c74509cdf58fb247329...
commit c74509cdf58fb2473290fcacb8b1cc885b53df87
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
move about fetcher into its own directory
diff --git a/content/fetch.c b/content/fetch.c
index a260799..533f75e 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -53,7 +53,7 @@
#include "content/fetch.h"
#include "content/fetchers.h"
#include "content/fetchers/resource.h"
-#include "content/fetchers/about.h"
+#include "content/fetchers/about/about.h"
#include "content/fetchers/curl.h"
#include "content/fetchers/data.h"
#include "content/fetchers/file/file.h"
diff --git a/content/fetchers/Makefile b/content/fetchers/Makefile
index e87a4e8..8f6e521 100644
--- a/content/fetchers/Makefile
+++ b/content/fetchers/Makefile
@@ -1,15 +1,15 @@
# Content fetchers sources
-S_FETCHERS_YES := data.c about.c resource.c
+S_FETCHERS_YES := data.c resource.c
S_FETCHERS_NO :=
S_FETCHERS_$(NETSURF_USE_CURL) += curl.c
S_FETCHERS := $(addprefix fetchers/,$(S_FETCHERS_YES))
-# File fetcher
-include content/fetchers/file/Makefile
+# about fetcher
+include content/fetchers/about/Makefile
+S_FETCHERS += $(addprefix fetchers/about/,$(S_FETCHER_ABOUT))
+# file fetcher
+include content/fetchers/file/Makefile
S_FETCHERS += $(addprefix fetchers/file/,$(S_FETCHER_FILE))
-
-# The following files depend on the testament
-content/fetchers/about.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about.c b/content/fetchers/about.c
deleted file mode 100644
index 28f0d1e..0000000
--- a/content/fetchers/about.c
+++ /dev/null
@@ -1,2976 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince(a)netsurf-browser.org>
- *
- * This file is part of NetSurf.
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- *
- * URL handling for the "about" scheme.
- *
- * Based on the data fetcher by Rob Kendrick
- * This fetcher provides a simple scheme for the user to access
- * information from the browser from a known, fixed URL.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#include "netsurf/inttypes.h"
-#include "netsurf/plot_style.h"
-
-#include "utils/log.h"
-#include "testament.h"
-#include "utils/corestrings.h"
-#include "utils/nscolour.h"
-#include "utils/nsoption.h"
-#include "utils/utils.h"
-#include "utils/messages.h"
-#include "utils/ring.h"
-
-#include "content/fetch.h"
-#include "content/fetchers.h"
-#include "content/fetchers/about.h"
-#include "image/image_cache.h"
-
-#include "desktop/system_colour.h"
-
-struct fetch_about_context;
-
-typedef bool (*fetch_about_handler)(struct fetch_about_context *);
-
-/**
- * Context for an about fetch
- */
-struct fetch_about_context {
- struct fetch_about_context *r_next, *r_prev;
-
- struct fetch *fetchh; /**< Handle for this fetch */
-
- bool aborted; /**< Flag indicating fetch has been aborted */
- bool locked; /**< Flag indicating entry is already entered */
-
- nsurl *url; /**< The full url the fetch refers to */
-
- const struct fetch_multipart_data *multipart; /**< post data */
-
- fetch_about_handler handler;
-};
-
-static struct fetch_about_context *ring = NULL;
-
-/**
- * handler info for about scheme
- */
-struct about_handlers {
- const char *name; /**< name to match in url */
- int name_len;
- lwc_string *lname; /**< Interned name */
- fetch_about_handler handler; /**< handler for the url */
- bool hidden; /**< If entry should be hidden in listing */
-};
-
-
-/**
- * issue fetch callbacks with locking
- */
-static inline bool
-fetch_about_send_callback(const fetch_msg *msg, struct fetch_about_context *ctx)
-{
- ctx->locked = true;
- fetch_send_callback(msg, ctx->fetchh);
- ctx->locked = false;
-
- return ctx->aborted;
-}
-
-static inline bool
-fetch_about_send_finished(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- msg.type = FETCH_FINISHED;
- return fetch_about_send_callback(&msg, ctx);
-}
-
-static bool
-fetch_about_send_header(struct fetch_about_context *ctx, const char *fmt, ...)
-{
- char header[64];
- fetch_msg msg;
- va_list ap;
-
- va_start(ap, fmt);
-
- vsnprintf(header, sizeof header, fmt, ap);
-
- va_end(ap);
-
- msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf = (const uint8_t *) header;
- msg.data.header_or_data.len = strlen(header);
-
- return fetch_about_send_callback(&msg, ctx);
-}
-
-/**
- * send formatted data on a fetch
- */
-static nserror ssenddataf(struct fetch_about_context *ctx, const char *fmt, ...)
-{
- char buffer[1024];
- char *dbuff;
- fetch_msg msg;
- va_list ap;
- int slen;
-
- va_start(ap, fmt);
-
- slen = vsnprintf(buffer, sizeof(buffer), fmt, ap);
-
- va_end(ap);
-
- if (slen < (int)sizeof(buffer)) {
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
- msg.data.header_or_data.len = slen;
-
- if (fetch_about_send_callback(&msg, ctx)) {
- return NSERROR_INVALID;
- }
-
- return NSERROR_OK;
- }
-
- dbuff = malloc(slen + 1);
- if (dbuff == NULL) {
- return NSERROR_NOSPACE;
- }
-
- va_start(ap, fmt);
-
- slen = vsnprintf(dbuff, slen + 1, fmt, ap);
-
- va_end(ap);
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *)dbuff;
- msg.data.header_or_data.len = slen;
-
- if (fetch_about_send_callback(&msg, ctx)) {
- free(dbuff);
- return NSERROR_INVALID;
- }
-
- free(dbuff);
- return NSERROR_OK;
-}
-
-
-/**
- * Generate a 500 server error respnse
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_srverror(struct fetch_about_context *ctx)
-{
- nserror res;
-
- fetch_set_http_code(ctx->fetchh, 500);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
- return false;
-
- res = ssenddataf(ctx, "Server error 500");
- if (res != NSERROR_OK) {
- return false;
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-}
-
-
-/**
- * Handler to generate about scheme cache page.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_blank_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- const char buffer[2] = { ' ', '\0' };
-
- /* 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"))
- goto fetch_about_blank_handler_aborted;
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
- msg.data.header_or_data.len = strlen(buffer);
-
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_blank_handler_aborted;
-
- msg.type = FETCH_FINISHED;
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-
-fetch_about_blank_handler_aborted:
- return false;
-}
-
-
-/**
- * Handler to generate about scheme credits page.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_credits_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
-
- /* content is going to return redirect */
- fetch_set_http_code(ctx->fetchh, 302);
-
- msg.type = FETCH_REDIRECT;
- msg.data.redirect = "resource:credits.html";
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-}
-
-
-/**
- * Handler to generate about scheme licence page.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
-
- /* content is going to return redirect */
- fetch_set_http_code(ctx->fetchh, 302);
-
- msg.type = FETCH_REDIRECT;
- msg.data.redirect = "resource:licence.html";
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-}
-
-
-/**
- * Handler to generate about:imagecache page.
- *
- * Shows details of current image cache.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- char buffer[2048]; /* output buffer */
- int code = 200;
- int slen;
- unsigned int cent_loop = 0;
- int elen = 0; /* entry length */
- nserror res;
- bool even = false;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, code);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/html"))
- goto fetch_about_imagecache_handler_aborted;
-
- /* page head */
- res = ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>Image Cache Status</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body id =\"cachelist\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
- "<h1 class=\"ns-border\">Image Cache Status</h1>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_imagecache_handler_aborted;
- }
-
- /* image cache summary */
- slen = image_cache_snsummaryf(buffer, sizeof(buffer),
- "<p>Configured limit of %a hysteresis of %b</p>\n"
- "<p>Total bitmap size in use %c (in %d)</p>\n"
- "<p>Age %es</p>\n"
- "<p>Peak size %f (in %g)</p>\n"
- "<p>Peak image count %h (size %i)</p>\n"
- "<p>Cache total/hit/miss/fail (counts) %j/%k/%l/%m "
- "(%pj%%/%pk%%/%pl%%/%pm%%)</p>\n"
- "<p>Cache total/hit/miss/fail (size) %n/%o/%q/%r "
- "(%pn%%/%po%%/%pq%%/%pr%%)</p>\n"
- "<p>Total images never rendered: %s "
- "(includes %t that were converted)</p>\n"
- "<p>Total number of excessive conversions: %u "
- "(from %v images converted more than once)"
- "</p>\n"
- "<p>Bitmap of size %w had most (%x) conversions</p>\n"
- "<h2 class=\"ns-border\">Current contents</h2>\n");
- if (slen >= (int) (sizeof(buffer))) {
- goto fetch_about_imagecache_handler_aborted; /* overflow */
- }
-
- /* send image cache summary */
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx)) {
- goto fetch_about_imagecache_handler_aborted;
- }
-
- /* image cache entry table */
- res = ssenddataf(ctx, "<p class=\"imagecachelist\">\n"
- "<strong>"
- "<span>Entry</span>"
- "<span>Content Key</span>"
- "<span>Redraw Count</span>"
- "<span>Conversion Count</span>"
- "<span>Last Redraw</span>"
- "<span>Bitmap Age</span>"
- "<span>Bitmap Size</span>"
- "<span>Source</span>"
- "</strong>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_imagecache_handler_aborted;
- }
-
- slen = 0;
- do {
- if (even) {
- elen = image_cache_snentryf(buffer + slen,
- sizeof buffer - slen,
- cent_loop,
- "<a href=\"%U\">"
- "<span class=\"ns-border\">%e</span>"
- "<span class=\"ns-border\">%k</span>"
- "<span class=\"ns-border\">%r</span>"
- "<span class=\"ns-border\">%c</span>"
- "<span class=\"ns-border\">%a</span>"
- "<span class=\"ns-border\">%g</span>"
- "<span class=\"ns-border\">%s</span>"
- "<span class=\"ns-border\">%o</span>"
- "</a>\n");
- } else {
- elen = image_cache_snentryf(buffer + slen,
- sizeof buffer - slen,
- cent_loop,
- "<a class=\"ns-odd-bg\" href=\"%U\">"
- "<span class=\"ns-border\">%e</span>"
- "<span class=\"ns-border\">%k</span>"
- "<span class=\"ns-border\">%r</span>"
- "<span class=\"ns-border\">%c</span>"
- "<span class=\"ns-border\">%a</span>"
- "<span class=\"ns-border\">%g</span>"
- "<span class=\"ns-border\">%s</span>"
- "<span class=\"ns-border\">%o</span>"
- "</a>\n");
- }
- if (elen <= 0)
- break; /* last option */
-
- if (elen >= (int) (sizeof buffer - slen)) {
- /* last entry would not fit in buffer, submit buffer */
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_imagecache_handler_aborted;
- slen = 0;
- } else {
- /* normal addition */
- slen += elen;
- cent_loop++;
- even = !even;
- }
- } while (elen > 0);
-
- slen += snprintf(buffer + slen, sizeof buffer - slen,
- "</p>\n</body>\n</html>\n");
-
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_imagecache_handler_aborted;
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_imagecache_handler_aborted:
- return false;
-}
-
-/**
- * certificate name parameters
- */
-struct ns_cert_name {
- char *common_name;
- char *organisation;
- char *organisation_unit;
- char *locality;
- char *province;
- char *country;
-};
-
-/**
- * Certificate public key parameters
- */
-struct ns_cert_pkey {
- char *algor;
- int size;
- char *modulus;
- char *exponent;
- char *curve;
- char *public;
-};
-
-/**
- * Certificate subject alternative name
- */
-struct ns_cert_san {
- struct ns_cert_san *next;
- char *name;
-};
-
-/**
- * certificate information for certificate chain
- */
-struct ns_cert_info {
- struct ns_cert_name subject_name; /**< Subject details */
- struct ns_cert_name issuer_name; /**< Issuer details */
- struct ns_cert_pkey public_key; /**< public key details */
- long version; /**< Certificate version */
- char *not_before; /**< Valid from date */
- char *not_after; /**< Valid to date */
- int sig_type; /**< Signature type */
- char *sig_algor; /**< Signature Algorithm */
- char *serialnum; /**< Serial number */
- char *sha1fingerprint; /**< fingerprint shar1 encoded */
- char *sha256fingerprint; /**< fingerprint shar256 encoded */
- struct ns_cert_san *san; /**< subject alternative names */
- ssl_cert_err err; /**< Whatever is wrong with this certificate */
-};
-
-/**
- * free all resources associated with a certificate information structure
- */
-static nserror free_ns_cert_info(struct ns_cert_info *cinfo)
-{
- struct ns_cert_san *san;
-
- free(cinfo->subject_name.common_name);
- free(cinfo->subject_name.organisation);
- free(cinfo->subject_name.organisation_unit);
- free(cinfo->subject_name.locality);
- free(cinfo->subject_name.province);
- free(cinfo->subject_name.country);
- free(cinfo->issuer_name.common_name);
- free(cinfo->issuer_name.organisation);
- free(cinfo->issuer_name.organisation_unit);
- free(cinfo->issuer_name.locality);
- free(cinfo->issuer_name.province);
- free(cinfo->issuer_name.country);
- free(cinfo->public_key.algor);
- free(cinfo->public_key.modulus);
- free(cinfo->public_key.exponent);
- free(cinfo->public_key.curve);
- free(cinfo->public_key.public);
- free(cinfo->not_before);
- free(cinfo->not_after);
- free(cinfo->sig_algor);
- free(cinfo->serialnum);
-
- /* free san list avoiding use after free */
- san = cinfo->san;
- while (san != NULL) {
- struct ns_cert_san *next;
- next = san->next;
- free(san);
- san = next;
- }
-
- free(cinfo);
-
- return NSERROR_OK;
-}
-
-#ifdef WITH_OPENSSL
-
-#include <openssl/ssl.h>
-#include <openssl/x509v3.h>
-
-/* OpenSSL 1.0.x, 1.0.2, 1.1.0 and 1.1.1 API all changed
- * LibreSSL declares its OpenSSL version as 2.1 but only supports 1.0.x API
- */
-#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL))
-/* 1.0.x */
-
-#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1000200fL))
-/* pre 1.0.2 */
-static int ns_X509_get_signature_nid(X509 *cert)
-{
- return OBJ_obj2nid(cert->cert_info->key->algor->algorithm);
-}
-#else
-#define ns_X509_get_signature_nid X509_get_signature_nid
-#endif
-
-static const unsigned char *ns_ASN1_STRING_get0_data(ASN1_STRING *asn1str)
-{
- return (const unsigned char *)ASN1_STRING_data(asn1str);
-}
-
-static const BIGNUM *ns_RSA_get0_n(const RSA *d)
-{
- return d->n;
-}
-
-static const BIGNUM *ns_RSA_get0_e(const RSA *d)
-{
- return d->e;
-}
-
-static int ns_RSA_bits(const RSA *rsa)
-{
- return RSA_size(rsa) * 8;
-}
-
-static int ns_DSA_bits(const DSA *dsa)
-{
- return DSA_size(dsa) * 8;
-}
-
-static int ns_DH_bits(const DH *dh)
-{
- return DH_size(dh) * 8;
-}
-
-#elif (OPENSSL_VERSION_NUMBER < 0x1010100fL)
-/* 1.1.0 */
-#define ns_X509_get_signature_nid X509_get_signature_nid
-#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
-
-static const BIGNUM *ns_RSA_get0_n(const RSA *r)
-{
- const BIGNUM *n;
- const BIGNUM *e;
- const BIGNUM *d;
- RSA_get0_key(r, &n, &e, &d);
- return n;
-}
-
-static const BIGNUM *ns_RSA_get0_e(const RSA *r)
-{
- const BIGNUM *n;
- const BIGNUM *e;
- const BIGNUM *d;
- RSA_get0_key(r, &n, &e, &d);
- return e;
-}
-
-#define ns_RSA_bits RSA_bits
-#define ns_DSA_bits DSA_bits
-#define ns_DH_bits DH_bits
-
-#else
-/* 1.1.1 and later */
-#define ns_X509_get_signature_nid X509_get_signature_nid
-#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
-#define ns_RSA_get0_n RSA_get0_n
-#define ns_RSA_get0_e RSA_get0_e
-#define ns_RSA_bits RSA_bits
-#define ns_DSA_bits DSA_bits
-#define ns_DH_bits DH_bits
-#endif
-
-/**
- * extract certificate name information
- *
- * \param xname The X509 name to convert. The reference is borrowed so is not freeed
- * \param iname The info structure to recive the extracted parameters.
- * \return NSERROR_OK on success else error code
- */
-static nserror
-xname_to_info(X509_NAME *xname, struct ns_cert_name *iname)
-{
- int entryidx;
- int entrycnt;
- X509_NAME_ENTRY *entry; /* current name entry */
- ASN1_STRING *value;
- const unsigned char *value_str;
- ASN1_OBJECT *name;
- int name_nid;
- char **field;
-
- entrycnt = X509_NAME_entry_count(xname);
-
- for (entryidx = 0; entryidx < entrycnt; entryidx++) {
- entry = X509_NAME_get_entry(xname, entryidx);
- name = X509_NAME_ENTRY_get_object(entry);
- name_nid = OBJ_obj2nid(name);
- value = X509_NAME_ENTRY_get_data(entry);
- value_str = ns_ASN1_STRING_get0_data(value);
- switch (name_nid) {
- case NID_commonName:
- field = &iname->common_name;
- break;
- case NID_countryName:
- field = &iname->country;
- break;
- case NID_localityName:
- field = &iname->locality;
- break;
- case NID_stateOrProvinceName:
- field = &iname->province;
- break;
- case NID_organizationName:
- field = &iname->organisation;
- break;
- case NID_organizationalUnitName:
- field = &iname->organisation_unit;
- break;
- default :
- field = NULL;
- break;
- }
- if (field != NULL) {
- *field = strdup((const char *)value_str);
- NSLOG(netsurf, DEEPDEBUG,
- "NID:%d value: %s", name_nid, *field);
- } else {
- NSLOG(netsurf, DEEPDEBUG, "NID:%d", name_nid);
- }
- }
-
- /*
- * ensure the common name is set to something, this being
- * missing means the certificate is broken but this should be
- * robust in the face of bad data
- */
- if (iname->common_name == NULL) {
- iname->common_name = strdup("Unknown");
- }
-
- return NSERROR_OK;
-}
-
-
-/**
- * duplicate a hex formatted string inserting the colons
- *
- * \todo only uses html entity as separator because netsurfs line breaking
- * fails otherwise.
- */
-static char *hexdup(const char *hex)
-{
- int hexlen;
- char *dst;
- char *out;
- int cn = 0;
-
- hexlen = strlen(hex);
- /* allow space fox XXYY to XX:YY: */
- dst = malloc(((hexlen * 7) + 6) / 2);
-
- if (dst != NULL) {
- for (out = dst; *hex != 0; hex++) {
- if (cn == 2) {
- cn = 0;
- *out++ = '&';
- *out++ = '#';
- *out++ = '5';
- *out++ = '8';
- *out++ = ';';
- }
- *out++ = *hex;
- cn++;
- }
- *out = 0;
- }
- return dst;
-}
-
-
-/**
- * create a hex formatted string inserting the colons from binary data
- *
- * \todo only uses html entity as separator because netsurfs line breaking
- * fails otherwise.
- */
-static char *bindup(unsigned char *bin, unsigned int binlen)
-{
- char *dst;
- char *out;
- unsigned int idx;
- const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
-
- /* allow space fox XY to expand to XX:YY: */
- dst = malloc(binlen * 7);
-
- if (dst != NULL) {
- out = dst;
- for (idx = 0; idx < binlen; idx++) {
- *out++ = hex[(bin[idx] & 0xf0) >> 4];
- *out++ = hex[bin[idx] & 0xf];
-
- *out++ = '&';
- *out++ = '#';
- *out++ = '5';
- *out++ = '8';
- *out++ = ';';
- }
- out -= 5;
- *out = 0;
- }
- return dst;
-}
-
-
-/**
- * extract RSA key information to info structure
- *
- * \param rsa The RSA key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-rsa_to_info(RSA *rsa, struct ns_cert_pkey *ikey)
-{
- char *tmp;
-
- if (rsa == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("RSA");
-
- ikey->size = ns_RSA_bits(rsa);
-
- tmp = BN_bn2hex(ns_RSA_get0_n(rsa));
- if (tmp != NULL) {
- ikey->modulus = hexdup(tmp);
- OPENSSL_free(tmp);
- }
-
- tmp = BN_bn2dec(ns_RSA_get0_e(rsa));
- if (tmp != NULL) {
- ikey->exponent = strdup(tmp);
- OPENSSL_free(tmp);
- }
-
- RSA_free(rsa);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract DSA key information to info structure
- *
- * \param dsa The RSA key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-dsa_to_info(DSA *dsa, struct ns_cert_pkey *ikey)
-{
- if (dsa == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("DSA");
-
- ikey->size = ns_DSA_bits(dsa);
-
- DSA_free(dsa);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract DH key information to info structure
- *
- * \param dsa The RSA key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-dh_to_info(DH *dh, struct ns_cert_pkey *ikey)
-{
- if (dh == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("Diffie Hellman");
-
- ikey->size = ns_DH_bits(dh);
-
- DH_free(dh);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract EC key information to info structure
- *
- * \param ec The EC key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-ec_to_info(EC_KEY *ec, struct ns_cert_pkey *ikey)
-{
- const EC_GROUP *ecgroup;
- const EC_POINT *ecpoint;
- BN_CTX *bnctx;
- char *ecpoint_hex;
-
- if (ec == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("Elliptic Curve");
-
- ecgroup = EC_KEY_get0_group(ec);
-
- if (ecgroup != NULL) {
- ikey->size = EC_GROUP_get_degree(ecgroup);
-
- ikey->curve = strdup(OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)));
-
- ecpoint = EC_KEY_get0_public_key(ec);
- if (ecpoint != NULL) {
- bnctx = BN_CTX_new();
- ecpoint_hex = EC_POINT_point2hex(ecgroup,
- ecpoint,
- POINT_CONVERSION_UNCOMPRESSED,
- bnctx);
- ikey->public = hexdup(ecpoint_hex);
- OPENSSL_free(ecpoint_hex);
- BN_CTX_free(bnctx);
- }
- }
- EC_KEY_free(ec);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract public key information to info structure
- *
- * \param pkey the public key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-pkey_to_info(EVP_PKEY *pkey, struct ns_cert_pkey *ikey)
-{
- nserror res;
-
- if (pkey == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- switch (EVP_PKEY_base_id(pkey)) {
- case EVP_PKEY_RSA:
- res = rsa_to_info(EVP_PKEY_get1_RSA(pkey), ikey);
- break;
-
- case EVP_PKEY_DSA:
- res = dsa_to_info(EVP_PKEY_get1_DSA(pkey), ikey);
- break;
-
- case EVP_PKEY_DH:
- res = dh_to_info(EVP_PKEY_get1_DH(pkey), ikey);
- break;
-
- case EVP_PKEY_EC:
- res = ec_to_info(EVP_PKEY_get1_EC_KEY(pkey), ikey);
- break;
-
- default:
- res = NSERROR_NOT_IMPLEMENTED;
- break;
- }
-
- EVP_PKEY_free(pkey);
-
- return res;
-}
-
-static nserror san_to_info(X509 *cert, struct ns_cert_san **prev_next)
-{
- int idx;
- int san_names_nb = -1;
- const GENERAL_NAME *current_name;
- const unsigned char *dns_name;
- struct ns_cert_san *isan;
-
- STACK_OF(GENERAL_NAME) *san_names = NULL;
-
- san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
- if (san_names == NULL) {
- return NSERROR_OK;
- }
-
- san_names_nb = sk_GENERAL_NAME_num(san_names);
-
- /* Check each name within the extension */
- for (idx = 0; idx < san_names_nb; idx++) {
- current_name = sk_GENERAL_NAME_value(san_names, idx);
-
- if (current_name->type == GEN_DNS) {
- /* extract DNS name into info structure */
- dns_name = ns_ASN1_STRING_get0_data(current_name->d.dNSName);
-
- isan = malloc(sizeof(struct ns_cert_san));
- if (isan != NULL) {
- isan->name = strdup((const char *)dns_name);
- isan->next = NULL;
- *prev_next = isan;
- prev_next = &isan->next;
- }
- }
- }
-
- /* AmiSSL can't cope with the "correct" mechanism of freeing
- * the GENERAL_NAME stack, which is:
- * sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
- * So instead we do this open-coded loop which does the same:
- */
- for (idx = 0; idx < san_names_nb; idx++) {
- GENERAL_NAME *entry = sk_GENERAL_NAME_pop(san_names);
- GENERAL_NAME_free(entry);
- }
- sk_GENERAL_NAME_free(san_names);
-
- return NSERROR_OK;
-}
-
-static nserror
-der_to_certinfo(const uint8_t *der,
- size_t der_length,
- struct ns_cert_info *info)
-{
- BIO *mem;
- BUF_MEM *buf;
- const ASN1_INTEGER *asn1_num;
- BIGNUM *bignum;
- X509 *cert; /**< Pointer to certificate */
-
- if (der == NULL) {
- return NSERROR_OK;
- }
-
- cert = d2i_X509(NULL, &der, der_length);
- if (cert == NULL) {
- return NSERROR_INVALID;
- }
-
- /*
- * get certificate version
- *
- * \note this is defined by standards (X.509 et al) to be one
- * less than the certificate version.
- */
- info->version = X509_get_version(cert) + 1;
-
- /* not before date */
- mem = BIO_new(BIO_s_mem());
- ASN1_TIME_print(mem, X509_get_notBefore(cert));
- BIO_get_mem_ptr(mem, &buf);
- (void) BIO_set_close(mem, BIO_NOCLOSE);
- BIO_free(mem);
- info->not_before = calloc(1, buf->length + 1);
- if (info->not_before != NULL) {
- memcpy(info->not_before, buf->data, (unsigned)buf->length);
- }
- BUF_MEM_free(buf);
-
- /* not after date */
- mem = BIO_new(BIO_s_mem());
- ASN1_TIME_print(mem,
- X509_get_notAfter(cert));
- BIO_get_mem_ptr(mem, &buf);
- (void) BIO_set_close(mem, BIO_NOCLOSE);
- BIO_free(mem);
- info->not_after = calloc(1, buf->length + 1);
- if (info->not_after != NULL) {
- memcpy(info->not_after, buf->data, (unsigned)buf->length);
- }
- BUF_MEM_free(buf);
-
- /* signature type */
- info->sig_type = X509_get_signature_type(cert);
-
- /* signature algorithm */
- int pkey_nid = ns_X509_get_signature_nid(cert);
- if (pkey_nid != NID_undef) {
- const char* sslbuf = OBJ_nid2ln(pkey_nid);
- if (sslbuf != NULL) {
- info->sig_algor = strdup(sslbuf);
- }
- }
-
- /* serial number */
- asn1_num = X509_get_serialNumber(cert);
- if (asn1_num != NULL) {
- bignum = ASN1_INTEGER_to_BN(asn1_num, NULL);
- if (bignum != NULL) {
- char *tmp = BN_bn2hex(bignum);
- if (tmp != NULL) {
- info->serialnum = hexdup(tmp);
- OPENSSL_free(tmp);
- }
- BN_free(bignum);
- bignum = NULL;
- }
- }
-
- /* fingerprints */
- const EVP_MD *digest;
- unsigned int dig_len;
- unsigned char *buff;
- int rc;
-
- digest = EVP_sha1();
- buff = malloc(EVP_MD_size(digest));
- if (buff != NULL) {
- rc = X509_digest(cert, digest, buff, &dig_len);
- if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
- info->sha1fingerprint = bindup(buff, dig_len);
- }
- free(buff);
- }
-
- digest = EVP_sha256();
- buff = malloc(EVP_MD_size(digest));
- if (buff != NULL) {
- rc = X509_digest(cert, digest, buff, &dig_len);
- if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
- info->sha256fingerprint = bindup(buff, dig_len);
- }
- free(buff);
- }
-
- /* subject alternative names */
- san_to_info(cert, &info->san);
-
- /* issuer name */
- xname_to_info(X509_get_issuer_name(cert), &info->issuer_name);
-
- /* subject */
- xname_to_info(X509_get_subject_name(cert), &info->subject_name);
-
- /* public key */
- pkey_to_info(X509_get_pubkey(cert), &info->public_key);
-
- X509_free(cert);
-
- return NSERROR_OK;
-}
-
-/* copy certificate data */
-static nserror
-convert_chain_to_cert_info(const struct cert_chain *chain,
- struct ns_cert_info **cert_info_out)
-{
- struct ns_cert_info *certs;
- size_t depth;
- nserror res;
-
- certs = calloc(chain->depth, sizeof(struct ns_cert_info));
- if (certs == NULL) {
- return NSERROR_NOMEM;
- }
-
- for (depth = 0; depth < chain->depth;depth++) {
- res = der_to_certinfo(chain->certs[depth].der,
- chain->certs[depth].der_length,
- certs + depth);
- if (res != NSERROR_OK) {
- free(certs);
- return res;
- }
- certs[depth].err = chain->certs[depth].err;
- }
-
- *cert_info_out = certs;
- return NSERROR_OK;
-}
-
-#else
-static nserror
-convert_chain_to_cert_info(const struct cert_chain *chain,
- struct ns_cert_info **cert_info_out)
-{
- return NSERROR_NOT_IMPLEMENTED;
-}
-#endif
-
-
-static nserror
-format_certificate_name(struct fetch_about_context *ctx,
- struct ns_cert_name *cert_name)
-{
- nserror res;
- res = ssenddataf(ctx,
- "<tr><th>Common Name</th><td>%s</td></tr>\n",
- cert_name->common_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_name->organisation != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Organisation</th><td>%s</td></tr>\n",
- cert_name->organisation);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->organisation_unit != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Organisation Unit</th><td>%s</td></tr>\n",
- cert_name->organisation_unit);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->locality != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Locality</th><td>%s</td></tr>\n",
- cert_name->locality);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->province != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Privince</th><td>%s</td></tr>\n",
- cert_name->province);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->country != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Country</th><td>%s</td></tr>\n",
- cert_name->country);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- return res;
-}
-
-/**
- * output formatted certificate subject alternate names
- */
-static nserror
-format_certificate_san(struct fetch_about_context *ctx,
- struct ns_cert_san *san)
-{
- nserror res;
-
- if (san == NULL) {
- return NSERROR_OK;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Alternative Names</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- while (san != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>DNS Name</th><td>%s</td></tr>\n",
- san->name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- san = san->next;
- }
-
- res = ssenddataf(ctx, "</table>\n");
-
- return res;
-
-}
-
-
-static nserror
-format_certificate_public_key(struct fetch_about_context *ctx,
- struct ns_cert_pkey *public_key)
-{
- nserror res;
-
- if (public_key->algor == NULL) {
- /* skip the table if no algorithm name */
- return NSERROR_OK;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Public Key</th><td><hr></td></tr>\n"
- "<tr><th>Algorithm</th><td>%s</td></tr>\n"
- "<tr><th>Key Size</th><td>%d</td></tr>\n",
- public_key->algor,
- public_key->size);
- if (res != NSERROR_OK) {
- return res;
- }
-
-
- if (public_key->exponent != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Exponent</th><td>%s</td></tr>\n",
- public_key->exponent);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (public_key->modulus != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Modulus</th><td class=\"data\">%s</td></tr>\n",
- public_key->modulus);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (public_key->curve != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Curve</th><td>%s</td></tr>\n",
- public_key->curve);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (public_key->public != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Public Value</th><td>%s</td></tr>\n",
- public_key->public);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = ssenddataf(ctx, "</table>\n");
-
- return res;
-}
-
-static nserror
-format_certificate_fingerprint(struct fetch_about_context *ctx,
- struct ns_cert_info *cert_info)
-{
- nserror res;
-
- if ((cert_info->sha1fingerprint == NULL) &&
- (cert_info->sha256fingerprint == NULL)) {
- /* skip the table if no fingerprints */
- return NSERROR_OK;
- }
-
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Fingerprints</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_info->sha256fingerprint != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>SHA-256</th><td class=\"data\">%s</td></tr>\n",
- cert_info->sha256fingerprint);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_info->sha1fingerprint != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>SHA-1</th><td class=\"data\">%s</td></tr>\n",
- cert_info->sha1fingerprint);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = ssenddataf(ctx, "</table>\n");
-
- return res;
-}
-
-static nserror
-format_certificate(struct fetch_about_context *ctx,
- struct ns_cert_info *cert_info,
- size_t depth)
-{
- nserror res;
-
- res = ssenddataf(ctx,
- "<h2 id=\"%"PRIsizet"\" class=\"ns-border\">%s</h2>\n",
- depth, cert_info->subject_name.common_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_info->err != SSL_CERT_ERR_OK) {
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr class=\"ns-even-fg-bad\">"
- "<th>Fault</th>"
- "<td>%s</td>"
- "</tr>"
- "</table>\n",
- messages_get_sslcode(cert_info->err));
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Issued To</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_name(ctx, &cert_info->subject_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "</table>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Issued By</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_name(ctx, &cert_info->issuer_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "</table>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Validity</th><td><hr></td></tr>\n"
- "<tr><th>Valid From</th><td>%s</td></tr>\n"
- "<tr><th>Valid Until</th><td>%s</td></tr>\n"
- "</table>\n",
- cert_info->not_before,
- cert_info->not_after);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_san(ctx, cert_info->san);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_public_key(ctx, &cert_info->public_key);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Miscellaneous</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_info->serialnum != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Serial Number</th><td>%s</td></tr>\n",
- cert_info->serialnum);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_info->sig_algor != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Signature Algorithm</th>"
- "<td>%s</td></tr>\n",
- cert_info->sig_algor);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = ssenddataf(ctx,
- "<tr><th>Version</th><td>%ld</td></tr>\n"
- "</table>\n",
- cert_info->version);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_fingerprint(ctx, cert_info);
- if (res != NSERROR_OK) {
- return res;
- }
-
- return res;
-}
-
-/**
- * Handler to generate about:certificate page.
- *
- * Shows details of a certificate chain
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
-{
- int code = 200;
- nserror res;
- struct cert_chain *chain = NULL;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, code);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/html"))
- goto fetch_about_certificate_handler_aborted;
-
- /* page head */
- res = ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>NetSurf Browser Certificate Viewer</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body id=\"certificate\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
- "<h1 class=\"ns-border\">Certificate</h1>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
-
- res = cert_chain_from_query(ctx->url, &chain);
- if (res != NSERROR_OK) {
- res = ssenddataf(ctx, "<p>Could not process that</p>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
- } else {
- struct ns_cert_info *cert_info;
- res = convert_chain_to_cert_info(chain, &cert_info);
- if (res == NSERROR_OK) {
- size_t depth;
- res = ssenddataf(ctx, "<ul>\n");
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- for (depth = 0; depth < chain->depth; depth++) {
- res = ssenddataf(ctx, "<li><a href=\"#%"PRIsizet"\">%s</a></li>\n",
- depth, (cert_info + depth)
- ->subject_name
- .common_name);
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- }
-
- res = ssenddataf(ctx, "</ul>\n");
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- for (depth = 0; depth < chain->depth; depth++) {
- res = format_certificate(ctx, cert_info + depth,
- depth);
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- }
- free_ns_cert_info(cert_info);
-
- } else {
- res = ssenddataf(ctx,
- "<p>Invalid certificate data</p>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
- }
- }
-
-
- /* page footer */
- res = ssenddataf(ctx, "</body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- cert_chain_free(chain);
-
- return true;
-
-fetch_about_certificate_handler_aborted:
- cert_chain_free(chain);
- return false;
-}
-
-
-/**
- * Handler to generate about scheme config page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_config_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- char buffer[1024];
- int slen = 0;
- unsigned int opt_loop = 0;
- int elen = 0; /* entry length */
- nserror res;
- bool even = false;
-
- /* 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")) {
- goto fetch_about_config_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>NetSurf Browser Config</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body "
- "id =\"configlist\" "
- "class=\"ns-even-bg ns-even-fg ns-border\" "
- "style=\"overflow: hidden;\">\n"
- "<h1 class=\"ns-border\">NetSurf Browser Config</h1>\n"
- "<table class=\"config\">\n"
- "<tr><th>Option</th>"
- "<th>Type</th>"
- "<th>Provenance</th>"
- "<th>Setting</th></tr>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_config_handler_aborted;
- }
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
-
- do {
- if (even) {
- elen = nsoption_snoptionf(buffer + slen,
- sizeof buffer - slen,
- opt_loop,
- "<tr class=\"ns-even-bg\">"
- "<th class=\"ns-border\">%k</th>"
- "<td class=\"ns-border\">%t</td>"
- "<td class=\"ns-border\">%p</td>"
- "<td class=\"ns-border\">%V</td>"
- "</tr>\n");
- } else {
- elen = nsoption_snoptionf(buffer + slen,
- sizeof buffer - slen,
- opt_loop,
- "<tr class=\"ns-odd-bg\">"
- "<th class=\"ns-border\">%k</th>"
- "<td class=\"ns-border\">%t</td>"
- "<td class=\"ns-border\">%p</td>"
- "<td class=\"ns-border\">%V</td>"
- "</tr>\n");
- }
- if (elen <= 0)
- break; /* last option */
-
- if (elen >= (int) (sizeof buffer - slen)) {
- /* last entry would not fit in buffer, submit buffer */
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_config_handler_aborted;
- slen = 0;
- } else {
- /* normal addition */
- slen += elen;
- opt_loop++;
- even = !even;
- }
- } while (elen > 0);
-
- slen += snprintf(buffer + slen, sizeof buffer - slen,
- "</table>\n</body>\n</html>\n");
-
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_config_handler_aborted;
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_config_handler_aborted:
- return false;
-}
-
-
-/**
- * Handler to generate the nscolours stylesheet
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_nscolours_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- const char *stylesheet;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, 200);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/css; charset=utf-8")) {
- goto aborted;
- }
-
- res = nscolour_get_stylesheet(&stylesheet);
- if (res != NSERROR_OK) {
- goto aborted;
- }
-
- res = ssenddataf(ctx,
- "html {\n"
- "\tbackground-color: #%06x;\n"
- "}\n"
- "%s",
- colour_rb_swap(nscolours[NSCOLOUR_WIN_ODD_BG]),
- stylesheet);
- if (res != NSERROR_OK) {
- goto aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-aborted:
-
- return false;
-}
-
-
-/**
- * Generate the text of a Choices file which represents the current
- * in use options.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_choices_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- char buffer[1024];
- int code = 200;
- int slen;
- unsigned int opt_loop = 0;
- int res = 0;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, code);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
- goto fetch_about_choices_handler_aborted;
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
-
- slen = snprintf(buffer, sizeof buffer,
- "# Automatically generated current NetSurf browser Choices\n");
-
- do {
- res = nsoption_snoptionf(buffer + slen,
- sizeof buffer - slen,
- opt_loop,
- "%k:%v\n");
- if (res <= 0)
- break; /* last option */
-
- if (res >= (int) (sizeof buffer - slen)) {
- /* last entry would not fit in buffer, submit buffer */
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_choices_handler_aborted;
- slen = 0;
- } else {
- /* normal addition */
- slen += res;
- opt_loop++;
- }
- } while (res > 0);
-
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_choices_handler_aborted;
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_choices_handler_aborted:
- return false;
-}
-
-
-typedef struct {
- const char *leaf;
- const char *modtype;
-} modification_t;
-
-/**
- * Generate the text of an svn testament which represents the current
- * build-tree status
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_testament_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- static modification_t modifications[] = WT_MODIFICATIONS;
- int modidx; /* midification index */
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, 200);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
- goto fetch_about_testament_handler_aborted;
-
- res = ssenddataf(ctx,
- "# Automatically generated by NetSurf build system\n\n");
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- res = ssenddataf(ctx,
-#if defined(WT_BRANCHISTRUNK) || defined(WT_BRANCHISMASTER)
- "# This is a *DEVELOPMENT* build from the main line.\n\n"
-#elif defined(WT_BRANCHISTAG) && (WT_MODIFIED == 0)
- "# This is a tagged build of NetSurf\n"
-#ifdef WT_TAGIS
- "# The tag used was '" WT_TAGIS "'\n\n"
-#else
- "\n"
-#endif
-#elif defined(WT_NO_SVN) || defined(WT_NO_GIT)
- "# This NetSurf was built outside of our revision "
- "control environment.\n"
- "# This testament is therefore not very useful.\n\n"
-#else
- "# This NetSurf was built from a branch (" WT_BRANCHPATH ").\n\n"
-#endif
-#if defined(CI_BUILD)
- "# This build carries the CI build number '" CI_BUILD "'\n\n"
-#endif
- );
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "Built by %s (%s) from %s at revision %s on %s\n\n",
- GECOS, USERNAME, WT_BRANCHPATH, WT_REVID, WT_COMPILEDATE);
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- res = ssenddataf(ctx, "Built on %s in %s\n\n", WT_HOSTNAME, WT_ROOT);
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- if (WT_MODIFIED > 0) {
- res = ssenddataf(ctx,
- "Working tree has %d modification%s\n\n",
- WT_MODIFIED, WT_MODIFIED == 1 ? "" : "s");
- } else {
- res = ssenddataf(ctx, "Working tree is not modified.\n");
- }
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- for (modidx = 0; modidx < WT_MODIFIED; ++modidx) {
- res = ssenddataf(ctx,
- " %s %s\n",
- modifications[modidx].modtype,
- modifications[modidx].leaf);
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_testament_handler_aborted:
- return false;
-}
-
-
-/**
- * Handler to generate about scheme logo page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_logo_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
-
- /* content is going to return redirect */
- fetch_set_http_code(ctx->fetchh, 302);
-
- msg.type = FETCH_REDIRECT;
- msg.data.redirect = "resource:netsurf.png";
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-}
-
-
-/**
- * Handler to generate about scheme welcome page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_welcome_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
-
- /* content is going to return redirect */
- fetch_set_http_code(ctx->fetchh, 302);
-
- msg.type = FETCH_REDIRECT;
- msg.data.redirect = "resource:welcome.html";
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-}
-
-
-/**
- * generate the description of the login query
- */
-static nserror
-get_authentication_description(struct nsurl *url,
- const char *realm,
- const char *username,
- const char *password,
- char **out_str)
-{
- nserror res;
- char *url_s;
- size_t url_l;
- char *str = NULL;
- const char *key;
-
- res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
- if (res != NSERROR_OK) {
- return res;
- }
-
- if ((*username == 0) && (*password == 0)) {
- key = "LoginDescription";
- } else {
- key = "LoginAgain";
- }
-
- str = messages_get_buff(key, url_s, realm);
- if (str != NULL) {
- NSLOG(netsurf, INFO,
- "key:%s url:%s realm:%s str:%s",
- key, url_s, realm, str);
- *out_str = str;
- } else {
- res = NSERROR_NOMEM;
- }
-
- free(url_s);
-
- return res;
-}
-
-
-/**
- * generate a generic query description
- */
-static nserror
-get_query_description(struct nsurl *url,
- const char *key,
- char **out_str)
-{
- nserror res;
- char *url_s;
- size_t url_l;
- char *str = NULL;
-
- /* get the host in question */
- res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
- if (res != NSERROR_OK) {
- return res;
- }
-
- /* obtain the description with the url substituted */
- str = messages_get_buff(key, url_s);
- if (str == NULL) {
- res = NSERROR_NOMEM;
- } else {
- *out_str = str;
- }
-
- free(url_s);
-
- return res;
-}
-
-
-/**
- * Handler to generate about scheme authentication query page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- char *url_s;
- size_t url_l;
- const char *realm = "";
- const char *username = "";
- const char *password = "";
- const char *title;
- char *description = NULL;
- struct nsurl *siteurl = 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, "realm") == 0) {
- realm = curmd->value;
- } else if (strcmp(curmd->name, "username") == 0) {
- username = curmd->value;
- } else if (strcmp(curmd->name, "password") == 0) {
- password = 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_auth_handler_aborted;
- }
-
- title = messages_get("LoginTitle");
- 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 class=\"ns-even-bg ns-even-fg ns-border\" id =\"authentication\">\n"
- "<h1 class=\"ns-border\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<form method=\"post\""
- " enctype=\"multipart/form-data\">");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = get_authentication_description(siteurl,
- realm,
- username,
- password,
- &description);
- if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<p>%s</p>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
- }
-
- res = ssenddataf(ctx, "<table>");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<tr>"
- "<th><label for=\"name\">%s:</label></th>"
- "<td><input type=\"text\" id=\"username\" "
- "name=\"username\" value=\"%s\"></td>"
- "</tr>",
- messages_get("Username"), username);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<tr>"
- "<th><label for=\"password\">%s:</label></th>"
- "<td><input type=\"password\" id=\"password\" "
- "name=\"password\" value=\"%s\"></td>"
- "</tr>",
- messages_get("Password"), password);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx, "</table>");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<div id=\"buttons\">"
- "<input type=\"submit\" id=\"login\" name=\"login\" "
- "value=\"%s\" class=\"default-action\">"
- "<input type=\"submit\" id=\"cancel\" name=\"cancel\" "
- "value=\"%s\">"
- "</div>",
- messages_get("Login"),
- messages_get("Cancel"));
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_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_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<input type=\"hidden\" name=\"realm\" value=\"%s\">",
- realm);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx, "</form></body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- nsurl_unref(siteurl);
-
- return true;
-
-fetch_about_query_auth_handler_aborted:
-
- nsurl_unref(siteurl);
-
- return false;
-}
-
-
-/**
- * Handler to generate about scheme privacy query page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_query_privacy_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 char *chainurl = 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;
- } else if (strcmp(curmd->name, "chainurl") == 0) {
- chainurl = 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_ssl_handler_aborted;
- }
-
- title = messages_get("PrivacyTitle");
- 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 class=\"ns-even-bg ns-even-fg ns-border\" id =\"privacy\">\n"
- "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<form method=\"post\""
- " enctype=\"multipart/form-data\">");
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- res = get_query_description(siteurl,
- "PrivacyDescription",
- &description);
- if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
- }
-
- if (chainurl == NULL) {
- res = ssenddataf(ctx,
- "<div><p>%s</p></div>"
- "<div><p>%s</p></div>",
- reason,
- messages_get("ViewCertificatesNotPossible"));
- } else {
- res = ssenddataf(ctx,
- "<div><p>%s</p></div>"
- "<div><p><a href=\"%s\" target=\"_blank\">%s</a></p></div>",
- reason,
- chainurl,
- messages_get("ViewCertificates"));
- }
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
- res = ssenddataf(ctx,
- "<div id=\"buttons\">"
- "<input type=\"submit\" id=\"back\" name=\"back\" "
- "value=\"%s\" class=\"default-action\">"
- "<input type=\"submit\" id=\"proceed\" name=\"proceed\" "
- "value=\"%s\">"
- "</div>",
- messages_get("Backtosafety"),
- messages_get("Proceed"));
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_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_ssl_handler_aborted;
- }
-
- res = ssenddataf(ctx, "</form></body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- nsurl_unref(siteurl);
-
- return true;
-
-fetch_about_query_ssl_handler_aborted:
- nsurl_unref(siteurl);
-
- return false;
-}
-
-
-/**
- * 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 class=\"ns-even-bg ns-even-fg ns-border\" id =\"timeout\">\n"
- "<h1 class=\"ns-border ns-odd-fg-bad\">%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",
- &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;
-}
-
-
-/**
- * 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,
- "<html>\n<head>\n"
- "<title>%s</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"fetcherror\">\n"
- "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<form method=\"post\""
- " enctype=\"multipart/form-data\">");
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
-
- res = get_query_description(siteurl,
- "FetchErrorDescription",
- &description);
- if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
- }
- res = ssenddataf(ctx, "<div><p>%s</p></div>", reason);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_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_fetcherror_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_fetcherror_handler_aborted;
- }
-
- res = ssenddataf(ctx, "</form></body>\n</html>\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);
-
-/**
- * List of about paths and their handlers
- */
-struct about_handlers about_handler_list[] = {
- {
- "credits",
- SLEN("credits"),
- NULL,
- fetch_about_credits_handler,
- false
- },
- {
- "licence",
- SLEN("licence"),
- NULL,
- fetch_about_licence_handler,
- false
- },
- {
- "license",
- SLEN("license"),
- NULL,
- fetch_about_licence_handler,
- true
- },
- {
- "welcome",
- SLEN("welcome"),
- NULL,
- fetch_about_welcome_handler,
- false
- },
- {
- "config",
- SLEN("config"),
- NULL,
- fetch_about_config_handler,
- false
- },
- {
- "Choices",
- SLEN("Choices"),
- NULL,
- fetch_about_choices_handler,
- false
- },
- {
- "testament",
- SLEN("testament"),
- NULL,
- fetch_about_testament_handler,
- false
- },
- {
- "about",
- SLEN("about"),
- NULL,
- fetch_about_about_handler,
- true
- },
- {
- "nscolours.css",
- SLEN("nscolours.css"),
- NULL,
- fetch_about_nscolours_handler,
- true
- },
- {
- "logo",
- SLEN("logo"),
- NULL,
- fetch_about_logo_handler,
- true
- },
- {
- /* details about the image cache */
- "imagecache",
- SLEN("imagecache"),
- NULL,
- fetch_about_imagecache_handler,
- true
- },
- {
- /* The default blank page */
- "blank",
- SLEN("blank"),
- NULL,
- fetch_about_blank_handler,
- true
- },
- {
- /* details about a certificate */
- "certificate",
- SLEN("certificate"),
- NULL,
- fetch_about_certificate_handler,
- true
- },
- {
- "query/auth",
- SLEN("query/auth"),
- NULL,
- fetch_about_query_auth_handler,
- true
- },
- {
- "query/ssl",
- SLEN("query/ssl"),
- NULL,
- fetch_about_query_privacy_handler,
- true
- },
- {
- "query/timeout",
- SLEN("query/timeout"),
- NULL,
- fetch_about_query_timeout_handler,
- true
- },
- {
- "query/fetcherror",
- SLEN("query/fetcherror"),
- NULL,
- fetch_about_query_fetcherror_handler,
- true
- }
-};
-
-#define about_handler_list_len \
- (sizeof(about_handler_list) / sizeof(struct about_handlers))
-
-/**
- * List all the valid about: paths available
- *
- * \param ctx The fetch context.
- * \return true for sucess or false to generate an error.
- */
-static bool fetch_about_about_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- unsigned int abt_loop = 0;
-
- /* 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"))
- goto fetch_about_config_handler_aborted;
-
- res = ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>List of NetSurf pages</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body class=\"ns-even-bg ns-even-fg ns-border\">\n"
- "<h1 class =\"ns-border\">List of NetSurf pages</h1>\n"
- "<ul>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_config_handler_aborted;
- }
-
- for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
-
- /* Skip over hidden entries */
- if (about_handler_list[abt_loop].hidden)
- continue;
-
- res = ssenddataf(ctx,
- "<li><a href=\"about:%s\">about:%s</a></li>\n",
- about_handler_list[abt_loop].name,
- about_handler_list[abt_loop].name);
- if (res != NSERROR_OK) {
- goto fetch_about_config_handler_aborted;
- }
- }
-
- res = ssenddataf(ctx, "</ul>\n</body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_config_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_config_handler_aborted:
- return false;
-}
-
-static bool
-fetch_about_404_handler(struct fetch_about_context *ctx)
-{
- nserror res;
-
- /* content is going to return 404 */
- fetch_set_http_code(ctx->fetchh, 404);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain; charset=utf-8")) {
- return false;
- }
-
- res = ssenddataf(ctx, "Unknown page: %s", nsurl_access(ctx->url));
- if (res != NSERROR_OK) {
- return false;
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-}
-
-/**
- * callback to initialise the about scheme fetcher.
- */
-static bool fetch_about_initialise(lwc_string *scheme)
-{
- unsigned int abt_loop = 0;
- lwc_error error;
-
- for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
- error = lwc_intern_string(about_handler_list[abt_loop].name,
- about_handler_list[abt_loop].name_len,
- &about_handler_list[abt_loop].lname);
- if (error != lwc_error_ok) {
- while (abt_loop-- != 0) {
- lwc_string_unref(about_handler_list[abt_loop].lname);
- }
- return false;
- }
- }
-
- return true;
-}
-
-
-/**
- * callback to finalise the about scheme fetcher.
- */
-static void fetch_about_finalise(lwc_string *scheme)
-{
- unsigned int abt_loop = 0;
- for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
- lwc_string_unref(about_handler_list[abt_loop].lname);
- }
-}
-
-
-static bool fetch_about_can_fetch(const nsurl *url)
-{
- return true;
-}
-
-
-/**
- * callback to set up a about scheme fetch.
- *
- * \param post_urlenc post data in urlenc format, owned by the llcache object
- * hence valid the entire lifetime of the fetch.
- * \param post_multipart post data in multipart format, owned by the llcache
- * object hence valid the entire lifetime of the fetch.
- */
-static void *
-fetch_about_setup(struct fetch *fetchh,
- nsurl *url,
- bool only_2xx,
- bool downgrade_tls,
- const char *post_urlenc,
- const struct fetch_multipart_data *post_multipart,
- const char **headers)
-{
- struct fetch_about_context *ctx;
- unsigned int handler_loop;
- lwc_string *path;
- bool match;
-
- ctx = calloc(1, sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- path = nsurl_get_component(url, NSURL_PATH);
-
- for (handler_loop = 0;
- handler_loop < about_handler_list_len;
- handler_loop++) {
- if (lwc_string_isequal(path,
- about_handler_list[handler_loop].lname,
- &match) == lwc_error_ok && match) {
- ctx->handler = about_handler_list[handler_loop].handler;
- break;
- }
- }
-
- if (path != NULL)
- lwc_string_unref(path);
-
- ctx->fetchh = fetchh;
- ctx->url = nsurl_ref(url);
- ctx->multipart = post_multipart;
-
- RING_INSERT(ring, ctx);
-
- return ctx;
-}
-
-
-/**
- * callback to free a about scheme fetch
- */
-static void fetch_about_free(void *ctx)
-{
- struct fetch_about_context *c = ctx;
- nsurl_unref(c->url);
- free(ctx);
-}
-
-
-/**
- * callback to start an about scheme fetch
- */
-static bool fetch_about_start(void *ctx)
-{
- return true;
-}
-
-
-/**
- * callback to abort a about fetch
- */
-static void fetch_about_abort(void *ctx)
-{
- struct fetch_about_context *c = ctx;
-
- /* To avoid the poll loop having to deal with the fetch context
- * disappearing from under it, we simply flag the abort here.
- * The poll loop itself will perform the appropriate cleanup.
- */
- c->aborted = true;
-}
-
-
-/**
- * callback to poll for additional about fetch contents
- */
-static void fetch_about_poll(lwc_string *scheme)
-{
- struct fetch_about_context *c, *save_ring = NULL;
-
- /* Iterate over ring, processing each pending fetch */
- while (ring != NULL) {
- /* Take the first entry from the ring */
- c = ring;
- RING_REMOVE(ring, c);
-
- /* Ignore fetches that have been flagged as locked.
- * This allows safe re-entrant calls to this function.
- * Re-entrancy can occur if, as a result of a callback,
- * the interested party causes fetch_poll() to be called
- * again.
- */
- if (c->locked == true) {
- RING_INSERT(save_ring, c);
- continue;
- }
-
- /* Only process non-aborted fetches */
- if (c->aborted == false) {
- /* about fetches can be processed in one go */
- if (c->handler == NULL) {
- fetch_about_404_handler(c);
- } else {
- c->handler(c);
- }
- }
-
- /* And now finish */
- fetch_remove_from_queues(c->fetchh);
- fetch_free(c->fetchh);
- }
-
- /* Finally, if we saved any fetches which were locked, put them back
- * into the ring for next time
- */
- ring = save_ring;
-}
-
-
-nserror fetch_about_register(void)
-{
- lwc_string *scheme = lwc_string_ref(corestring_lwc_about);
- const struct fetcher_operation_table fetcher_ops = {
- .initialise = fetch_about_initialise,
- .acceptable = fetch_about_can_fetch,
- .setup = fetch_about_setup,
- .start = fetch_about_start,
- .abort = fetch_about_abort,
- .free = fetch_about_free,
- .poll = fetch_about_poll,
- .finalise = fetch_about_finalise
- };
-
- return fetcher_add(scheme, &fetcher_ops);
-}
diff --git a/content/fetchers/about.h b/content/fetchers/about.h
deleted file mode 100644
index 944f84a..0000000
--- a/content/fetchers/about.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince(a)netsurf-browser.org>
- *
- * This file is part of NetSurf.
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * about: URL method handler
- */
-
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
-
-/**
- * Register about scheme handler.
- *
- * \return NSERROR_OK on successful registration or error code on failure.
- */
-nserror fetch_about_register(void);
-
-#endif
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
new file mode 100644
index 0000000..88786ec
--- /dev/null
+++ b/content/fetchers/about/Makefile
@@ -0,0 +1,6 @@
+# about fetcher sources
+
+S_FETCHER_ABOUT := about.c
+
+# The following files depend on the testament
+content/fetchers/about/about.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
new file mode 100644
index 0000000..e2fbd4d
--- /dev/null
+++ b/content/fetchers/about/about.c
@@ -0,0 +1,2977 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ *
+ * URL handling for the "about" scheme.
+ *
+ * Based on the data fetcher by Rob Kendrick
+ * This fetcher provides a simple scheme for the user to access
+ * information from the browser from a known, fixed URL.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "netsurf/inttypes.h"
+#include "netsurf/plot_style.h"
+
+#include "utils/log.h"
+#include "testament.h"
+#include "utils/corestrings.h"
+#include "utils/nscolour.h"
+#include "utils/nsoption.h"
+#include "utils/utils.h"
+#include "utils/messages.h"
+#include "utils/ring.h"
+
+#include "content/fetch.h"
+#include "content/fetchers.h"
+#include "image/image_cache.h"
+
+#include "desktop/system_colour.h"
+
+#include "about.h"
+
+struct fetch_about_context;
+
+typedef bool (*fetch_about_handler)(struct fetch_about_context *);
+
+/**
+ * Context for an about fetch
+ */
+struct fetch_about_context {
+ struct fetch_about_context *r_next, *r_prev;
+
+ struct fetch *fetchh; /**< Handle for this fetch */
+
+ bool aborted; /**< Flag indicating fetch has been aborted */
+ bool locked; /**< Flag indicating entry is already entered */
+
+ nsurl *url; /**< The full url the fetch refers to */
+
+ const struct fetch_multipart_data *multipart; /**< post data */
+
+ fetch_about_handler handler;
+};
+
+static struct fetch_about_context *ring = NULL;
+
+/**
+ * handler info for about scheme
+ */
+struct about_handlers {
+ const char *name; /**< name to match in url */
+ int name_len;
+ lwc_string *lname; /**< Interned name */
+ fetch_about_handler handler; /**< handler for the url */
+ bool hidden; /**< If entry should be hidden in listing */
+};
+
+
+/**
+ * issue fetch callbacks with locking
+ */
+static inline bool
+fetch_about_send_callback(const fetch_msg *msg, struct fetch_about_context *ctx)
+{
+ ctx->locked = true;
+ fetch_send_callback(msg, ctx->fetchh);
+ ctx->locked = false;
+
+ return ctx->aborted;
+}
+
+static inline bool
+fetch_about_send_finished(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+ msg.type = FETCH_FINISHED;
+ return fetch_about_send_callback(&msg, ctx);
+}
+
+static bool
+fetch_about_send_header(struct fetch_about_context *ctx, const char *fmt, ...)
+{
+ char header[64];
+ fetch_msg msg;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ vsnprintf(header, sizeof header, fmt, ap);
+
+ va_end(ap);
+
+ msg.type = FETCH_HEADER;
+ msg.data.header_or_data.buf = (const uint8_t *) header;
+ msg.data.header_or_data.len = strlen(header);
+
+ return fetch_about_send_callback(&msg, ctx);
+}
+
+/**
+ * send formatted data on a fetch
+ */
+static nserror ssenddataf(struct fetch_about_context *ctx, const char *fmt, ...)
+{
+ char buffer[1024];
+ char *dbuff;
+ fetch_msg msg;
+ va_list ap;
+ int slen;
+
+ va_start(ap, fmt);
+
+ slen = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+
+ va_end(ap);
+
+ if (slen < (int)sizeof(buffer)) {
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buffer;
+ msg.data.header_or_data.len = slen;
+
+ if (fetch_about_send_callback(&msg, ctx)) {
+ return NSERROR_INVALID;
+ }
+
+ return NSERROR_OK;
+ }
+
+ dbuff = malloc(slen + 1);
+ if (dbuff == NULL) {
+ return NSERROR_NOSPACE;
+ }
+
+ va_start(ap, fmt);
+
+ slen = vsnprintf(dbuff, slen + 1, fmt, ap);
+
+ va_end(ap);
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *)dbuff;
+ msg.data.header_or_data.len = slen;
+
+ if (fetch_about_send_callback(&msg, ctx)) {
+ free(dbuff);
+ return NSERROR_INVALID;
+ }
+
+ free(dbuff);
+ return NSERROR_OK;
+}
+
+
+/**
+ * Generate a 500 server error respnse
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_srverror(struct fetch_about_context *ctx)
+{
+ nserror res;
+
+ fetch_set_http_code(ctx->fetchh, 500);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
+ return false;
+
+ res = ssenddataf(ctx, "Server error 500");
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+}
+
+
+/**
+ * Handler to generate about scheme cache page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_blank_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+ const char buffer[2] = { ' ', '\0' };
+
+ /* 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"))
+ goto fetch_about_blank_handler_aborted;
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buffer;
+ msg.data.header_or_data.len = strlen(buffer);
+
+ if (fetch_about_send_callback(&msg, ctx))
+ goto fetch_about_blank_handler_aborted;
+
+ msg.type = FETCH_FINISHED;
+
+ fetch_about_send_callback(&msg, ctx);
+
+ return true;
+
+fetch_about_blank_handler_aborted:
+ return false;
+}
+
+
+/**
+ * Handler to generate about scheme credits page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_credits_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+
+ /* content is going to return redirect */
+ fetch_set_http_code(ctx->fetchh, 302);
+
+ msg.type = FETCH_REDIRECT;
+ msg.data.redirect = "resource:credits.html";
+
+ fetch_about_send_callback(&msg, ctx);
+
+ return true;
+}
+
+
+/**
+ * Handler to generate about scheme licence page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+
+ /* content is going to return redirect */
+ fetch_set_http_code(ctx->fetchh, 302);
+
+ msg.type = FETCH_REDIRECT;
+ msg.data.redirect = "resource:licence.html";
+
+ fetch_about_send_callback(&msg, ctx);
+
+ return true;
+}
+
+
+/**
+ * Handler to generate about:imagecache page.
+ *
+ * Shows details of current image cache.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+ char buffer[2048]; /* output buffer */
+ int code = 200;
+ int slen;
+ unsigned int cent_loop = 0;
+ int elen = 0; /* entry length */
+ nserror res;
+ bool even = false;
+
+ /* content is going to return ok */
+ fetch_set_http_code(ctx->fetchh, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_about_imagecache_handler_aborted;
+
+ /* page head */
+ res = ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>Image Cache Status</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body id =\"cachelist\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
+ "<h1 class=\"ns-border\">Image Cache Status</h1>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ /* image cache summary */
+ slen = image_cache_snsummaryf(buffer, sizeof(buffer),
+ "<p>Configured limit of %a hysteresis of %b</p>\n"
+ "<p>Total bitmap size in use %c (in %d)</p>\n"
+ "<p>Age %es</p>\n"
+ "<p>Peak size %f (in %g)</p>\n"
+ "<p>Peak image count %h (size %i)</p>\n"
+ "<p>Cache total/hit/miss/fail (counts) %j/%k/%l/%m "
+ "(%pj%%/%pk%%/%pl%%/%pm%%)</p>\n"
+ "<p>Cache total/hit/miss/fail (size) %n/%o/%q/%r "
+ "(%pn%%/%po%%/%pq%%/%pr%%)</p>\n"
+ "<p>Total images never rendered: %s "
+ "(includes %t that were converted)</p>\n"
+ "<p>Total number of excessive conversions: %u "
+ "(from %v images converted more than once)"
+ "</p>\n"
+ "<p>Bitmap of size %w had most (%x) conversions</p>\n"
+ "<h2 class=\"ns-border\">Current contents</h2>\n");
+ if (slen >= (int) (sizeof(buffer))) {
+ goto fetch_about_imagecache_handler_aborted; /* overflow */
+ }
+
+ /* send image cache summary */
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buffer;
+ msg.data.header_or_data.len = slen;
+ if (fetch_about_send_callback(&msg, ctx)) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ /* image cache entry table */
+ res = ssenddataf(ctx, "<p class=\"imagecachelist\">\n"
+ "<strong>"
+ "<span>Entry</span>"
+ "<span>Content Key</span>"
+ "<span>Redraw Count</span>"
+ "<span>Conversion Count</span>"
+ "<span>Last Redraw</span>"
+ "<span>Bitmap Age</span>"
+ "<span>Bitmap Size</span>"
+ "<span>Source</span>"
+ "</strong>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ slen = 0;
+ do {
+ if (even) {
+ elen = image_cache_snentryf(buffer + slen,
+ sizeof buffer - slen,
+ cent_loop,
+ "<a href=\"%U\">"
+ "<span class=\"ns-border\">%e</span>"
+ "<span class=\"ns-border\">%k</span>"
+ "<span class=\"ns-border\">%r</span>"
+ "<span class=\"ns-border\">%c</span>"
+ "<span class=\"ns-border\">%a</span>"
+ "<span class=\"ns-border\">%g</span>"
+ "<span class=\"ns-border\">%s</span>"
+ "<span class=\"ns-border\">%o</span>"
+ "</a>\n");
+ } else {
+ elen = image_cache_snentryf(buffer + slen,
+ sizeof buffer - slen,
+ cent_loop,
+ "<a class=\"ns-odd-bg\" href=\"%U\">"
+ "<span class=\"ns-border\">%e</span>"
+ "<span class=\"ns-border\">%k</span>"
+ "<span class=\"ns-border\">%r</span>"
+ "<span class=\"ns-border\">%c</span>"
+ "<span class=\"ns-border\">%a</span>"
+ "<span class=\"ns-border\">%g</span>"
+ "<span class=\"ns-border\">%s</span>"
+ "<span class=\"ns-border\">%o</span>"
+ "</a>\n");
+ }
+ if (elen <= 0)
+ break; /* last option */
+
+ if (elen >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ msg.data.header_or_data.len = slen;
+ if (fetch_about_send_callback(&msg, ctx))
+ goto fetch_about_imagecache_handler_aborted;
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += elen;
+ cent_loop++;
+ even = !even;
+ }
+ } while (elen > 0);
+
+ slen += snprintf(buffer + slen, sizeof buffer - slen,
+ "</p>\n</body>\n</html>\n");
+
+ msg.data.header_or_data.len = slen;
+ if (fetch_about_send_callback(&msg, ctx))
+ goto fetch_about_imagecache_handler_aborted;
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_imagecache_handler_aborted:
+ return false;
+}
+
+/**
+ * certificate name parameters
+ */
+struct ns_cert_name {
+ char *common_name;
+ char *organisation;
+ char *organisation_unit;
+ char *locality;
+ char *province;
+ char *country;
+};
+
+/**
+ * Certificate public key parameters
+ */
+struct ns_cert_pkey {
+ char *algor;
+ int size;
+ char *modulus;
+ char *exponent;
+ char *curve;
+ char *public;
+};
+
+/**
+ * Certificate subject alternative name
+ */
+struct ns_cert_san {
+ struct ns_cert_san *next;
+ char *name;
+};
+
+/**
+ * certificate information for certificate chain
+ */
+struct ns_cert_info {
+ struct ns_cert_name subject_name; /**< Subject details */
+ struct ns_cert_name issuer_name; /**< Issuer details */
+ struct ns_cert_pkey public_key; /**< public key details */
+ long version; /**< Certificate version */
+ char *not_before; /**< Valid from date */
+ char *not_after; /**< Valid to date */
+ int sig_type; /**< Signature type */
+ char *sig_algor; /**< Signature Algorithm */
+ char *serialnum; /**< Serial number */
+ char *sha1fingerprint; /**< fingerprint shar1 encoded */
+ char *sha256fingerprint; /**< fingerprint shar256 encoded */
+ struct ns_cert_san *san; /**< subject alternative names */
+ ssl_cert_err err; /**< Whatever is wrong with this certificate */
+};
+
+/**
+ * free all resources associated with a certificate information structure
+ */
+static nserror free_ns_cert_info(struct ns_cert_info *cinfo)
+{
+ struct ns_cert_san *san;
+
+ free(cinfo->subject_name.common_name);
+ free(cinfo->subject_name.organisation);
+ free(cinfo->subject_name.organisation_unit);
+ free(cinfo->subject_name.locality);
+ free(cinfo->subject_name.province);
+ free(cinfo->subject_name.country);
+ free(cinfo->issuer_name.common_name);
+ free(cinfo->issuer_name.organisation);
+ free(cinfo->issuer_name.organisation_unit);
+ free(cinfo->issuer_name.locality);
+ free(cinfo->issuer_name.province);
+ free(cinfo->issuer_name.country);
+ free(cinfo->public_key.algor);
+ free(cinfo->public_key.modulus);
+ free(cinfo->public_key.exponent);
+ free(cinfo->public_key.curve);
+ free(cinfo->public_key.public);
+ free(cinfo->not_before);
+ free(cinfo->not_after);
+ free(cinfo->sig_algor);
+ free(cinfo->serialnum);
+
+ /* free san list avoiding use after free */
+ san = cinfo->san;
+ while (san != NULL) {
+ struct ns_cert_san *next;
+ next = san->next;
+ free(san);
+ san = next;
+ }
+
+ free(cinfo);
+
+ return NSERROR_OK;
+}
+
+#ifdef WITH_OPENSSL
+
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+
+/* OpenSSL 1.0.x, 1.0.2, 1.1.0 and 1.1.1 API all changed
+ * LibreSSL declares its OpenSSL version as 2.1 but only supports 1.0.x API
+ */
+#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL))
+/* 1.0.x */
+
+#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1000200fL))
+/* pre 1.0.2 */
+static int ns_X509_get_signature_nid(X509 *cert)
+{
+ return OBJ_obj2nid(cert->cert_info->key->algor->algorithm);
+}
+#else
+#define ns_X509_get_signature_nid X509_get_signature_nid
+#endif
+
+static const unsigned char *ns_ASN1_STRING_get0_data(ASN1_STRING *asn1str)
+{
+ return (const unsigned char *)ASN1_STRING_data(asn1str);
+}
+
+static const BIGNUM *ns_RSA_get0_n(const RSA *d)
+{
+ return d->n;
+}
+
+static const BIGNUM *ns_RSA_get0_e(const RSA *d)
+{
+ return d->e;
+}
+
+static int ns_RSA_bits(const RSA *rsa)
+{
+ return RSA_size(rsa) * 8;
+}
+
+static int ns_DSA_bits(const DSA *dsa)
+{
+ return DSA_size(dsa) * 8;
+}
+
+static int ns_DH_bits(const DH *dh)
+{
+ return DH_size(dh) * 8;
+}
+
+#elif (OPENSSL_VERSION_NUMBER < 0x1010100fL)
+/* 1.1.0 */
+#define ns_X509_get_signature_nid X509_get_signature_nid
+#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
+
+static const BIGNUM *ns_RSA_get0_n(const RSA *r)
+{
+ const BIGNUM *n;
+ const BIGNUM *e;
+ const BIGNUM *d;
+ RSA_get0_key(r, &n, &e, &d);
+ return n;
+}
+
+static const BIGNUM *ns_RSA_get0_e(const RSA *r)
+{
+ const BIGNUM *n;
+ const BIGNUM *e;
+ const BIGNUM *d;
+ RSA_get0_key(r, &n, &e, &d);
+ return e;
+}
+
+#define ns_RSA_bits RSA_bits
+#define ns_DSA_bits DSA_bits
+#define ns_DH_bits DH_bits
+
+#else
+/* 1.1.1 and later */
+#define ns_X509_get_signature_nid X509_get_signature_nid
+#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
+#define ns_RSA_get0_n RSA_get0_n
+#define ns_RSA_get0_e RSA_get0_e
+#define ns_RSA_bits RSA_bits
+#define ns_DSA_bits DSA_bits
+#define ns_DH_bits DH_bits
+#endif
+
+/**
+ * extract certificate name information
+ *
+ * \param xname The X509 name to convert. The reference is borrowed so is not freeed
+ * \param iname The info structure to recive the extracted parameters.
+ * \return NSERROR_OK on success else error code
+ */
+static nserror
+xname_to_info(X509_NAME *xname, struct ns_cert_name *iname)
+{
+ int entryidx;
+ int entrycnt;
+ X509_NAME_ENTRY *entry; /* current name entry */
+ ASN1_STRING *value;
+ const unsigned char *value_str;
+ ASN1_OBJECT *name;
+ int name_nid;
+ char **field;
+
+ entrycnt = X509_NAME_entry_count(xname);
+
+ for (entryidx = 0; entryidx < entrycnt; entryidx++) {
+ entry = X509_NAME_get_entry(xname, entryidx);
+ name = X509_NAME_ENTRY_get_object(entry);
+ name_nid = OBJ_obj2nid(name);
+ value = X509_NAME_ENTRY_get_data(entry);
+ value_str = ns_ASN1_STRING_get0_data(value);
+ switch (name_nid) {
+ case NID_commonName:
+ field = &iname->common_name;
+ break;
+ case NID_countryName:
+ field = &iname->country;
+ break;
+ case NID_localityName:
+ field = &iname->locality;
+ break;
+ case NID_stateOrProvinceName:
+ field = &iname->province;
+ break;
+ case NID_organizationName:
+ field = &iname->organisation;
+ break;
+ case NID_organizationalUnitName:
+ field = &iname->organisation_unit;
+ break;
+ default :
+ field = NULL;
+ break;
+ }
+ if (field != NULL) {
+ *field = strdup((const char *)value_str);
+ NSLOG(netsurf, DEEPDEBUG,
+ "NID:%d value: %s", name_nid, *field);
+ } else {
+ NSLOG(netsurf, DEEPDEBUG, "NID:%d", name_nid);
+ }
+ }
+
+ /*
+ * ensure the common name is set to something, this being
+ * missing means the certificate is broken but this should be
+ * robust in the face of bad data
+ */
+ if (iname->common_name == NULL) {
+ iname->common_name = strdup("Unknown");
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * duplicate a hex formatted string inserting the colons
+ *
+ * \todo only uses html entity as separator because netsurfs line breaking
+ * fails otherwise.
+ */
+static char *hexdup(const char *hex)
+{
+ int hexlen;
+ char *dst;
+ char *out;
+ int cn = 0;
+
+ hexlen = strlen(hex);
+ /* allow space fox XXYY to XX:YY: */
+ dst = malloc(((hexlen * 7) + 6) / 2);
+
+ if (dst != NULL) {
+ for (out = dst; *hex != 0; hex++) {
+ if (cn == 2) {
+ cn = 0;
+ *out++ = '&';
+ *out++ = '#';
+ *out++ = '5';
+ *out++ = '8';
+ *out++ = ';';
+ }
+ *out++ = *hex;
+ cn++;
+ }
+ *out = 0;
+ }
+ return dst;
+}
+
+
+/**
+ * create a hex formatted string inserting the colons from binary data
+ *
+ * \todo only uses html entity as separator because netsurfs line breaking
+ * fails otherwise.
+ */
+static char *bindup(unsigned char *bin, unsigned int binlen)
+{
+ char *dst;
+ char *out;
+ unsigned int idx;
+ const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ /* allow space fox XY to expand to XX:YY: */
+ dst = malloc(binlen * 7);
+
+ if (dst != NULL) {
+ out = dst;
+ for (idx = 0; idx < binlen; idx++) {
+ *out++ = hex[(bin[idx] & 0xf0) >> 4];
+ *out++ = hex[bin[idx] & 0xf];
+
+ *out++ = '&';
+ *out++ = '#';
+ *out++ = '5';
+ *out++ = '8';
+ *out++ = ';';
+ }
+ out -= 5;
+ *out = 0;
+ }
+ return dst;
+}
+
+
+/**
+ * extract RSA key information to info structure
+ *
+ * \param rsa The RSA key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+rsa_to_info(RSA *rsa, struct ns_cert_pkey *ikey)
+{
+ char *tmp;
+
+ if (rsa == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("RSA");
+
+ ikey->size = ns_RSA_bits(rsa);
+
+ tmp = BN_bn2hex(ns_RSA_get0_n(rsa));
+ if (tmp != NULL) {
+ ikey->modulus = hexdup(tmp);
+ OPENSSL_free(tmp);
+ }
+
+ tmp = BN_bn2dec(ns_RSA_get0_e(rsa));
+ if (tmp != NULL) {
+ ikey->exponent = strdup(tmp);
+ OPENSSL_free(tmp);
+ }
+
+ RSA_free(rsa);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract DSA key information to info structure
+ *
+ * \param dsa The RSA key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+dsa_to_info(DSA *dsa, struct ns_cert_pkey *ikey)
+{
+ if (dsa == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("DSA");
+
+ ikey->size = ns_DSA_bits(dsa);
+
+ DSA_free(dsa);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract DH key information to info structure
+ *
+ * \param dsa The RSA key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+dh_to_info(DH *dh, struct ns_cert_pkey *ikey)
+{
+ if (dh == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("Diffie Hellman");
+
+ ikey->size = ns_DH_bits(dh);
+
+ DH_free(dh);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract EC key information to info structure
+ *
+ * \param ec The EC key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+ec_to_info(EC_KEY *ec, struct ns_cert_pkey *ikey)
+{
+ const EC_GROUP *ecgroup;
+ const EC_POINT *ecpoint;
+ BN_CTX *bnctx;
+ char *ecpoint_hex;
+
+ if (ec == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("Elliptic Curve");
+
+ ecgroup = EC_KEY_get0_group(ec);
+
+ if (ecgroup != NULL) {
+ ikey->size = EC_GROUP_get_degree(ecgroup);
+
+ ikey->curve = strdup(OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)));
+
+ ecpoint = EC_KEY_get0_public_key(ec);
+ if (ecpoint != NULL) {
+ bnctx = BN_CTX_new();
+ ecpoint_hex = EC_POINT_point2hex(ecgroup,
+ ecpoint,
+ POINT_CONVERSION_UNCOMPRESSED,
+ bnctx);
+ ikey->public = hexdup(ecpoint_hex);
+ OPENSSL_free(ecpoint_hex);
+ BN_CTX_free(bnctx);
+ }
+ }
+ EC_KEY_free(ec);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract public key information to info structure
+ *
+ * \param pkey the public key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+pkey_to_info(EVP_PKEY *pkey, struct ns_cert_pkey *ikey)
+{
+ nserror res;
+
+ if (pkey == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ switch (EVP_PKEY_base_id(pkey)) {
+ case EVP_PKEY_RSA:
+ res = rsa_to_info(EVP_PKEY_get1_RSA(pkey), ikey);
+ break;
+
+ case EVP_PKEY_DSA:
+ res = dsa_to_info(EVP_PKEY_get1_DSA(pkey), ikey);
+ break;
+
+ case EVP_PKEY_DH:
+ res = dh_to_info(EVP_PKEY_get1_DH(pkey), ikey);
+ break;
+
+ case EVP_PKEY_EC:
+ res = ec_to_info(EVP_PKEY_get1_EC_KEY(pkey), ikey);
+ break;
+
+ default:
+ res = NSERROR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ EVP_PKEY_free(pkey);
+
+ return res;
+}
+
+static nserror san_to_info(X509 *cert, struct ns_cert_san **prev_next)
+{
+ int idx;
+ int san_names_nb = -1;
+ const GENERAL_NAME *current_name;
+ const unsigned char *dns_name;
+ struct ns_cert_san *isan;
+
+ STACK_OF(GENERAL_NAME) *san_names = NULL;
+
+ san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+ if (san_names == NULL) {
+ return NSERROR_OK;
+ }
+
+ san_names_nb = sk_GENERAL_NAME_num(san_names);
+
+ /* Check each name within the extension */
+ for (idx = 0; idx < san_names_nb; idx++) {
+ current_name = sk_GENERAL_NAME_value(san_names, idx);
+
+ if (current_name->type == GEN_DNS) {
+ /* extract DNS name into info structure */
+ dns_name = ns_ASN1_STRING_get0_data(current_name->d.dNSName);
+
+ isan = malloc(sizeof(struct ns_cert_san));
+ if (isan != NULL) {
+ isan->name = strdup((const char *)dns_name);
+ isan->next = NULL;
+ *prev_next = isan;
+ prev_next = &isan->next;
+ }
+ }
+ }
+
+ /* AmiSSL can't cope with the "correct" mechanism of freeing
+ * the GENERAL_NAME stack, which is:
+ * sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+ * So instead we do this open-coded loop which does the same:
+ */
+ for (idx = 0; idx < san_names_nb; idx++) {
+ GENERAL_NAME *entry = sk_GENERAL_NAME_pop(san_names);
+ GENERAL_NAME_free(entry);
+ }
+ sk_GENERAL_NAME_free(san_names);
+
+ return NSERROR_OK;
+}
+
+static nserror
+der_to_certinfo(const uint8_t *der,
+ size_t der_length,
+ struct ns_cert_info *info)
+{
+ BIO *mem;
+ BUF_MEM *buf;
+ const ASN1_INTEGER *asn1_num;
+ BIGNUM *bignum;
+ X509 *cert; /**< Pointer to certificate */
+
+ if (der == NULL) {
+ return NSERROR_OK;
+ }
+
+ cert = d2i_X509(NULL, &der, der_length);
+ if (cert == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ /*
+ * get certificate version
+ *
+ * \note this is defined by standards (X.509 et al) to be one
+ * less than the certificate version.
+ */
+ info->version = X509_get_version(cert) + 1;
+
+ /* not before date */
+ mem = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(mem, X509_get_notBefore(cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ info->not_before = calloc(1, buf->length + 1);
+ if (info->not_before != NULL) {
+ memcpy(info->not_before, buf->data, (unsigned)buf->length);
+ }
+ BUF_MEM_free(buf);
+
+ /* not after date */
+ mem = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(mem,
+ X509_get_notAfter(cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ info->not_after = calloc(1, buf->length + 1);
+ if (info->not_after != NULL) {
+ memcpy(info->not_after, buf->data, (unsigned)buf->length);
+ }
+ BUF_MEM_free(buf);
+
+ /* signature type */
+ info->sig_type = X509_get_signature_type(cert);
+
+ /* signature algorithm */
+ int pkey_nid = ns_X509_get_signature_nid(cert);
+ if (pkey_nid != NID_undef) {
+ const char* sslbuf = OBJ_nid2ln(pkey_nid);
+ if (sslbuf != NULL) {
+ info->sig_algor = strdup(sslbuf);
+ }
+ }
+
+ /* serial number */
+ asn1_num = X509_get_serialNumber(cert);
+ if (asn1_num != NULL) {
+ bignum = ASN1_INTEGER_to_BN(asn1_num, NULL);
+ if (bignum != NULL) {
+ char *tmp = BN_bn2hex(bignum);
+ if (tmp != NULL) {
+ info->serialnum = hexdup(tmp);
+ OPENSSL_free(tmp);
+ }
+ BN_free(bignum);
+ bignum = NULL;
+ }
+ }
+
+ /* fingerprints */
+ const EVP_MD *digest;
+ unsigned int dig_len;
+ unsigned char *buff;
+ int rc;
+
+ digest = EVP_sha1();
+ buff = malloc(EVP_MD_size(digest));
+ if (buff != NULL) {
+ rc = X509_digest(cert, digest, buff, &dig_len);
+ if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
+ info->sha1fingerprint = bindup(buff, dig_len);
+ }
+ free(buff);
+ }
+
+ digest = EVP_sha256();
+ buff = malloc(EVP_MD_size(digest));
+ if (buff != NULL) {
+ rc = X509_digest(cert, digest, buff, &dig_len);
+ if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
+ info->sha256fingerprint = bindup(buff, dig_len);
+ }
+ free(buff);
+ }
+
+ /* subject alternative names */
+ san_to_info(cert, &info->san);
+
+ /* issuer name */
+ xname_to_info(X509_get_issuer_name(cert), &info->issuer_name);
+
+ /* subject */
+ xname_to_info(X509_get_subject_name(cert), &info->subject_name);
+
+ /* public key */
+ pkey_to_info(X509_get_pubkey(cert), &info->public_key);
+
+ X509_free(cert);
+
+ return NSERROR_OK;
+}
+
+/* copy certificate data */
+static nserror
+convert_chain_to_cert_info(const struct cert_chain *chain,
+ struct ns_cert_info **cert_info_out)
+{
+ struct ns_cert_info *certs;
+ size_t depth;
+ nserror res;
+
+ certs = calloc(chain->depth, sizeof(struct ns_cert_info));
+ if (certs == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ for (depth = 0; depth < chain->depth;depth++) {
+ res = der_to_certinfo(chain->certs[depth].der,
+ chain->certs[depth].der_length,
+ certs + depth);
+ if (res != NSERROR_OK) {
+ free(certs);
+ return res;
+ }
+ certs[depth].err = chain->certs[depth].err;
+ }
+
+ *cert_info_out = certs;
+ return NSERROR_OK;
+}
+
+#else
+static nserror
+convert_chain_to_cert_info(const struct cert_chain *chain,
+ struct ns_cert_info **cert_info_out)
+{
+ return NSERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+
+static nserror
+format_certificate_name(struct fetch_about_context *ctx,
+ struct ns_cert_name *cert_name)
+{
+ nserror res;
+ res = ssenddataf(ctx,
+ "<tr><th>Common Name</th><td>%s</td></tr>\n",
+ cert_name->common_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_name->organisation != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Organisation</th><td>%s</td></tr>\n",
+ cert_name->organisation);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->organisation_unit != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Organisation Unit</th><td>%s</td></tr>\n",
+ cert_name->organisation_unit);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->locality != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Locality</th><td>%s</td></tr>\n",
+ cert_name->locality);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->province != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Privince</th><td>%s</td></tr>\n",
+ cert_name->province);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->country != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Country</th><td>%s</td></tr>\n",
+ cert_name->country);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ return res;
+}
+
+/**
+ * output formatted certificate subject alternate names
+ */
+static nserror
+format_certificate_san(struct fetch_about_context *ctx,
+ struct ns_cert_san *san)
+{
+ nserror res;
+
+ if (san == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Alternative Names</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ while (san != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>DNS Name</th><td>%s</td></tr>\n",
+ san->name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ san = san->next;
+ }
+
+ res = ssenddataf(ctx, "</table>\n");
+
+ return res;
+
+}
+
+
+static nserror
+format_certificate_public_key(struct fetch_about_context *ctx,
+ struct ns_cert_pkey *public_key)
+{
+ nserror res;
+
+ if (public_key->algor == NULL) {
+ /* skip the table if no algorithm name */
+ return NSERROR_OK;
+ }
+
+ res = ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Public Key</th><td><hr></td></tr>\n"
+ "<tr><th>Algorithm</th><td>%s</td></tr>\n"
+ "<tr><th>Key Size</th><td>%d</td></tr>\n",
+ public_key->algor,
+ public_key->size);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+
+ if (public_key->exponent != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Exponent</th><td>%s</td></tr>\n",
+ public_key->exponent);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (public_key->modulus != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Modulus</th><td class=\"data\">%s</td></tr>\n",
+ public_key->modulus);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (public_key->curve != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Curve</th><td>%s</td></tr>\n",
+ public_key->curve);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (public_key->public != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Public Value</th><td>%s</td></tr>\n",
+ public_key->public);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = ssenddataf(ctx, "</table>\n");
+
+ return res;
+}
+
+static nserror
+format_certificate_fingerprint(struct fetch_about_context *ctx,
+ struct ns_cert_info *cert_info)
+{
+ nserror res;
+
+ if ((cert_info->sha1fingerprint == NULL) &&
+ (cert_info->sha256fingerprint == NULL)) {
+ /* skip the table if no fingerprints */
+ return NSERROR_OK;
+ }
+
+
+ res = ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Fingerprints</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_info->sha256fingerprint != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>SHA-256</th><td class=\"data\">%s</td></tr>\n",
+ cert_info->sha256fingerprint);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_info->sha1fingerprint != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>SHA-1</th><td class=\"data\">%s</td></tr>\n",
+ cert_info->sha1fingerprint);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = ssenddataf(ctx, "</table>\n");
+
+ return res;
+}
+
+static nserror
+format_certificate(struct fetch_about_context *ctx,
+ struct ns_cert_info *cert_info,
+ size_t depth)
+{
+ nserror res;
+
+ res = ssenddataf(ctx,
+ "<h2 id=\"%"PRIsizet"\" class=\"ns-border\">%s</h2>\n",
+ depth, cert_info->subject_name.common_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_info->err != SSL_CERT_ERR_OK) {
+ res = ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr class=\"ns-even-fg-bad\">"
+ "<th>Fault</th>"
+ "<td>%s</td>"
+ "</tr>"
+ "</table>\n",
+ messages_get_sslcode(cert_info->err));
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Issued To</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_name(ctx, &cert_info->subject_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = ssenddataf(ctx,
+ "</table>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Issued By</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_name(ctx, &cert_info->issuer_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = ssenddataf(ctx,
+ "</table>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Validity</th><td><hr></td></tr>\n"
+ "<tr><th>Valid From</th><td>%s</td></tr>\n"
+ "<tr><th>Valid Until</th><td>%s</td></tr>\n"
+ "</table>\n",
+ cert_info->not_before,
+ cert_info->not_after);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_san(ctx, cert_info->san);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_public_key(ctx, &cert_info->public_key);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Miscellaneous</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_info->serialnum != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Serial Number</th><td>%s</td></tr>\n",
+ cert_info->serialnum);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_info->sig_algor != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>Signature Algorithm</th>"
+ "<td>%s</td></tr>\n",
+ cert_info->sig_algor);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = ssenddataf(ctx,
+ "<tr><th>Version</th><td>%ld</td></tr>\n"
+ "</table>\n",
+ cert_info->version);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_fingerprint(ctx, cert_info);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ return res;
+}
+
+/**
+ * Handler to generate about:certificate page.
+ *
+ * Shows details of a certificate chain
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
+{
+ int code = 200;
+ nserror res;
+ struct cert_chain *chain = NULL;
+
+ /* content is going to return ok */
+ fetch_set_http_code(ctx->fetchh, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_about_certificate_handler_aborted;
+
+ /* page head */
+ res = ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>NetSurf Browser Certificate Viewer</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body id=\"certificate\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
+ "<h1 class=\"ns-border\">Certificate</h1>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ res = cert_chain_from_query(ctx->url, &chain);
+ if (res != NSERROR_OK) {
+ res = ssenddataf(ctx, "<p>Could not process that</p>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+ } else {
+ struct ns_cert_info *cert_info;
+ res = convert_chain_to_cert_info(chain, &cert_info);
+ if (res == NSERROR_OK) {
+ size_t depth;
+ res = ssenddataf(ctx, "<ul>\n");
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ for (depth = 0; depth < chain->depth; depth++) {
+ res = ssenddataf(ctx, "<li><a href=\"#%"PRIsizet"\">%s</a></li>\n",
+ depth, (cert_info + depth)
+ ->subject_name
+ .common_name);
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ }
+
+ res = ssenddataf(ctx, "</ul>\n");
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ for (depth = 0; depth < chain->depth; depth++) {
+ res = format_certificate(ctx, cert_info + depth,
+ depth);
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ }
+ free_ns_cert_info(cert_info);
+
+ } else {
+ res = ssenddataf(ctx,
+ "<p>Invalid certificate data</p>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+ }
+ }
+
+
+ /* page footer */
+ res = ssenddataf(ctx, "</body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ cert_chain_free(chain);
+
+ return true;
+
+fetch_about_certificate_handler_aborted:
+ cert_chain_free(chain);
+ return false;
+}
+
+
+/**
+ * Handler to generate about scheme config page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_config_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+ char buffer[1024];
+ int slen = 0;
+ unsigned int opt_loop = 0;
+ int elen = 0; /* entry length */
+ nserror res;
+ bool even = false;
+
+ /* 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")) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>NetSurf Browser Config</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body "
+ "id =\"configlist\" "
+ "class=\"ns-even-bg ns-even-fg ns-border\" "
+ "style=\"overflow: hidden;\">\n"
+ "<h1 class=\"ns-border\">NetSurf Browser Config</h1>\n"
+ "<table class=\"config\">\n"
+ "<tr><th>Option</th>"
+ "<th>Type</th>"
+ "<th>Provenance</th>"
+ "<th>Setting</th></tr>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buffer;
+
+ do {
+ if (even) {
+ elen = nsoption_snoptionf(buffer + slen,
+ sizeof buffer - slen,
+ opt_loop,
+ "<tr class=\"ns-even-bg\">"
+ "<th class=\"ns-border\">%k</th>"
+ "<td class=\"ns-border\">%t</td>"
+ "<td class=\"ns-border\">%p</td>"
+ "<td class=\"ns-border\">%V</td>"
+ "</tr>\n");
+ } else {
+ elen = nsoption_snoptionf(buffer + slen,
+ sizeof buffer - slen,
+ opt_loop,
+ "<tr class=\"ns-odd-bg\">"
+ "<th class=\"ns-border\">%k</th>"
+ "<td class=\"ns-border\">%t</td>"
+ "<td class=\"ns-border\">%p</td>"
+ "<td class=\"ns-border\">%V</td>"
+ "</tr>\n");
+ }
+ if (elen <= 0)
+ break; /* last option */
+
+ if (elen >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ msg.data.header_or_data.len = slen;
+ if (fetch_about_send_callback(&msg, ctx))
+ goto fetch_about_config_handler_aborted;
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += elen;
+ opt_loop++;
+ even = !even;
+ }
+ } while (elen > 0);
+
+ slen += snprintf(buffer + slen, sizeof buffer - slen,
+ "</table>\n</body>\n</html>\n");
+
+ msg.data.header_or_data.len = slen;
+ if (fetch_about_send_callback(&msg, ctx))
+ goto fetch_about_config_handler_aborted;
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_config_handler_aborted:
+ return false;
+}
+
+
+/**
+ * Handler to generate the nscolours stylesheet
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_nscolours_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ const char *stylesheet;
+
+ /* content is going to return ok */
+ fetch_set_http_code(ctx->fetchh, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/css; charset=utf-8")) {
+ goto aborted;
+ }
+
+ res = nscolour_get_stylesheet(&stylesheet);
+ if (res != NSERROR_OK) {
+ goto aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "html {\n"
+ "\tbackground-color: #%06x;\n"
+ "}\n"
+ "%s",
+ colour_rb_swap(nscolours[NSCOLOUR_WIN_ODD_BG]),
+ stylesheet);
+ if (res != NSERROR_OK) {
+ goto aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+aborted:
+
+ return false;
+}
+
+
+/**
+ * Generate the text of a Choices file which represents the current
+ * in use options.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_choices_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+ char buffer[1024];
+ int code = 200;
+ int slen;
+ unsigned int opt_loop = 0;
+ int res = 0;
+
+ /* content is going to return ok */
+ fetch_set_http_code(ctx->fetchh, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
+ goto fetch_about_choices_handler_aborted;
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buffer;
+
+ slen = snprintf(buffer, sizeof buffer,
+ "# Automatically generated current NetSurf browser Choices\n");
+
+ do {
+ res = nsoption_snoptionf(buffer + slen,
+ sizeof buffer - slen,
+ opt_loop,
+ "%k:%v\n");
+ if (res <= 0)
+ break; /* last option */
+
+ if (res >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ msg.data.header_or_data.len = slen;
+ if (fetch_about_send_callback(&msg, ctx))
+ goto fetch_about_choices_handler_aborted;
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += res;
+ opt_loop++;
+ }
+ } while (res > 0);
+
+ msg.data.header_or_data.len = slen;
+ if (fetch_about_send_callback(&msg, ctx))
+ goto fetch_about_choices_handler_aborted;
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_choices_handler_aborted:
+ return false;
+}
+
+
+typedef struct {
+ const char *leaf;
+ const char *modtype;
+} modification_t;
+
+/**
+ * Generate the text of an svn testament which represents the current
+ * build-tree status
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_testament_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ static modification_t modifications[] = WT_MODIFICATIONS;
+ int modidx; /* midification index */
+
+ /* content is going to return ok */
+ fetch_set_http_code(ctx->fetchh, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
+ goto fetch_about_testament_handler_aborted;
+
+ res = ssenddataf(ctx,
+ "# Automatically generated by NetSurf build system\n\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+#if defined(WT_BRANCHISTRUNK) || defined(WT_BRANCHISMASTER)
+ "# This is a *DEVELOPMENT* build from the main line.\n\n"
+#elif defined(WT_BRANCHISTAG) && (WT_MODIFIED == 0)
+ "# This is a tagged build of NetSurf\n"
+#ifdef WT_TAGIS
+ "# The tag used was '" WT_TAGIS "'\n\n"
+#else
+ "\n"
+#endif
+#elif defined(WT_NO_SVN) || defined(WT_NO_GIT)
+ "# This NetSurf was built outside of our revision "
+ "control environment.\n"
+ "# This testament is therefore not very useful.\n\n"
+#else
+ "# This NetSurf was built from a branch (" WT_BRANCHPATH ").\n\n"
+#endif
+#if defined(CI_BUILD)
+ "# This build carries the CI build number '" CI_BUILD "'\n\n"
+#endif
+ );
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "Built by %s (%s) from %s at revision %s on %s\n\n",
+ GECOS, USERNAME, WT_BRANCHPATH, WT_REVID, WT_COMPILEDATE);
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ res = ssenddataf(ctx, "Built on %s in %s\n\n", WT_HOSTNAME, WT_ROOT);
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ if (WT_MODIFIED > 0) {
+ res = ssenddataf(ctx,
+ "Working tree has %d modification%s\n\n",
+ WT_MODIFIED, WT_MODIFIED == 1 ? "" : "s");
+ } else {
+ res = ssenddataf(ctx, "Working tree is not modified.\n");
+ }
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ for (modidx = 0; modidx < WT_MODIFIED; ++modidx) {
+ res = ssenddataf(ctx,
+ " %s %s\n",
+ modifications[modidx].modtype,
+ modifications[modidx].leaf);
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_testament_handler_aborted:
+ return false;
+}
+
+
+/**
+ * Handler to generate about scheme logo page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_logo_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+
+ /* content is going to return redirect */
+ fetch_set_http_code(ctx->fetchh, 302);
+
+ msg.type = FETCH_REDIRECT;
+ msg.data.redirect = "resource:netsurf.png";
+
+ fetch_about_send_callback(&msg, ctx);
+
+ return true;
+}
+
+
+/**
+ * Handler to generate about scheme welcome page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_welcome_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+
+ /* content is going to return redirect */
+ fetch_set_http_code(ctx->fetchh, 302);
+
+ msg.type = FETCH_REDIRECT;
+ msg.data.redirect = "resource:welcome.html";
+
+ fetch_about_send_callback(&msg, ctx);
+
+ return true;
+}
+
+
+/**
+ * generate the description of the login query
+ */
+static nserror
+get_authentication_description(struct nsurl *url,
+ const char *realm,
+ const char *username,
+ const char *password,
+ char **out_str)
+{
+ nserror res;
+ char *url_s;
+ size_t url_l;
+ char *str = NULL;
+ const char *key;
+
+ res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if ((*username == 0) && (*password == 0)) {
+ key = "LoginDescription";
+ } else {
+ key = "LoginAgain";
+ }
+
+ str = messages_get_buff(key, url_s, realm);
+ if (str != NULL) {
+ NSLOG(netsurf, INFO,
+ "key:%s url:%s realm:%s str:%s",
+ key, url_s, realm, str);
+ *out_str = str;
+ } else {
+ res = NSERROR_NOMEM;
+ }
+
+ free(url_s);
+
+ return res;
+}
+
+
+/**
+ * generate a generic query description
+ */
+static nserror
+get_query_description(struct nsurl *url,
+ const char *key,
+ char **out_str)
+{
+ nserror res;
+ char *url_s;
+ size_t url_l;
+ char *str = NULL;
+
+ /* get the host in question */
+ res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* obtain the description with the url substituted */
+ str = messages_get_buff(key, url_s);
+ if (str == NULL) {
+ res = NSERROR_NOMEM;
+ } else {
+ *out_str = str;
+ }
+
+ free(url_s);
+
+ return res;
+}
+
+
+/**
+ * Handler to generate about scheme authentication query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ char *url_s;
+ size_t url_l;
+ const char *realm = "";
+ const char *username = "";
+ const char *password = "";
+ const char *title;
+ char *description = NULL;
+ struct nsurl *siteurl = 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, "realm") == 0) {
+ realm = curmd->value;
+ } else if (strcmp(curmd->name, "username") == 0) {
+ username = curmd->value;
+ } else if (strcmp(curmd->name, "password") == 0) {
+ password = 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_auth_handler_aborted;
+ }
+
+ title = messages_get("LoginTitle");
+ 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 class=\"ns-even-bg ns-even-fg ns-border\" id =\"authentication\">\n"
+ "<h1 class=\"ns-border\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = get_authentication_description(siteurl,
+ realm,
+ username,
+ password,
+ &description);
+ if (res == NSERROR_OK) {
+ res = ssenddataf(ctx, "<p>%s</p>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+ }
+
+ res = ssenddataf(ctx, "<table>");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<tr>"
+ "<th><label for=\"name\">%s:</label></th>"
+ "<td><input type=\"text\" id=\"username\" "
+ "name=\"username\" value=\"%s\"></td>"
+ "</tr>",
+ messages_get("Username"), username);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<tr>"
+ "<th><label for=\"password\">%s:</label></th>"
+ "<td><input type=\"password\" id=\"password\" "
+ "name=\"password\" value=\"%s\"></td>"
+ "</tr>",
+ messages_get("Password"), password);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = ssenddataf(ctx, "</table>");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<div id=\"buttons\">"
+ "<input type=\"submit\" id=\"login\" name=\"login\" "
+ "value=\"%s\" class=\"default-action\">"
+ "<input type=\"submit\" id=\"cancel\" name=\"cancel\" "
+ "value=\"%s\">"
+ "</div>",
+ messages_get("Login"),
+ messages_get("Cancel"));
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_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_auth_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"realm\" value=\"%s\">",
+ realm);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = ssenddataf(ctx, "</form></body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ nsurl_unref(siteurl);
+
+ return true;
+
+fetch_about_query_auth_handler_aborted:
+
+ nsurl_unref(siteurl);
+
+ return false;
+}
+
+
+/**
+ * Handler to generate about scheme privacy query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_query_privacy_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 char *chainurl = 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;
+ } else if (strcmp(curmd->name, "chainurl") == 0) {
+ chainurl = 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_ssl_handler_aborted;
+ }
+
+ title = messages_get("PrivacyTitle");
+ 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 class=\"ns-even-bg ns-even-fg ns-border\" id =\"privacy\">\n"
+ "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = get_query_description(siteurl,
+ "PrivacyDescription",
+ &description);
+ if (res == NSERROR_OK) {
+ res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+ }
+
+ if (chainurl == NULL) {
+ res = ssenddataf(ctx,
+ "<div><p>%s</p></div>"
+ "<div><p>%s</p></div>",
+ reason,
+ messages_get("ViewCertificatesNotPossible"));
+ } else {
+ res = ssenddataf(ctx,
+ "<div><p>%s</p></div>"
+ "<div><p><a href=\"%s\" target=\"_blank\">%s</a></p></div>",
+ reason,
+ chainurl,
+ messages_get("ViewCertificates"));
+ }
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+ res = ssenddataf(ctx,
+ "<div id=\"buttons\">"
+ "<input type=\"submit\" id=\"back\" name=\"back\" "
+ "value=\"%s\" class=\"default-action\">"
+ "<input type=\"submit\" id=\"proceed\" name=\"proceed\" "
+ "value=\"%s\">"
+ "</div>",
+ messages_get("Backtosafety"),
+ messages_get("Proceed"));
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_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_ssl_handler_aborted;
+ }
+
+ res = ssenddataf(ctx, "</form></body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ nsurl_unref(siteurl);
+
+ return true;
+
+fetch_about_query_ssl_handler_aborted:
+ nsurl_unref(siteurl);
+
+ return false;
+}
+
+
+/**
+ * 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 class=\"ns-even-bg ns-even-fg ns-border\" id =\"timeout\">\n"
+ "<h1 class=\"ns-border ns-odd-fg-bad\">%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",
+ &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;
+}
+
+
+/**
+ * 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,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"fetcherror\">\n"
+ "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = get_query_description(siteurl,
+ "FetchErrorDescription",
+ &description);
+ if (res == NSERROR_OK) {
+ res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+ }
+ res = ssenddataf(ctx, "<div><p>%s</p></div>", reason);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_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_fetcherror_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_fetcherror_handler_aborted;
+ }
+
+ res = ssenddataf(ctx, "</form></body>\n</html>\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);
+
+/**
+ * List of about paths and their handlers
+ */
+struct about_handlers about_handler_list[] = {
+ {
+ "credits",
+ SLEN("credits"),
+ NULL,
+ fetch_about_credits_handler,
+ false
+ },
+ {
+ "licence",
+ SLEN("licence"),
+ NULL,
+ fetch_about_licence_handler,
+ false
+ },
+ {
+ "license",
+ SLEN("license"),
+ NULL,
+ fetch_about_licence_handler,
+ true
+ },
+ {
+ "welcome",
+ SLEN("welcome"),
+ NULL,
+ fetch_about_welcome_handler,
+ false
+ },
+ {
+ "config",
+ SLEN("config"),
+ NULL,
+ fetch_about_config_handler,
+ false
+ },
+ {
+ "Choices",
+ SLEN("Choices"),
+ NULL,
+ fetch_about_choices_handler,
+ false
+ },
+ {
+ "testament",
+ SLEN("testament"),
+ NULL,
+ fetch_about_testament_handler,
+ false
+ },
+ {
+ "about",
+ SLEN("about"),
+ NULL,
+ fetch_about_about_handler,
+ true
+ },
+ {
+ "nscolours.css",
+ SLEN("nscolours.css"),
+ NULL,
+ fetch_about_nscolours_handler,
+ true
+ },
+ {
+ "logo",
+ SLEN("logo"),
+ NULL,
+ fetch_about_logo_handler,
+ true
+ },
+ {
+ /* details about the image cache */
+ "imagecache",
+ SLEN("imagecache"),
+ NULL,
+ fetch_about_imagecache_handler,
+ true
+ },
+ {
+ /* The default blank page */
+ "blank",
+ SLEN("blank"),
+ NULL,
+ fetch_about_blank_handler,
+ true
+ },
+ {
+ /* details about a certificate */
+ "certificate",
+ SLEN("certificate"),
+ NULL,
+ fetch_about_certificate_handler,
+ true
+ },
+ {
+ "query/auth",
+ SLEN("query/auth"),
+ NULL,
+ fetch_about_query_auth_handler,
+ true
+ },
+ {
+ "query/ssl",
+ SLEN("query/ssl"),
+ NULL,
+ fetch_about_query_privacy_handler,
+ true
+ },
+ {
+ "query/timeout",
+ SLEN("query/timeout"),
+ NULL,
+ fetch_about_query_timeout_handler,
+ true
+ },
+ {
+ "query/fetcherror",
+ SLEN("query/fetcherror"),
+ NULL,
+ fetch_about_query_fetcherror_handler,
+ true
+ }
+};
+
+#define about_handler_list_len \
+ (sizeof(about_handler_list) / sizeof(struct about_handlers))
+
+/**
+ * List all the valid about: paths available
+ *
+ * \param ctx The fetch context.
+ * \return true for sucess or false to generate an error.
+ */
+static bool fetch_about_about_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ unsigned int abt_loop = 0;
+
+ /* 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"))
+ goto fetch_about_config_handler_aborted;
+
+ res = ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>List of NetSurf pages</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\">\n"
+ "<h1 class =\"ns-border\">List of NetSurf pages</h1>\n"
+ "<ul>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
+
+ /* Skip over hidden entries */
+ if (about_handler_list[abt_loop].hidden)
+ continue;
+
+ res = ssenddataf(ctx,
+ "<li><a href=\"about:%s\">about:%s</a></li>\n",
+ about_handler_list[abt_loop].name,
+ about_handler_list[abt_loop].name);
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+ }
+
+ res = ssenddataf(ctx, "</ul>\n</body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_config_handler_aborted:
+ return false;
+}
+
+static bool
+fetch_about_404_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+
+ /* content is going to return 404 */
+ fetch_set_http_code(ctx->fetchh, 404);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain; charset=utf-8")) {
+ return false;
+ }
+
+ res = ssenddataf(ctx, "Unknown page: %s", nsurl_access(ctx->url));
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+}
+
+/**
+ * callback to initialise the about scheme fetcher.
+ */
+static bool fetch_about_initialise(lwc_string *scheme)
+{
+ unsigned int abt_loop = 0;
+ lwc_error error;
+
+ for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
+ error = lwc_intern_string(about_handler_list[abt_loop].name,
+ about_handler_list[abt_loop].name_len,
+ &about_handler_list[abt_loop].lname);
+ if (error != lwc_error_ok) {
+ while (abt_loop-- != 0) {
+ lwc_string_unref(about_handler_list[abt_loop].lname);
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * callback to finalise the about scheme fetcher.
+ */
+static void fetch_about_finalise(lwc_string *scheme)
+{
+ unsigned int abt_loop = 0;
+ for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
+ lwc_string_unref(about_handler_list[abt_loop].lname);
+ }
+}
+
+
+static bool fetch_about_can_fetch(const nsurl *url)
+{
+ return true;
+}
+
+
+/**
+ * callback to set up a about scheme fetch.
+ *
+ * \param post_urlenc post data in urlenc format, owned by the llcache object
+ * hence valid the entire lifetime of the fetch.
+ * \param post_multipart post data in multipart format, owned by the llcache
+ * object hence valid the entire lifetime of the fetch.
+ */
+static void *
+fetch_about_setup(struct fetch *fetchh,
+ nsurl *url,
+ bool only_2xx,
+ bool downgrade_tls,
+ const char *post_urlenc,
+ const struct fetch_multipart_data *post_multipart,
+ const char **headers)
+{
+ struct fetch_about_context *ctx;
+ unsigned int handler_loop;
+ lwc_string *path;
+ bool match;
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ path = nsurl_get_component(url, NSURL_PATH);
+
+ for (handler_loop = 0;
+ handler_loop < about_handler_list_len;
+ handler_loop++) {
+ if (lwc_string_isequal(path,
+ about_handler_list[handler_loop].lname,
+ &match) == lwc_error_ok && match) {
+ ctx->handler = about_handler_list[handler_loop].handler;
+ break;
+ }
+ }
+
+ if (path != NULL)
+ lwc_string_unref(path);
+
+ ctx->fetchh = fetchh;
+ ctx->url = nsurl_ref(url);
+ ctx->multipart = post_multipart;
+
+ RING_INSERT(ring, ctx);
+
+ return ctx;
+}
+
+
+/**
+ * callback to free a about scheme fetch
+ */
+static void fetch_about_free(void *ctx)
+{
+ struct fetch_about_context *c = ctx;
+ nsurl_unref(c->url);
+ free(ctx);
+}
+
+
+/**
+ * callback to start an about scheme fetch
+ */
+static bool fetch_about_start(void *ctx)
+{
+ return true;
+}
+
+
+/**
+ * callback to abort a about fetch
+ */
+static void fetch_about_abort(void *ctx)
+{
+ struct fetch_about_context *c = ctx;
+
+ /* To avoid the poll loop having to deal with the fetch context
+ * disappearing from under it, we simply flag the abort here.
+ * The poll loop itself will perform the appropriate cleanup.
+ */
+ c->aborted = true;
+}
+
+
+/**
+ * callback to poll for additional about fetch contents
+ */
+static void fetch_about_poll(lwc_string *scheme)
+{
+ struct fetch_about_context *c, *save_ring = NULL;
+
+ /* Iterate over ring, processing each pending fetch */
+ while (ring != NULL) {
+ /* Take the first entry from the ring */
+ c = ring;
+ RING_REMOVE(ring, c);
+
+ /* Ignore fetches that have been flagged as locked.
+ * This allows safe re-entrant calls to this function.
+ * Re-entrancy can occur if, as a result of a callback,
+ * the interested party causes fetch_poll() to be called
+ * again.
+ */
+ if (c->locked == true) {
+ RING_INSERT(save_ring, c);
+ continue;
+ }
+
+ /* Only process non-aborted fetches */
+ if (c->aborted == false) {
+ /* about fetches can be processed in one go */
+ if (c->handler == NULL) {
+ fetch_about_404_handler(c);
+ } else {
+ c->handler(c);
+ }
+ }
+
+ /* And now finish */
+ fetch_remove_from_queues(c->fetchh);
+ fetch_free(c->fetchh);
+ }
+
+ /* Finally, if we saved any fetches which were locked, put them back
+ * into the ring for next time
+ */
+ ring = save_ring;
+}
+
+
+nserror fetch_about_register(void)
+{
+ lwc_string *scheme = lwc_string_ref(corestring_lwc_about);
+ const struct fetcher_operation_table fetcher_ops = {
+ .initialise = fetch_about_initialise,
+ .acceptable = fetch_about_can_fetch,
+ .setup = fetch_about_setup,
+ .start = fetch_about_start,
+ .abort = fetch_about_abort,
+ .free = fetch_about_free,
+ .poll = fetch_about_poll,
+ .finalise = fetch_about_finalise
+ };
+
+ return fetcher_add(scheme, &fetcher_ops);
+}
diff --git a/content/fetchers/about/about.h b/content/fetchers/about/about.h
new file mode 100644
index 0000000..944f84a
--- /dev/null
+++ b/content/fetchers/about/about.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * about: URL method handler
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
+#define NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
+
+/**
+ * Register about scheme handler.
+ *
+ * \return NSERROR_OK on successful registration or error code on failure.
+ */
+nserror fetch_about_register(void);
+
+#endif
-----------------------------------------------------------------------
Summary of changes:
content/fetch.c | 2 +-
content/fetchers/Makefile | 12 +-
content/fetchers/about.c | 2976 --------------------
content/fetchers/about/Makefile | 19 +
content/fetchers/about/about.c | 749 +++++
content/fetchers/{ => about}/about.h | 9 +-
.../fetchers/{file/file.h => about/atestament.h} | 15 +-
content/fetchers/about/blank.c | 59 +
content/fetchers/{file/file.h => about/blank.h} | 15 +-
content/fetchers/about/certificate.c | 1189 ++++++++
.../box_special.h => fetchers/about/certificate.h} | 16 +-
content/fetchers/about/choices.c | 93 +
content/fetchers/{file/file.h => about/choices.h} | 15 +-
content/fetchers/about/config.c | 133 +
content/fetchers/{file/file.h => about/config.h} | 15 +-
content/fetchers/about/imagecache.c | 174 ++
.../box_special.h => fetchers/about/imagecache.h} | 18 +-
content/fetchers/about/nscolours.c | 81 +
.../fetchers/{file/file.h => about/nscolours.h} | 15 +-
content/fetchers/about/private.h | 77 +
content/fetchers/about/query.c | 60 +
.../html/box_special.h => fetchers/about/query.h} | 17 +-
content/fetchers/about/query_auth.c | 246 ++
.../fetchers/{file/file.h => about/query_auth.h} | 15 +-
content/fetchers/about/query_fetcherror.c | 158 ++
.../about/query_fetcherror.h} | 16 +-
content/fetchers/about/query_privacy.c | 174 ++
.../about/query_privacy.h} | 16 +-
content/fetchers/about/query_timeout.c | 158 ++
.../about/query_timeout.h} | 16 +-
content/fetchers/about/testament.c | 129 +
content/handlers/image/image_cache.h | 1 +
32 files changed, 3611 insertions(+), 3077 deletions(-)
delete mode 100644 content/fetchers/about.c
create mode 100644 content/fetchers/about/Makefile
create mode 100644 content/fetchers/about/about.c
rename content/fetchers/{ => about}/about.h (85%)
copy content/fetchers/{file/file.h => about/atestament.h} (62%)
create mode 100644 content/fetchers/about/blank.c
copy content/fetchers/{file/file.h => about/blank.h} (63%)
create mode 100644 content/fetchers/about/certificate.c
copy content/{handlers/html/box_special.h => fetchers/about/certificate.h} (61%)
create mode 100644 content/fetchers/about/choices.c
copy content/fetchers/{file/file.h => about/choices.h} (62%)
create mode 100644 content/fetchers/about/config.c
copy content/fetchers/{file/file.h => about/config.h} (63%)
create mode 100644 content/fetchers/about/imagecache.c
copy content/{handlers/html/box_special.h => fetchers/about/imagecache.h} (61%)
create mode 100644 content/fetchers/about/nscolours.c
copy content/fetchers/{file/file.h => about/nscolours.h} (62%)
create mode 100644 content/fetchers/about/private.h
create mode 100644 content/fetchers/about/query.c
copy content/{handlers/html/box_special.h => fetchers/about/query.h} (61%)
create mode 100644 content/fetchers/about/query_auth.c
copy content/fetchers/{file/file.h => about/query_auth.h} (61%)
create mode 100644 content/fetchers/about/query_fetcherror.c
copy content/{handlers/html/box_special.h => fetchers/about/query_fetcherror.h} (61%)
create mode 100644 content/fetchers/about/query_privacy.c
copy content/{handlers/html/box_special.h => fetchers/about/query_privacy.h} (61%)
create mode 100644 content/fetchers/about/query_timeout.c
copy content/{handlers/html/box_special.h => fetchers/about/query_timeout.h} (61%)
create mode 100644 content/fetchers/about/testament.c
diff --git a/content/fetch.c b/content/fetch.c
index a260799..533f75e 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -53,7 +53,7 @@
#include "content/fetch.h"
#include "content/fetchers.h"
#include "content/fetchers/resource.h"
-#include "content/fetchers/about.h"
+#include "content/fetchers/about/about.h"
#include "content/fetchers/curl.h"
#include "content/fetchers/data.h"
#include "content/fetchers/file/file.h"
diff --git a/content/fetchers/Makefile b/content/fetchers/Makefile
index e87a4e8..8f6e521 100644
--- a/content/fetchers/Makefile
+++ b/content/fetchers/Makefile
@@ -1,15 +1,15 @@
# Content fetchers sources
-S_FETCHERS_YES := data.c about.c resource.c
+S_FETCHERS_YES := data.c resource.c
S_FETCHERS_NO :=
S_FETCHERS_$(NETSURF_USE_CURL) += curl.c
S_FETCHERS := $(addprefix fetchers/,$(S_FETCHERS_YES))
-# File fetcher
-include content/fetchers/file/Makefile
+# about fetcher
+include content/fetchers/about/Makefile
+S_FETCHERS += $(addprefix fetchers/about/,$(S_FETCHER_ABOUT))
+# file fetcher
+include content/fetchers/file/Makefile
S_FETCHERS += $(addprefix fetchers/file/,$(S_FETCHER_FILE))
-
-# The following files depend on the testament
-content/fetchers/about.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about.c b/content/fetchers/about.c
deleted file mode 100644
index 28f0d1e..0000000
--- a/content/fetchers/about.c
+++ /dev/null
@@ -1,2976 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince(a)netsurf-browser.org>
- *
- * This file is part of NetSurf.
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- *
- * URL handling for the "about" scheme.
- *
- * Based on the data fetcher by Rob Kendrick
- * This fetcher provides a simple scheme for the user to access
- * information from the browser from a known, fixed URL.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#include "netsurf/inttypes.h"
-#include "netsurf/plot_style.h"
-
-#include "utils/log.h"
-#include "testament.h"
-#include "utils/corestrings.h"
-#include "utils/nscolour.h"
-#include "utils/nsoption.h"
-#include "utils/utils.h"
-#include "utils/messages.h"
-#include "utils/ring.h"
-
-#include "content/fetch.h"
-#include "content/fetchers.h"
-#include "content/fetchers/about.h"
-#include "image/image_cache.h"
-
-#include "desktop/system_colour.h"
-
-struct fetch_about_context;
-
-typedef bool (*fetch_about_handler)(struct fetch_about_context *);
-
-/**
- * Context for an about fetch
- */
-struct fetch_about_context {
- struct fetch_about_context *r_next, *r_prev;
-
- struct fetch *fetchh; /**< Handle for this fetch */
-
- bool aborted; /**< Flag indicating fetch has been aborted */
- bool locked; /**< Flag indicating entry is already entered */
-
- nsurl *url; /**< The full url the fetch refers to */
-
- const struct fetch_multipart_data *multipart; /**< post data */
-
- fetch_about_handler handler;
-};
-
-static struct fetch_about_context *ring = NULL;
-
-/**
- * handler info for about scheme
- */
-struct about_handlers {
- const char *name; /**< name to match in url */
- int name_len;
- lwc_string *lname; /**< Interned name */
- fetch_about_handler handler; /**< handler for the url */
- bool hidden; /**< If entry should be hidden in listing */
-};
-
-
-/**
- * issue fetch callbacks with locking
- */
-static inline bool
-fetch_about_send_callback(const fetch_msg *msg, struct fetch_about_context *ctx)
-{
- ctx->locked = true;
- fetch_send_callback(msg, ctx->fetchh);
- ctx->locked = false;
-
- return ctx->aborted;
-}
-
-static inline bool
-fetch_about_send_finished(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- msg.type = FETCH_FINISHED;
- return fetch_about_send_callback(&msg, ctx);
-}
-
-static bool
-fetch_about_send_header(struct fetch_about_context *ctx, const char *fmt, ...)
-{
- char header[64];
- fetch_msg msg;
- va_list ap;
-
- va_start(ap, fmt);
-
- vsnprintf(header, sizeof header, fmt, ap);
-
- va_end(ap);
-
- msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf = (const uint8_t *) header;
- msg.data.header_or_data.len = strlen(header);
-
- return fetch_about_send_callback(&msg, ctx);
-}
-
-/**
- * send formatted data on a fetch
- */
-static nserror ssenddataf(struct fetch_about_context *ctx, const char *fmt, ...)
-{
- char buffer[1024];
- char *dbuff;
- fetch_msg msg;
- va_list ap;
- int slen;
-
- va_start(ap, fmt);
-
- slen = vsnprintf(buffer, sizeof(buffer), fmt, ap);
-
- va_end(ap);
-
- if (slen < (int)sizeof(buffer)) {
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
- msg.data.header_or_data.len = slen;
-
- if (fetch_about_send_callback(&msg, ctx)) {
- return NSERROR_INVALID;
- }
-
- return NSERROR_OK;
- }
-
- dbuff = malloc(slen + 1);
- if (dbuff == NULL) {
- return NSERROR_NOSPACE;
- }
-
- va_start(ap, fmt);
-
- slen = vsnprintf(dbuff, slen + 1, fmt, ap);
-
- va_end(ap);
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *)dbuff;
- msg.data.header_or_data.len = slen;
-
- if (fetch_about_send_callback(&msg, ctx)) {
- free(dbuff);
- return NSERROR_INVALID;
- }
-
- free(dbuff);
- return NSERROR_OK;
-}
-
-
-/**
- * Generate a 500 server error respnse
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_srverror(struct fetch_about_context *ctx)
-{
- nserror res;
-
- fetch_set_http_code(ctx->fetchh, 500);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
- return false;
-
- res = ssenddataf(ctx, "Server error 500");
- if (res != NSERROR_OK) {
- return false;
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-}
-
-
-/**
- * Handler to generate about scheme cache page.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_blank_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- const char buffer[2] = { ' ', '\0' };
-
- /* 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"))
- goto fetch_about_blank_handler_aborted;
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
- msg.data.header_or_data.len = strlen(buffer);
-
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_blank_handler_aborted;
-
- msg.type = FETCH_FINISHED;
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-
-fetch_about_blank_handler_aborted:
- return false;
-}
-
-
-/**
- * Handler to generate about scheme credits page.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_credits_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
-
- /* content is going to return redirect */
- fetch_set_http_code(ctx->fetchh, 302);
-
- msg.type = FETCH_REDIRECT;
- msg.data.redirect = "resource:credits.html";
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-}
-
-
-/**
- * Handler to generate about scheme licence page.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
-
- /* content is going to return redirect */
- fetch_set_http_code(ctx->fetchh, 302);
-
- msg.type = FETCH_REDIRECT;
- msg.data.redirect = "resource:licence.html";
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-}
-
-
-/**
- * Handler to generate about:imagecache page.
- *
- * Shows details of current image cache.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- char buffer[2048]; /* output buffer */
- int code = 200;
- int slen;
- unsigned int cent_loop = 0;
- int elen = 0; /* entry length */
- nserror res;
- bool even = false;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, code);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/html"))
- goto fetch_about_imagecache_handler_aborted;
-
- /* page head */
- res = ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>Image Cache Status</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body id =\"cachelist\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
- "<h1 class=\"ns-border\">Image Cache Status</h1>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_imagecache_handler_aborted;
- }
-
- /* image cache summary */
- slen = image_cache_snsummaryf(buffer, sizeof(buffer),
- "<p>Configured limit of %a hysteresis of %b</p>\n"
- "<p>Total bitmap size in use %c (in %d)</p>\n"
- "<p>Age %es</p>\n"
- "<p>Peak size %f (in %g)</p>\n"
- "<p>Peak image count %h (size %i)</p>\n"
- "<p>Cache total/hit/miss/fail (counts) %j/%k/%l/%m "
- "(%pj%%/%pk%%/%pl%%/%pm%%)</p>\n"
- "<p>Cache total/hit/miss/fail (size) %n/%o/%q/%r "
- "(%pn%%/%po%%/%pq%%/%pr%%)</p>\n"
- "<p>Total images never rendered: %s "
- "(includes %t that were converted)</p>\n"
- "<p>Total number of excessive conversions: %u "
- "(from %v images converted more than once)"
- "</p>\n"
- "<p>Bitmap of size %w had most (%x) conversions</p>\n"
- "<h2 class=\"ns-border\">Current contents</h2>\n");
- if (slen >= (int) (sizeof(buffer))) {
- goto fetch_about_imagecache_handler_aborted; /* overflow */
- }
-
- /* send image cache summary */
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx)) {
- goto fetch_about_imagecache_handler_aborted;
- }
-
- /* image cache entry table */
- res = ssenddataf(ctx, "<p class=\"imagecachelist\">\n"
- "<strong>"
- "<span>Entry</span>"
- "<span>Content Key</span>"
- "<span>Redraw Count</span>"
- "<span>Conversion Count</span>"
- "<span>Last Redraw</span>"
- "<span>Bitmap Age</span>"
- "<span>Bitmap Size</span>"
- "<span>Source</span>"
- "</strong>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_imagecache_handler_aborted;
- }
-
- slen = 0;
- do {
- if (even) {
- elen = image_cache_snentryf(buffer + slen,
- sizeof buffer - slen,
- cent_loop,
- "<a href=\"%U\">"
- "<span class=\"ns-border\">%e</span>"
- "<span class=\"ns-border\">%k</span>"
- "<span class=\"ns-border\">%r</span>"
- "<span class=\"ns-border\">%c</span>"
- "<span class=\"ns-border\">%a</span>"
- "<span class=\"ns-border\">%g</span>"
- "<span class=\"ns-border\">%s</span>"
- "<span class=\"ns-border\">%o</span>"
- "</a>\n");
- } else {
- elen = image_cache_snentryf(buffer + slen,
- sizeof buffer - slen,
- cent_loop,
- "<a class=\"ns-odd-bg\" href=\"%U\">"
- "<span class=\"ns-border\">%e</span>"
- "<span class=\"ns-border\">%k</span>"
- "<span class=\"ns-border\">%r</span>"
- "<span class=\"ns-border\">%c</span>"
- "<span class=\"ns-border\">%a</span>"
- "<span class=\"ns-border\">%g</span>"
- "<span class=\"ns-border\">%s</span>"
- "<span class=\"ns-border\">%o</span>"
- "</a>\n");
- }
- if (elen <= 0)
- break; /* last option */
-
- if (elen >= (int) (sizeof buffer - slen)) {
- /* last entry would not fit in buffer, submit buffer */
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_imagecache_handler_aborted;
- slen = 0;
- } else {
- /* normal addition */
- slen += elen;
- cent_loop++;
- even = !even;
- }
- } while (elen > 0);
-
- slen += snprintf(buffer + slen, sizeof buffer - slen,
- "</p>\n</body>\n</html>\n");
-
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_imagecache_handler_aborted;
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_imagecache_handler_aborted:
- return false;
-}
-
-/**
- * certificate name parameters
- */
-struct ns_cert_name {
- char *common_name;
- char *organisation;
- char *organisation_unit;
- char *locality;
- char *province;
- char *country;
-};
-
-/**
- * Certificate public key parameters
- */
-struct ns_cert_pkey {
- char *algor;
- int size;
- char *modulus;
- char *exponent;
- char *curve;
- char *public;
-};
-
-/**
- * Certificate subject alternative name
- */
-struct ns_cert_san {
- struct ns_cert_san *next;
- char *name;
-};
-
-/**
- * certificate information for certificate chain
- */
-struct ns_cert_info {
- struct ns_cert_name subject_name; /**< Subject details */
- struct ns_cert_name issuer_name; /**< Issuer details */
- struct ns_cert_pkey public_key; /**< public key details */
- long version; /**< Certificate version */
- char *not_before; /**< Valid from date */
- char *not_after; /**< Valid to date */
- int sig_type; /**< Signature type */
- char *sig_algor; /**< Signature Algorithm */
- char *serialnum; /**< Serial number */
- char *sha1fingerprint; /**< fingerprint shar1 encoded */
- char *sha256fingerprint; /**< fingerprint shar256 encoded */
- struct ns_cert_san *san; /**< subject alternative names */
- ssl_cert_err err; /**< Whatever is wrong with this certificate */
-};
-
-/**
- * free all resources associated with a certificate information structure
- */
-static nserror free_ns_cert_info(struct ns_cert_info *cinfo)
-{
- struct ns_cert_san *san;
-
- free(cinfo->subject_name.common_name);
- free(cinfo->subject_name.organisation);
- free(cinfo->subject_name.organisation_unit);
- free(cinfo->subject_name.locality);
- free(cinfo->subject_name.province);
- free(cinfo->subject_name.country);
- free(cinfo->issuer_name.common_name);
- free(cinfo->issuer_name.organisation);
- free(cinfo->issuer_name.organisation_unit);
- free(cinfo->issuer_name.locality);
- free(cinfo->issuer_name.province);
- free(cinfo->issuer_name.country);
- free(cinfo->public_key.algor);
- free(cinfo->public_key.modulus);
- free(cinfo->public_key.exponent);
- free(cinfo->public_key.curve);
- free(cinfo->public_key.public);
- free(cinfo->not_before);
- free(cinfo->not_after);
- free(cinfo->sig_algor);
- free(cinfo->serialnum);
-
- /* free san list avoiding use after free */
- san = cinfo->san;
- while (san != NULL) {
- struct ns_cert_san *next;
- next = san->next;
- free(san);
- san = next;
- }
-
- free(cinfo);
-
- return NSERROR_OK;
-}
-
-#ifdef WITH_OPENSSL
-
-#include <openssl/ssl.h>
-#include <openssl/x509v3.h>
-
-/* OpenSSL 1.0.x, 1.0.2, 1.1.0 and 1.1.1 API all changed
- * LibreSSL declares its OpenSSL version as 2.1 but only supports 1.0.x API
- */
-#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL))
-/* 1.0.x */
-
-#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1000200fL))
-/* pre 1.0.2 */
-static int ns_X509_get_signature_nid(X509 *cert)
-{
- return OBJ_obj2nid(cert->cert_info->key->algor->algorithm);
-}
-#else
-#define ns_X509_get_signature_nid X509_get_signature_nid
-#endif
-
-static const unsigned char *ns_ASN1_STRING_get0_data(ASN1_STRING *asn1str)
-{
- return (const unsigned char *)ASN1_STRING_data(asn1str);
-}
-
-static const BIGNUM *ns_RSA_get0_n(const RSA *d)
-{
- return d->n;
-}
-
-static const BIGNUM *ns_RSA_get0_e(const RSA *d)
-{
- return d->e;
-}
-
-static int ns_RSA_bits(const RSA *rsa)
-{
- return RSA_size(rsa) * 8;
-}
-
-static int ns_DSA_bits(const DSA *dsa)
-{
- return DSA_size(dsa) * 8;
-}
-
-static int ns_DH_bits(const DH *dh)
-{
- return DH_size(dh) * 8;
-}
-
-#elif (OPENSSL_VERSION_NUMBER < 0x1010100fL)
-/* 1.1.0 */
-#define ns_X509_get_signature_nid X509_get_signature_nid
-#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
-
-static const BIGNUM *ns_RSA_get0_n(const RSA *r)
-{
- const BIGNUM *n;
- const BIGNUM *e;
- const BIGNUM *d;
- RSA_get0_key(r, &n, &e, &d);
- return n;
-}
-
-static const BIGNUM *ns_RSA_get0_e(const RSA *r)
-{
- const BIGNUM *n;
- const BIGNUM *e;
- const BIGNUM *d;
- RSA_get0_key(r, &n, &e, &d);
- return e;
-}
-
-#define ns_RSA_bits RSA_bits
-#define ns_DSA_bits DSA_bits
-#define ns_DH_bits DH_bits
-
-#else
-/* 1.1.1 and later */
-#define ns_X509_get_signature_nid X509_get_signature_nid
-#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
-#define ns_RSA_get0_n RSA_get0_n
-#define ns_RSA_get0_e RSA_get0_e
-#define ns_RSA_bits RSA_bits
-#define ns_DSA_bits DSA_bits
-#define ns_DH_bits DH_bits
-#endif
-
-/**
- * extract certificate name information
- *
- * \param xname The X509 name to convert. The reference is borrowed so is not freeed
- * \param iname The info structure to recive the extracted parameters.
- * \return NSERROR_OK on success else error code
- */
-static nserror
-xname_to_info(X509_NAME *xname, struct ns_cert_name *iname)
-{
- int entryidx;
- int entrycnt;
- X509_NAME_ENTRY *entry; /* current name entry */
- ASN1_STRING *value;
- const unsigned char *value_str;
- ASN1_OBJECT *name;
- int name_nid;
- char **field;
-
- entrycnt = X509_NAME_entry_count(xname);
-
- for (entryidx = 0; entryidx < entrycnt; entryidx++) {
- entry = X509_NAME_get_entry(xname, entryidx);
- name = X509_NAME_ENTRY_get_object(entry);
- name_nid = OBJ_obj2nid(name);
- value = X509_NAME_ENTRY_get_data(entry);
- value_str = ns_ASN1_STRING_get0_data(value);
- switch (name_nid) {
- case NID_commonName:
- field = &iname->common_name;
- break;
- case NID_countryName:
- field = &iname->country;
- break;
- case NID_localityName:
- field = &iname->locality;
- break;
- case NID_stateOrProvinceName:
- field = &iname->province;
- break;
- case NID_organizationName:
- field = &iname->organisation;
- break;
- case NID_organizationalUnitName:
- field = &iname->organisation_unit;
- break;
- default :
- field = NULL;
- break;
- }
- if (field != NULL) {
- *field = strdup((const char *)value_str);
- NSLOG(netsurf, DEEPDEBUG,
- "NID:%d value: %s", name_nid, *field);
- } else {
- NSLOG(netsurf, DEEPDEBUG, "NID:%d", name_nid);
- }
- }
-
- /*
- * ensure the common name is set to something, this being
- * missing means the certificate is broken but this should be
- * robust in the face of bad data
- */
- if (iname->common_name == NULL) {
- iname->common_name = strdup("Unknown");
- }
-
- return NSERROR_OK;
-}
-
-
-/**
- * duplicate a hex formatted string inserting the colons
- *
- * \todo only uses html entity as separator because netsurfs line breaking
- * fails otherwise.
- */
-static char *hexdup(const char *hex)
-{
- int hexlen;
- char *dst;
- char *out;
- int cn = 0;
-
- hexlen = strlen(hex);
- /* allow space fox XXYY to XX:YY: */
- dst = malloc(((hexlen * 7) + 6) / 2);
-
- if (dst != NULL) {
- for (out = dst; *hex != 0; hex++) {
- if (cn == 2) {
- cn = 0;
- *out++ = '&';
- *out++ = '#';
- *out++ = '5';
- *out++ = '8';
- *out++ = ';';
- }
- *out++ = *hex;
- cn++;
- }
- *out = 0;
- }
- return dst;
-}
-
-
-/**
- * create a hex formatted string inserting the colons from binary data
- *
- * \todo only uses html entity as separator because netsurfs line breaking
- * fails otherwise.
- */
-static char *bindup(unsigned char *bin, unsigned int binlen)
-{
- char *dst;
- char *out;
- unsigned int idx;
- const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
-
- /* allow space fox XY to expand to XX:YY: */
- dst = malloc(binlen * 7);
-
- if (dst != NULL) {
- out = dst;
- for (idx = 0; idx < binlen; idx++) {
- *out++ = hex[(bin[idx] & 0xf0) >> 4];
- *out++ = hex[bin[idx] & 0xf];
-
- *out++ = '&';
- *out++ = '#';
- *out++ = '5';
- *out++ = '8';
- *out++ = ';';
- }
- out -= 5;
- *out = 0;
- }
- return dst;
-}
-
-
-/**
- * extract RSA key information to info structure
- *
- * \param rsa The RSA key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-rsa_to_info(RSA *rsa, struct ns_cert_pkey *ikey)
-{
- char *tmp;
-
- if (rsa == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("RSA");
-
- ikey->size = ns_RSA_bits(rsa);
-
- tmp = BN_bn2hex(ns_RSA_get0_n(rsa));
- if (tmp != NULL) {
- ikey->modulus = hexdup(tmp);
- OPENSSL_free(tmp);
- }
-
- tmp = BN_bn2dec(ns_RSA_get0_e(rsa));
- if (tmp != NULL) {
- ikey->exponent = strdup(tmp);
- OPENSSL_free(tmp);
- }
-
- RSA_free(rsa);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract DSA key information to info structure
- *
- * \param dsa The RSA key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-dsa_to_info(DSA *dsa, struct ns_cert_pkey *ikey)
-{
- if (dsa == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("DSA");
-
- ikey->size = ns_DSA_bits(dsa);
-
- DSA_free(dsa);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract DH key information to info structure
- *
- * \param dsa The RSA key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-dh_to_info(DH *dh, struct ns_cert_pkey *ikey)
-{
- if (dh == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("Diffie Hellman");
-
- ikey->size = ns_DH_bits(dh);
-
- DH_free(dh);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract EC key information to info structure
- *
- * \param ec The EC key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-ec_to_info(EC_KEY *ec, struct ns_cert_pkey *ikey)
-{
- const EC_GROUP *ecgroup;
- const EC_POINT *ecpoint;
- BN_CTX *bnctx;
- char *ecpoint_hex;
-
- if (ec == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- ikey->algor = strdup("Elliptic Curve");
-
- ecgroup = EC_KEY_get0_group(ec);
-
- if (ecgroup != NULL) {
- ikey->size = EC_GROUP_get_degree(ecgroup);
-
- ikey->curve = strdup(OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)));
-
- ecpoint = EC_KEY_get0_public_key(ec);
- if (ecpoint != NULL) {
- bnctx = BN_CTX_new();
- ecpoint_hex = EC_POINT_point2hex(ecgroup,
- ecpoint,
- POINT_CONVERSION_UNCOMPRESSED,
- bnctx);
- ikey->public = hexdup(ecpoint_hex);
- OPENSSL_free(ecpoint_hex);
- BN_CTX_free(bnctx);
- }
- }
- EC_KEY_free(ec);
-
- return NSERROR_OK;
-}
-
-
-/**
- * extract public key information to info structure
- *
- * \param pkey the public key to examine. The reference is dropped on return
- * \param ikey The public key info structure to fill
- * \rerun NSERROR_OK on success else error code.
- */
-static nserror
-pkey_to_info(EVP_PKEY *pkey, struct ns_cert_pkey *ikey)
-{
- nserror res;
-
- if (pkey == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- switch (EVP_PKEY_base_id(pkey)) {
- case EVP_PKEY_RSA:
- res = rsa_to_info(EVP_PKEY_get1_RSA(pkey), ikey);
- break;
-
- case EVP_PKEY_DSA:
- res = dsa_to_info(EVP_PKEY_get1_DSA(pkey), ikey);
- break;
-
- case EVP_PKEY_DH:
- res = dh_to_info(EVP_PKEY_get1_DH(pkey), ikey);
- break;
-
- case EVP_PKEY_EC:
- res = ec_to_info(EVP_PKEY_get1_EC_KEY(pkey), ikey);
- break;
-
- default:
- res = NSERROR_NOT_IMPLEMENTED;
- break;
- }
-
- EVP_PKEY_free(pkey);
-
- return res;
-}
-
-static nserror san_to_info(X509 *cert, struct ns_cert_san **prev_next)
-{
- int idx;
- int san_names_nb = -1;
- const GENERAL_NAME *current_name;
- const unsigned char *dns_name;
- struct ns_cert_san *isan;
-
- STACK_OF(GENERAL_NAME) *san_names = NULL;
-
- san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
- if (san_names == NULL) {
- return NSERROR_OK;
- }
-
- san_names_nb = sk_GENERAL_NAME_num(san_names);
-
- /* Check each name within the extension */
- for (idx = 0; idx < san_names_nb; idx++) {
- current_name = sk_GENERAL_NAME_value(san_names, idx);
-
- if (current_name->type == GEN_DNS) {
- /* extract DNS name into info structure */
- dns_name = ns_ASN1_STRING_get0_data(current_name->d.dNSName);
-
- isan = malloc(sizeof(struct ns_cert_san));
- if (isan != NULL) {
- isan->name = strdup((const char *)dns_name);
- isan->next = NULL;
- *prev_next = isan;
- prev_next = &isan->next;
- }
- }
- }
-
- /* AmiSSL can't cope with the "correct" mechanism of freeing
- * the GENERAL_NAME stack, which is:
- * sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
- * So instead we do this open-coded loop which does the same:
- */
- for (idx = 0; idx < san_names_nb; idx++) {
- GENERAL_NAME *entry = sk_GENERAL_NAME_pop(san_names);
- GENERAL_NAME_free(entry);
- }
- sk_GENERAL_NAME_free(san_names);
-
- return NSERROR_OK;
-}
-
-static nserror
-der_to_certinfo(const uint8_t *der,
- size_t der_length,
- struct ns_cert_info *info)
-{
- BIO *mem;
- BUF_MEM *buf;
- const ASN1_INTEGER *asn1_num;
- BIGNUM *bignum;
- X509 *cert; /**< Pointer to certificate */
-
- if (der == NULL) {
- return NSERROR_OK;
- }
-
- cert = d2i_X509(NULL, &der, der_length);
- if (cert == NULL) {
- return NSERROR_INVALID;
- }
-
- /*
- * get certificate version
- *
- * \note this is defined by standards (X.509 et al) to be one
- * less than the certificate version.
- */
- info->version = X509_get_version(cert) + 1;
-
- /* not before date */
- mem = BIO_new(BIO_s_mem());
- ASN1_TIME_print(mem, X509_get_notBefore(cert));
- BIO_get_mem_ptr(mem, &buf);
- (void) BIO_set_close(mem, BIO_NOCLOSE);
- BIO_free(mem);
- info->not_before = calloc(1, buf->length + 1);
- if (info->not_before != NULL) {
- memcpy(info->not_before, buf->data, (unsigned)buf->length);
- }
- BUF_MEM_free(buf);
-
- /* not after date */
- mem = BIO_new(BIO_s_mem());
- ASN1_TIME_print(mem,
- X509_get_notAfter(cert));
- BIO_get_mem_ptr(mem, &buf);
- (void) BIO_set_close(mem, BIO_NOCLOSE);
- BIO_free(mem);
- info->not_after = calloc(1, buf->length + 1);
- if (info->not_after != NULL) {
- memcpy(info->not_after, buf->data, (unsigned)buf->length);
- }
- BUF_MEM_free(buf);
-
- /* signature type */
- info->sig_type = X509_get_signature_type(cert);
-
- /* signature algorithm */
- int pkey_nid = ns_X509_get_signature_nid(cert);
- if (pkey_nid != NID_undef) {
- const char* sslbuf = OBJ_nid2ln(pkey_nid);
- if (sslbuf != NULL) {
- info->sig_algor = strdup(sslbuf);
- }
- }
-
- /* serial number */
- asn1_num = X509_get_serialNumber(cert);
- if (asn1_num != NULL) {
- bignum = ASN1_INTEGER_to_BN(asn1_num, NULL);
- if (bignum != NULL) {
- char *tmp = BN_bn2hex(bignum);
- if (tmp != NULL) {
- info->serialnum = hexdup(tmp);
- OPENSSL_free(tmp);
- }
- BN_free(bignum);
- bignum = NULL;
- }
- }
-
- /* fingerprints */
- const EVP_MD *digest;
- unsigned int dig_len;
- unsigned char *buff;
- int rc;
-
- digest = EVP_sha1();
- buff = malloc(EVP_MD_size(digest));
- if (buff != NULL) {
- rc = X509_digest(cert, digest, buff, &dig_len);
- if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
- info->sha1fingerprint = bindup(buff, dig_len);
- }
- free(buff);
- }
-
- digest = EVP_sha256();
- buff = malloc(EVP_MD_size(digest));
- if (buff != NULL) {
- rc = X509_digest(cert, digest, buff, &dig_len);
- if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
- info->sha256fingerprint = bindup(buff, dig_len);
- }
- free(buff);
- }
-
- /* subject alternative names */
- san_to_info(cert, &info->san);
-
- /* issuer name */
- xname_to_info(X509_get_issuer_name(cert), &info->issuer_name);
-
- /* subject */
- xname_to_info(X509_get_subject_name(cert), &info->subject_name);
-
- /* public key */
- pkey_to_info(X509_get_pubkey(cert), &info->public_key);
-
- X509_free(cert);
-
- return NSERROR_OK;
-}
-
-/* copy certificate data */
-static nserror
-convert_chain_to_cert_info(const struct cert_chain *chain,
- struct ns_cert_info **cert_info_out)
-{
- struct ns_cert_info *certs;
- size_t depth;
- nserror res;
-
- certs = calloc(chain->depth, sizeof(struct ns_cert_info));
- if (certs == NULL) {
- return NSERROR_NOMEM;
- }
-
- for (depth = 0; depth < chain->depth;depth++) {
- res = der_to_certinfo(chain->certs[depth].der,
- chain->certs[depth].der_length,
- certs + depth);
- if (res != NSERROR_OK) {
- free(certs);
- return res;
- }
- certs[depth].err = chain->certs[depth].err;
- }
-
- *cert_info_out = certs;
- return NSERROR_OK;
-}
-
-#else
-static nserror
-convert_chain_to_cert_info(const struct cert_chain *chain,
- struct ns_cert_info **cert_info_out)
-{
- return NSERROR_NOT_IMPLEMENTED;
-}
-#endif
-
-
-static nserror
-format_certificate_name(struct fetch_about_context *ctx,
- struct ns_cert_name *cert_name)
-{
- nserror res;
- res = ssenddataf(ctx,
- "<tr><th>Common Name</th><td>%s</td></tr>\n",
- cert_name->common_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_name->organisation != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Organisation</th><td>%s</td></tr>\n",
- cert_name->organisation);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->organisation_unit != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Organisation Unit</th><td>%s</td></tr>\n",
- cert_name->organisation_unit);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->locality != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Locality</th><td>%s</td></tr>\n",
- cert_name->locality);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->province != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Privince</th><td>%s</td></tr>\n",
- cert_name->province);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_name->country != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Country</th><td>%s</td></tr>\n",
- cert_name->country);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- return res;
-}
-
-/**
- * output formatted certificate subject alternate names
- */
-static nserror
-format_certificate_san(struct fetch_about_context *ctx,
- struct ns_cert_san *san)
-{
- nserror res;
-
- if (san == NULL) {
- return NSERROR_OK;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Alternative Names</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- while (san != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>DNS Name</th><td>%s</td></tr>\n",
- san->name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- san = san->next;
- }
-
- res = ssenddataf(ctx, "</table>\n");
-
- return res;
-
-}
-
-
-static nserror
-format_certificate_public_key(struct fetch_about_context *ctx,
- struct ns_cert_pkey *public_key)
-{
- nserror res;
-
- if (public_key->algor == NULL) {
- /* skip the table if no algorithm name */
- return NSERROR_OK;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Public Key</th><td><hr></td></tr>\n"
- "<tr><th>Algorithm</th><td>%s</td></tr>\n"
- "<tr><th>Key Size</th><td>%d</td></tr>\n",
- public_key->algor,
- public_key->size);
- if (res != NSERROR_OK) {
- return res;
- }
-
-
- if (public_key->exponent != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Exponent</th><td>%s</td></tr>\n",
- public_key->exponent);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (public_key->modulus != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Modulus</th><td class=\"data\">%s</td></tr>\n",
- public_key->modulus);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (public_key->curve != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Curve</th><td>%s</td></tr>\n",
- public_key->curve);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (public_key->public != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Public Value</th><td>%s</td></tr>\n",
- public_key->public);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = ssenddataf(ctx, "</table>\n");
-
- return res;
-}
-
-static nserror
-format_certificate_fingerprint(struct fetch_about_context *ctx,
- struct ns_cert_info *cert_info)
-{
- nserror res;
-
- if ((cert_info->sha1fingerprint == NULL) &&
- (cert_info->sha256fingerprint == NULL)) {
- /* skip the table if no fingerprints */
- return NSERROR_OK;
- }
-
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Fingerprints</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_info->sha256fingerprint != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>SHA-256</th><td class=\"data\">%s</td></tr>\n",
- cert_info->sha256fingerprint);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_info->sha1fingerprint != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>SHA-1</th><td class=\"data\">%s</td></tr>\n",
- cert_info->sha1fingerprint);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = ssenddataf(ctx, "</table>\n");
-
- return res;
-}
-
-static nserror
-format_certificate(struct fetch_about_context *ctx,
- struct ns_cert_info *cert_info,
- size_t depth)
-{
- nserror res;
-
- res = ssenddataf(ctx,
- "<h2 id=\"%"PRIsizet"\" class=\"ns-border\">%s</h2>\n",
- depth, cert_info->subject_name.common_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_info->err != SSL_CERT_ERR_OK) {
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr class=\"ns-even-fg-bad\">"
- "<th>Fault</th>"
- "<td>%s</td>"
- "</tr>"
- "</table>\n",
- messages_get_sslcode(cert_info->err));
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Issued To</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_name(ctx, &cert_info->subject_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "</table>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Issued By</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_name(ctx, &cert_info->issuer_name);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "</table>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Validity</th><td><hr></td></tr>\n"
- "<tr><th>Valid From</th><td>%s</td></tr>\n"
- "<tr><th>Valid Until</th><td>%s</td></tr>\n"
- "</table>\n",
- cert_info->not_before,
- cert_info->not_after);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_san(ctx, cert_info->san);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_public_key(ctx, &cert_info->public_key);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = ssenddataf(ctx,
- "<table class=\"info\">\n"
- "<tr><th>Miscellaneous</th><td><hr></td></tr>\n");
- if (res != NSERROR_OK) {
- return res;
- }
-
- if (cert_info->serialnum != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Serial Number</th><td>%s</td></tr>\n",
- cert_info->serialnum);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- if (cert_info->sig_algor != NULL) {
- res = ssenddataf(ctx,
- "<tr><th>Signature Algorithm</th>"
- "<td>%s</td></tr>\n",
- cert_info->sig_algor);
- if (res != NSERROR_OK) {
- return res;
- }
- }
-
- res = ssenddataf(ctx,
- "<tr><th>Version</th><td>%ld</td></tr>\n"
- "</table>\n",
- cert_info->version);
- if (res != NSERROR_OK) {
- return res;
- }
-
- res = format_certificate_fingerprint(ctx, cert_info);
- if (res != NSERROR_OK) {
- return res;
- }
-
- return res;
-}
-
-/**
- * Handler to generate about:certificate page.
- *
- * Shows details of a certificate chain
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
-{
- int code = 200;
- nserror res;
- struct cert_chain *chain = NULL;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, code);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/html"))
- goto fetch_about_certificate_handler_aborted;
-
- /* page head */
- res = ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>NetSurf Browser Certificate Viewer</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body id=\"certificate\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
- "<h1 class=\"ns-border\">Certificate</h1>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
-
- res = cert_chain_from_query(ctx->url, &chain);
- if (res != NSERROR_OK) {
- res = ssenddataf(ctx, "<p>Could not process that</p>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
- } else {
- struct ns_cert_info *cert_info;
- res = convert_chain_to_cert_info(chain, &cert_info);
- if (res == NSERROR_OK) {
- size_t depth;
- res = ssenddataf(ctx, "<ul>\n");
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- for (depth = 0; depth < chain->depth; depth++) {
- res = ssenddataf(ctx, "<li><a href=\"#%"PRIsizet"\">%s</a></li>\n",
- depth, (cert_info + depth)
- ->subject_name
- .common_name);
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- }
-
- res = ssenddataf(ctx, "</ul>\n");
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- for (depth = 0; depth < chain->depth; depth++) {
- res = format_certificate(ctx, cert_info + depth,
- depth);
- if (res != NSERROR_OK) {
- free_ns_cert_info(cert_info);
- goto fetch_about_certificate_handler_aborted;
- }
-
- }
- free_ns_cert_info(cert_info);
-
- } else {
- res = ssenddataf(ctx,
- "<p>Invalid certificate data</p>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
- }
- }
-
-
- /* page footer */
- res = ssenddataf(ctx, "</body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_certificate_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- cert_chain_free(chain);
-
- return true;
-
-fetch_about_certificate_handler_aborted:
- cert_chain_free(chain);
- return false;
-}
-
-
-/**
- * Handler to generate about scheme config page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_config_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- char buffer[1024];
- int slen = 0;
- unsigned int opt_loop = 0;
- int elen = 0; /* entry length */
- nserror res;
- bool even = false;
-
- /* 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")) {
- goto fetch_about_config_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>NetSurf Browser Config</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body "
- "id =\"configlist\" "
- "class=\"ns-even-bg ns-even-fg ns-border\" "
- "style=\"overflow: hidden;\">\n"
- "<h1 class=\"ns-border\">NetSurf Browser Config</h1>\n"
- "<table class=\"config\">\n"
- "<tr><th>Option</th>"
- "<th>Type</th>"
- "<th>Provenance</th>"
- "<th>Setting</th></tr>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_config_handler_aborted;
- }
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
-
- do {
- if (even) {
- elen = nsoption_snoptionf(buffer + slen,
- sizeof buffer - slen,
- opt_loop,
- "<tr class=\"ns-even-bg\">"
- "<th class=\"ns-border\">%k</th>"
- "<td class=\"ns-border\">%t</td>"
- "<td class=\"ns-border\">%p</td>"
- "<td class=\"ns-border\">%V</td>"
- "</tr>\n");
- } else {
- elen = nsoption_snoptionf(buffer + slen,
- sizeof buffer - slen,
- opt_loop,
- "<tr class=\"ns-odd-bg\">"
- "<th class=\"ns-border\">%k</th>"
- "<td class=\"ns-border\">%t</td>"
- "<td class=\"ns-border\">%p</td>"
- "<td class=\"ns-border\">%V</td>"
- "</tr>\n");
- }
- if (elen <= 0)
- break; /* last option */
-
- if (elen >= (int) (sizeof buffer - slen)) {
- /* last entry would not fit in buffer, submit buffer */
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_config_handler_aborted;
- slen = 0;
- } else {
- /* normal addition */
- slen += elen;
- opt_loop++;
- even = !even;
- }
- } while (elen > 0);
-
- slen += snprintf(buffer + slen, sizeof buffer - slen,
- "</table>\n</body>\n</html>\n");
-
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_config_handler_aborted;
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_config_handler_aborted:
- return false;
-}
-
-
-/**
- * Handler to generate the nscolours stylesheet
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_nscolours_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- const char *stylesheet;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, 200);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/css; charset=utf-8")) {
- goto aborted;
- }
-
- res = nscolour_get_stylesheet(&stylesheet);
- if (res != NSERROR_OK) {
- goto aborted;
- }
-
- res = ssenddataf(ctx,
- "html {\n"
- "\tbackground-color: #%06x;\n"
- "}\n"
- "%s",
- colour_rb_swap(nscolours[NSCOLOUR_WIN_ODD_BG]),
- stylesheet);
- if (res != NSERROR_OK) {
- goto aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-aborted:
-
- return false;
-}
-
-
-/**
- * Generate the text of a Choices file which represents the current
- * in use options.
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_choices_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
- char buffer[1024];
- int code = 200;
- int slen;
- unsigned int opt_loop = 0;
- int res = 0;
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, code);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
- goto fetch_about_choices_handler_aborted;
-
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf = (const uint8_t *) buffer;
-
- slen = snprintf(buffer, sizeof buffer,
- "# Automatically generated current NetSurf browser Choices\n");
-
- do {
- res = nsoption_snoptionf(buffer + slen,
- sizeof buffer - slen,
- opt_loop,
- "%k:%v\n");
- if (res <= 0)
- break; /* last option */
-
- if (res >= (int) (sizeof buffer - slen)) {
- /* last entry would not fit in buffer, submit buffer */
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_choices_handler_aborted;
- slen = 0;
- } else {
- /* normal addition */
- slen += res;
- opt_loop++;
- }
- } while (res > 0);
-
- msg.data.header_or_data.len = slen;
- if (fetch_about_send_callback(&msg, ctx))
- goto fetch_about_choices_handler_aborted;
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_choices_handler_aborted:
- return false;
-}
-
-
-typedef struct {
- const char *leaf;
- const char *modtype;
-} modification_t;
-
-/**
- * Generate the text of an svn testament which represents the current
- * build-tree status
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_testament_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- static modification_t modifications[] = WT_MODIFICATIONS;
- int modidx; /* midification index */
-
- /* content is going to return ok */
- fetch_set_http_code(ctx->fetchh, 200);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
- goto fetch_about_testament_handler_aborted;
-
- res = ssenddataf(ctx,
- "# Automatically generated by NetSurf build system\n\n");
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- res = ssenddataf(ctx,
-#if defined(WT_BRANCHISTRUNK) || defined(WT_BRANCHISMASTER)
- "# This is a *DEVELOPMENT* build from the main line.\n\n"
-#elif defined(WT_BRANCHISTAG) && (WT_MODIFIED == 0)
- "# This is a tagged build of NetSurf\n"
-#ifdef WT_TAGIS
- "# The tag used was '" WT_TAGIS "'\n\n"
-#else
- "\n"
-#endif
-#elif defined(WT_NO_SVN) || defined(WT_NO_GIT)
- "# This NetSurf was built outside of our revision "
- "control environment.\n"
- "# This testament is therefore not very useful.\n\n"
-#else
- "# This NetSurf was built from a branch (" WT_BRANCHPATH ").\n\n"
-#endif
-#if defined(CI_BUILD)
- "# This build carries the CI build number '" CI_BUILD "'\n\n"
-#endif
- );
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "Built by %s (%s) from %s at revision %s on %s\n\n",
- GECOS, USERNAME, WT_BRANCHPATH, WT_REVID, WT_COMPILEDATE);
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- res = ssenddataf(ctx, "Built on %s in %s\n\n", WT_HOSTNAME, WT_ROOT);
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- if (WT_MODIFIED > 0) {
- res = ssenddataf(ctx,
- "Working tree has %d modification%s\n\n",
- WT_MODIFIED, WT_MODIFIED == 1 ? "" : "s");
- } else {
- res = ssenddataf(ctx, "Working tree is not modified.\n");
- }
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
-
- for (modidx = 0; modidx < WT_MODIFIED; ++modidx) {
- res = ssenddataf(ctx,
- " %s %s\n",
- modifications[modidx].modtype,
- modifications[modidx].leaf);
- if (res != NSERROR_OK) {
- goto fetch_about_testament_handler_aborted;
- }
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_testament_handler_aborted:
- return false;
-}
-
-
-/**
- * Handler to generate about scheme logo page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_logo_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
-
- /* content is going to return redirect */
- fetch_set_http_code(ctx->fetchh, 302);
-
- msg.type = FETCH_REDIRECT;
- msg.data.redirect = "resource:netsurf.png";
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-}
-
-
-/**
- * Handler to generate about scheme welcome page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_welcome_handler(struct fetch_about_context *ctx)
-{
- fetch_msg msg;
-
- /* content is going to return redirect */
- fetch_set_http_code(ctx->fetchh, 302);
-
- msg.type = FETCH_REDIRECT;
- msg.data.redirect = "resource:welcome.html";
-
- fetch_about_send_callback(&msg, ctx);
-
- return true;
-}
-
-
-/**
- * generate the description of the login query
- */
-static nserror
-get_authentication_description(struct nsurl *url,
- const char *realm,
- const char *username,
- const char *password,
- char **out_str)
-{
- nserror res;
- char *url_s;
- size_t url_l;
- char *str = NULL;
- const char *key;
-
- res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
- if (res != NSERROR_OK) {
- return res;
- }
-
- if ((*username == 0) && (*password == 0)) {
- key = "LoginDescription";
- } else {
- key = "LoginAgain";
- }
-
- str = messages_get_buff(key, url_s, realm);
- if (str != NULL) {
- NSLOG(netsurf, INFO,
- "key:%s url:%s realm:%s str:%s",
- key, url_s, realm, str);
- *out_str = str;
- } else {
- res = NSERROR_NOMEM;
- }
-
- free(url_s);
-
- return res;
-}
-
-
-/**
- * generate a generic query description
- */
-static nserror
-get_query_description(struct nsurl *url,
- const char *key,
- char **out_str)
-{
- nserror res;
- char *url_s;
- size_t url_l;
- char *str = NULL;
-
- /* get the host in question */
- res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
- if (res != NSERROR_OK) {
- return res;
- }
-
- /* obtain the description with the url substituted */
- str = messages_get_buff(key, url_s);
- if (str == NULL) {
- res = NSERROR_NOMEM;
- } else {
- *out_str = str;
- }
-
- free(url_s);
-
- return res;
-}
-
-
-/**
- * Handler to generate about scheme authentication query page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- char *url_s;
- size_t url_l;
- const char *realm = "";
- const char *username = "";
- const char *password = "";
- const char *title;
- char *description = NULL;
- struct nsurl *siteurl = 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, "realm") == 0) {
- realm = curmd->value;
- } else if (strcmp(curmd->name, "username") == 0) {
- username = curmd->value;
- } else if (strcmp(curmd->name, "password") == 0) {
- password = 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_auth_handler_aborted;
- }
-
- title = messages_get("LoginTitle");
- 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 class=\"ns-even-bg ns-even-fg ns-border\" id =\"authentication\">\n"
- "<h1 class=\"ns-border\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<form method=\"post\""
- " enctype=\"multipart/form-data\">");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = get_authentication_description(siteurl,
- realm,
- username,
- password,
- &description);
- if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<p>%s</p>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
- }
-
- res = ssenddataf(ctx, "<table>");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<tr>"
- "<th><label for=\"name\">%s:</label></th>"
- "<td><input type=\"text\" id=\"username\" "
- "name=\"username\" value=\"%s\"></td>"
- "</tr>",
- messages_get("Username"), username);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<tr>"
- "<th><label for=\"password\">%s:</label></th>"
- "<td><input type=\"password\" id=\"password\" "
- "name=\"password\" value=\"%s\"></td>"
- "</tr>",
- messages_get("Password"), password);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx, "</table>");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<div id=\"buttons\">"
- "<input type=\"submit\" id=\"login\" name=\"login\" "
- "value=\"%s\" class=\"default-action\">"
- "<input type=\"submit\" id=\"cancel\" name=\"cancel\" "
- "value=\"%s\">"
- "</div>",
- messages_get("Login"),
- messages_get("Cancel"));
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_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_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<input type=\"hidden\" name=\"realm\" value=\"%s\">",
- realm);
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- res = ssenddataf(ctx, "</form></body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_query_auth_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- nsurl_unref(siteurl);
-
- return true;
-
-fetch_about_query_auth_handler_aborted:
-
- nsurl_unref(siteurl);
-
- return false;
-}
-
-
-/**
- * Handler to generate about scheme privacy query page
- *
- * \param ctx The fetcher context.
- * \return true if handled false if aborted.
- */
-static bool fetch_about_query_privacy_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 char *chainurl = 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;
- } else if (strcmp(curmd->name, "chainurl") == 0) {
- chainurl = 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_ssl_handler_aborted;
- }
-
- title = messages_get("PrivacyTitle");
- 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 class=\"ns-even-bg ns-even-fg ns-border\" id =\"privacy\">\n"
- "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<form method=\"post\""
- " enctype=\"multipart/form-data\">");
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- res = get_query_description(siteurl,
- "PrivacyDescription",
- &description);
- if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
- }
-
- if (chainurl == NULL) {
- res = ssenddataf(ctx,
- "<div><p>%s</p></div>"
- "<div><p>%s</p></div>",
- reason,
- messages_get("ViewCertificatesNotPossible"));
- } else {
- res = ssenddataf(ctx,
- "<div><p>%s</p></div>"
- "<div><p><a href=\"%s\" target=\"_blank\">%s</a></p></div>",
- reason,
- chainurl,
- messages_get("ViewCertificates"));
- }
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
- res = ssenddataf(ctx,
- "<div id=\"buttons\">"
- "<input type=\"submit\" id=\"back\" name=\"back\" "
- "value=\"%s\" class=\"default-action\">"
- "<input type=\"submit\" id=\"proceed\" name=\"proceed\" "
- "value=\"%s\">"
- "</div>",
- messages_get("Backtosafety"),
- messages_get("Proceed"));
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_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_ssl_handler_aborted;
- }
-
- res = ssenddataf(ctx, "</form></body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_query_ssl_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- nsurl_unref(siteurl);
-
- return true;
-
-fetch_about_query_ssl_handler_aborted:
- nsurl_unref(siteurl);
-
- return false;
-}
-
-
-/**
- * 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 class=\"ns-even-bg ns-even-fg ns-border\" id =\"timeout\">\n"
- "<h1 class=\"ns-border ns-odd-fg-bad\">%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",
- &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;
-}
-
-
-/**
- * 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,
- "<html>\n<head>\n"
- "<title>%s</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"fetcherror\">\n"
- "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
- title, title);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
-
- res = ssenddataf(ctx,
- "<form method=\"post\""
- " enctype=\"multipart/form-data\">");
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
-
- res = get_query_description(siteurl,
- "FetchErrorDescription",
- &description);
- if (res == NSERROR_OK) {
- res = ssenddataf(ctx, "<div><p>%s</p></div>", description);
- free(description);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_handler_aborted;
- }
- }
- res = ssenddataf(ctx, "<div><p>%s</p></div>", reason);
- if (res != NSERROR_OK) {
- goto fetch_about_query_fetcherror_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_fetcherror_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_fetcherror_handler_aborted;
- }
-
- res = ssenddataf(ctx, "</form></body>\n</html>\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);
-
-/**
- * List of about paths and their handlers
- */
-struct about_handlers about_handler_list[] = {
- {
- "credits",
- SLEN("credits"),
- NULL,
- fetch_about_credits_handler,
- false
- },
- {
- "licence",
- SLEN("licence"),
- NULL,
- fetch_about_licence_handler,
- false
- },
- {
- "license",
- SLEN("license"),
- NULL,
- fetch_about_licence_handler,
- true
- },
- {
- "welcome",
- SLEN("welcome"),
- NULL,
- fetch_about_welcome_handler,
- false
- },
- {
- "config",
- SLEN("config"),
- NULL,
- fetch_about_config_handler,
- false
- },
- {
- "Choices",
- SLEN("Choices"),
- NULL,
- fetch_about_choices_handler,
- false
- },
- {
- "testament",
- SLEN("testament"),
- NULL,
- fetch_about_testament_handler,
- false
- },
- {
- "about",
- SLEN("about"),
- NULL,
- fetch_about_about_handler,
- true
- },
- {
- "nscolours.css",
- SLEN("nscolours.css"),
- NULL,
- fetch_about_nscolours_handler,
- true
- },
- {
- "logo",
- SLEN("logo"),
- NULL,
- fetch_about_logo_handler,
- true
- },
- {
- /* details about the image cache */
- "imagecache",
- SLEN("imagecache"),
- NULL,
- fetch_about_imagecache_handler,
- true
- },
- {
- /* The default blank page */
- "blank",
- SLEN("blank"),
- NULL,
- fetch_about_blank_handler,
- true
- },
- {
- /* details about a certificate */
- "certificate",
- SLEN("certificate"),
- NULL,
- fetch_about_certificate_handler,
- true
- },
- {
- "query/auth",
- SLEN("query/auth"),
- NULL,
- fetch_about_query_auth_handler,
- true
- },
- {
- "query/ssl",
- SLEN("query/ssl"),
- NULL,
- fetch_about_query_privacy_handler,
- true
- },
- {
- "query/timeout",
- SLEN("query/timeout"),
- NULL,
- fetch_about_query_timeout_handler,
- true
- },
- {
- "query/fetcherror",
- SLEN("query/fetcherror"),
- NULL,
- fetch_about_query_fetcherror_handler,
- true
- }
-};
-
-#define about_handler_list_len \
- (sizeof(about_handler_list) / sizeof(struct about_handlers))
-
-/**
- * List all the valid about: paths available
- *
- * \param ctx The fetch context.
- * \return true for sucess or false to generate an error.
- */
-static bool fetch_about_about_handler(struct fetch_about_context *ctx)
-{
- nserror res;
- unsigned int abt_loop = 0;
-
- /* 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"))
- goto fetch_about_config_handler_aborted;
-
- res = ssenddataf(ctx,
- "<html>\n<head>\n"
- "<title>List of NetSurf pages</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"resource:internal.css\">\n"
- "</head>\n"
- "<body class=\"ns-even-bg ns-even-fg ns-border\">\n"
- "<h1 class =\"ns-border\">List of NetSurf pages</h1>\n"
- "<ul>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_config_handler_aborted;
- }
-
- for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
-
- /* Skip over hidden entries */
- if (about_handler_list[abt_loop].hidden)
- continue;
-
- res = ssenddataf(ctx,
- "<li><a href=\"about:%s\">about:%s</a></li>\n",
- about_handler_list[abt_loop].name,
- about_handler_list[abt_loop].name);
- if (res != NSERROR_OK) {
- goto fetch_about_config_handler_aborted;
- }
- }
-
- res = ssenddataf(ctx, "</ul>\n</body>\n</html>\n");
- if (res != NSERROR_OK) {
- goto fetch_about_config_handler_aborted;
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-
-fetch_about_config_handler_aborted:
- return false;
-}
-
-static bool
-fetch_about_404_handler(struct fetch_about_context *ctx)
-{
- nserror res;
-
- /* content is going to return 404 */
- fetch_set_http_code(ctx->fetchh, 404);
-
- /* content type */
- if (fetch_about_send_header(ctx, "Content-Type: text/plain; charset=utf-8")) {
- return false;
- }
-
- res = ssenddataf(ctx, "Unknown page: %s", nsurl_access(ctx->url));
- if (res != NSERROR_OK) {
- return false;
- }
-
- fetch_about_send_finished(ctx);
-
- return true;
-}
-
-/**
- * callback to initialise the about scheme fetcher.
- */
-static bool fetch_about_initialise(lwc_string *scheme)
-{
- unsigned int abt_loop = 0;
- lwc_error error;
-
- for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
- error = lwc_intern_string(about_handler_list[abt_loop].name,
- about_handler_list[abt_loop].name_len,
- &about_handler_list[abt_loop].lname);
- if (error != lwc_error_ok) {
- while (abt_loop-- != 0) {
- lwc_string_unref(about_handler_list[abt_loop].lname);
- }
- return false;
- }
- }
-
- return true;
-}
-
-
-/**
- * callback to finalise the about scheme fetcher.
- */
-static void fetch_about_finalise(lwc_string *scheme)
-{
- unsigned int abt_loop = 0;
- for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
- lwc_string_unref(about_handler_list[abt_loop].lname);
- }
-}
-
-
-static bool fetch_about_can_fetch(const nsurl *url)
-{
- return true;
-}
-
-
-/**
- * callback to set up a about scheme fetch.
- *
- * \param post_urlenc post data in urlenc format, owned by the llcache object
- * hence valid the entire lifetime of the fetch.
- * \param post_multipart post data in multipart format, owned by the llcache
- * object hence valid the entire lifetime of the fetch.
- */
-static void *
-fetch_about_setup(struct fetch *fetchh,
- nsurl *url,
- bool only_2xx,
- bool downgrade_tls,
- const char *post_urlenc,
- const struct fetch_multipart_data *post_multipart,
- const char **headers)
-{
- struct fetch_about_context *ctx;
- unsigned int handler_loop;
- lwc_string *path;
- bool match;
-
- ctx = calloc(1, sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- path = nsurl_get_component(url, NSURL_PATH);
-
- for (handler_loop = 0;
- handler_loop < about_handler_list_len;
- handler_loop++) {
- if (lwc_string_isequal(path,
- about_handler_list[handler_loop].lname,
- &match) == lwc_error_ok && match) {
- ctx->handler = about_handler_list[handler_loop].handler;
- break;
- }
- }
-
- if (path != NULL)
- lwc_string_unref(path);
-
- ctx->fetchh = fetchh;
- ctx->url = nsurl_ref(url);
- ctx->multipart = post_multipart;
-
- RING_INSERT(ring, ctx);
-
- return ctx;
-}
-
-
-/**
- * callback to free a about scheme fetch
- */
-static void fetch_about_free(void *ctx)
-{
- struct fetch_about_context *c = ctx;
- nsurl_unref(c->url);
- free(ctx);
-}
-
-
-/**
- * callback to start an about scheme fetch
- */
-static bool fetch_about_start(void *ctx)
-{
- return true;
-}
-
-
-/**
- * callback to abort a about fetch
- */
-static void fetch_about_abort(void *ctx)
-{
- struct fetch_about_context *c = ctx;
-
- /* To avoid the poll loop having to deal with the fetch context
- * disappearing from under it, we simply flag the abort here.
- * The poll loop itself will perform the appropriate cleanup.
- */
- c->aborted = true;
-}
-
-
-/**
- * callback to poll for additional about fetch contents
- */
-static void fetch_about_poll(lwc_string *scheme)
-{
- struct fetch_about_context *c, *save_ring = NULL;
-
- /* Iterate over ring, processing each pending fetch */
- while (ring != NULL) {
- /* Take the first entry from the ring */
- c = ring;
- RING_REMOVE(ring, c);
-
- /* Ignore fetches that have been flagged as locked.
- * This allows safe re-entrant calls to this function.
- * Re-entrancy can occur if, as a result of a callback,
- * the interested party causes fetch_poll() to be called
- * again.
- */
- if (c->locked == true) {
- RING_INSERT(save_ring, c);
- continue;
- }
-
- /* Only process non-aborted fetches */
- if (c->aborted == false) {
- /* about fetches can be processed in one go */
- if (c->handler == NULL) {
- fetch_about_404_handler(c);
- } else {
- c->handler(c);
- }
- }
-
- /* And now finish */
- fetch_remove_from_queues(c->fetchh);
- fetch_free(c->fetchh);
- }
-
- /* Finally, if we saved any fetches which were locked, put them back
- * into the ring for next time
- */
- ring = save_ring;
-}
-
-
-nserror fetch_about_register(void)
-{
- lwc_string *scheme = lwc_string_ref(corestring_lwc_about);
- const struct fetcher_operation_table fetcher_ops = {
- .initialise = fetch_about_initialise,
- .acceptable = fetch_about_can_fetch,
- .setup = fetch_about_setup,
- .start = fetch_about_start,
- .abort = fetch_about_abort,
- .free = fetch_about_free,
- .poll = fetch_about_poll,
- .finalise = fetch_about_finalise
- };
-
- return fetcher_add(scheme, &fetcher_ops);
-}
diff --git a/content/fetchers/about/Makefile b/content/fetchers/about/Makefile
new file mode 100644
index 0000000..10c9a6a
--- /dev/null
+++ b/content/fetchers/about/Makefile
@@ -0,0 +1,19 @@
+# about fetcher sources
+
+S_FETCHER_ABOUT := \
+ about.c \
+ blank.c \
+ certificate.c \
+ choices.c \
+ config.c \
+ imagecache.c \
+ nscolours.c \
+ query.c \
+ query_auth.c \
+ query_fetcherror.c \
+ query_privacy.c \
+ query_timeout.c \
+ testament.c
+
+# The following files depend on the testament
+content/fetchers/about/testament.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about/about.c b/content/fetchers/about/about.c
new file mode 100644
index 0000000..fe9eba7
--- /dev/null
+++ b/content/fetchers/about/about.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ *
+ * URL handling for the "about" scheme.
+ *
+ * Based on the data fetcher by Rob Kendrick
+ * This fetcher provides a simple scheme for the user to access
+ * information from the browser from a known, fixed URL.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "netsurf/inttypes.h"
+
+#include "utils/errors.h"
+#include "utils/nsurl.h"
+#include "utils/corestrings.h"
+#include "utils/utils.h"
+#include "utils/ring.h"
+
+#include "content/fetch.h"
+#include "content/fetchers.h"
+
+#include "private.h"
+#include "about.h"
+#include "blank.h"
+#include "certificate.h"
+#include "config.h"
+#include "choices.h"
+#include "imagecache.h"
+#include "nscolours.h"
+#include "query.h"
+#include "query_auth.h"
+#include "query_fetcherror.h"
+#include "query_privacy.h"
+#include "query_timeout.h"
+#include "atestament.h"
+
+typedef bool (*fetch_about_handler)(struct fetch_about_context *);
+
+/**
+ * Context for an about fetch
+ */
+struct fetch_about_context {
+ struct fetch_about_context *r_next, *r_prev;
+
+ struct fetch *fetchh; /**< Handle for this fetch */
+
+ bool aborted; /**< Flag indicating fetch has been aborted */
+ bool locked; /**< Flag indicating entry is already entered */
+
+ nsurl *url; /**< The full url the fetch refers to */
+
+ const struct fetch_multipart_data *multipart; /**< post data */
+
+ fetch_about_handler handler;
+};
+
+static struct fetch_about_context *ring = NULL;
+
+/**
+ * handler info for about scheme
+ */
+struct about_handlers {
+ const char *name; /**< name to match in url */
+ int name_len;
+ lwc_string *lname; /**< Interned name */
+ fetch_about_handler handler; /**< handler for the url */
+ bool hidden; /**< If entry should be hidden in listing */
+};
+
+
+
+/**
+ * issue fetch callbacks with locking
+ */
+static bool
+fetch_about_send_callback(const fetch_msg *msg, struct fetch_about_context *ctx)
+{
+ ctx->locked = true;
+ fetch_send_callback(msg, ctx->fetchh);
+ ctx->locked = false;
+
+ return ctx->aborted;
+}
+
+/* exported interface documented in about/private.h */
+bool
+fetch_about_send_finished(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+ msg.type = FETCH_FINISHED;
+ return fetch_about_send_callback(&msg, ctx);
+}
+
+/* exported interface documented in about/private.h */
+bool fetch_about_set_http_code(struct fetch_about_context *ctx, long code)
+{
+ fetch_set_http_code(ctx->fetchh, code);
+
+ return ctx->aborted;
+}
+
+/* exported interface documented in about/private.h */
+bool
+fetch_about_send_header(struct fetch_about_context *ctx, const char *fmt, ...)
+{
+ char header[64];
+ fetch_msg msg;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ vsnprintf(header, sizeof header, fmt, ap);
+
+ va_end(ap);
+
+ msg.type = FETCH_HEADER;
+ msg.data.header_or_data.buf = (const uint8_t *) header;
+ msg.data.header_or_data.len = strlen(header);
+
+ return fetch_about_send_callback(&msg, ctx);
+}
+
+/* exported interface documented in about/private.h */
+nserror
+fetch_about_senddata(struct fetch_about_context *ctx, const uint8_t *data, size_t data_len)
+{
+ fetch_msg msg;
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = data;
+ msg.data.header_or_data.len = data_len;
+
+ if (fetch_about_send_callback(&msg, ctx)) {
+ return NSERROR_INVALID;
+ }
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in about/private.h */
+nserror
+fetch_about_ssenddataf(struct fetch_about_context *ctx, const char *fmt, ...)
+{
+ char buffer[1024];
+ char *dbuff;
+ fetch_msg msg;
+ va_list ap;
+ int slen;
+
+ va_start(ap, fmt);
+
+ slen = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+
+ va_end(ap);
+
+ if (slen < (int)sizeof(buffer)) {
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) buffer;
+ msg.data.header_or_data.len = slen;
+
+ if (fetch_about_send_callback(&msg, ctx)) {
+ return NSERROR_INVALID;
+ }
+
+ return NSERROR_OK;
+ }
+
+ dbuff = malloc(slen + 1);
+ if (dbuff == NULL) {
+ return NSERROR_NOSPACE;
+ }
+
+ va_start(ap, fmt);
+
+ slen = vsnprintf(dbuff, slen + 1, fmt, ap);
+
+ va_end(ap);
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *)dbuff;
+ msg.data.header_or_data.len = slen;
+
+ if (fetch_about_send_callback(&msg, ctx)) {
+ free(dbuff);
+ return NSERROR_INVALID;
+ }
+
+ free(dbuff);
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in about/private.h */
+nsurl *fetch_about_get_url(struct fetch_about_context *ctx)
+{
+ return ctx->url;
+}
+
+
+/* exported interface documented in about/private.h */
+const struct fetch_multipart_data *
+fetch_about_get_multipart(struct fetch_about_context *ctx)
+{
+ return ctx->multipart;
+}
+
+
+/* exported interface documented in about/private.h */
+bool fetch_about_srverror(struct fetch_about_context *ctx)
+{
+ nserror res;
+
+ fetch_set_http_code(ctx->fetchh, 500);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
+ return false;
+
+ res = fetch_about_ssenddataf(ctx, "Server error 500");
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+}
+
+
+/**
+ * Handler to generate about scheme credits page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_credits_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+
+ /* content is going to return redirect */
+ fetch_set_http_code(ctx->fetchh, 302);
+
+ msg.type = FETCH_REDIRECT;
+ msg.data.redirect = "resource:credits.html";
+
+ fetch_about_send_callback(&msg, ctx);
+
+ return true;
+}
+
+
+/**
+ * Handler to generate about scheme licence page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+
+ /* content is going to return redirect */
+ fetch_set_http_code(ctx->fetchh, 302);
+
+ msg.type = FETCH_REDIRECT;
+ msg.data.redirect = "resource:licence.html";
+
+ fetch_about_send_callback(&msg, ctx);
+
+ return true;
+}
+
+
+/**
+ * Handler to generate about scheme logo page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_logo_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+
+ /* content is going to return redirect */
+ fetch_set_http_code(ctx->fetchh, 302);
+
+ msg.type = FETCH_REDIRECT;
+ msg.data.redirect = "resource:netsurf.png";
+
+ fetch_about_send_callback(&msg, ctx);
+
+ return true;
+}
+
+
+/**
+ * Handler to generate about scheme welcome page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_welcome_handler(struct fetch_about_context *ctx)
+{
+ fetch_msg msg;
+
+ /* content is going to return redirect */
+ fetch_set_http_code(ctx->fetchh, 302);
+
+ msg.type = FETCH_REDIRECT;
+ msg.data.redirect = "resource:welcome.html";
+
+ fetch_about_send_callback(&msg, ctx);
+
+ return true;
+}
+
+
+/* Forward declaration because this handler requires the handler table. */
+static bool fetch_about_about_handler(struct fetch_about_context *ctx);
+
+/**
+ * List of about paths and their handlers
+ */
+struct about_handlers about_handler_list[] = {
+ {
+ "credits",
+ SLEN("credits"),
+ NULL,
+ fetch_about_credits_handler,
+ false
+ },
+ {
+ "licence",
+ SLEN("licence"),
+ NULL,
+ fetch_about_licence_handler,
+ false
+ },
+ {
+ "license",
+ SLEN("license"),
+ NULL,
+ fetch_about_licence_handler,
+ true
+ },
+ {
+ "welcome",
+ SLEN("welcome"),
+ NULL,
+ fetch_about_welcome_handler,
+ false
+ },
+ {
+ "config",
+ SLEN("config"),
+ NULL,
+ fetch_about_config_handler,
+ false
+ },
+ {
+ "Choices",
+ SLEN("Choices"),
+ NULL,
+ fetch_about_choices_handler,
+ false
+ },
+ {
+ "testament",
+ SLEN("testament"),
+ NULL,
+ fetch_about_testament_handler,
+ false
+ },
+ {
+ "about",
+ SLEN("about"),
+ NULL,
+ fetch_about_about_handler,
+ true
+ },
+ {
+ "nscolours.css",
+ SLEN("nscolours.css"),
+ NULL,
+ fetch_about_nscolours_handler,
+ true
+ },
+ {
+ "logo",
+ SLEN("logo"),
+ NULL,
+ fetch_about_logo_handler,
+ true
+ },
+ {
+ /* details about the image cache */
+ "imagecache",
+ SLEN("imagecache"),
+ NULL,
+ fetch_about_imagecache_handler,
+ true
+ },
+ {
+ /* The default blank page */
+ "blank",
+ SLEN("blank"),
+ NULL,
+ fetch_about_blank_handler,
+ true
+ },
+ {
+ /* details about a certificate */
+ "certificate",
+ SLEN("certificate"),
+ NULL,
+ fetch_about_certificate_handler,
+ true
+ },
+ {
+ "query/auth",
+ SLEN("query/auth"),
+ NULL,
+ fetch_about_query_auth_handler,
+ true
+ },
+ {
+ "query/ssl",
+ SLEN("query/ssl"),
+ NULL,
+ fetch_about_query_privacy_handler,
+ true
+ },
+ {
+ "query/timeout",
+ SLEN("query/timeout"),
+ NULL,
+ fetch_about_query_timeout_handler,
+ true
+ },
+ {
+ "query/fetcherror",
+ SLEN("query/fetcherror"),
+ NULL,
+ fetch_about_query_fetcherror_handler,
+ true
+ }
+};
+
+#define about_handler_list_len \
+ (sizeof(about_handler_list) / sizeof(struct about_handlers))
+
+/**
+ * List all the valid about: paths available
+ *
+ * \param ctx The fetch context.
+ * \return true for sucess or false to generate an error.
+ */
+static bool fetch_about_about_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ unsigned int abt_loop = 0;
+
+ /* 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"))
+ goto fetch_about_config_handler_aborted;
+
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>List of NetSurf pages</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\">\n"
+ "<h1 class =\"ns-border\">List of NetSurf pages</h1>\n"
+ "<ul>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
+
+ /* Skip over hidden entries */
+ if (about_handler_list[abt_loop].hidden)
+ continue;
+
+ res = fetch_about_ssenddataf(ctx,
+ "<li><a href=\"about:%s\">about:%s</a></li>\n",
+ about_handler_list[abt_loop].name,
+ about_handler_list[abt_loop].name);
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</ul>\n</body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_config_handler_aborted:
+ return false;
+}
+
+static bool
+fetch_about_404_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+
+ /* content is going to return 404 */
+ fetch_set_http_code(ctx->fetchh, 404);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain; charset=utf-8")) {
+ return false;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "Unknown page: %s", nsurl_access(ctx->url));
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+}
+
+/**
+ * callback to initialise the about scheme fetcher.
+ */
+static bool fetch_about_initialise(lwc_string *scheme)
+{
+ unsigned int abt_loop = 0;
+ lwc_error error;
+
+ for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
+ error = lwc_intern_string(about_handler_list[abt_loop].name,
+ about_handler_list[abt_loop].name_len,
+ &about_handler_list[abt_loop].lname);
+ if (error != lwc_error_ok) {
+ while (abt_loop-- != 0) {
+ lwc_string_unref(about_handler_list[abt_loop].lname);
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * callback to finalise the about scheme fetcher.
+ */
+static void fetch_about_finalise(lwc_string *scheme)
+{
+ unsigned int abt_loop = 0;
+ for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
+ lwc_string_unref(about_handler_list[abt_loop].lname);
+ }
+}
+
+
+static bool fetch_about_can_fetch(const nsurl *url)
+{
+ return true;
+}
+
+
+/**
+ * callback to set up a about scheme fetch.
+ *
+ * \param post_urlenc post data in urlenc format, owned by the llcache object
+ * hence valid the entire lifetime of the fetch.
+ * \param post_multipart post data in multipart format, owned by the llcache
+ * object hence valid the entire lifetime of the fetch.
+ */
+static void *
+fetch_about_setup(struct fetch *fetchh,
+ nsurl *url,
+ bool only_2xx,
+ bool downgrade_tls,
+ const char *post_urlenc,
+ const struct fetch_multipart_data *post_multipart,
+ const char **headers)
+{
+ struct fetch_about_context *ctx;
+ unsigned int handler_loop;
+ lwc_string *path;
+ bool match;
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ path = nsurl_get_component(url, NSURL_PATH);
+
+ for (handler_loop = 0;
+ handler_loop < about_handler_list_len;
+ handler_loop++) {
+ if (lwc_string_isequal(path,
+ about_handler_list[handler_loop].lname,
+ &match) == lwc_error_ok && match) {
+ ctx->handler = about_handler_list[handler_loop].handler;
+ break;
+ }
+ }
+
+ if (path != NULL)
+ lwc_string_unref(path);
+
+ ctx->fetchh = fetchh;
+ ctx->url = nsurl_ref(url);
+ ctx->multipart = post_multipart;
+
+ RING_INSERT(ring, ctx);
+
+ return ctx;
+}
+
+
+/**
+ * callback to free a about scheme fetch
+ */
+static void fetch_about_free(void *ctx)
+{
+ struct fetch_about_context *c = ctx;
+ nsurl_unref(c->url);
+ free(ctx);
+}
+
+
+/**
+ * callback to start an about scheme fetch
+ */
+static bool fetch_about_start(void *ctx)
+{
+ return true;
+}
+
+
+/**
+ * callback to abort a about fetch
+ */
+static void fetch_about_abort(void *ctx)
+{
+ struct fetch_about_context *c = ctx;
+
+ /* To avoid the poll loop having to deal with the fetch context
+ * disappearing from under it, we simply flag the abort here.
+ * The poll loop itself will perform the appropriate cleanup.
+ */
+ c->aborted = true;
+}
+
+
+/**
+ * callback to poll for additional about fetch contents
+ */
+static void fetch_about_poll(lwc_string *scheme)
+{
+ struct fetch_about_context *c, *save_ring = NULL;
+
+ /* Iterate over ring, processing each pending fetch */
+ while (ring != NULL) {
+ /* Take the first entry from the ring */
+ c = ring;
+ RING_REMOVE(ring, c);
+
+ /* Ignore fetches that have been flagged as locked.
+ * This allows safe re-entrant calls to this function.
+ * Re-entrancy can occur if, as a result of a callback,
+ * the interested party causes fetch_poll() to be called
+ * again.
+ */
+ if (c->locked == true) {
+ RING_INSERT(save_ring, c);
+ continue;
+ }
+
+ /* Only process non-aborted fetches */
+ if (c->aborted == false) {
+ /* about fetches can be processed in one go */
+ if (c->handler == NULL) {
+ fetch_about_404_handler(c);
+ } else {
+ c->handler(c);
+ }
+ }
+
+ /* And now finish */
+ fetch_remove_from_queues(c->fetchh);
+ fetch_free(c->fetchh);
+ }
+
+ /* Finally, if we saved any fetches which were locked, put them back
+ * into the ring for next time
+ */
+ ring = save_ring;
+}
+
+
+nserror fetch_about_register(void)
+{
+ lwc_string *scheme = lwc_string_ref(corestring_lwc_about);
+ const struct fetcher_operation_table fetcher_ops = {
+ .initialise = fetch_about_initialise,
+ .acceptable = fetch_about_can_fetch,
+ .setup = fetch_about_setup,
+ .start = fetch_about_start,
+ .abort = fetch_about_abort,
+ .free = fetch_about_free,
+ .poll = fetch_about_poll,
+ .finalise = fetch_about_finalise
+ };
+
+ return fetcher_add(scheme, &fetcher_ops);
+}
diff --git a/content/fetchers/about.h b/content/fetchers/about/about.h
similarity index 85%
rename from content/fetchers/about.h
rename to content/fetchers/about/about.h
index 944f84a..bf63797 100644
--- a/content/fetchers/about.h
+++ b/content/fetchers/about/about.h
@@ -16,12 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * about: URL method handler
+/**
+ * \file
+ * about scheme URL method handler
*/
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_ABOUT_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_ABOUT_H
/**
* Register about scheme handler.
diff --git a/content/fetchers/file/file.h b/content/fetchers/about/atestament.h
similarity index 62%
copy from content/fetchers/file/file.h
copy to content/fetchers/about/atestament.h
index 5a5cfe8..1851e8f 100644
--- a/content/fetchers/file/file.h
+++ b/content/fetchers/about/atestament.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
* This file is part of NetSurf.
*
@@ -18,17 +18,18 @@
/**
* \file
- * file scheme fetcher handler interface.
+ * about scheme testament handler interface
*/
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_TESTAMENT_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_TESTAMENT_H
/**
- * Register file scheme handler.
+ * Handler to generate about scheme testament page.
*
- * \return NSERROR_OK on successful registration or error code on failure.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-nserror fetch_file_register(void);
+bool fetch_about_testament_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/blank.c b/content/fetchers/about/blank.c
new file mode 100644
index 0000000..b7ba52e
--- /dev/null
+++ b/content/fetchers/about/blank.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme blank page
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "netsurf/types.h"
+#include "utils/errors.h"
+
+#include "private.h"
+#include "blank.h"
+
+/**
+ * Handler to generate about scheme cache page.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_blank_handler(struct fetch_about_context *ctx)
+{
+ const char buffer[2] = { ' ', '\0' };
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_about_blank_handler_aborted;
+
+ fetch_about_senddata(ctx, (const uint8_t *) buffer, strlen(buffer));
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_blank_handler_aborted:
+ return false;
+}
diff --git a/content/fetchers/file/file.h b/content/fetchers/about/blank.h
similarity index 63%
copy from content/fetchers/file/file.h
copy to content/fetchers/about/blank.h
index 5a5cfe8..09dcc1f 100644
--- a/content/fetchers/file/file.h
+++ b/content/fetchers/about/blank.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
* This file is part of NetSurf.
*
@@ -18,17 +18,18 @@
/**
* \file
- * file scheme fetcher handler interface.
+ * about scheme blank handler interface
*/
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_BLANK_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_BLANK_H
/**
- * Register file scheme handler.
+ * Handler to generate about scheme blank page.
*
- * \return NSERROR_OK on successful registration or error code on failure.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-nserror fetch_file_register(void);
+bool fetch_about_blank_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/certificate.c b/content/fetchers/about/certificate.c
new file mode 100644
index 0000000..0d0d6f5
--- /dev/null
+++ b/content/fetchers/about/certificate.c
@@ -0,0 +1,1189 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme certificate page
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "netsurf/inttypes.h"
+#include "netsurf/ssl_certs.h"
+
+#include "private.h"
+#include "certificate.h"
+
+/**
+ * certificate name parameters
+ */
+struct ns_cert_name {
+ char *common_name;
+ char *organisation;
+ char *organisation_unit;
+ char *locality;
+ char *province;
+ char *country;
+};
+
+/**
+ * Certificate public key parameters
+ */
+struct ns_cert_pkey {
+ char *algor;
+ int size;
+ char *modulus;
+ char *exponent;
+ char *curve;
+ char *public;
+};
+
+/**
+ * Certificate subject alternative name
+ */
+struct ns_cert_san {
+ struct ns_cert_san *next;
+ char *name;
+};
+
+/**
+ * certificate information for certificate chain
+ */
+struct ns_cert_info {
+ struct ns_cert_name subject_name; /**< Subject details */
+ struct ns_cert_name issuer_name; /**< Issuer details */
+ struct ns_cert_pkey public_key; /**< public key details */
+ long version; /**< Certificate version */
+ char *not_before; /**< Valid from date */
+ char *not_after; /**< Valid to date */
+ int sig_type; /**< Signature type */
+ char *sig_algor; /**< Signature Algorithm */
+ char *serialnum; /**< Serial number */
+ char *sha1fingerprint; /**< fingerprint shar1 encoded */
+ char *sha256fingerprint; /**< fingerprint shar256 encoded */
+ struct ns_cert_san *san; /**< subject alternative names */
+ ssl_cert_err err; /**< Whatever is wrong with this certificate */
+};
+
+/**
+ * free all resources associated with a certificate information structure
+ */
+static nserror free_ns_cert_info(struct ns_cert_info *cinfo)
+{
+ struct ns_cert_san *san;
+
+ free(cinfo->subject_name.common_name);
+ free(cinfo->subject_name.organisation);
+ free(cinfo->subject_name.organisation_unit);
+ free(cinfo->subject_name.locality);
+ free(cinfo->subject_name.province);
+ free(cinfo->subject_name.country);
+ free(cinfo->issuer_name.common_name);
+ free(cinfo->issuer_name.organisation);
+ free(cinfo->issuer_name.organisation_unit);
+ free(cinfo->issuer_name.locality);
+ free(cinfo->issuer_name.province);
+ free(cinfo->issuer_name.country);
+ free(cinfo->public_key.algor);
+ free(cinfo->public_key.modulus);
+ free(cinfo->public_key.exponent);
+ free(cinfo->public_key.curve);
+ free(cinfo->public_key.public);
+ free(cinfo->not_before);
+ free(cinfo->not_after);
+ free(cinfo->sig_algor);
+ free(cinfo->serialnum);
+
+ /* free san list avoiding use after free */
+ san = cinfo->san;
+ while (san != NULL) {
+ struct ns_cert_san *next;
+ next = san->next;
+ free(san);
+ san = next;
+ }
+
+ free(cinfo);
+
+ return NSERROR_OK;
+}
+
+#ifdef WITH_OPENSSL
+
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+
+/* OpenSSL 1.0.x, 1.0.2, 1.1.0 and 1.1.1 API all changed
+ * LibreSSL declares its OpenSSL version as 2.1 but only supports 1.0.x API
+ */
+#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL))
+/* 1.0.x */
+
+#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1000200fL))
+/* pre 1.0.2 */
+static int ns_X509_get_signature_nid(X509 *cert)
+{
+ return OBJ_obj2nid(cert->cert_info->key->algor->algorithm);
+}
+#else
+#define ns_X509_get_signature_nid X509_get_signature_nid
+#endif
+
+static const unsigned char *ns_ASN1_STRING_get0_data(ASN1_STRING *asn1str)
+{
+ return (const unsigned char *)ASN1_STRING_data(asn1str);
+}
+
+static const BIGNUM *ns_RSA_get0_n(const RSA *d)
+{
+ return d->n;
+}
+
+static const BIGNUM *ns_RSA_get0_e(const RSA *d)
+{
+ return d->e;
+}
+
+static int ns_RSA_bits(const RSA *rsa)
+{
+ return RSA_size(rsa) * 8;
+}
+
+static int ns_DSA_bits(const DSA *dsa)
+{
+ return DSA_size(dsa) * 8;
+}
+
+static int ns_DH_bits(const DH *dh)
+{
+ return DH_size(dh) * 8;
+}
+
+#elif (OPENSSL_VERSION_NUMBER < 0x1010100fL)
+/* 1.1.0 */
+#define ns_X509_get_signature_nid X509_get_signature_nid
+#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
+
+static const BIGNUM *ns_RSA_get0_n(const RSA *r)
+{
+ const BIGNUM *n;
+ const BIGNUM *e;
+ const BIGNUM *d;
+ RSA_get0_key(r, &n, &e, &d);
+ return n;
+}
+
+static const BIGNUM *ns_RSA_get0_e(const RSA *r)
+{
+ const BIGNUM *n;
+ const BIGNUM *e;
+ const BIGNUM *d;
+ RSA_get0_key(r, &n, &e, &d);
+ return e;
+}
+
+#define ns_RSA_bits RSA_bits
+#define ns_DSA_bits DSA_bits
+#define ns_DH_bits DH_bits
+
+#else
+/* 1.1.1 and later */
+#define ns_X509_get_signature_nid X509_get_signature_nid
+#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data
+#define ns_RSA_get0_n RSA_get0_n
+#define ns_RSA_get0_e RSA_get0_e
+#define ns_RSA_bits RSA_bits
+#define ns_DSA_bits DSA_bits
+#define ns_DH_bits DH_bits
+#endif
+
+/**
+ * extract certificate name information
+ *
+ * \param xname The X509 name to convert. The reference is borrowed so is not freeed
+ * \param iname The info structure to recive the extracted parameters.
+ * \return NSERROR_OK on success else error code
+ */
+static nserror
+xname_to_info(X509_NAME *xname, struct ns_cert_name *iname)
+{
+ int entryidx;
+ int entrycnt;
+ X509_NAME_ENTRY *entry; /* current name entry */
+ ASN1_STRING *value;
+ const unsigned char *value_str;
+ ASN1_OBJECT *name;
+ int name_nid;
+ char **field;
+
+ entrycnt = X509_NAME_entry_count(xname);
+
+ for (entryidx = 0; entryidx < entrycnt; entryidx++) {
+ entry = X509_NAME_get_entry(xname, entryidx);
+ name = X509_NAME_ENTRY_get_object(entry);
+ name_nid = OBJ_obj2nid(name);
+ value = X509_NAME_ENTRY_get_data(entry);
+ value_str = ns_ASN1_STRING_get0_data(value);
+ switch (name_nid) {
+ case NID_commonName:
+ field = &iname->common_name;
+ break;
+ case NID_countryName:
+ field = &iname->country;
+ break;
+ case NID_localityName:
+ field = &iname->locality;
+ break;
+ case NID_stateOrProvinceName:
+ field = &iname->province;
+ break;
+ case NID_organizationName:
+ field = &iname->organisation;
+ break;
+ case NID_organizationalUnitName:
+ field = &iname->organisation_unit;
+ break;
+ default :
+ field = NULL;
+ break;
+ }
+ if (field != NULL) {
+ *field = strdup((const char *)value_str);
+ NSLOG(netsurf, DEEPDEBUG,
+ "NID:%d value: %s", name_nid, *field);
+ } else {
+ NSLOG(netsurf, DEEPDEBUG, "NID:%d", name_nid);
+ }
+ }
+
+ /*
+ * ensure the common name is set to something, this being
+ * missing means the certificate is broken but this should be
+ * robust in the face of bad data
+ */
+ if (iname->common_name == NULL) {
+ iname->common_name = strdup("Unknown");
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * duplicate a hex formatted string inserting the colons
+ *
+ * \todo only uses html entity as separator because netsurfs line breaking
+ * fails otherwise.
+ */
+static char *hexdup(const char *hex)
+{
+ int hexlen;
+ char *dst;
+ char *out;
+ int cn = 0;
+
+ hexlen = strlen(hex);
+ /* allow space fox XXYY to XX:YY: */
+ dst = malloc(((hexlen * 7) + 6) / 2);
+
+ if (dst != NULL) {
+ for (out = dst; *hex != 0; hex++) {
+ if (cn == 2) {
+ cn = 0;
+ *out++ = '&';
+ *out++ = '#';
+ *out++ = '5';
+ *out++ = '8';
+ *out++ = ';';
+ }
+ *out++ = *hex;
+ cn++;
+ }
+ *out = 0;
+ }
+ return dst;
+}
+
+
+/**
+ * create a hex formatted string inserting the colons from binary data
+ *
+ * \todo only uses html entity as separator because netsurfs line breaking
+ * fails otherwise.
+ */
+static char *bindup(unsigned char *bin, unsigned int binlen)
+{
+ char *dst;
+ char *out;
+ unsigned int idx;
+ const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ /* allow space fox XY to expand to XX:YY: */
+ dst = malloc(binlen * 7);
+
+ if (dst != NULL) {
+ out = dst;
+ for (idx = 0; idx < binlen; idx++) {
+ *out++ = hex[(bin[idx] & 0xf0) >> 4];
+ *out++ = hex[bin[idx] & 0xf];
+
+ *out++ = '&';
+ *out++ = '#';
+ *out++ = '5';
+ *out++ = '8';
+ *out++ = ';';
+ }
+ out -= 5;
+ *out = 0;
+ }
+ return dst;
+}
+
+
+/**
+ * extract RSA key information to info structure
+ *
+ * \param rsa The RSA key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+rsa_to_info(RSA *rsa, struct ns_cert_pkey *ikey)
+{
+ char *tmp;
+
+ if (rsa == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("RSA");
+
+ ikey->size = ns_RSA_bits(rsa);
+
+ tmp = BN_bn2hex(ns_RSA_get0_n(rsa));
+ if (tmp != NULL) {
+ ikey->modulus = hexdup(tmp);
+ OPENSSL_free(tmp);
+ }
+
+ tmp = BN_bn2dec(ns_RSA_get0_e(rsa));
+ if (tmp != NULL) {
+ ikey->exponent = strdup(tmp);
+ OPENSSL_free(tmp);
+ }
+
+ RSA_free(rsa);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract DSA key information to info structure
+ *
+ * \param dsa The RSA key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+dsa_to_info(DSA *dsa, struct ns_cert_pkey *ikey)
+{
+ if (dsa == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("DSA");
+
+ ikey->size = ns_DSA_bits(dsa);
+
+ DSA_free(dsa);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract DH key information to info structure
+ *
+ * \param dsa The RSA key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+dh_to_info(DH *dh, struct ns_cert_pkey *ikey)
+{
+ if (dh == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("Diffie Hellman");
+
+ ikey->size = ns_DH_bits(dh);
+
+ DH_free(dh);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract EC key information to info structure
+ *
+ * \param ec The EC key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+ec_to_info(EC_KEY *ec, struct ns_cert_pkey *ikey)
+{
+ const EC_GROUP *ecgroup;
+ const EC_POINT *ecpoint;
+ BN_CTX *bnctx;
+ char *ecpoint_hex;
+
+ if (ec == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ikey->algor = strdup("Elliptic Curve");
+
+ ecgroup = EC_KEY_get0_group(ec);
+
+ if (ecgroup != NULL) {
+ ikey->size = EC_GROUP_get_degree(ecgroup);
+
+ ikey->curve = strdup(OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)));
+
+ ecpoint = EC_KEY_get0_public_key(ec);
+ if (ecpoint != NULL) {
+ bnctx = BN_CTX_new();
+ ecpoint_hex = EC_POINT_point2hex(ecgroup,
+ ecpoint,
+ POINT_CONVERSION_UNCOMPRESSED,
+ bnctx);
+ ikey->public = hexdup(ecpoint_hex);
+ OPENSSL_free(ecpoint_hex);
+ BN_CTX_free(bnctx);
+ }
+ }
+ EC_KEY_free(ec);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * extract public key information to info structure
+ *
+ * \param pkey the public key to examine. The reference is dropped on return
+ * \param ikey The public key info structure to fill
+ * \rerun NSERROR_OK on success else error code.
+ */
+static nserror
+pkey_to_info(EVP_PKEY *pkey, struct ns_cert_pkey *ikey)
+{
+ nserror res;
+
+ if (pkey == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ switch (EVP_PKEY_base_id(pkey)) {
+ case EVP_PKEY_RSA:
+ res = rsa_to_info(EVP_PKEY_get1_RSA(pkey), ikey);
+ break;
+
+ case EVP_PKEY_DSA:
+ res = dsa_to_info(EVP_PKEY_get1_DSA(pkey), ikey);
+ break;
+
+ case EVP_PKEY_DH:
+ res = dh_to_info(EVP_PKEY_get1_DH(pkey), ikey);
+ break;
+
+ case EVP_PKEY_EC:
+ res = ec_to_info(EVP_PKEY_get1_EC_KEY(pkey), ikey);
+ break;
+
+ default:
+ res = NSERROR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ EVP_PKEY_free(pkey);
+
+ return res;
+}
+
+static nserror san_to_info(X509 *cert, struct ns_cert_san **prev_next)
+{
+ int idx;
+ int san_names_nb = -1;
+ const GENERAL_NAME *current_name;
+ const unsigned char *dns_name;
+ struct ns_cert_san *isan;
+
+ STACK_OF(GENERAL_NAME) *san_names = NULL;
+
+ san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+ if (san_names == NULL) {
+ return NSERROR_OK;
+ }
+
+ san_names_nb = sk_GENERAL_NAME_num(san_names);
+
+ /* Check each name within the extension */
+ for (idx = 0; idx < san_names_nb; idx++) {
+ current_name = sk_GENERAL_NAME_value(san_names, idx);
+
+ if (current_name->type == GEN_DNS) {
+ /* extract DNS name into info structure */
+ dns_name = ns_ASN1_STRING_get0_data(current_name->d.dNSName);
+
+ isan = malloc(sizeof(struct ns_cert_san));
+ if (isan != NULL) {
+ isan->name = strdup((const char *)dns_name);
+ isan->next = NULL;
+ *prev_next = isan;
+ prev_next = &isan->next;
+ }
+ }
+ }
+
+ /* AmiSSL can't cope with the "correct" mechanism of freeing
+ * the GENERAL_NAME stack, which is:
+ * sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+ * So instead we do this open-coded loop which does the same:
+ */
+ for (idx = 0; idx < san_names_nb; idx++) {
+ GENERAL_NAME *entry = sk_GENERAL_NAME_pop(san_names);
+ GENERAL_NAME_free(entry);
+ }
+ sk_GENERAL_NAME_free(san_names);
+
+ return NSERROR_OK;
+}
+
+static nserror
+der_to_certinfo(const uint8_t *der,
+ size_t der_length,
+ struct ns_cert_info *info)
+{
+ BIO *mem;
+ BUF_MEM *buf;
+ const ASN1_INTEGER *asn1_num;
+ BIGNUM *bignum;
+ X509 *cert; /**< Pointer to certificate */
+
+ if (der == NULL) {
+ return NSERROR_OK;
+ }
+
+ cert = d2i_X509(NULL, &der, der_length);
+ if (cert == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ /*
+ * get certificate version
+ *
+ * \note this is defined by standards (X.509 et al) to be one
+ * less than the certificate version.
+ */
+ info->version = X509_get_version(cert) + 1;
+
+ /* not before date */
+ mem = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(mem, X509_get_notBefore(cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ info->not_before = calloc(1, buf->length + 1);
+ if (info->not_before != NULL) {
+ memcpy(info->not_before, buf->data, (unsigned)buf->length);
+ }
+ BUF_MEM_free(buf);
+
+ /* not after date */
+ mem = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(mem,
+ X509_get_notAfter(cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ info->not_after = calloc(1, buf->length + 1);
+ if (info->not_after != NULL) {
+ memcpy(info->not_after, buf->data, (unsigned)buf->length);
+ }
+ BUF_MEM_free(buf);
+
+ /* signature type */
+ info->sig_type = X509_get_signature_type(cert);
+
+ /* signature algorithm */
+ int pkey_nid = ns_X509_get_signature_nid(cert);
+ if (pkey_nid != NID_undef) {
+ const char* sslbuf = OBJ_nid2ln(pkey_nid);
+ if (sslbuf != NULL) {
+ info->sig_algor = strdup(sslbuf);
+ }
+ }
+
+ /* serial number */
+ asn1_num = X509_get_serialNumber(cert);
+ if (asn1_num != NULL) {
+ bignum = ASN1_INTEGER_to_BN(asn1_num, NULL);
+ if (bignum != NULL) {
+ char *tmp = BN_bn2hex(bignum);
+ if (tmp != NULL) {
+ info->serialnum = hexdup(tmp);
+ OPENSSL_free(tmp);
+ }
+ BN_free(bignum);
+ bignum = NULL;
+ }
+ }
+
+ /* fingerprints */
+ const EVP_MD *digest;
+ unsigned int dig_len;
+ unsigned char *buff;
+ int rc;
+
+ digest = EVP_sha1();
+ buff = malloc(EVP_MD_size(digest));
+ if (buff != NULL) {
+ rc = X509_digest(cert, digest, buff, &dig_len);
+ if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
+ info->sha1fingerprint = bindup(buff, dig_len);
+ }
+ free(buff);
+ }
+
+ digest = EVP_sha256();
+ buff = malloc(EVP_MD_size(digest));
+ if (buff != NULL) {
+ rc = X509_digest(cert, digest, buff, &dig_len);
+ if ((rc == 1) && (dig_len == (unsigned int)EVP_MD_size(digest))) {
+ info->sha256fingerprint = bindup(buff, dig_len);
+ }
+ free(buff);
+ }
+
+ /* subject alternative names */
+ san_to_info(cert, &info->san);
+
+ /* issuer name */
+ xname_to_info(X509_get_issuer_name(cert), &info->issuer_name);
+
+ /* subject */
+ xname_to_info(X509_get_subject_name(cert), &info->subject_name);
+
+ /* public key */
+ pkey_to_info(X509_get_pubkey(cert), &info->public_key);
+
+ X509_free(cert);
+
+ return NSERROR_OK;
+}
+
+/* copy certificate data */
+static nserror
+convert_chain_to_cert_info(const struct cert_chain *chain,
+ struct ns_cert_info **cert_info_out)
+{
+ struct ns_cert_info *certs;
+ size_t depth;
+ nserror res;
+
+ certs = calloc(chain->depth, sizeof(struct ns_cert_info));
+ if (certs == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ for (depth = 0; depth < chain->depth;depth++) {
+ res = der_to_certinfo(chain->certs[depth].der,
+ chain->certs[depth].der_length,
+ certs + depth);
+ if (res != NSERROR_OK) {
+ free(certs);
+ return res;
+ }
+ certs[depth].err = chain->certs[depth].err;
+ }
+
+ *cert_info_out = certs;
+ return NSERROR_OK;
+}
+
+#else
+static nserror
+convert_chain_to_cert_info(const struct cert_chain *chain,
+ struct ns_cert_info **cert_info_out)
+{
+ return NSERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+
+static nserror
+format_certificate_name(struct fetch_about_context *ctx,
+ struct ns_cert_name *cert_name)
+{
+ nserror res;
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Common Name</th><td>%s</td></tr>\n",
+ cert_name->common_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_name->organisation != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Organisation</th><td>%s</td></tr>\n",
+ cert_name->organisation);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->organisation_unit != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Organisation Unit</th><td>%s</td></tr>\n",
+ cert_name->organisation_unit);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->locality != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Locality</th><td>%s</td></tr>\n",
+ cert_name->locality);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->province != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Privince</th><td>%s</td></tr>\n",
+ cert_name->province);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_name->country != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Country</th><td>%s</td></tr>\n",
+ cert_name->country);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ return res;
+}
+
+/**
+ * output formatted certificate subject alternate names
+ */
+static nserror
+format_certificate_san(struct fetch_about_context *ctx,
+ struct ns_cert_san *san)
+{
+ nserror res;
+
+ if (san == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Alternative Names</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ while (san != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>DNS Name</th><td>%s</td></tr>\n",
+ san->name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ san = san->next;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</table>\n");
+
+ return res;
+
+}
+
+
+static nserror
+format_certificate_public_key(struct fetch_about_context *ctx,
+ struct ns_cert_pkey *public_key)
+{
+ nserror res;
+
+ if (public_key->algor == NULL) {
+ /* skip the table if no algorithm name */
+ return NSERROR_OK;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Public Key</th><td><hr></td></tr>\n"
+ "<tr><th>Algorithm</th><td>%s</td></tr>\n"
+ "<tr><th>Key Size</th><td>%d</td></tr>\n",
+ public_key->algor,
+ public_key->size);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+
+ if (public_key->exponent != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Exponent</th><td>%s</td></tr>\n",
+ public_key->exponent);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (public_key->modulus != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Modulus</th><td class=\"data\">%s</td></tr>\n",
+ public_key->modulus);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (public_key->curve != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Curve</th><td>%s</td></tr>\n",
+ public_key->curve);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (public_key->public != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Public Value</th><td>%s</td></tr>\n",
+ public_key->public);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</table>\n");
+
+ return res;
+}
+
+static nserror
+format_certificate_fingerprint(struct fetch_about_context *ctx,
+ struct ns_cert_info *cert_info)
+{
+ nserror res;
+
+ if ((cert_info->sha1fingerprint == NULL) &&
+ (cert_info->sha256fingerprint == NULL)) {
+ /* skip the table if no fingerprints */
+ return NSERROR_OK;
+ }
+
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Fingerprints</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_info->sha256fingerprint != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>SHA-256</th><td class=\"data\">%s</td></tr>\n",
+ cert_info->sha256fingerprint);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_info->sha1fingerprint != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>SHA-1</th><td class=\"data\">%s</td></tr>\n",
+ cert_info->sha1fingerprint);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</table>\n");
+
+ return res;
+}
+
+static nserror
+format_certificate(struct fetch_about_context *ctx,
+ struct ns_cert_info *cert_info,
+ size_t depth)
+{
+ nserror res;
+
+ res = fetch_about_ssenddataf(ctx,
+ "<h2 id=\"%"PRIsizet"\" class=\"ns-border\">%s</h2>\n",
+ depth, cert_info->subject_name.common_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_info->err != SSL_CERT_ERR_OK) {
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr class=\"ns-even-fg-bad\">"
+ "<th>Fault</th>"
+ "<td>%s</td>"
+ "</tr>"
+ "</table>\n",
+ messages_get_sslcode(cert_info->err));
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Issued To</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_name(ctx, &cert_info->subject_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "</table>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Issued By</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_name(ctx, &cert_info->issuer_name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "</table>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Validity</th><td><hr></td></tr>\n"
+ "<tr><th>Valid From</th><td>%s</td></tr>\n"
+ "<tr><th>Valid Until</th><td>%s</td></tr>\n"
+ "</table>\n",
+ cert_info->not_before,
+ cert_info->not_after);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_san(ctx, cert_info->san);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_public_key(ctx, &cert_info->public_key);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Miscellaneous</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if (cert_info->serialnum != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Serial Number</th><td>%s</td></tr>\n",
+ cert_info->serialnum);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ if (cert_info->sig_algor != NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Signature Algorithm</th>"
+ "<td>%s</td></tr>\n",
+ cert_info->sig_algor);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<tr><th>Version</th><td>%ld</td></tr>\n"
+ "</table>\n",
+ cert_info->version);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = format_certificate_fingerprint(ctx, cert_info);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ return res;
+}
+
+/**
+ * Handler to generate about:certificate page.
+ *
+ * Shows details of a certificate chain
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
+{
+ int code = 200;
+ nserror res;
+ struct cert_chain *chain = NULL;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_about_certificate_handler_aborted;
+
+ /* page head */
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>NetSurf Browser Certificate Viewer</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body id=\"certificate\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
+ "<h1 class=\"ns-border\">Certificate</h1>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ res = cert_chain_from_query(fetch_about_get_url(ctx), &chain);
+ if (res != NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<p>Could not process that</p>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+ } else {
+ struct ns_cert_info *cert_info;
+ res = convert_chain_to_cert_info(chain, &cert_info);
+ if (res == NSERROR_OK) {
+ size_t depth;
+ res = fetch_about_ssenddataf(ctx, "<ul>\n");
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ for (depth = 0; depth < chain->depth; depth++) {
+ res = fetch_about_ssenddataf(ctx, "<li><a href=\"#%"PRIsizet"\">%s</a></li>\n",
+ depth, (cert_info + depth)
+ ->subject_name
+ .common_name);
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</ul>\n");
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ for (depth = 0; depth < chain->depth; depth++) {
+ res = format_certificate(ctx, cert_info + depth,
+ depth);
+ if (res != NSERROR_OK) {
+ free_ns_cert_info(cert_info);
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ }
+ free_ns_cert_info(cert_info);
+
+ } else {
+ res = fetch_about_ssenddataf(ctx,
+ "<p>Invalid certificate data</p>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+ }
+ }
+
+
+ /* page footer */
+ res = fetch_about_ssenddataf(ctx, "</body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_certificate_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ cert_chain_free(chain);
+
+ return true;
+
+fetch_about_certificate_handler_aborted:
+ cert_chain_free(chain);
+ return false;
+}
diff --git a/content/handlers/html/box_special.h b/content/fetchers/about/certificate.h
similarity index 61%
copy from content/handlers/html/box_special.h
copy to content/fetchers/about/certificate.h
index 973ab97..80ac068 100644
--- a/content/handlers/html/box_special.h
+++ b/content/fetchers/about/certificate.h
@@ -1,7 +1,7 @@
/*
* Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
- * This file is part of NetSurf, http://www.netsurf-browser.org/
+ * This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,18 +18,18 @@
/**
* \file
- * HTML Box tree construction special element conversion interface.
+ * about scheme certificate handler interface
*/
-#ifndef NETSURF_HTML_BOX_SPECIAL_H
-#define NETSURF_HTML_BOX_SPECIAL_H
-
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_CERTIFICATE_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_CERTIFICATE_H
/**
- * call an elements special conversion handler
+ * Handler to generate about scheme certificate page.
*
- * \return true if box construction should continue else false on error.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-bool convert_special_elements(dom_node *node, html_content *content, struct box *box, bool *convert_children);
+bool fetch_about_certificate_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/choices.c b/content/fetchers/about/choices.c
new file mode 100644
index 0000000..a95502e
--- /dev/null
+++ b/content/fetchers/about/choices.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme blank page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include "netsurf/types.h"
+#include "utils/errors.h"
+#include "utils/nsoption.h"
+
+#include "private.h"
+#include "choices.h"
+
+/**
+ * Generate the text of a Choices file which represents the current
+ * in use options.
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_choices_handler(struct fetch_about_context *ctx)
+{
+ char buffer[1024];
+ int code = 200;
+ int slen;
+ unsigned int opt_loop = 0;
+ int res = 0;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
+ goto fetch_about_choices_handler_aborted;
+
+ slen = snprintf(buffer, sizeof buffer,
+ "# Automatically generated current NetSurf browser Choices\n");
+
+ do {
+ res = nsoption_snoptionf(buffer + slen,
+ sizeof buffer - slen,
+ opt_loop,
+ "%k:%v\n");
+ if (res <= 0)
+ break; /* last option */
+
+ if (res >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_choices_handler_aborted;
+ }
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += res;
+ opt_loop++;
+ }
+ } while (res > 0);
+
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_choices_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_choices_handler_aborted:
+ return false;
+}
diff --git a/content/fetchers/file/file.h b/content/fetchers/about/choices.h
similarity index 62%
copy from content/fetchers/file/file.h
copy to content/fetchers/about/choices.h
index 5a5cfe8..0548f5b 100644
--- a/content/fetchers/file/file.h
+++ b/content/fetchers/about/choices.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
* This file is part of NetSurf.
*
@@ -18,17 +18,18 @@
/**
* \file
- * file scheme fetcher handler interface.
+ * about scheme choices handler interface
*/
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_CHOICES_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_CHOICES_H
/**
- * Register file scheme handler.
+ * Handler to generate about scheme choices page.
*
- * \return NSERROR_OK on successful registration or error code on failure.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-nserror fetch_file_register(void);
+bool fetch_about_choices_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/config.c b/content/fetchers/about/config.c
new file mode 100644
index 0000000..a18af95
--- /dev/null
+++ b/content/fetchers/about/config.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme blank page
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "netsurf/types.h"
+#include "utils/errors.h"
+#include "utils/nsoption.h"
+
+#include "private.h"
+#include "config.h"
+
+/**
+ * Handler to generate about scheme config page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_config_handler(struct fetch_about_context *ctx)
+{
+ char buffer[1024];
+ int slen = 0;
+ unsigned int opt_loop = 0;
+ int elen = 0; /* entry length */
+ nserror res;
+ bool even = false;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html")) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>NetSurf Browser Config</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body "
+ "id =\"configlist\" "
+ "class=\"ns-even-bg ns-even-fg ns-border\" "
+ "style=\"overflow: hidden;\">\n"
+ "<h1 class=\"ns-border\">NetSurf Browser Config</h1>\n"
+ "<table class=\"config\">\n"
+ "<tr><th>Option</th>"
+ "<th>Type</th>"
+ "<th>Provenance</th>"
+ "<th>Setting</th></tr>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+
+ do {
+ if (even) {
+ elen = nsoption_snoptionf(buffer + slen,
+ sizeof buffer - slen,
+ opt_loop,
+ "<tr class=\"ns-even-bg\">"
+ "<th class=\"ns-border\">%k</th>"
+ "<td class=\"ns-border\">%t</td>"
+ "<td class=\"ns-border\">%p</td>"
+ "<td class=\"ns-border\">%V</td>"
+ "</tr>\n");
+ } else {
+ elen = nsoption_snoptionf(buffer + slen,
+ sizeof buffer - slen,
+ opt_loop,
+ "<tr class=\"ns-odd-bg\">"
+ "<th class=\"ns-border\">%k</th>"
+ "<td class=\"ns-border\">%t</td>"
+ "<td class=\"ns-border\">%p</td>"
+ "<td class=\"ns-border\">%V</td>"
+ "</tr>\n");
+ }
+ if (elen <= 0)
+ break; /* last option */
+
+ if (elen >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += elen;
+ opt_loop++;
+ even = !even;
+ }
+ } while (elen > 0);
+
+ slen += snprintf(buffer + slen, sizeof buffer - slen,
+ "</table>\n</body>\n</html>\n");
+
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_config_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_config_handler_aborted:
+ return false;
+}
diff --git a/content/fetchers/file/file.h b/content/fetchers/about/config.h
similarity index 63%
copy from content/fetchers/file/file.h
copy to content/fetchers/about/config.h
index 5a5cfe8..efef239 100644
--- a/content/fetchers/file/file.h
+++ b/content/fetchers/about/config.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
* This file is part of NetSurf.
*
@@ -18,17 +18,18 @@
/**
* \file
- * file scheme fetcher handler interface.
+ * about scheme config handler interface
*/
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_CONFIG_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_CONFIG_H
/**
- * Register file scheme handler.
+ * Handler to generate about scheme config page.
*
- * \return NSERROR_OK on successful registration or error code on failure.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-nserror fetch_file_register(void);
+bool fetch_about_config_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/imagecache.c b/content/fetchers/about/imagecache.c
new file mode 100644
index 0000000..5e2abcb
--- /dev/null
+++ b/content/fetchers/about/imagecache.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme imagecache page
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "netsurf/types.h"
+
+#include "image/image_cache.h"
+
+#include "private.h"
+#include "imagecache.h"
+
+/* exported interface documented in about/imagecache.h */
+bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
+{
+ char buffer[2048]; /* output buffer */
+ int code = 200;
+ int slen;
+ unsigned int cent_loop = 0;
+ int elen = 0; /* entry length */
+ nserror res;
+ bool even = false;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_about_imagecache_handler_aborted;
+
+ /* page head */
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>Image Cache Status</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body id =\"cachelist\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
+ "<h1 class=\"ns-border\">Image Cache Status</h1>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ /* image cache summary */
+ slen = image_cache_snsummaryf(buffer, sizeof(buffer),
+ "<p>Configured limit of %a hysteresis of %b</p>\n"
+ "<p>Total bitmap size in use %c (in %d)</p>\n"
+ "<p>Age %es</p>\n"
+ "<p>Peak size %f (in %g)</p>\n"
+ "<p>Peak image count %h (size %i)</p>\n"
+ "<p>Cache total/hit/miss/fail (counts) %j/%k/%l/%m "
+ "(%pj%%/%pk%%/%pl%%/%pm%%)</p>\n"
+ "<p>Cache total/hit/miss/fail (size) %n/%o/%q/%r "
+ "(%pn%%/%po%%/%pq%%/%pr%%)</p>\n"
+ "<p>Total images never rendered: %s "
+ "(includes %t that were converted)</p>\n"
+ "<p>Total number of excessive conversions: %u "
+ "(from %v images converted more than once)"
+ "</p>\n"
+ "<p>Bitmap of size %w had most (%x) conversions</p>\n"
+ "<h2 class=\"ns-border\">Current contents</h2>\n");
+ if (slen >= (int) (sizeof(buffer))) {
+ goto fetch_about_imagecache_handler_aborted; /* overflow */
+ }
+
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ /* image cache entry table */
+ res = fetch_about_ssenddataf(ctx, "<p class=\"imagecachelist\">\n"
+ "<strong>"
+ "<span>Entry</span>"
+ "<span>Content Key</span>"
+ "<span>Redraw Count</span>"
+ "<span>Conversion Count</span>"
+ "<span>Last Redraw</span>"
+ "<span>Bitmap Age</span>"
+ "<span>Bitmap Size</span>"
+ "<span>Source</span>"
+ "</strong>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ slen = 0;
+ do {
+ if (even) {
+ elen = image_cache_snentryf(buffer + slen,
+ sizeof buffer - slen,
+ cent_loop,
+ "<a href=\"%U\">"
+ "<span class=\"ns-border\">%e</span>"
+ "<span class=\"ns-border\">%k</span>"
+ "<span class=\"ns-border\">%r</span>"
+ "<span class=\"ns-border\">%c</span>"
+ "<span class=\"ns-border\">%a</span>"
+ "<span class=\"ns-border\">%g</span>"
+ "<span class=\"ns-border\">%s</span>"
+ "<span class=\"ns-border\">%o</span>"
+ "</a>\n");
+ } else {
+ elen = image_cache_snentryf(buffer + slen,
+ sizeof buffer - slen,
+ cent_loop,
+ "<a class=\"ns-odd-bg\" href=\"%U\">"
+ "<span class=\"ns-border\">%e</span>"
+ "<span class=\"ns-border\">%k</span>"
+ "<span class=\"ns-border\">%r</span>"
+ "<span class=\"ns-border\">%c</span>"
+ "<span class=\"ns-border\">%a</span>"
+ "<span class=\"ns-border\">%g</span>"
+ "<span class=\"ns-border\">%s</span>"
+ "<span class=\"ns-border\">%o</span>"
+ "</a>\n");
+ }
+ if (elen <= 0)
+ break; /* last option */
+
+ if (elen >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ res = fetch_about_senddata(ctx,
+ (const uint8_t *)buffer,
+ slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += elen;
+ cent_loop++;
+ even = !even;
+ }
+ } while (elen > 0);
+
+ slen += snprintf(buffer + slen, sizeof buffer - slen,
+ "</p>\n</body>\n</html>\n");
+
+ res = fetch_about_senddata(ctx, (const uint8_t *)buffer, slen);
+ if (res != NSERROR_OK) {
+ goto fetch_about_imagecache_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_imagecache_handler_aborted:
+ return false;
+}
diff --git a/content/handlers/html/box_special.h b/content/fetchers/about/imagecache.h
similarity index 61%
copy from content/handlers/html/box_special.h
copy to content/fetchers/about/imagecache.h
index 973ab97..d1419ce 100644
--- a/content/handlers/html/box_special.h
+++ b/content/fetchers/about/imagecache.h
@@ -1,7 +1,7 @@
/*
* Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
- * This file is part of NetSurf, http://www.netsurf-browser.org/
+ * This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,18 +18,20 @@
/**
* \file
- * HTML Box tree construction special element conversion interface.
+ * about scheme imagecache handler interface
*/
-#ifndef NETSURF_HTML_BOX_SPECIAL_H
-#define NETSURF_HTML_BOX_SPECIAL_H
-
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_IMAGECACHE_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_IMAGECACHE_H
/**
- * call an elements special conversion handler
+ * Handler to generate about scheme imagecache page.
+ *
+ * Shows details of current image cache.
*
- * \return true if box construction should continue else false on error.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-bool convert_special_elements(dom_node *node, html_content *content, struct box *box, bool *convert_children);
+bool fetch_about_imagecache_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/nscolours.c b/content/fetchers/about/nscolours.c
new file mode 100644
index 0000000..bd7a5ed
--- /dev/null
+++ b/content/fetchers/about/nscolours.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "netsurf/plot_style.h"
+
+#include "utils/errors.h"
+#include "utils/nscolour.h"
+
+#include "private.h"
+#include "nscolours.h"
+
+/**
+ * Handler to generate the nscolours stylesheet
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_nscolours_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ const char *stylesheet;
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/css; charset=utf-8")) {
+ goto aborted;
+ }
+
+ res = nscolour_get_stylesheet(&stylesheet);
+ if (res != NSERROR_OK) {
+ goto aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "html {\n"
+ "\tbackground-color: #%06x;\n"
+ "}\n"
+ "%s",
+ colour_rb_swap(nscolours[NSCOLOUR_WIN_ODD_BG]),
+ stylesheet);
+ if (res != NSERROR_OK) {
+ goto aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+aborted:
+
+ return false;
+}
diff --git a/content/fetchers/file/file.h b/content/fetchers/about/nscolours.h
similarity index 62%
copy from content/fetchers/file/file.h
copy to content/fetchers/about/nscolours.h
index 5a5cfe8..a602e4d 100644
--- a/content/fetchers/file/file.h
+++ b/content/fetchers/about/nscolours.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
* This file is part of NetSurf.
*
@@ -18,17 +18,18 @@
/**
* \file
- * file scheme fetcher handler interface.
+ * about scheme nscolours handler interface
*/
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_NSCOLOURS_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_NSCOLOURS_H
/**
- * Register file scheme handler.
+ * Handler to generate the nscolours stylesheet
*
- * \return NSERROR_OK on successful registration or error code on failure.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-nserror fetch_file_register(void);
+bool fetch_about_nscolours_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/private.h b/content/fetchers/about/private.h
new file mode 100644
index 0000000..fcf9b19
--- /dev/null
+++ b/content/fetchers/about/private.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Private interfaces for the about scheme fetcher.
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_PRIVATE_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_PRIVATE_H
+
+struct fetch_about_context;
+struct fetch_multipart_data;
+
+/**
+ * set http response code on about response
+ */
+bool fetch_about_set_http_code(struct fetch_about_context *ctx, long code);
+
+/**
+ * Send a header on the about response
+ *
+ * \param ctx The about fetch context
+ * \param fmt The format specifier of the header
+ * \return true if the fetch has been aborted else false
+ */
+bool fetch_about_send_header(struct fetch_about_context *ctx, const char *fmt, ...);
+
+/**
+ * send data on the about response
+ */
+nserror fetch_about_senddata(struct fetch_about_context *ctx, const uint8_t *data, size_t data_len);
+
+/**
+ * send formatted data on the about response
+ */
+nserror fetch_about_ssenddataf(struct fetch_about_context *ctx, const char *fmt, ...);
+
+/**
+ * complete the about fetch response
+ */
+bool fetch_about_send_finished(struct fetch_about_context *ctx);
+
+/**
+ * Generate a 500 server error respnse
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_srverror(struct fetch_about_context *ctx);
+
+/**
+ * get the fetch url
+ */
+struct nsurl *fetch_about_get_url(struct fetch_about_context *ctx);
+
+/**
+ * get multipart fetch data
+ */
+const struct fetch_multipart_data *fetch_about_get_multipart(struct fetch_about_context *ctx);
+
+#endif
diff --git a/content/fetchers/about/query.c b/content/fetchers/about/query.c
new file mode 100644
index 0000000..7c4e9f4
--- /dev/null
+++ b/content/fetchers/about/query.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/nsurl.h"
+#include "utils/messages.h"
+
+#include "query.h"
+
+/* exported interface documented in about/query.h */
+nserror
+get_query_description(struct nsurl *url,
+ const char *key,
+ char **out_str)
+{
+ nserror res;
+ char *url_s;
+ size_t url_l;
+ char *str = NULL;
+
+ /* get the host in question */
+ res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* obtain the description with the url substituted */
+ str = messages_get_buff(key, url_s);
+ if (str == NULL) {
+ res = NSERROR_NOMEM;
+ } else {
+ *out_str = str;
+ }
+
+ free(url_s);
+
+ return res;
+}
diff --git a/content/handlers/html/box_special.h b/content/fetchers/about/query.h
similarity index 61%
copy from content/handlers/html/box_special.h
copy to content/fetchers/about/query.h
index 973ab97..889a9ec 100644
--- a/content/handlers/html/box_special.h
+++ b/content/fetchers/about/query.h
@@ -1,7 +1,7 @@
/*
* Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
- * This file is part of NetSurf, http://www.netsurf-browser.org/
+ * This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,18 +18,19 @@
/**
* \file
- * HTML Box tree construction special element conversion interface.
+ * about scheme query handlers support interface
*/
-#ifndef NETSURF_HTML_BOX_SPECIAL_H
-#define NETSURF_HTML_BOX_SPECIAL_H
-
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_H
/**
- * call an elements special conversion handler
+ * generate a generic query description
*
- * \return true if box construction should continue else false on error.
+ * \param url The site url
+ * \param key message key
+ * \param out_str pointer to buffer with output
*/
-bool convert_special_elements(dom_node *node, html_content *content, struct box *box, bool *convert_children);
+nserror get_query_description(struct nsurl *url, const char *key, char **out_str);
#endif
diff --git a/content/fetchers/about/query_auth.c b/content/fetchers/about/query_auth.c
new file mode 100644
index 0000000..1ed2e80
--- /dev/null
+++ b/content/fetchers/about/query_auth.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "content/fetch.h"
+
+#include "private.h"
+#include "query_auth.h"
+
+
+/**
+ * generate the description of the login query
+ */
+static nserror
+get_authentication_description(struct nsurl *url,
+ const char *realm,
+ const char *username,
+ const char *password,
+ char **out_str)
+{
+ nserror res;
+ char *url_s;
+ size_t url_l;
+ char *str = NULL;
+ const char *key;
+
+ res = nsurl_get(url, NSURL_HOST, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ if ((*username == 0) && (*password == 0)) {
+ key = "LoginDescription";
+ } else {
+ key = "LoginAgain";
+ }
+
+ str = messages_get_buff(key, url_s, realm);
+ if (str != NULL) {
+ NSLOG(netsurf, INFO,
+ "key:%s url:%s realm:%s str:%s",
+ key, url_s, realm, str);
+ *out_str = str;
+ } else {
+ res = NSERROR_NOMEM;
+ }
+
+ free(url_s);
+
+ return res;
+}
+
+
+/**
+ * Handler to generate about scheme authentication query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_query_auth_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ char *url_s;
+ size_t url_l;
+ const char *realm = "";
+ const char *username = "";
+ const char *password = "";
+ const char *title;
+ char *description = NULL;
+ struct nsurl *siteurl = NULL;
+ const struct fetch_multipart_data *curmd; /* mutipart data iterator */
+
+ /* extract parameters from multipart post data */
+ curmd = fetch_about_get_multipart(ctx);
+ 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, "realm") == 0) {
+ realm = curmd->value;
+ } else if (strcmp(curmd->name, "username") == 0) {
+ username = curmd->value;
+ } else if (strcmp(curmd->name, "password") == 0) {
+ password = curmd->value;
+ }
+ curmd = curmd->next;
+ }
+
+ if (siteurl == NULL) {
+ return fetch_about_srverror(ctx);
+ }
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html; charset=utf-8")) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ title = messages_get("LoginTitle");
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"authentication\">\n"
+ "<h1 class=\"ns-border\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = get_authentication_description(siteurl,
+ realm,
+ username,
+ password,
+ &description);
+ if (res == NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<p>%s</p>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+ }
+
+ res = fetch_about_ssenddataf(ctx, "<table>");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<tr>"
+ "<th><label for=\"name\">%s:</label></th>"
+ "<td><input type=\"text\" id=\"username\" "
+ "name=\"username\" value=\"%s\"></td>"
+ "</tr>",
+ messages_get("Username"), username);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<tr>"
+ "<th><label for=\"password\">%s:</label></th>"
+ "<td><input type=\"password\" id=\"password\" "
+ "name=\"password\" value=\"%s\"></td>"
+ "</tr>",
+ messages_get("Password"), password);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</table>");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<div id=\"buttons\">"
+ "<input type=\"submit\" id=\"login\" name=\"login\" "
+ "value=\"%s\" class=\"default-action\">"
+ "<input type=\"submit\" id=\"cancel\" name=\"cancel\" "
+ "value=\"%s\">"
+ "</div>",
+ messages_get("Login"),
+ messages_get("Cancel"));
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ url_s = strdup("");
+ }
+ res = fetch_about_ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
+ url_s);
+ free(url_s);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"realm\" value=\"%s\">",
+ realm);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_auth_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ nsurl_unref(siteurl);
+
+ return true;
+
+fetch_about_query_auth_handler_aborted:
+
+ nsurl_unref(siteurl);
+
+ return false;
+}
diff --git a/content/fetchers/file/file.h b/content/fetchers/about/query_auth.h
similarity index 61%
copy from content/fetchers/file/file.h
copy to content/fetchers/about/query_auth.h
index 5a5cfe8..1c7f658 100644
--- a/content/fetchers/file/file.h
+++ b/content/fetchers/about/query_auth.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
* This file is part of NetSurf.
*
@@ -18,17 +18,18 @@
/**
* \file
- * file scheme fetcher handler interface.
+ * about scheme query auth handler interface
*/
-#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
-#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_AUTH_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_AUTH_H
/**
- * Register file scheme handler.
+ * Handler to generate about scheme query auth page.
*
- * \return NSERROR_OK on successful registration or error code on failure.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-nserror fetch_file_register(void);
+bool fetch_about_query_auth_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/query_fetcherror.c b/content/fetchers/about/query_fetcherror.c
new file mode 100644
index 0000000..010a597
--- /dev/null
+++ b/content/fetchers/about/query_fetcherror.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/messages.h"
+#include "content/fetch.h"
+
+#include "private.h"
+#include "query.h"
+#include "query_fetcherror.h"
+
+/**
+ * Handler to generate about scheme fetch error query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+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 = fetch_about_get_multipart(ctx);
+ 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_about_set_http_code(ctx, 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 = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"fetcherror\">\n"
+ "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = get_query_description(siteurl,
+ "FetchErrorDescription",
+ &description);
+ if (res == NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+ }
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", reason);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = fetch_about_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_fetcherror_handler_aborted;
+ }
+
+ res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ url_s = strdup("");
+ }
+ res = fetch_about_ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
+ url_s);
+ free(url_s);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_fetcherror_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\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;
+}
diff --git a/content/handlers/html/box_special.h b/content/fetchers/about/query_fetcherror.h
similarity index 61%
copy from content/handlers/html/box_special.h
copy to content/fetchers/about/query_fetcherror.h
index 973ab97..85d972f 100644
--- a/content/handlers/html/box_special.h
+++ b/content/fetchers/about/query_fetcherror.h
@@ -1,7 +1,7 @@
/*
* Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
- * This file is part of NetSurf, http://www.netsurf-browser.org/
+ * This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,18 +18,18 @@
/**
* \file
- * HTML Box tree construction special element conversion interface.
+ * about scheme query fetch error handler interface
*/
-#ifndef NETSURF_HTML_BOX_SPECIAL_H
-#define NETSURF_HTML_BOX_SPECIAL_H
-
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_FETCHERROR_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_FETCHERROR_H
/**
- * call an elements special conversion handler
+ * Handler to generate about scheme fetch error query page
*
- * \return true if box construction should continue else false on error.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-bool convert_special_elements(dom_node *node, html_content *content, struct box *box, bool *convert_children);
+bool fetch_about_query_fetcherror_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/query_privacy.c b/content/fetchers/about/query_privacy.c
new file mode 100644
index 0000000..030672b
--- /dev/null
+++ b/content/fetchers/about/query_privacy.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query privacy page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/messages.h"
+#include "content/fetch.h"
+
+#include "private.h"
+#include "query.h"
+#include "query_privacy.h"
+
+/**
+ * Handler to generate about scheme privacy query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_query_privacy_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 char *chainurl = NULL;
+ const struct fetch_multipart_data *curmd; /* mutipart data iterator */
+
+ /* extract parameters from multipart post data */
+ curmd = fetch_about_get_multipart(ctx);
+ 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;
+ } else if (strcmp(curmd->name, "chainurl") == 0) {
+ chainurl = curmd->value;
+ }
+ curmd = curmd->next;
+ }
+
+ if (siteurl == NULL) {
+ return fetch_about_srverror(ctx);
+ }
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html; charset=utf-8")) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ title = messages_get("PrivacyTitle");
+ res = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"privacy\">\n"
+ "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "<form method=\"post\""
+ " enctype=\"multipart/form-data\">");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = get_query_description(siteurl,
+ "PrivacyDescription",
+ &description);
+ if (res == NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+ }
+
+ if (chainurl == NULL) {
+ res = fetch_about_ssenddataf(ctx,
+ "<div><p>%s</p></div>"
+ "<div><p>%s</p></div>",
+ reason,
+ messages_get("ViewCertificatesNotPossible"));
+ } else {
+ res = fetch_about_ssenddataf(ctx,
+ "<div><p>%s</p></div>"
+ "<div><p><a href=\"%s\" target=\"_blank\">%s</a></p></div>",
+ reason,
+ chainurl,
+ messages_get("ViewCertificates"));
+ }
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+ res = fetch_about_ssenddataf(ctx,
+ "<div id=\"buttons\">"
+ "<input type=\"submit\" id=\"back\" name=\"back\" "
+ "value=\"%s\" class=\"default-action\">"
+ "<input type=\"submit\" id=\"proceed\" name=\"proceed\" "
+ "value=\"%s\">"
+ "</div>",
+ messages_get("Backtosafety"),
+ messages_get("Proceed"));
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = nsurl_get(siteurl, NSURL_COMPLETE, &url_s, &url_l);
+ if (res != NSERROR_OK) {
+ url_s = strdup("");
+ }
+ res = fetch_about_ssenddataf(ctx,
+ "<input type=\"hidden\" name=\"siteurl\" value=\"%s\">",
+ url_s);
+ free(url_s);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "</form></body>\n</html>\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_ssl_handler_aborted;
+ }
+
+ fetch_about_send_finished(ctx);
+
+ nsurl_unref(siteurl);
+
+ return true;
+
+fetch_about_query_ssl_handler_aborted:
+ nsurl_unref(siteurl);
+
+ return false;
+}
diff --git a/content/handlers/html/box_special.h b/content/fetchers/about/query_privacy.h
similarity index 61%
copy from content/handlers/html/box_special.h
copy to content/fetchers/about/query_privacy.h
index 973ab97..38ddbe8 100644
--- a/content/handlers/html/box_special.h
+++ b/content/fetchers/about/query_privacy.h
@@ -1,7 +1,7 @@
/*
* Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
- * This file is part of NetSurf, http://www.netsurf-browser.org/
+ * This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,18 +18,18 @@
/**
* \file
- * HTML Box tree construction special element conversion interface.
+ * about scheme query privacy handler interface
*/
-#ifndef NETSURF_HTML_BOX_SPECIAL_H
-#define NETSURF_HTML_BOX_SPECIAL_H
-
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_PRIVACY_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_PRIVACY_H
/**
- * call an elements special conversion handler
+ * Handler to generate about scheme query privacy page.
*
- * \return true if box construction should continue else false on error.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-bool convert_special_elements(dom_node *node, html_content *content, struct box *box, bool *convert_children);
+bool fetch_about_query_privacy_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/query_timeout.c b/content/fetchers/about/query_timeout.c
new file mode 100644
index 0000000..5c014bc
--- /dev/null
+++ b/content/fetchers/about/query_timeout.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme query timeout page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "utils/errors.h"
+#include "utils/messages.h"
+#include "content/fetch.h"
+
+#include "private.h"
+#include "query.h"
+#include "query_timeout.h"
+
+/**
+ * Handler to generate about scheme timeout query page
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+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 = fetch_about_get_multipart(ctx);
+ 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_about_set_http_code(ctx, 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 = fetch_about_ssenddataf(ctx,
+ "<html>\n<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body class=\"ns-even-bg ns-even-fg ns-border\" id =\"timeout\">\n"
+ "<h1 class=\"ns-border ns-odd-fg-bad\">%s</h1>\n",
+ title, title);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ res = fetch_about_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",
+ &description);
+ if (res == NSERROR_OK) {
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", description);
+ free(description);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+ }
+ res = fetch_about_ssenddataf(ctx, "<div><p>%s</p></div>", reason);
+ if (res != NSERROR_OK) {
+ goto fetch_about_query_timeout_handler_aborted;
+ }
+
+ res = fetch_about_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 = fetch_about_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 = fetch_about_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;
+}
diff --git a/content/handlers/html/box_special.h b/content/fetchers/about/query_timeout.h
similarity index 61%
copy from content/handlers/html/box_special.h
copy to content/fetchers/about/query_timeout.h
index 973ab97..a64757f 100644
--- a/content/handlers/html/box_special.h
+++ b/content/fetchers/about/query_timeout.h
@@ -1,7 +1,7 @@
/*
* Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
*
- * This file is part of NetSurf, http://www.netsurf-browser.org/
+ * This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,18 +18,18 @@
/**
* \file
- * HTML Box tree construction special element conversion interface.
+ * about scheme query timeout handler interface
*/
-#ifndef NETSURF_HTML_BOX_SPECIAL_H
-#define NETSURF_HTML_BOX_SPECIAL_H
-
+#ifndef NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_TIMEOUT_H
+#define NETSURF_CONTENT_FETCHERS_ABOUT_QUERY_TIMEOUT_H
/**
- * call an elements special conversion handler
+ * Handler to generate about scheme timeout query page
*
- * \return true if box construction should continue else false on error.
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
*/
-bool convert_special_elements(dom_node *node, html_content *content, struct box *box, bool *convert_children);
+bool fetch_about_query_timeout_handler(struct fetch_about_context *ctx);
#endif
diff --git a/content/fetchers/about/testament.c b/content/fetchers/about/testament.c
new file mode 100644
index 0000000..ae992ec
--- /dev/null
+++ b/content/fetchers/about/testament.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * content generator for the about scheme testament page
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "utils/errors.h"
+#include "netsurf/inttypes.h"
+#include "testament.h"
+
+#include "private.h"
+#include "atestament.h"
+
+typedef struct {
+ const char *leaf;
+ const char *modtype;
+} modification_t;
+
+/**
+ * Generate the text of an svn testament which represents the current
+ * build-tree status
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+bool fetch_about_testament_handler(struct fetch_about_context *ctx)
+{
+ nserror res;
+ static modification_t modifications[] = WT_MODIFICATIONS;
+ int modidx; /* midification index */
+
+ /* content is going to return ok */
+ fetch_about_set_http_code(ctx, 200);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
+ goto fetch_about_testament_handler_aborted;
+
+ res = fetch_about_ssenddataf(ctx,
+ "# Automatically generated by NetSurf build system\n\n");
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+#if defined(WT_BRANCHISTRUNK) || defined(WT_BRANCHISMASTER)
+ "# This is a *DEVELOPMENT* build from the main line.\n\n"
+#elif defined(WT_BRANCHISTAG) && (WT_MODIFIED == 0)
+ "# This is a tagged build of NetSurf\n"
+#ifdef WT_TAGIS
+ "# The tag used was '" WT_TAGIS "'\n\n"
+#else
+ "\n"
+#endif
+#elif defined(WT_NO_SVN) || defined(WT_NO_GIT)
+ "# This NetSurf was built outside of our revision "
+ "control environment.\n"
+ "# This testament is therefore not very useful.\n\n"
+#else
+ "# This NetSurf was built from a branch (" WT_BRANCHPATH ").\n\n"
+#endif
+#if defined(CI_BUILD)
+ "# This build carries the CI build number '" CI_BUILD "'\n\n"
+#endif
+ );
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx,
+ "Built by %s (%s) from %s at revision %s on %s\n\n",
+ GECOS, USERNAME, WT_BRANCHPATH, WT_REVID, WT_COMPILEDATE);
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ res = fetch_about_ssenddataf(ctx, "Built on %s in %s\n\n", WT_HOSTNAME, WT_ROOT);
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ if (WT_MODIFIED > 0) {
+ res = fetch_about_ssenddataf(ctx,
+ "Working tree has %d modification%s\n\n",
+ WT_MODIFIED, WT_MODIFIED == 1 ? "" : "s");
+ } else {
+ res = fetch_about_ssenddataf(ctx, "Working tree is not modified.\n");
+ }
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+
+ for (modidx = 0; modidx < WT_MODIFIED; ++modidx) {
+ res = fetch_about_ssenddataf(ctx,
+ " %s %s\n",
+ modifications[modidx].modtype,
+ modifications[modidx].leaf);
+ if (res != NSERROR_OK) {
+ goto fetch_about_testament_handler_aborted;
+ }
+ }
+
+ fetch_about_send_finished(ctx);
+
+ return true;
+
+fetch_about_testament_handler_aborted:
+ return false;
+}
diff --git a/content/handlers/image/image_cache.h b/content/handlers/image/image_cache.h
index 955306e..1c2d621 100644
--- a/content/handlers/image/image_cache.h
+++ b/content/handlers/image/image_cache.h
@@ -40,6 +40,7 @@
#include "utils/errors.h"
#include "netsurf/content_type.h"
+struct content;
struct content_redraw_data;
struct redraw_context;
--
NetSurf Browser
2 years, 8 months
netsurf: branch master updated. release/3.10-49-g7997182
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/7997182cc0748ce449e29...
...commit http://git.netsurf-browser.org/netsurf.git/commit/7997182cc0748ce449e2946...
...tree http://git.netsurf-browser.org/netsurf.git/tree/7997182cc0748ce449e29460b...
The branch, master has been updated
via 7997182cc0748ce449e29460b0534aed8013b6e8 (commit)
from b0b271274c98274d4c53608c856194270ae12d0f (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=7997182cc0748ce449e...
commit 7997182cc0748ce449e29460b0534aed8013b6e8
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
Improve the framebuffer docs a bit
diff --git a/docs/quick-start.md b/docs/quick-start.md
index 652c3e3..449b956 100644
--- a/docs/quick-start.md
+++ b/docs/quick-start.md
@@ -84,6 +84,8 @@ To build the framebuffer front end, you could do:
$ make TARGET=framebuffer
$ ./nsfb
+More detailed documentation on using the [framebuffer](docs/using-framebuffer.md)
+ frontend are available.
Cross Compiling
===============
diff --git a/docs/user-interface.md b/docs/user-interface.md
index 36b0103..49ca7a1 100644
--- a/docs/user-interface.md
+++ b/docs/user-interface.md
@@ -31,7 +31,7 @@ Frontend specific to the Haiku OS
## framebuffer
-There is a basic user guide for the[framebuffer](docs/using-framebuffer.md)
+There is a basic user guide for the [framebuffer](docs/using-framebuffer.md)
## gtk
diff --git a/docs/using-framebuffer.md b/docs/using-framebuffer.md
index 3af8f98..98a100a 100644
--- a/docs/using-framebuffer.md
+++ b/docs/using-framebuffer.md
@@ -62,6 +62,56 @@ Overview
the GTK frontend is a vastly superior choice. The framebuffer
frontend will appear exceptionally limited on such capable systems.
+Running
+=======
+
+ The framebuffer frontend is executed with the nsfb command. This
+ command takes parameters to control the operation of the
+ browser. The 'Configuring' section describes the available options
+ in detail.
+
+ The selection of the display surface is controlled with the -f
+ switch, the available display surfaces can be shown by passing '?'
+ as the parameter.
+
+ $ ./nsfb -f ?
+ ./nsfb: Valid surface names are:
+ ./nsfb: ram
+ ./nsfb: sdl
+ ./nsfb: x
+ ./nsfb: vnc
+ ./nsfb: wld
+
+ The avilable surfaces are dependant on what was compiled into the
+ nsfb library.
+
+ Common issues
+ -------------
+
+ - The browser appears to "hang" with no output
+
+ This is often cause by the unintentianal selection of the debug
+ "ram" surface. In this case the browser is in fact operating but
+ the output is being rendered to a memory buffer. the solution is
+ to explictly select the intended surface using the -f switch
+
+ - The displayed browser interface has no visible icons
+
+ This is generally because the necessary resources are not availale
+ on the resource search path.
+
+ - There is no displayed text.
+
+ The font configuration is incorrect either it has been compiled
+ wrongly or the configured freetype font is not available
+
+ - The browser messages are "bad"
+
+ If the browser messages are being emited as unrecognisable short
+ text symbols or in the wrong language it is likely the Messages
+ file could not be located. This can be confirmed by looking for
+ the text "Message translations failed to load" in the verbose log
+ output (run the browser with the -v switch)
Configuring
===========
@@ -72,11 +122,11 @@ Configuring
for details.
As with any NetSurf frontend run-time configuration is read from a
- "Choices" file. This file is a simple key:value list and is located
- in "${HOME}/.netsurf/Choices".
+ "Choices" file. This file is a simple key:value list and by default
+ is located in "${HOME}/.netsurf/Choices".
- The standard values supported by the NetSurf core are documented in
- the Options document. In addition to these there are a number of
+ The standard [core user options](docs/netsurf-options.md) are
+ available. In addition to the core options there are a number of
values to control specific aspects of the framebuffer version.
Toolkit Options
diff --git a/frontends/framebuffer/gui.c b/frontends/framebuffer/gui.c
index d7f2272..934ba05 100644
--- a/frontends/framebuffer/gui.c
+++ b/frontends/framebuffer/gui.c
@@ -525,7 +525,7 @@ process_cmdline(int argc, char** argv)
default:
fprintf(stderr,
- "Usage: %s [-f frontend] [-b bpp] url\n",
+ "Usage: %s [-f frontend] [-b bpp] [-w width] [-h height] <url>\n",
argv[0]);
return false;
}
-----------------------------------------------------------------------
Summary of changes:
docs/quick-start.md | 2 ++
docs/user-interface.md | 2 +-
docs/using-framebuffer.md | 58 ++++++++++++++++++++++++++++++++++++++++---
frontends/framebuffer/gui.c | 2 +-
4 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/docs/quick-start.md b/docs/quick-start.md
index 652c3e3..449b956 100644
--- a/docs/quick-start.md
+++ b/docs/quick-start.md
@@ -84,6 +84,8 @@ To build the framebuffer front end, you could do:
$ make TARGET=framebuffer
$ ./nsfb
+More detailed documentation on using the [framebuffer](docs/using-framebuffer.md)
+ frontend are available.
Cross Compiling
===============
diff --git a/docs/user-interface.md b/docs/user-interface.md
index 36b0103..49ca7a1 100644
--- a/docs/user-interface.md
+++ b/docs/user-interface.md
@@ -31,7 +31,7 @@ Frontend specific to the Haiku OS
## framebuffer
-There is a basic user guide for the[framebuffer](docs/using-framebuffer.md)
+There is a basic user guide for the [framebuffer](docs/using-framebuffer.md)
## gtk
diff --git a/docs/using-framebuffer.md b/docs/using-framebuffer.md
index 3af8f98..98a100a 100644
--- a/docs/using-framebuffer.md
+++ b/docs/using-framebuffer.md
@@ -62,6 +62,56 @@ Overview
the GTK frontend is a vastly superior choice. The framebuffer
frontend will appear exceptionally limited on such capable systems.
+Running
+=======
+
+ The framebuffer frontend is executed with the nsfb command. This
+ command takes parameters to control the operation of the
+ browser. The 'Configuring' section describes the available options
+ in detail.
+
+ The selection of the display surface is controlled with the -f
+ switch, the available display surfaces can be shown by passing '?'
+ as the parameter.
+
+ $ ./nsfb -f ?
+ ./nsfb: Valid surface names are:
+ ./nsfb: ram
+ ./nsfb: sdl
+ ./nsfb: x
+ ./nsfb: vnc
+ ./nsfb: wld
+
+ The avilable surfaces are dependant on what was compiled into the
+ nsfb library.
+
+ Common issues
+ -------------
+
+ - The browser appears to "hang" with no output
+
+ This is often cause by the unintentianal selection of the debug
+ "ram" surface. In this case the browser is in fact operating but
+ the output is being rendered to a memory buffer. the solution is
+ to explictly select the intended surface using the -f switch
+
+ - The displayed browser interface has no visible icons
+
+ This is generally because the necessary resources are not availale
+ on the resource search path.
+
+ - There is no displayed text.
+
+ The font configuration is incorrect either it has been compiled
+ wrongly or the configured freetype font is not available
+
+ - The browser messages are "bad"
+
+ If the browser messages are being emited as unrecognisable short
+ text symbols or in the wrong language it is likely the Messages
+ file could not be located. This can be confirmed by looking for
+ the text "Message translations failed to load" in the verbose log
+ output (run the browser with the -v switch)
Configuring
===========
@@ -72,11 +122,11 @@ Configuring
for details.
As with any NetSurf frontend run-time configuration is read from a
- "Choices" file. This file is a simple key:value list and is located
- in "${HOME}/.netsurf/Choices".
+ "Choices" file. This file is a simple key:value list and by default
+ is located in "${HOME}/.netsurf/Choices".
- The standard values supported by the NetSurf core are documented in
- the Options document. In addition to these there are a number of
+ The standard [core user options](docs/netsurf-options.md) are
+ available. In addition to the core options there are a number of
values to control specific aspects of the framebuffer version.
Toolkit Options
diff --git a/frontends/framebuffer/gui.c b/frontends/framebuffer/gui.c
index d7f2272..934ba05 100644
--- a/frontends/framebuffer/gui.c
+++ b/frontends/framebuffer/gui.c
@@ -525,7 +525,7 @@ process_cmdline(int argc, char** argv)
default:
fprintf(stderr,
- "Usage: %s [-f frontend] [-b bpp] url\n",
+ "Usage: %s [-f frontend] [-b bpp] [-w width] [-h height] <url>\n",
argv[0]);
return false;
}
--
NetSurf Browser
2 years, 8 months