summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/fetchers/resource.c199
-rw-r--r--desktop/gui_factory.c16
-rw-r--r--desktop/gui_fetch.h31
3 files changed, 196 insertions, 50 deletions
diff --git a/content/fetchers/resource.c b/content/fetchers/resource.c
index 1a439aa5f..6472dc506 100644
--- a/content/fetchers/resource.c
+++ b/content/fetchers/resource.c
@@ -52,26 +52,7 @@
#include "content/fetchers/resource.h"
#include "content/urldb.h"
-struct fetch_resource_context;
-
-typedef bool (*fetch_resource_handler)(struct fetch_resource_context *);
-
-/** Context for an resource fetch */
-struct fetch_resource_context {
- struct fetch_resource_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;
- nsurl *redirect_url; /**< The url the fetch redirects to */
-
- fetch_resource_handler handler;
-};
-
-static struct fetch_resource_context *ring = NULL;
+#define DIRECT_ETAG_VALUE 123456
/** Valid resource paths */
static const char *fetch_resource_paths[] = {
@@ -95,11 +76,41 @@ static const char *fetch_resource_paths[] = {
"icons/hotlist-rmv.png",
"icons/search.png"
};
+
+/**
+ * map of resource scheme paths to redirect urls
+ */
static struct fetch_resource_map_entry {
- lwc_string *path;
- nsurl *url;
+ lwc_string *path; /**< resource scheme path */
+ nsurl *redirect_url; /**< url to redirect to */
+ const uint8_t *data; /**< direct pointer to data */
+ size_t data_len; /**< length of direct data */
} fetch_resource_map[NOF_ELEMENTS(fetch_resource_paths)];
+struct fetch_resource_context;
+
+typedef bool (*fetch_resource_handler)(struct fetch_resource_context *);
+
+/** Context for an resource fetch */
+struct fetch_resource_context {
+ struct fetch_resource_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; /**< requested url */
+
+ struct fetch_resource_map_entry *entry; /**< resource map entry */
+
+ fetch_resource_handler handler;
+
+ int etag;
+};
+
+static struct fetch_resource_context *ring = NULL;
+
static uint32_t fetch_resource_path_count;
/** issue fetch callbacks with locking */
@@ -136,7 +147,9 @@ static bool fetch_resource_send_header(struct fetch_resource_context *ctx,
-
+/**
+ * resource handler that results in a redirect to another url.
+ */
static bool fetch_resource_redirect_handler(struct fetch_resource_context *ctx)
{
fetch_msg msg;
@@ -145,12 +158,65 @@ static bool fetch_resource_redirect_handler(struct fetch_resource_context *ctx)
fetch_set_http_code(ctx->fetchh, 302);
msg.type = FETCH_REDIRECT;
- msg.data.redirect = nsurl_access(ctx->redirect_url);
- fetch_resource_send_callback(&msg, ctx);
+ msg.data.redirect = nsurl_access(ctx->entry->redirect_url);
+ fetch_resource_send_callback(&msg, ctx);
return true;
}
+/* resource handler that returns data directly */
+static bool fetch_resource_data_handler(struct fetch_resource_context *ctx)
+{
+ fetch_msg msg;
+
+ /* Check if we can just return not modified */
+ if (ctx->etag != 0 && ctx->etag == DIRECT_ETAG_VALUE) {
+ fetch_set_http_code(ctx->fetchh, 304);
+ msg.type = FETCH_NOTMODIFIED;
+ fetch_resource_send_callback(&msg, ctx);
+ return true;
+ }
+
+ /* fetch is going to be successful */
+ fetch_set_http_code(ctx->fetchh, 200);
+
+ /* Any callback can result in the fetch being aborted.
+ * Therefore, we _must_ check for this after _every_ call to
+ * fetch_file_send_callback().
+ */
+
+ /* content type */
+ if (fetch_resource_send_header(ctx, "Content-Type: %s",
+ guit->fetch->filetype(lwc_string_data(ctx->entry->path))))
+ goto fetch_resource_data_aborted;
+
+ /* content length */
+ if (fetch_resource_send_header(ctx,
+ "Content-Length: %"SSIZET_FMT,
+ ctx->entry->data_len))
+ goto fetch_resource_data_aborted;
+
+ /* create etag */
+ if (fetch_resource_send_header(ctx,
+ "ETag: \"%10" PRId64 "\"",
+ (int64_t) DIRECT_ETAG_VALUE))
+ goto fetch_resource_data_aborted;
+
+
+ msg.type = FETCH_DATA;
+ msg.data.header_or_data.buf = (const uint8_t *) ctx->entry->data;
+ msg.data.header_or_data.len = ctx->entry->data_len;
+ fetch_resource_send_callback(&msg, ctx);
+
+ if (ctx->aborted == false) {
+ msg.type = FETCH_FINISHED;
+ fetch_resource_send_callback(&msg, ctx);
+ }
+
+fetch_resource_data_aborted:
+
+ return true;
+}
static bool fetch_resource_notfound_handler(struct fetch_resource_context *ctx)
{
@@ -195,6 +261,7 @@ static bool fetch_resource_initialise(lwc_string *scheme)
{
struct fetch_resource_map_entry *e;
uint32_t i;
+ nserror res;
fetch_resource_path_count = 0;
@@ -207,15 +274,26 @@ static bool fetch_resource_initialise(lwc_string *scheme)
while (i > 0) {
i--;
lwc_string_unref(fetch_resource_map[i].path);
- nsurl_unref(fetch_resource_map[i].url);
+ nsurl_unref(fetch_resource_map[i].redirect_url);
}
+ /** \todo should this exit with an error condition? */
}
- e->url = guit->fetch->get_resource_url(fetch_resource_paths[i]);
- if (e->url == NULL) {
- lwc_string_unref(e->path);
- } else {
+ e->data = NULL;
+ res = guit->fetch->get_resource_data(lwc_string_data(e->path),
+ &e->data,
+ &e->data_len);
+ if (res == NSERROR_OK) {
+ LOG("direct data for %s", fetch_resource_paths[i]);
fetch_resource_path_count++;
+ } else {
+ e->redirect_url = guit->fetch->get_resource_url(fetch_resource_paths[i]);
+ if (e->redirect_url == NULL) {
+ lwc_string_unref(e->path);
+ } else {
+ LOG("redirect url for %s", fetch_resource_paths[i]);
+ fetch_resource_path_count++;
+ }
}
}
@@ -229,7 +307,11 @@ static void fetch_resource_finalise(lwc_string *scheme)
for (i = 0; i < fetch_resource_path_count; i++) {
lwc_string_unref(fetch_resource_map[i].path);
- nsurl_unref(fetch_resource_map[i].url);
+ if (fetch_resource_map[i].data != NULL) {
+ guit->fetch->release_resource_data(fetch_resource_map[i].data);
+ } else {
+ nsurl_unref(fetch_resource_map[i].redirect_url);
+ }
}
}
@@ -238,38 +320,44 @@ static bool fetch_resource_can_fetch(const nsurl *url)
return true;
}
-/** callback to set up a resource fetch context. */
+/**
+ * set up a resource fetch context.
+ */
static void *
fetch_resource_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)
+ nsurl *url,
+ bool only_2xx,
+ bool downgrade_tls,
+ const char *post_urlenc,
+ const struct fetch_multipart_data *post_multipart,
+ const char **headers)
{
struct fetch_resource_context *ctx;
lwc_string *path;
+ uint32_t i;
ctx = calloc(1, sizeof(*ctx));
- if (ctx == NULL)
+ if (ctx == NULL) {
return NULL;
+ }
ctx->handler = fetch_resource_notfound_handler;
if ((path = nsurl_get_component(url, NSURL_PATH)) != NULL) {
- uint32_t i;
bool match;
/* Ensure requested path is valid */
for (i = 0; i < fetch_resource_path_count; i++) {
- if (lwc_string_isequal(path,
- fetch_resource_map[i].path,
+ if (lwc_string_isequal(path,
+ fetch_resource_map[i].path,
&match) == lwc_error_ok && match) {
- ctx->redirect_url =
- nsurl_ref(fetch_resource_map[i].url);
- ctx->handler =
- fetch_resource_redirect_handler;
+ /* found a url match, select handler */
+ ctx->entry = &fetch_resource_map[i];
+ if (ctx->entry->data != NULL) {
+ ctx->handler = fetch_resource_data_handler;
+ } else {
+ ctx->handler = fetch_resource_redirect_handler;
+ }
break;
}
}
@@ -279,6 +367,23 @@ fetch_resource_setup(struct fetch *fetchh,
ctx->url = nsurl_ref(url);
+ /* Scan request headers looking for If-None-Match */
+ for (i = 0; headers[i] != NULL; i++) {
+ if (strncasecmp(headers[i], "If-None-Match:",
+ SLEN("If-None-Match:")) == 0) {
+ /* If-None-Match: "12345678" */
+ const char *d = headers[i] + SLEN("If-None-Match:");
+
+ /* Scan to first digit, if any */
+ while (*d != '\0' && (*d < '0' || '9' < *d))
+ d++;
+
+ /* Convert to time_t */
+ if (*d != '\0')
+ ctx->etag = atoi(d);
+ }
+ }
+
ctx->fetchh = fetchh;
RING_INSERT(ring, ctx);
@@ -290,8 +395,6 @@ fetch_resource_setup(struct fetch *fetchh,
static void fetch_resource_free(void *ctx)
{
struct fetch_resource_context *c = ctx;
- if (c->redirect_url != NULL)
- nsurl_unref(c->redirect_url);
if (c->url != NULL)
nsurl_unref(c->url);
RING_REMOVE(ring, c);
diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c
index 50244e334..22364ab97 100644
--- a/desktop/gui_factory.c
+++ b/desktop/gui_factory.c
@@ -501,6 +501,16 @@ static nsurl *gui_default_get_resource_url(const char *path)
return NULL;
}
+static nserror gui_default_get_resource_data(const char *path, const uint8_t **data, size_t *data_len)
+{
+ return NSERROR_NOT_FOUND;
+}
+
+static nserror gui_default_release_resource_data(const uint8_t *data)
+{
+ return NSERROR_OK;
+}
+
static char *gui_default_mimetype(const char *path)
{
return strdup(guit->fetch->filetype(path));
@@ -523,6 +533,12 @@ static nserror verify_fetch_register(struct gui_fetch_table *gft)
if (gft->get_resource_url == NULL) {
gft->get_resource_url = gui_default_get_resource_url;
}
+ if (gft->get_resource_data == NULL) {
+ gft->get_resource_data = gui_default_get_resource_data;
+ }
+ if (gft->release_resource_data == NULL) {
+ gft->release_resource_data = gui_default_release_resource_data;
+ }
if (gft->mimetype == NULL) {
gft->mimetype = gui_default_mimetype;
}
diff --git a/desktop/gui_fetch.h b/desktop/gui_fetch.h
index 46d31e0f4..20db39d20 100644
--- a/desktop/gui_fetch.h
+++ b/desktop/gui_fetch.h
@@ -47,9 +47,9 @@ struct gui_fetch_table {
/* Optional entries */
/**
- * Callback to translate resource to full url.
+ * Translate resource to full url.
*
- * @note used in resource fetcher
+ * @note Only used in resource fetcher
*
* Transforms a resource: path into a full URL. The returned URL
* is used as the target for a redirect. The caller takes ownership of
@@ -62,6 +62,33 @@ struct gui_fetch_table {
struct nsurl* (*get_resource_url)(const char *path);
/**
+ * Translate resource to source data.
+ *
+ * @note Only used in resource fetcher
+ *
+ * Obtains the data for a resource directly
+ *
+ * \param path The path of the resource to locate.
+ * \param data Pointer to recive data into
+ * \param data_len Pointer to length of returned data
+ * \return NSERROR_OK and the data and length values updated
+ * else appropriate error code.
+ */
+ nserror (*get_resource_data)(const char *path, const uint8_t **data, size_t *data_len);
+
+ /**
+ * Releases source data.
+ *
+ * @note Only used in resource fetcher
+ *
+ * Releases source data obtained from get_resource_data()
+ *
+ * \param data The value returned from a previous get_resource_data call
+ * \return NSERROR_OK on success else appropriate error code.
+ */
+ nserror (*release_resource_data)(const uint8_t *data);
+
+ /**
* Find a MIME type for a local file
*
* @note only used in curl fetcher on RISC OS otherwise its a