NetSurf
fetch_rsrc.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
3 * Copyright 2008 Rob Kendrick <rjek@netsurf-browser.org>
4 *
5 * This file is part of NetSurf.
6 *
7 * NetSurf is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * NetSurf is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/* rsrc: URL handling. */
21
22#define __STDBOOL_H__ 1
23#include <stdlib.h>
24#include <assert.h>
25#include <errno.h>
26#include <stdbool.h>
27#include <string.h>
28#include <strings.h>
29#include <time.h>
30#include <sys/select.h>
31#include <sys/stat.h>
32#include <sys/utsname.h>
33#include <image.h>
34#include <Resources.h>
35#include <String.h>
36#include <libwapcaplet/libwapcaplet.h>
37
38extern "C" {
39#include "utils/config.h"
40#include "utils/nsoption.h"
41#include "utils/log.h"
42#include "utils/messages.h"
43#include "utils/utils.h"
44#include "utils/ring.h"
45#include "content/fetch.h"
46#include "content/fetchers.h"
47}
48
49#include "beos/fetch_rsrc.h"
50#include "beos/filetype.h"
51#include "beos/gui.h"
52
53
56 char *name;
57 char *url;
58 char *mimetype;
59 char *data;
60 size_t datalen;
61
62 bool aborted;
63 bool locked;
64
66};
67
68static struct fetch_rsrc_context *ring = NULL;
69
70BResources *gAppResources = NULL;
71
72static bool fetch_rsrc_initialise(lwc_string *scheme)
73{
74 NSLOG(netsurf, INFO, "fetch_rsrc_initialise called for %s",
75 lwc_string_data(scheme));
76 return true;
77}
78
79static void fetch_rsrc_finalise(lwc_string *scheme)
80{
81 NSLOG(netsurf, INFO, "fetch_rsrc_finalise called for %s",
82 lwc_string_data(scheme));
83}
84
85static bool fetch_rsrc_can_fetch(const nsurl *url)
86{
87 return true;
88}
89
91 bool only_2xx, bool downgrade_tls, const char *post_urlenc,
92 const struct fetch_multipart_data *post_multipart,
93 const char **headers)
94{
95 struct fetch_rsrc_context *ctx;
96 ctx = (struct fetch_rsrc_context *)calloc(1, sizeof(*ctx));
97
98 if (ctx == NULL)
99 return NULL;
100
102 /* TODO: keep as nsurl to avoid copy */
103 ctx->url = (char *)malloc(nsurl_length(url) + 1);
104
105 if (ctx->url == NULL) {
106 free(ctx);
107 return NULL;
108 }
109 memcpy(ctx->url, nsurl_access(url), nsurl_length(url) + 1);
110
111 RING_INSERT(ring, ctx);
112
113 return ctx;
114}
115
116static bool fetch_rsrc_start(void *ctx)
117{
118 return true;
119}
120
121static void fetch_rsrc_free(void *ctx)
122{
123 struct fetch_rsrc_context *c = (struct fetch_rsrc_context *)ctx;
124
125 free(c->name);
126 free(c->url);
127 free(c->data);
128 free(c->mimetype);
129 RING_REMOVE(ring, c);
130 free(ctx);
131}
132
133static void fetch_rsrc_abort(void *ctx)
134{
135 struct fetch_rsrc_context *c = (struct fetch_rsrc_context *)ctx;
136
137 /* To avoid the poll loop having to deal with the fetch context
138 * disappearing from under it, we simply flag the abort here.
139 * The poll loop itself will perform the appropriate cleanup.
140 */
141 c->aborted = true;
142}
143
144static void fetch_rsrc_send_callback(const fetch_msg *msg,
145 struct fetch_rsrc_context *c)
146{
147 c->locked = true;
149 c->locked = false;
150}
151
153{
154 fetch_msg msg;
155 char *params;
156 //char *at = NULL;
157 char *slash;
158 //char *comma = NULL;
159 //char *unescaped;
160 uint32 type = 'data'; // default for embeded files
161 int32 id = 0;
162
163 /* format of a rsrc: URL is:
164 * rsrc://[TYPE][@NUM]/name[,mime]
165 */
166
167 NSLOG(netsurf, INFO, "*** Processing %s", c->url);
168
169 if (strlen(c->url) < 7) {
170 /* 7 is the minimum possible length (rsrc://) */
171 msg.type = FETCH_ERROR;
172 msg.data.error = "Malformed rsrc: URL";
174 return false;
175 }
176
177 /* skip the rsrc: part */
178 params = c->url + sizeof("rsrc://") - 1;
179
180 /* find the slash */
181 if ( (slash = strchr(params, '/')) == NULL) {
182 msg.type = FETCH_ERROR;
183 msg.data.error = "Malformed rsrc: URL";
185 return false;
186 }
187
188 // doesn't exist in the filesystem but we should hit the internal types.
189 c->mimetype = strdup(fetch_filetype(slash));
190 c->name = strdup(slash + 1);
191
192 if (c->mimetype == NULL) {
193 msg.type = FETCH_ERROR;
194 msg.data.error =
195 "Unable to allocate memory for mimetype in rsrc: URL";
197 return false;
198 }
199
200 if (params[0] != '/') {
201 uint8 c1, c2, c3, c4;
202 if (sscanf(params, "%c%c%c%c", &c1, &c2, &c3, &c4) > 3) {
203 type = c1 << 24 | c2 << 16 | c3 << 8 | c4;
204 NSLOG(netsurf, INFO, "fetch_rsrc: type:%4.4s\n",
205 (char *)&type);
206 }
207 }
208
209 NSLOG(netsurf, INFO, "fetch_rsrc: 0x%08lx, %ld, '%s'\n", type, id,
210 c->name);
211
212 bool found;
213 if (id)
214 found = gAppResources->HasResource(type, id);
215 else
216 found = gAppResources->HasResource(type, c->name);
217 if (!found) {
218 BString error("Cannot locate resource: ");
219 if (id)
220 error << id;
221 else
222 error << c->name;
223 msg.type = FETCH_ERROR;
224 msg.data.error = error.String();
226 return false;
227 }
228
229 size_t len;
230 const void *data;
231 if (id)
232 data = gAppResources->LoadResource(type, id, &len);
233 else
234 data = gAppResources->LoadResource(type, c->name, &len);
235
236 if (!data) {
237 msg.type = FETCH_ERROR;
238 msg.data.error = "Cannot load rsrc: URL";
240 return false;
241 }
242
243 c->datalen = len;
244 c->data = (char *)malloc(c->datalen);
245 if (c->data == NULL) {
246 msg.type = FETCH_ERROR;
247 msg.data.error = "Unable to allocate memory for rsrc: URL";
249 return false;
250 }
251 memcpy(c->data, data, c->datalen);
252
253 return true;
254}
255
256static void fetch_rsrc_poll(lwc_string *scheme)
257{
258 fetch_msg msg;
259 struct fetch_rsrc_context *c, *next;
260
261 if (ring == NULL) return;
262
263 /* Iterate over ring, processing each pending fetch */
264 c = ring;
265 do {
266 /* Take a copy of the next pointer as we may destroy
267 * the ring item we're currently processing */
268 next = c->r_next;
269
270 /* Ignore fetches that have been flagged as locked.
271 * This allows safe re-entrant calls to this function.
272 * Re-entrancy can occur if, as a result of a callback,
273 * the interested party causes fetch_poll() to be called
274 * again.
275 */
276 if (c->locked == true) {
277 continue;
278 }
279
280 /* Only process non-aborted fetches */
281 if (!c->aborted && fetch_rsrc_process(c) == true) {
282 char header[64];
283
285 NSLOG(netsurf, INFO,
286 "setting rsrc: MIME type to %s, length to %zd",
287 c->mimetype,
288 c->datalen);
289 /* Any callback can result in the fetch being aborted.
290 * Therefore, we _must_ check for this after _every_
291 * call to fetch_rsrc_send_callback().
292 */
293 snprintf(header, sizeof header, "Content-Type: %s",
294 c->mimetype);
295 msg.type = FETCH_HEADER;
296 msg.data.header_or_data.buf = (const uint8_t *) header;
297 msg.data.header_or_data.len = strlen(header);
299
300 snprintf(header, sizeof header, "Content-Length: %zd",
301 c->datalen);
302 msg.type = FETCH_HEADER;
303 msg.data.header_or_data.buf = (const uint8_t *) header;
304 msg.data.header_or_data.len = strlen(header);
306
307 if (!c->aborted) {
308 msg.type = FETCH_DATA;
309 msg.data.header_or_data.buf = (const uint8_t *) c->data;
312 }
313 if (!c->aborted) {
314 msg.type = FETCH_FINISHED;
316 }
317 } else {
318 NSLOG(netsurf, INFO, "Processing of %s failed!",
319 c->url);
320
321 /* Ensure that we're unlocked here. If we aren't,
322 * then fetch_rsrc_process() is broken.
323 */
324 assert(c->locked == false);
325 }
326
329
330 /* Advance to next ring entry, exiting if we've reached
331 * the start of the ring or the ring has become empty
332 */
333 } while ( (c = next) != ring && ring != NULL);
334}
335
336/* BAppFileInfo is supposed to find the app's resources for us,
337 * but this won't work if we ever want to be used as a replicant.
338 * This trick should work regardless,
339 */
341{
342 char path[B_PATH_NAME_LENGTH];
343 if (nsbeos_find_app_path(path) < B_OK)
344 return B_ERROR;
345 //fprintf(stderr, "loading resources from '%s'\n", path);
346
347 BFile file(path, B_READ_ONLY);
348 if (file.InitCheck() < 0)
349 return file.InitCheck();
350 gAppResources = new BResources;
351 status_t err;
352 err = gAppResources->SetTo(&file);
353 if (err >= B_OK)
354 return B_OK;
355 delete gAppResources;
356 gAppResources = NULL;
357 return err;
358}
359
360BResources *get_app_resources()
361{
362 return gAppResources;
363}
364
366{
367 lwc_string *scheme;
368 int err;
369 nserror ret;
370
371 const struct fetcher_operation_table fetcher_ops_rsrc = {
379 NULL,
381 };
382
383 err = find_app_resources();
384
385 if (err < B_OK) {
386 beos_warn_user("Resources", strerror(err));
387 return;
388 }
389
390 if (lwc_intern_string("rsrc", SLEN("rsrc"), &scheme) != lwc_error_ok) {
391 die("Failed to initialise the fetch module "
392 "(couldn't intern \"rsrc\").");
393 }
394
395 ret = fetcher_add(scheme, &fetcher_ops_rsrc);
396 if (ret != NSERROR_OK) {
397 die("unable to add rsrc fetcher.");
398 }
399}
400
402{
403 delete gAppResources;
404 gAppResources = NULL;
405}
const char * fetch_filetype(const char *unix_path)
Determine the MIME type of a local file.
Definition: filetype.c:58
void die(const char *error)
Cause an abnormal program termination.
Definition: misc.c:69
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_DATA
Definition: fetch.h:44
@ FETCH_HEADER
Definition: fetch.h:43
@ FETCH_FINISHED
Definition: fetch.h:46
@ FETCH_ERROR
Definition: fetch.h:48
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_OK
No error.
Definition: errors.h:30
BResources * gAppResources
Definition: fetch_rsrc.cpp:70
static void fetch_rsrc_finalise(lwc_string *scheme)
Definition: fetch_rsrc.cpp:79
static int find_app_resources()
Definition: fetch_rsrc.cpp:340
static void fetch_rsrc_free(void *ctx)
Definition: fetch_rsrc.cpp:121
static bool fetch_rsrc_process(struct fetch_rsrc_context *c)
Definition: fetch_rsrc.cpp:152
static void fetch_rsrc_poll(lwc_string *scheme)
Definition: fetch_rsrc.cpp:256
static bool fetch_rsrc_start(void *ctx)
Definition: fetch_rsrc.cpp:116
static void fetch_rsrc_send_callback(const fetch_msg *msg, struct fetch_rsrc_context *c)
Definition: fetch_rsrc.cpp:144
static struct fetch_rsrc_context * ring
Definition: fetch_rsrc.cpp:68
void fetch_rsrc_unregister(void)
Definition: fetch_rsrc.cpp:401
void fetch_rsrc_register(void)
Definition: fetch_rsrc.cpp:365
static void fetch_rsrc_abort(void *ctx)
Definition: fetch_rsrc.cpp:133
static bool fetch_rsrc_can_fetch(const nsurl *url)
Definition: fetch_rsrc.cpp:85
BResources * get_app_resources()
Definition: fetch_rsrc.cpp:360
static bool fetch_rsrc_initialise(lwc_string *scheme)
Definition: fetch_rsrc.cpp:72
static void * fetch_rsrc_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)
Definition: fetch_rsrc.cpp:90
rsrc: URL method handler
Interface for fetchers factory.
const char * type
Definition: filetype.cpp:44
image_id nsbeos_find_app_path(char *path)
Definition: gui.cpp:246
nserror beos_warn_user(const char *warning, const char *detail)
Display a warning for a serious problem (eg memory exhaustion).
Definition: gui.cpp:116
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
Localised message support (interface).
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
size_t nsurl_length(const nsurl *url)
Find the length of a NetSurf URL object's URL, as returned by nsurl_access.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
uint8_t uint8
Definition: os3support.h:180
int32_t int32
Definition: os3support.h:183
uint32_t uint32
Definition: os3support.h:184
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 * error
Definition: fetch.h:83
Fetch POST multipart data.
Definition: fetch.h:109
struct fetch_rsrc_context * r_next
Definition: fetch_rsrc.cpp:65
struct fetch_rsrc_context * r_prev
Definition: fetch_rsrc.cpp:65
struct fetch * parent_fetch
Definition: fetch_rsrc.cpp:55
Information for a single fetch.
Definition: fetch.c:89
Fetcher operations API.
Definition: fetchers.h:49
Interface to time operations.
Option reading and saving interface.
Interface to a number of general purpose functionality.
#define SLEN(x)
Calculate length of constant C string.
Definition: utils.h:88
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