summaryrefslogtreecommitdiff
path: root/content/handlers/html/html_css_fetcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'content/handlers/html/html_css_fetcher.c')
-rw-r--r--content/handlers/html/html_css_fetcher.c325
1 files changed, 325 insertions, 0 deletions
diff --git a/content/handlers/html/html_css_fetcher.c b/content/handlers/html/html_css_fetcher.c
new file mode 100644
index 000000000..7987ea094
--- /dev/null
+++ b/content/handlers/html/html_css_fetcher.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2008 Rob Kendrick <rjek@netsurf-browser.org>
+ * Copyright 2013 John-Mark Bell <jmb@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
+ * HTML fetcher for CSS objects
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dom/dom.h>
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "netsurf/inttypes.h"
+#include "utils/config.h"
+#include "utils/log.h"
+#include "utils/ring.h"
+#include "utils/nsurl.h"
+#include "utils/utils.h"
+#include "content/fetch.h"
+#include "content/fetchers.h"
+
+#include "html/html_internal.h"
+
+typedef struct html_css_fetcher_item {
+ uint32_t key;
+ dom_string *data;
+ nsurl *base_url;
+
+ struct html_css_fetcher_item *r_next, *r_prev;
+} html_css_fetcher_item;
+
+typedef struct html_css_fetcher_context {
+ struct fetch *parent_fetch;
+
+ nsurl *url;
+ html_css_fetcher_item *item;
+
+ bool aborted;
+ bool locked;
+
+ struct html_css_fetcher_context *r_next, *r_prev;
+} html_css_fetcher_context;
+
+static uint32_t current_key = 0;
+static html_css_fetcher_item *items = NULL;
+static html_css_fetcher_context *ring = NULL;
+
+static bool html_css_fetcher_initialise(lwc_string *scheme)
+{
+ NSLOG(netsurf, INFO, "html_css_fetcher_initialise called for %s",
+ lwc_string_data(scheme));
+ return true;
+}
+
+static void html_css_fetcher_finalise(lwc_string *scheme)
+{
+ NSLOG(netsurf, INFO, "html_css_fetcher_finalise called for %s",
+ lwc_string_data(scheme));
+}
+
+static bool html_css_fetcher_can_fetch(const nsurl *url)
+{
+ return true;
+}
+
+static void *html_css_fetcher_setup(struct fetch *parent_fetch, nsurl *url,
+ bool only_2xx, bool downgrade_tls, const char *post_urlenc,
+ const struct fetch_multipart_data *post_multipart,
+ const char **headers)
+{
+ html_css_fetcher_context *ctx;
+ lwc_string *path;
+ uint32_t key;
+ html_css_fetcher_item *item, *found = NULL;
+
+ /* format of a x-ns-css URL is:
+ * x-ns-url:<key>
+ * Where key is an unsigned 32bit integer
+ */
+
+ path = nsurl_get_component(url, NSURL_PATH);
+ /* The path must exist */
+ if (path == NULL) {
+ return NULL;
+ }
+
+ key = strtoul(lwc_string_data(path), NULL, 10);
+
+ lwc_string_unref(path);
+
+ /* There must be at least one item */
+ if (items == NULL) {
+ return NULL;
+ }
+
+ item = items;
+ do {
+ if (item->key == key) {
+ found = item;
+ break;
+ }
+
+ item = item->r_next;
+ } while (item != items);
+
+ /* We must have found the item */
+ if (found == NULL) {
+ return NULL;
+ }
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->parent_fetch = parent_fetch;
+ ctx->url = nsurl_ref(url);
+ ctx->item = found;
+
+ RING_INSERT(ring, ctx);
+
+ return ctx;
+}
+
+static bool html_css_fetcher_start(void *ctx)
+{
+ return true;
+}
+
+static void html_css_fetcher_free(void *ctx)
+{
+ html_css_fetcher_context *c = ctx;
+
+ nsurl_unref(c->url);
+ if (c->item != NULL) {
+ nsurl_unref(c->item->base_url);
+ dom_string_unref(c->item->data);
+ RING_REMOVE(items, c->item);
+ free(c->item);
+ }
+ RING_REMOVE(ring, c);
+ free(ctx);
+}
+
+static void html_css_fetcher_abort(void *ctx)
+{
+ html_css_fetcher_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;
+}
+
+static void html_css_fetcher_send_callback(const fetch_msg *msg,
+ html_css_fetcher_context *c)
+{
+ c->locked = true;
+ fetch_send_callback(msg, c->parent_fetch);
+ c->locked = false;
+}
+
+static void html_css_fetcher_poll(lwc_string *scheme)
+{
+ fetch_msg msg;
+ html_css_fetcher_context *c, *next;
+
+ if (ring == NULL) return;
+
+ /* Iterate over ring, processing each pending fetch */
+ c = ring;
+ do {
+ /* 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) {
+ next = c->r_next;
+ continue;
+ }
+
+ /* Only process non-aborted fetches */
+ if (c->aborted) {
+ /* Nothing to do */
+ assert(c->locked == false);
+ } else if (c->item != NULL) {
+ char header[4096];
+
+ fetch_set_http_code(c->parent_fetch, 200);
+
+ /* Any callback can result in the fetch being aborted.
+ * Therefore, we _must_ check for this after _every_
+ * call to html_css_fetcher_send_callback().
+ */
+ snprintf(header, sizeof header,
+ "Content-Type: text/css; charset=utf-8");
+ msg.type = FETCH_HEADER;
+ msg.data.header_or_data.buf = (const uint8_t *) header;
+ msg.data.header_or_data.len = strlen(header);
+ html_css_fetcher_send_callback(&msg, c);
+
+ if (c->aborted == false) {
+ snprintf(header, sizeof header,
+ "Content-Length: %"PRIsizet,
+ dom_string_byte_length(c->item->data));
+ msg.type = FETCH_HEADER;
+ msg.data.header_or_data.buf =
+ (const uint8_t *) header;
+ msg.data.header_or_data.len = strlen(header);
+ html_css_fetcher_send_callback(&msg, c);
+ }
+
+ if (c->aborted == false) {
+ snprintf(header, sizeof header,
+ "X-NS-Base: %.*s",
+ (int) nsurl_length(c->item->base_url),
+ nsurl_access(c->item->base_url));
+ msg.type = FETCH_HEADER;
+ msg.data.header_or_data.buf =
+ (const uint8_t *) header;
+ msg.data.header_or_data.len = strlen(header);
+ html_css_fetcher_send_callback(&msg, c);
+ }
+
+ if (c->aborted == false) {
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf =
+ (const uint8_t *)
+ dom_string_data(c->item->data);
+ msg.data.header_or_data.len =
+ dom_string_byte_length(c->item->data);
+ html_css_fetcher_send_callback(&msg, c);
+ }
+
+ if (c->aborted == false) {
+ msg.type = FETCH_FINISHED;
+ html_css_fetcher_send_callback(&msg, c);
+ }
+ } else {
+ NSLOG(netsurf, INFO, "Processing of %s failed!",
+ nsurl_access(c->url));
+
+ /* Ensure that we're unlocked here. If we aren't,
+ * then html_css_fetcher_process() is broken.
+ */
+ assert(c->locked == false);
+ }
+
+ /* Compute next fetch item at the last possible moment as
+ * processing this item may have added to the ring.
+ */
+ next = c->r_next;
+
+ fetch_remove_from_queues(c->parent_fetch);
+ fetch_free(c->parent_fetch);
+
+ /* Advance to next ring entry, exiting if we've reached
+ * the start of the ring or the ring has become empty
+ */
+ } while ( (c = next) != ring && ring != NULL);
+}
+
+/* exported interface documented in html_internal.h */
+nserror html_css_fetcher_register(void)
+{
+ lwc_string *scheme;
+ const struct fetcher_operation_table html_css_fetcher_ops = {
+ .initialise = html_css_fetcher_initialise,
+ .acceptable = html_css_fetcher_can_fetch,
+ .setup = html_css_fetcher_setup,
+ .start = html_css_fetcher_start,
+ .abort = html_css_fetcher_abort,
+ .free = html_css_fetcher_free,
+ .poll = html_css_fetcher_poll,
+ .finalise = html_css_fetcher_finalise
+ };
+
+ if (lwc_intern_string("x-ns-css", SLEN("x-ns-css"),
+ &scheme) != lwc_error_ok) {
+ NSLOG(netsurf, INFO, "could not intern \"x-ns-css\".");
+ return NSERROR_INIT_FAILED;
+ }
+
+ return fetcher_add(scheme, &html_css_fetcher_ops);
+}
+
+/* exported interface documented in html_internal.h */
+nserror
+html_css_fetcher_add_item(dom_string *data, nsurl *base_url, uint32_t *key)
+{
+ html_css_fetcher_item *item = malloc(sizeof(*item));
+
+ if (item == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ *key = item->key = current_key++;
+ item->data = dom_string_ref(data);
+ item->base_url = nsurl_ref(base_url);
+
+ RING_INSERT(items, item);
+
+ return NSERROR_OK;
+}