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 "netsurf/inttypes.h"
46#include "content/fetch.h"
47#include "content/fetchers.h"
48}
49
50#include "beos/fetch_rsrc.h"
51#include "beos/filetype.h"
52#include "beos/gui.h"
53
54
57 char *name;
58 char *url;
59 char *mimetype;
60 char *data;
61 size_t datalen;
62
63 bool aborted;
64 bool locked;
65
67};
68
69static struct fetch_rsrc_context *ring = NULL;
70
71BResources *gAppResources = NULL;
72
73static bool fetch_rsrc_initialise(lwc_string *scheme)
74{
75 NSLOG(netsurf, INFO, "fetch_rsrc_initialise called for %s",
76 lwc_string_data(scheme));
77 return true;
78}
79
80static void fetch_rsrc_finalise(lwc_string *scheme)
81{
82 NSLOG(netsurf, INFO, "fetch_rsrc_finalise called for %s",
83 lwc_string_data(scheme));
84}
85
86static bool fetch_rsrc_can_fetch(const nsurl *url)
87{
88 return true;
89}
90
92 bool only_2xx, bool downgrade_tls, const char *post_urlenc,
93 const struct fetch_multipart_data *post_multipart,
94 const char **headers)
95{
96 struct fetch_rsrc_context *ctx;
97 ctx = (struct fetch_rsrc_context *)calloc(1, sizeof(*ctx));
98
99 if (ctx == NULL)
100 return NULL;
101
103 /* TODO: keep as nsurl to avoid copy */
104 ctx->url = (char *)malloc(nsurl_length(url) + 1);
105
106 if (ctx->url == NULL) {
107 free(ctx);
108 return NULL;
109 }
110 memcpy(ctx->url, nsurl_access(url), nsurl_length(url) + 1);
111
112 RING_INSERT(ring, ctx);
113
114 return ctx;
115}
116
117static bool fetch_rsrc_start(void *ctx)
118{
119 return true;
120}
121
122static void fetch_rsrc_free(void *ctx)
123{
124 struct fetch_rsrc_context *c = (struct fetch_rsrc_context *)ctx;
125
126 free(c->name);
127 free(c->url);
128 free(c->data);
129 free(c->mimetype);
130 RING_REMOVE(ring, c);
131 free(ctx);
132}
133
134static void fetch_rsrc_abort(void *ctx)
135{
136 struct fetch_rsrc_context *c = (struct fetch_rsrc_context *)ctx;
137
138 /* To avoid the poll loop having to deal with the fetch context
139 * disappearing from under it, we simply flag the abort here.
140 * The poll loop itself will perform the appropriate cleanup.
141 */
142 c->aborted = true;
143}
144
145static void fetch_rsrc_send_callback(const fetch_msg *msg,
146 struct fetch_rsrc_context *c)
147{
148 c->locked = true;
150 c->locked = false;
151}
152
154{
155 fetch_msg msg;
156 char *params;
157 //char *at = NULL;
158 char *slash;
159 //char *comma = NULL;
160 //char *unescaped;
161 uint32 type = 'data'; // default for embeded files
162 int32 id = 0;
163
164 /* format of a rsrc: URL is:
165 * rsrc://[TYPE][@NUM]/name[,mime]
166 */
167
168 NSLOG(netsurf, INFO, "*** Processing %s", c->url);
169
170 if (strlen(c->url) < 7) {
171 /* 7 is the minimum possible length (rsrc://) */
172 msg.type = FETCH_ERROR;
173 msg.data.error = "Malformed rsrc: URL";
175 return false;
176 }
177
178 /* skip the rsrc: part */
179 params = c->url + sizeof("rsrc://") - 1;
180
181 /* find the slash */
182 if ( (slash = strchr(params, '/')) == NULL) {
183 msg.type = FETCH_ERROR;
184 msg.data.error = "Malformed rsrc: URL";
186 return false;
187 }
188
189 // doesn't exist in the filesystem but we should hit the internal types.
190 c->mimetype = strdup(fetch_filetype(slash));
191 c->name = strdup(slash + 1);
192
193 if (c->mimetype == NULL) {
194 msg.type = FETCH_ERROR;
195 msg.data.error =
196 "Unable to allocate memory for mimetype in rsrc: URL";
198 return false;
199 }
200
201 if (params[0] != '/') {
202 uint8 c1, c2, c3, c4;
203 if (sscanf(params, "%c%c%c%c", &c1, &c2, &c3, &c4) > 3) {
204 type = c1 << 24 | c2 << 16 | c3 << 8 | c4;
205 NSLOG(netsurf, INFO, "fetch_rsrc: type:%4.4s\n",
206 (char *)&type);
207 }
208 }
209
210 NSLOG(netsurf, INFO, "fetch_rsrc: 0x%08" PRIx32 ", %" PRId32 ", '%s'\n",
211 type, id, c->name);
212
213 bool found;
214 if (id)
215 found = gAppResources->HasResource(type, id);
216 else
217 found = gAppResources->HasResource(type, c->name);
218 if (!found) {
219 BString error("Cannot locate resource: ");
220 if (id)
221 error << id;
222 else
223 error << c->name;
224 msg.type = FETCH_ERROR;
225 msg.data.error = error.String();
227 return false;
228 }
229
230 size_t len;
231 const void *data;
232 if (id)
233 data = gAppResources->LoadResource(type, id, &len);
234 else
235 data = gAppResources->LoadResource(type, c->name, &len);
236
237 if (!data) {
238 msg.type = FETCH_ERROR;
239 msg.data.error = "Cannot load rsrc: URL";
241 return false;
242 }
243
244 c->datalen = len;
245 c->data = (char *)malloc(c->datalen);
246 if (c->data == NULL) {
247 msg.type = FETCH_ERROR;
248 msg.data.error = "Unable to allocate memory for rsrc: URL";
250 return false;
251 }
252 memcpy(c->data, data, c->datalen);
253
254 return true;
255}
256
257static void fetch_rsrc_poll(lwc_string *scheme)
258{
259 fetch_msg msg;
260 struct fetch_rsrc_context *c, *next;
261
262 if (ring == NULL) return;
263
264 /* Iterate over ring, processing each pending fetch */
265 c = ring;
266 do {
267 /* Take a copy of the next pointer as we may destroy
268 * the ring item we're currently processing */
269 next = c->r_next;
270
271 /* Ignore fetches that have been flagged as locked.
272 * This allows safe re-entrant calls to this function.
273 * Re-entrancy can occur if, as a result of a callback,
274 * the interested party causes fetch_poll() to be called
275 * again.
276 */
277 if (c->locked == true) {
278 continue;
279 }
280
281 /* Only process non-aborted fetches */
282 if (!c->aborted && fetch_rsrc_process(c) == true) {
283 char header[64];
284
286 NSLOG(netsurf, INFO,
287 "setting rsrc: MIME type to %s, length to %zd",
288 c->mimetype,
289 c->datalen);
290 /* Any callback can result in the fetch being aborted.
291 * Therefore, we _must_ check for this after _every_
292 * call to fetch_rsrc_send_callback().
293 */
294 snprintf(header, sizeof header, "Content-Type: %s",
295 c->mimetype);
296 msg.type = FETCH_HEADER;
297 msg.data.header_or_data.buf = (const uint8_t *) header;
298 msg.data.header_or_data.len = strlen(header);
300
301 snprintf(header, sizeof header, "Content-Length: %zd",
302 c->datalen);
303 msg.type = FETCH_HEADER;
304 msg.data.header_or_data.buf = (const uint8_t *) header;
305 msg.data.header_or_data.len = strlen(header);
307
308 if (!c->aborted) {
309 msg.type = FETCH_DATA;
310 msg.data.header_or_data.buf = (const uint8_t *) c->data;
313 }
314 if (!c->aborted) {
315 msg.type = FETCH_FINISHED;
317 }
318 } else {
319 NSLOG(netsurf, INFO, "Processing of %s failed!",
320 c->url);
321
322 /* Ensure that we're unlocked here. If we aren't,
323 * then fetch_rsrc_process() is broken.
324 */
325 assert(c->locked == false);
326 }
327
330
331 /* Advance to next ring entry, exiting if we've reached
332 * the start of the ring or the ring has become empty
333 */
334 } while ( (c = next) != ring && ring != NULL);
335}
336
337/* BAppFileInfo is supposed to find the app's resources for us,
338 * but this won't work if we ever want to be used as a replicant.
339 * This trick should work regardless,
340 */
342{
343 char path[B_PATH_NAME_LENGTH];
344 if (nsbeos_find_app_path(path) < B_OK)
345 return B_ERROR;
346 //fprintf(stderr, "loading resources from '%s'\n", path);
347
348 BFile file(path, B_READ_ONLY);
349 if (file.InitCheck() < 0)
350 return file.InitCheck();
351 gAppResources = new BResources;
352 status_t err;
353 err = gAppResources->SetTo(&file);
354 if (err >= B_OK)
355 return B_OK;
356 delete gAppResources;
357 gAppResources = NULL;
358 return err;
359}
360
361BResources *get_app_resources()
362{
363 return gAppResources;
364}
365
367{
368 lwc_string *scheme;
369 int err;
370 nserror ret;
371
372 const struct fetcher_operation_table fetcher_ops_rsrc = {
380 NULL,
382 };
383
384 err = find_app_resources();
385
386 if (err < B_OK) {
387 beos_warn_user("Resources", strerror(err));
388 return;
389 }
390
391 if (lwc_intern_string("rsrc", SLEN("rsrc"), &scheme) != lwc_error_ok) {
392 die("Failed to initialise the fetch module "
393 "(couldn't intern \"rsrc\").");
394 }
395
396 ret = fetcher_add(scheme, &fetcher_ops_rsrc);
397 if (ret != NSERROR_OK) {
398 die("unable to add rsrc fetcher.");
399 }
400}
401
403{
404 delete gAppResources;
405 gAppResources = NULL;
406}
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:790
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:753
void fetch_free(struct fetch *f)
Free a fetch structure and associated resources.
Definition: fetch.c:546
void fetch_remove_from_queues(struct fetch *fetch)
remove a queued fetch
Definition: fetch.c:763
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:71
static void fetch_rsrc_finalise(lwc_string *scheme)
Definition: fetch_rsrc.cpp:80
static int find_app_resources()
Definition: fetch_rsrc.cpp:341
static void fetch_rsrc_free(void *ctx)
Definition: fetch_rsrc.cpp:122
static bool fetch_rsrc_process(struct fetch_rsrc_context *c)
Definition: fetch_rsrc.cpp:153
static void fetch_rsrc_poll(lwc_string *scheme)
Definition: fetch_rsrc.cpp:257
static bool fetch_rsrc_start(void *ctx)
Definition: fetch_rsrc.cpp:117
static void fetch_rsrc_send_callback(const fetch_msg *msg, struct fetch_rsrc_context *c)
Definition: fetch_rsrc.cpp:145
static struct fetch_rsrc_context * ring
Definition: fetch_rsrc.cpp:69
void fetch_rsrc_unregister(void)
Definition: fetch_rsrc.cpp:402
void fetch_rsrc_register(void)
Definition: fetch_rsrc.cpp:366
static void fetch_rsrc_abort(void *ctx)
Definition: fetch_rsrc.cpp:134
static bool fetch_rsrc_can_fetch(const nsurl *url)
Definition: fetch_rsrc.cpp:86
BResources * get_app_resources()
Definition: fetch_rsrc.cpp:361
static bool fetch_rsrc_initialise(lwc_string *scheme)
Definition: fetch_rsrc.cpp:73
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:91
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
Netsurf additional integer type formatting macros.
#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:66
struct fetch_rsrc_context * r_prev
Definition: fetch_rsrc.cpp:66
struct fetch * parent_fetch
Definition: fetch_rsrc.cpp:56
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