NetSurf
resource.c
Go to the documentation of this file.
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/**
20 * \file
21 * resource scheme URL handling. Based on the data fetcher by Rob Kendrick
22 */
23
24#include <stdlib.h>
25#include <stdbool.h>
26#include <string.h>
27#include <strings.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <libwapcaplet/libwapcaplet.h>
31
32#include "netsurf/inttypes.h"
33#include "utils/nsurl.h"
34#include "utils/corestrings.h"
35#include "utils/log.h"
36#include "utils/time.h"
37#include "utils/messages.h"
38#include "utils/utils.h"
39#include "utils/ring.h"
40#include "netsurf/fetch.h"
42
43#include "content/fetch.h"
44#include "content/fetchers.h"
46
47#define DIRECT_ETAG_VALUE 123456
48
49/** Valid resource paths */
50static const char *fetch_resource_paths[] = {
51 "adblock.css",
52 "default.css",
53 "internal.css",
54 "quirks.css",
55 "user.css",
56 "credits.html",
57 "licence.html",
58 "welcome.html",
59 "favicon.ico",
60 "default.ico",
61 "netsurf.png",
62 "icons/arrow-l.png",
63 "icons/content.png",
64 "icons/directory.png",
65 "icons/directory2.png",
66 "icons/hotlist-add.png",
67 "icons/hotlist-rmv.png",
68 "icons/search.png"
69};
70
71/**
72 * map of resource scheme paths to redirect urls
73 */
75 lwc_string *path; /**< resource scheme path */
76 nsurl *redirect_url; /**< url to redirect to */
77 const uint8_t *data; /**< direct pointer to data */
78 size_t data_len; /**< length of direct data */
80
82
84
85/** Context for an resource fetch */
88
89 struct fetch *fetchh; /**< Handle for this fetch */
90
91 bool aborted; /**< Flag indicating fetch has been aborted */
92 bool locked; /**< Flag indicating entry is already entered */
93
94 nsurl *url; /**< requested url */
95
96 struct fetch_resource_map_entry *entry; /**< resource map entry */
97
99
100 time_t etag;
101};
102
103static struct fetch_resource_context *ring = NULL;
104
106
107/** issue fetch callbacks with locking */
108static inline bool fetch_resource_send_callback(const fetch_msg *msg,
109 struct fetch_resource_context *ctx)
110{
111 ctx->locked = true;
112 fetch_send_callback(msg, ctx->fetchh);
113 ctx->locked = false;
114
115 return ctx->aborted;
116}
117
119 const char *fmt, ...)
120{
121 fetch_msg msg;
122 char header[64];
123 va_list ap;
124 int len;
125
126 va_start(ap, fmt);
127 len = vsnprintf(header, sizeof header, fmt, ap);
128 va_end(ap);
129
130 if (len >= (int)sizeof(header) || len < 0) {
131 return false;
132 }
133
134 msg.type = FETCH_HEADER;
135 msg.data.header_or_data.buf = (const uint8_t *) header;
136 msg.data.header_or_data.len = len;
137
138 return fetch_resource_send_callback(&msg, ctx);
139}
140
141
142
143/**
144 * resource handler that results in a redirect to another url.
145 */
147{
148 fetch_msg msg;
149
150 /* content is going to return redirect */
151 fetch_set_http_code(ctx->fetchh, 302);
152
153 msg.type = FETCH_REDIRECT;
156
157 return true;
158}
159
160/* resource handler that returns data directly */
162{
163 fetch_msg msg;
164
165 /* Check if we can just return not modified */
166 if (ctx->etag != 0 && ctx->etag == DIRECT_ETAG_VALUE) {
167 fetch_set_http_code(ctx->fetchh, 304);
170 return true;
171 }
172
173 /* fetch is going to be successful */
174 fetch_set_http_code(ctx->fetchh, 200);
175
176 /* Any callback can result in the fetch being aborted.
177 * Therefore, we _must_ check for this after _every_ call to
178 * fetch_file_send_callback().
179 */
180
181 /* content type */
182 if (fetch_resource_send_header(ctx, "Content-Type: %s",
183 guit->fetch->filetype(lwc_string_data(ctx->entry->path)))) {
184 goto fetch_resource_data_aborted;
185 }
186
187 /* content length */
188 if (fetch_resource_send_header(ctx, "Content-Length: %" PRIsizet,
189 ctx->entry->data_len)) {
190 goto fetch_resource_data_aborted;
191 }
192
193 /* create etag */
194 if (fetch_resource_send_header(ctx, "ETag: \"%10" PRId64 "\"",
195 (int64_t) DIRECT_ETAG_VALUE)) {
196 goto fetch_resource_data_aborted;
197 }
198
199 /* create max-age of 1 year */
201 "Cache-Control: max-age=31536000")) {
202 goto fetch_resource_data_aborted;
203 }
204
205 msg.type = FETCH_DATA;
206 msg.data.header_or_data.buf = (const uint8_t *) ctx->entry->data;
209
210 if (ctx->aborted == false) {
211 msg.type = FETCH_FINISHED;
213 }
214
215fetch_resource_data_aborted:
216
217 return true;
218}
219
221{
222 fetch_msg msg;
223 int code = 404;
224 char buffer[1024];
225 const char *title;
226 char key[8];
227
228 /* content is going to return error code */
229 fetch_set_http_code(ctx->fetchh, code);
230
231 /* content type */
232 if (fetch_resource_send_header(ctx, "Content-Type: text/html"))
233 goto fetch_resource_notfound_handler_aborted;
234
235 snprintf(key, sizeof key, "HTTP%03d", code);
236 title = messages_get(key);
237
238 snprintf(buffer, sizeof buffer, "<html><head><title>%s</title></head>"
239 "<body><h1>%s</h1>"
240 "<p>Error %d while fetching file %s</p></body></html>",
241 title, title, code, nsurl_access(ctx->url));
242
243 msg.type = FETCH_DATA;
244 msg.data.header_or_data.buf = (const uint8_t *) buffer;
245 msg.data.header_or_data.len = strlen(buffer);
246 if (fetch_resource_send_callback(&msg, ctx))
247 goto fetch_resource_notfound_handler_aborted;
248
249 msg.type = FETCH_FINISHED;
251
252fetch_resource_notfound_handler_aborted:
253 return false;
254}
255
256
257
258/** callback to initialise the resource fetcher. */
259static bool fetch_resource_initialise(lwc_string *scheme)
260{
261 struct fetch_resource_map_entry *e;
262 uint32_t i;
263 nserror res;
264
266
267 for (i = 0; i < NOF_ELEMENTS(fetch_resource_paths); i++) {
269
270 if (lwc_intern_string(fetch_resource_paths[i],
271 strlen(fetch_resource_paths[i]),
272 &e->path) != lwc_error_ok) {
273 while (i > 0) {
274 i--;
275 lwc_string_unref(fetch_resource_map[i].path);
277 }
278 /** \todo should this exit with an error condition? */
279 }
280
281 e->data = NULL;
282 res = guit->fetch->get_resource_data(lwc_string_data(e->path),
283 &e->data,
284 &e->data_len);
285 if (res == NSERROR_OK) {
286 NSLOG(netsurf, INFO, "direct data for %s",
289 } else {
291 if (e->redirect_url == NULL) {
292 lwc_string_unref(e->path);
293 } else {
294 NSLOG(netsurf, INFO, "redirect url for %s",
297 }
298 }
299 }
300
301 return true;
302}
303
304/** callback to finalise the resource fetcher. */
305static void fetch_resource_finalise(lwc_string *scheme)
306{
307 uint32_t i;
308
309 for (i = 0; i < fetch_resource_path_count; i++) {
310 lwc_string_unref(fetch_resource_map[i].path);
311 if (fetch_resource_map[i].data != NULL) {
313 } else {
315 }
316 }
317}
318
319static bool fetch_resource_can_fetch(const nsurl *url)
320{
321 return true;
322}
323
324/**
325 * set up a resource fetch context.
326 */
327static void *
329 nsurl *url,
330 bool only_2xx,
331 bool downgrade_tls,
332 const char *post_urlenc,
333 const struct fetch_multipart_data *post_multipart,
334 const char **headers)
335{
336 struct fetch_resource_context *ctx;
337 lwc_string *path;
338 nserror ret;
339 uint32_t i;
340
341 ctx = calloc(1, sizeof(*ctx));
342 if (ctx == NULL) {
343 return NULL;
344 }
345
347
348 if ((path = nsurl_get_component(url, NSURL_PATH)) != NULL) {
349 bool match;
350
351 /* Ensure requested path is valid */
352 for (i = 0; i < fetch_resource_path_count; i++) {
353 if (lwc_string_isequal(path,
355 &match) == lwc_error_ok && match) {
356 /* found a url match, select handler */
357 ctx->entry = &fetch_resource_map[i];
358 if (ctx->entry->data != NULL) {
360 } else {
362 }
363 break;
364 }
365 }
366
367 lwc_string_unref(path);
368 }
369
370 ctx->url = nsurl_ref(url);
371
372 /* Scan request headers looking for If-None-Match */
373 for (i = 0; headers[i] != NULL; i++) {
374 if (strncasecmp(headers[i], "If-None-Match:",
375 SLEN("If-None-Match:")) != 0) {
376 continue;
377 }
378
379 /* If-None-Match: "12345678" */
380 const char *d = headers[i] + SLEN("If-None-Match:");
381
382 /* Scan to first digit, if any */
383 while (*d != '\0' && (*d < '0' || '9' < *d))
384 d++;
385
386 /* Convert to time_t */
387 if (*d != '\0') {
388 ret = nsc_snptimet(d, strlen(d), &ctx->etag);
389 if (ret != NSERROR_OK) {
390 NSLOG(fetch, WARNING,
391 "Bad If-None-Match value");
392 }
393 }
394 }
395
396 ctx->fetchh = fetchh;
397
398 RING_INSERT(ring, ctx);
399
400 return ctx;
401}
402
403/** callback to free a resource fetch */
404static void fetch_resource_free(void *ctx)
405{
406 struct fetch_resource_context *c = ctx;
407 if (c->url != NULL)
408 nsurl_unref(c->url);
409 free(ctx);
410}
411
412/** callback to start a resource fetch */
413static bool fetch_resource_start(void *ctx)
414{
415 return true;
416}
417
418/** callback to abort a resource fetch */
419static void fetch_resource_abort(void *ctx)
420{
421 struct fetch_resource_context *c = ctx;
422
423 /* To avoid the poll loop having to deal with the fetch context
424 * disappearing from under it, we simply flag the abort here.
425 * The poll loop itself will perform the appropriate cleanup.
426 */
427 c->aborted = true;
428}
429
430
431/** callback to poll for additional resource fetch contents */
432static void fetch_resource_poll(lwc_string *scheme)
433{
434 struct fetch_resource_context *c, *save_ring = NULL;
435
436 while (ring != NULL) {
437 /* Take the first entry from the ring */
438 c = ring;
439 RING_REMOVE(ring, c);
440
441 /* Ignore fetches that have been flagged as locked.
442 * This allows safe re-entrant calls to this function.
443 * Re-entrancy can occur if, as a result of a callback,
444 * the interested party causes fetch_poll() to be called
445 * again.
446 */
447 if (c->locked == true) {
448 RING_INSERT(save_ring, c);
449 continue;
450 }
451
452 /* Only process non-aborted fetches */
453 if (c->aborted == false) {
454 /* resource fetches can be processed in one go */
455 c->handler(c);
456 }
457
458 /* And now finish */
460 fetch_free(c->fetchh);
461 }
462
463 /* Finally, if we saved any fetches which were locked, put them back
464 * into the ring for next time
465 */
466 ring = save_ring;
467}
468
470{
471 lwc_string *scheme = lwc_string_ref(corestring_lwc_resource);
472 const struct fetcher_operation_table fetcher_ops = {
474 .acceptable = fetch_resource_can_fetch,
475 .setup = fetch_resource_setup,
476 .start = fetch_resource_start,
477 .abort = fetch_resource_abort,
478 .free = fetch_resource_free,
479 .poll = fetch_resource_poll,
480 .finalise = fetch_resource_finalise
481 };
482
483 return fetcher_add(scheme, &fetcher_ops);
484}
static osspriteop_area * buffer
The buffer characteristics.
Definition: buffer.c:55
void fetch_set_http_code(struct fetch *fetch, long http_code)
set the http code of a fetch
Definition: fetch.c:794
nserror fetcher_add(lwc_string *scheme, const struct fetcher_operation_table *ops)
Register a fetcher for a scheme.
Definition: fetch.c:357
void fetch_send_callback(const fetch_msg *msg, struct fetch *fetch)
send message to fetch
Definition: fetch.c:757
void fetch_free(struct fetch *f)
Free a fetch structure and associated resources.
Definition: fetch.c:548
void fetch_remove_from_queues(struct fetch *fetch)
remove a queued fetch
Definition: fetch.c:767
Fetching of data from a URL (interface).
@ FETCH_REDIRECT
Definition: fetch.h:49
@ FETCH_DATA
Definition: fetch.h:44
@ FETCH_HEADER
Definition: fetch.h:43
@ FETCH_NOTMODIFIED
Definition: fetch.h:50
@ FETCH_FINISHED
Definition: fetch.h:46
Useful interned string pointers (interface).
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_OK
No error.
Definition: errors.h:30
Interface for fetchers factory.
#define NOF_ELEMENTS(array)
Definition: search.c:67
struct netsurf_table * guit
The global interface table.
Definition: gui_factory.c:49
Interface to core interface table.
Interface to platform-specific fetcher operations.
Netsurf additional integer type formatting macros.
#define PRIsizet
c99 standard printf formatting for size_t type
Definition: inttypes.h:53
#define PRId64
Definition: inttypes.h:34
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
Localised message support (interface).
NetSurf URL handling (interface).
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
nsurl * nsurl_ref(nsurl *url)
Increment the reference count to a NetSurf URL object.
lwc_string * nsurl_get_component(const nsurl *url, nsurl_component part)
Get part of a URL as a lwc_string, from a NetSurf URL object.
@ NSURL_PATH
Definition: nsurl.h:52
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
static bool fetch_resource_send_header(struct fetch_resource_context *ctx, const char *fmt,...)
Definition: resource.c:118
static void fetch_resource_poll(lwc_string *scheme)
callback to poll for additional resource fetch contents
Definition: resource.c:432
static struct fetch_resource_map_entry fetch_resource_map[NOF_ELEMENTS(fetch_resource_paths)]
static void fetch_resource_finalise(lwc_string *scheme)
callback to finalise the resource fetcher.
Definition: resource.c:305
static bool fetch_resource_start(void *ctx)
callback to start a resource fetch
Definition: resource.c:413
bool(* fetch_resource_handler)(struct fetch_resource_context *)
Definition: resource.c:83
static void fetch_resource_free(void *ctx)
callback to free a resource fetch
Definition: resource.c:404
static bool fetch_resource_notfound_handler(struct fetch_resource_context *ctx)
Definition: resource.c:220
static void fetch_resource_abort(void *ctx)
callback to abort a resource fetch
Definition: resource.c:419
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)
set up a resource fetch context.
Definition: resource.c:328
static bool fetch_resource_data_handler(struct fetch_resource_context *ctx)
Definition: resource.c:161
static bool fetch_resource_can_fetch(const nsurl *url)
Definition: resource.c:319
static struct fetch_resource_context * ring
Definition: resource.c:103
nserror fetch_resource_register(void)
Register the resource scheme.
Definition: resource.c:469
static uint32_t fetch_resource_path_count
Definition: resource.c:105
static bool fetch_resource_initialise(lwc_string *scheme)
callback to initialise the resource fetcher.
Definition: resource.c:259
static bool fetch_resource_send_callback(const fetch_msg *msg, struct fetch_resource_context *ctx)
issue fetch callbacks with locking
Definition: resource.c:108
static bool fetch_resource_redirect_handler(struct fetch_resource_context *ctx)
resource handler that results in a redirect to another url.
Definition: resource.c:146
#define DIRECT_ETAG_VALUE
Definition: resource.c:47
static const char * fetch_resource_paths[]
Valid resource paths.
Definition: resource.c:50
resource URL scheme handler interface.
Ring list structure.
#define RING_REMOVE(ring, element)
Remove the given element from the specified ring.
Definition: ring.h:53
#define RING_INSERT(ring, element)
Insert the given item into the specified ring.
Definition: ring.h:40
Interface to utility string handling.
Fetcher message data.
Definition: fetch.h:72
const uint8_t * buf
Definition: fetch.h:79
fetch_msg_type type
Definition: fetch.h:73
struct fetch_msg::@118::@119 header_or_data
size_t len
Definition: fetch.h:80
union fetch_msg::@118 data
const char * redirect
Definition: fetch.h:86
Fetch POST multipart data.
Definition: fetch.h:109
Context for an resource fetch.
Definition: resource.c:86
struct fetch_resource_map_entry * entry
resource map entry
Definition: resource.c:96
bool aborted
Flag indicating fetch has been aborted.
Definition: resource.c:91
bool locked
Flag indicating entry is already entered.
Definition: resource.c:92
nsurl * url
requested url
Definition: resource.c:94
fetch_resource_handler handler
Definition: resource.c:98
struct fetch_resource_context * r_next
Definition: resource.c:87
struct fetch * fetchh
Handle for this fetch.
Definition: resource.c:89
struct fetch_resource_context * r_prev
Definition: resource.c:87
map of resource scheme paths to redirect urls
Definition: resource.c:74
const uint8_t * data
direct pointer to data
Definition: resource.c:77
size_t data_len
length of direct data
Definition: resource.c:78
nsurl * redirect_url
url to redirect to
Definition: resource.c:76
lwc_string * path
resource scheme path
Definition: resource.c:75
Information for a single fetch.
Definition: fetch.c:89
Fetcher operations API.
Definition: fetchers.h:49
bool(* initialise)(lwc_string *scheme)
The initialiser for the fetcher.
Definition: fetchers.h:55
const char *(* filetype)(const char *unix_path)
Determine the MIME type of a local file.
Definition: fetch.h:45
nserror(* release_resource_data)(const uint8_t *data)
Releases source data.
Definition: fetch.h:89
nserror(* get_resource_data)(const char *path, const uint8_t **data, size_t *data_len)
Translate resource to source data.
Definition: fetch.h:77
struct nsurl *(* get_resource_url)(const char *path)
Translate resource to full url.
Definition: fetch.h:62
struct gui_fetch_table * fetch
Fetcher table.
Definition: gui_table.h:85
nserror nsc_snptimet(const char *str, size_t size, time_t *timep)
Parse time in seconds since epoc.
Definition: time.c:147
Interface to time operations.
Interface to a number of general purpose functionality.
#define SLEN(x)
Calculate length of constant C string.
Definition: utils.h:84
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821