Subversion Repositories Kolibri OS

Rev

Rev 3584 | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
  3.  *
  4.  * This file is part of NetSurf.
  5.  *
  6.  * NetSurf is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; version 2 of the License.
  9.  *
  10.  * NetSurf is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. /* resource: URL handling. Based on the data fetcher by Rob Kendrick */
  20.  
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <fcntl.h>
  24. #include <unistd.h>
  25. #include <assert.h>
  26. #include <errno.h>
  27. #include <stdbool.h>
  28. #include <inttypes.h>
  29. #include <string.h>
  30. #include <strings.h>
  31. #include <time.h>
  32. #include <stdio.h>
  33. #include <dirent.h>
  34. #include <limits.h>
  35. #include <stdarg.h>
  36.  
  37. #include <libwapcaplet/libwapcaplet.h>
  38.  
  39. #include "utils/config.h"
  40. #include "content/dirlist.h"
  41. #include "content/fetch.h"
  42. #include "content/fetchers/resource.h"
  43. #include "content/urldb.h"
  44. #include "desktop/gui.h"
  45. #include "desktop/options.h"
  46. #include "utils/log.h"
  47. #include "utils/messages.h"
  48. #include "utils/url.h"
  49. #include "utils/utils.h"
  50. #include "utils/ring.h"
  51.  
  52. struct fetch_resource_context;
  53.  
  54. typedef bool (*fetch_resource_handler)(struct fetch_resource_context *);
  55.  
  56. /** Context for an resource fetch */
  57. struct fetch_resource_context {
  58.         struct fetch_resource_context *r_next, *r_prev;
  59.  
  60.         struct fetch *fetchh; /**< Handle for this fetch */
  61.  
  62.         bool aborted; /**< Flag indicating fetch has been aborted */
  63.         bool locked; /**< Flag indicating entry is already entered */
  64.  
  65.         nsurl *url;
  66.         nsurl *redirect_url; /**< The url the fetch redirects to */
  67.  
  68.         fetch_resource_handler handler;
  69. };
  70.  
  71. static struct fetch_resource_context *ring = NULL;
  72.  
  73. /** Valid resource paths */
  74. static const char *fetch_resource_paths[] = {
  75.         "adblock.css",
  76.         "default.css",
  77.         "internal.css",
  78.         "quirks.css",
  79.         "user.css",
  80.         "credits.html",
  81.         "licence.html",
  82.         "welcome.html",
  83.         "favicon.ico",
  84.         "netsurf.png"
  85. };
  86. static struct fetch_resource_map_entry {
  87.         lwc_string *path;
  88.         nsurl *url;
  89. } fetch_resource_map[NOF_ELEMENTS(fetch_resource_paths)];
  90.  
  91. static uint32_t fetch_resource_path_count;
  92.  
  93. /** issue fetch callbacks with locking */
  94. static inline bool fetch_resource_send_callback(const fetch_msg *msg,
  95.                 struct fetch_resource_context *ctx)
  96. {
  97.         ctx->locked = true;
  98.         fetch_send_callback(msg, ctx->fetchh);
  99.         ctx->locked = false;
  100.  
  101.         return ctx->aborted;
  102. }
  103.  
  104. static bool fetch_resource_send_header(struct fetch_resource_context *ctx,
  105.                 const char *fmt, ...)
  106. {
  107.         fetch_msg msg;
  108.         char header[64];
  109.         va_list ap;
  110.  
  111.         va_start(ap, fmt);
  112.  
  113.         vsnprintf(header, sizeof header, fmt, ap);
  114.  
  115.         va_end(ap);
  116.  
  117.         msg.type = FETCH_HEADER;
  118.         msg.data.header_or_data.buf = (const uint8_t *) header;
  119.         msg.data.header_or_data.len = strlen(header);
  120.         fetch_resource_send_callback(&msg, ctx);
  121.  
  122.         return ctx->aborted;
  123. }
  124.  
  125.  
  126.  
  127.  
  128. static bool fetch_resource_redirect_handler(struct fetch_resource_context *ctx)
  129. {
  130.         fetch_msg msg;
  131.  
  132.         /* content is going to return redirect */
  133.         fetch_set_http_code(ctx->fetchh, 302);
  134.  
  135.         msg.type = FETCH_REDIRECT;
  136.         msg.data.redirect = nsurl_access(ctx->redirect_url);
  137.         fetch_resource_send_callback(&msg, ctx);
  138.  
  139.         return true;
  140. }
  141.  
  142.  
  143. static bool fetch_resource_notfound_handler(struct fetch_resource_context *ctx)
  144. {
  145.         fetch_msg msg;
  146.         int code = 404;
  147.         char buffer[1024];
  148.         const char *title;
  149.         char key[8];
  150.  
  151.         /* content is going to return error code */
  152.         fetch_set_http_code(ctx->fetchh, code);
  153.  
  154.         /* content type */
  155.         if (fetch_resource_send_header(ctx, "Content-Type: text/html"))
  156.                 goto fetch_resource_notfound_handler_aborted;
  157.  
  158.         snprintf(key, sizeof key, "HTTP%03d", code);
  159.         title = messages_get(key);
  160.  
  161.         snprintf(buffer, sizeof buffer, "<html><head><title>%s</title></head>"
  162.                         "<body><h1>%s</h1>"
  163.                         "<p>Error %d while fetching file %s</p></body></html>",
  164.                         title, title, code, nsurl_access(ctx->url));
  165.  
  166.         msg.type = FETCH_DATA;
  167.         msg.data.header_or_data.buf = (const uint8_t *) buffer;
  168.         msg.data.header_or_data.len = strlen(buffer);
  169.         if (fetch_resource_send_callback(&msg, ctx))
  170.                 goto fetch_resource_notfound_handler_aborted;
  171.  
  172.         msg.type = FETCH_FINISHED;
  173.         fetch_resource_send_callback(&msg, ctx);
  174.  
  175. fetch_resource_notfound_handler_aborted:
  176.         return false;
  177. }
  178.  
  179.  
  180.  
  181. /** callback to initialise the resource fetcher. */
  182. static bool fetch_resource_initialise(lwc_string *scheme)
  183. {
  184.         struct fetch_resource_map_entry *e;
  185.         uint32_t i;
  186.  
  187.         fetch_resource_path_count = 0;
  188.  
  189.         for (i = 0; i < NOF_ELEMENTS(fetch_resource_paths); i++) {
  190.                 e = &fetch_resource_map[fetch_resource_path_count];
  191.  
  192.                 if (lwc_intern_string(fetch_resource_paths[i],
  193.                                 strlen(fetch_resource_paths[i]),
  194.                                 &e->path) != lwc_error_ok) {
  195.                         while (i > 0) {
  196.                                 i--;
  197.                                 lwc_string_unref(fetch_resource_map[i].path);
  198.                                 nsurl_unref(fetch_resource_map[i].url);
  199.                         }
  200.                 }
  201.  
  202.                 e->url = gui_get_resource_url(fetch_resource_paths[i]);
  203.                 LOG(("URL is %s " ,lwc_string_data(e->path)));
  204.                 if (e->url == NULL) {
  205.                         lwc_string_unref(e->path);
  206.                 } else {
  207.                         fetch_resource_path_count++;
  208.                 }
  209.         }
  210.  
  211.         return true;
  212. }
  213.  
  214. /** callback to finalise the resource fetcher. */
  215. static void fetch_resource_finalise(lwc_string *scheme)
  216. {
  217.         uint32_t i;
  218.  
  219.         for (i = 0; i < fetch_resource_path_count; i++) {
  220.                 lwc_string_unref(fetch_resource_map[i].path);
  221.                 nsurl_unref(fetch_resource_map[i].url);
  222.         }
  223. }
  224.  
  225. static bool fetch_resource_can_fetch(const nsurl *url)
  226. {
  227.         return true;
  228. }
  229.  
  230. /** callback to set up a resource fetch context. */
  231. static void *
  232. fetch_resource_setup(struct fetch *fetchh,
  233.                  nsurl *url,
  234.                  bool only_2xx,
  235.                  bool downgrade_tls,
  236.                  const char *post_urlenc,
  237.                  const struct fetch_multipart_data *post_multipart,
  238.                  const char **headers)
  239. {
  240.         struct fetch_resource_context *ctx;
  241.         lwc_string *path;
  242.  
  243.         ctx = calloc(1, sizeof(*ctx));
  244.         if (ctx == NULL)
  245.                 return NULL;
  246.  
  247.         ctx->handler = fetch_resource_notfound_handler;
  248.  
  249.         if ((path = nsurl_get_component(url, NSURL_PATH)) != NULL) {
  250.                 uint32_t i;
  251.                 bool match;
  252.  
  253.                 /* Ensure requested path is valid */
  254.                 for (i = 0; i < fetch_resource_path_count; i++) {
  255.                         if (lwc_string_isequal(path,
  256.                                         fetch_resource_map[i].path,
  257.                                         &match) == lwc_error_ok && match) {
  258.                                 ctx->redirect_url =
  259.                                         nsurl_ref(fetch_resource_map[i].url);
  260.                                 ctx->handler =
  261.                                         fetch_resource_redirect_handler;
  262.                                 break;
  263.                         }
  264.                 }
  265.  
  266.                 lwc_string_unref(path);
  267.         }
  268.  
  269.         ctx->url = nsurl_ref(url);
  270.  
  271.         ctx->fetchh = fetchh;
  272.  
  273.         RING_INSERT(ring, ctx);
  274.  
  275.         return ctx;
  276. }
  277.  
  278. /** callback to free a resource fetch */
  279. static void fetch_resource_free(void *ctx)
  280. {
  281.         struct fetch_resource_context *c = ctx;
  282.         if (c->redirect_url != NULL)
  283.                 nsurl_unref(c->redirect_url);
  284.         if (c->url != NULL)
  285.                 nsurl_unref(c->url);
  286.         RING_REMOVE(ring, c);
  287.         free(ctx);
  288. }
  289.  
  290. /** callback to start a resource fetch */
  291. static bool fetch_resource_start(void *ctx)
  292. {
  293.         return true;
  294. }
  295.  
  296. /** callback to abort a resource fetch */
  297. static void fetch_resource_abort(void *ctx)
  298. {
  299.         struct fetch_resource_context *c = ctx;
  300.  
  301.         /* To avoid the poll loop having to deal with the fetch context
  302.          * disappearing from under it, we simply flag the abort here.
  303.          * The poll loop itself will perform the appropriate cleanup.
  304.          */
  305.         c->aborted = true;
  306. }
  307.  
  308.  
  309. /** callback to poll for additional resource fetch contents */
  310. static void fetch_resource_poll(lwc_string *scheme)
  311. {
  312.         struct fetch_resource_context *c, *next;
  313.  
  314.         if (ring == NULL) return;
  315.  
  316.         /* Iterate over ring, processing each pending fetch */
  317.         c = ring;
  318.         do {
  319.                 /* Ignore fetches that have been flagged as locked.
  320.                  * This allows safe re-entrant calls to this function.
  321.                  * Re-entrancy can occur if, as a result of a callback,
  322.                  * the interested party causes fetch_poll() to be called
  323.                  * again.
  324.                  */
  325.                 if (c->locked == true) {
  326.                         next = c->r_next;
  327.                         continue;
  328.                 }
  329.  
  330.                 /* Only process non-aborted fetches */
  331.                 if (c->aborted == false) {
  332.                         /* resource fetches can be processed in one go */
  333.                         c->handler(c);
  334.                 }
  335.  
  336.                 /* Compute next fetch item at the last possible moment
  337.                  * as processing this item may have added to the ring
  338.                  */
  339.                 next = c->r_next;
  340.  
  341.                 fetch_remove_from_queues(c->fetchh);
  342.                 fetch_free(c->fetchh);
  343.  
  344.                 /* Advance to next ring entry, exiting if we've reached
  345.                  * the start of the ring or the ring has become empty
  346.                  */
  347.         } while ( (c = next) != ring && ring != NULL);
  348. }
  349.  
  350. void fetch_resource_register(void)
  351. {
  352.         lwc_string *scheme;
  353.  
  354.         if (lwc_intern_string("resource", SLEN("resource"),
  355.                         &scheme) != lwc_error_ok) {
  356.                 die("Failed to initialise the fetch module "
  357.                                 "(couldn't intern \"resource\").");
  358.         }
  359.  
  360.         fetch_add_fetcher(scheme,
  361.                 fetch_resource_initialise,
  362.                 fetch_resource_can_fetch,
  363.                 fetch_resource_setup,
  364.                 fetch_resource_start,
  365.                 fetch_resource_abort,
  366.                 fetch_resource_free,
  367.                 fetch_resource_poll,
  368.                 fetch_resource_finalise);
  369. }
  370.