Subversion Repositories Kolibri OS

Rev

Rev 3620 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3584 sourcerer 1
/*
2
 * Copyright 2006 Daniel Silverstone 
3
 * Copyright 2007 James Bursa 
4
 * Copyright 2003 Phil Mellor 
5
 *
6
 * This file is part of NetSurf.
7
 *
8
 * NetSurf is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; version 2 of the License.
11
 *
12
 * NetSurf is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see .
19
 */
20
 
21
/** \file
22
 * Fetching of data from a URL (implementation).
23
 *
24
 * This implementation uses libcurl's 'multi' interface.
25
 *
26
 *
27
 * The CURL handles are cached in the curl_handle_ring. There are at most
28
 * ::max_cached_fetch_handles in this ring.
29
 */
30
 
31
#include 
32
#include 
33
#include 
34
#include 
35
#include 
36
#include 
37
#include 
38
#include 
39
 
40
#include 
41
 
42
#include "utils/config.h"
43
//#include 
44
#include "content/fetch.h"
45
#include "content/fetchers/curl.h"
46
#include "content/urldb.h"
47
#include "desktop/netsurf.h"
48
#include "desktop/options.h"
49
#include "utils/log.h"
50
#include "utils/messages.h"
51
#include "utils/schedule.h"
52
#include "utils/utils.h"
53
#include "utils/ring.h"
54
#include "utils/useragent.h"
55
 
56
/* BIG FAT WARNING: This is here because curl doesn't give you an FD to
57
 * poll on, until it has processed a bit of the handle.	 So we need schedules
58
 * in order to make this work.
59
 */
60
#include 
61
 
62
/* uncomment this to use scheduler based calling
63
#define FETCHER_CURLL_SCHEDULED 1
64
*/
65
 
66
 
3616 sourcerer 67
struct fetch_curl_context {
68
	struct fetch_curl_context *r_next, *r_prev;
3584 sourcerer 69
 
3616 sourcerer 70
	struct fetch *fetchh; /**< Handle for this fetch */
3584 sourcerer 71
 
3616 sourcerer 72
	bool aborted; /**< Flag indicating fetch has been aborted */
73
	bool locked; /**< Flag indicating entry is already entered */
74
 
75
	nsurl *url; /**< The full url the fetch refers to */
76
	char *path; /**< The actual path to be used with open() */
77
 
78
	time_t file_etag; /**< Request etag for file (previous st.m_time) */
3584 sourcerer 79
};
80
 
3616 sourcerer 81
static struct fetch_curl_context *ring = NULL;
3584 sourcerer 82
 
83
 
3616 sourcerer 84
static bool fetch_curl_initialise(lwc_string *scheme); //here
85
static void fetch_curl_finalise(lwc_string *scheme); //here
86
static bool fetch_curl_can_fetch(const nsurl *url); //here
3584 sourcerer 87
static void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url,
88
		 bool only_2xx, bool downgrade_tls, const char *post_urlenc,
89
		 const struct fetch_multipart_data *post_multipart,
3616 sourcerer 90
		 const char **headers); //here
91
static bool fetch_curl_start(void *vfetch); //here
3584 sourcerer 92
 
3616 sourcerer 93
static void fetch_curl_abort(void *vf); //here
94
static void fetch_curl_free(void *f); //here
95
static void fetch_curl_poll(lwc_string *scheme_ignored); //here
3584 sourcerer 96
 
3616 sourcerer 97
 
3584 sourcerer 98
/**
99
 * Initialise the fetcher.
100
 *
101
 * Must be called once before any other function.
102
 */
103
 
104
void fetch_curl_register(void)
105
{
106
 
107
lwc_string *scheme;
108
 
109
 
110
LOG(("curl register\n"));
111
 
112
lwc_intern_string("http", SLEN("http"), &scheme);
113
 
114
	if (!fetch_add_fetcher(scheme,
3616 sourcerer 115
				fetch_curl_initialise, //here
116
				fetch_curl_can_fetch, //here
3584 sourcerer 117
				fetch_curl_setup,
118
				fetch_curl_start,
3616 sourcerer 119
				fetch_curl_abort, //here
120
				fetch_curl_free, //here
3584 sourcerer 121
#ifdef FETCHER_CURLL_SCHEDULED
122
				       NULL,
123
#else
3616 sourcerer 124
				fetch_curl_poll, //here
3584 sourcerer 125
#endif
3616 sourcerer 126
				fetch_curl_finalise)) {  //here
3584 sourcerer 127
			LOG(("Unable to register cURL fetcher for HTTP"));
128
		}
129
 
130
 
131
		lwc_intern_string("https", SLEN("https"), &scheme);
132
 
133
	if (!fetch_add_fetcher(scheme,
134
				fetch_curl_initialise,
135
				fetch_curl_can_fetch,
136
				fetch_curl_setup,
137
				fetch_curl_start,
138
				fetch_curl_abort,
139
				fetch_curl_free,
140
#ifdef FETCHER_CURLL_SCHEDULED
141
				       NULL,
142
#else
143
				fetch_curl_poll,
144
#endif
145
				fetch_curl_finalise)) {
146
			LOG(("Unable to register cURL fetcher for HTTPS"));
147
		}
148
 
149
}
150
 
151
 
152
/**
153
 * Initialise a cURL fetcher.
154
 */
155
 
156
bool fetch_curl_initialise(lwc_string *scheme)
157
{
158
 
159
LOG(("curl initi lwc\n"));
160
	return true; /* Always succeeds */
161
}
162
 
163
 
164
/**
165
 * Finalise a cURL fetcher
166
 */
167
 
168
void fetch_curl_finalise(lwc_string *scheme)
169
{
170
LOG(("curl finali\n"));
171
}
172
 
3616 sourcerer 173
static bool fetch_curl_can_fetch(const nsurl *url)
3584 sourcerer 174
{
175
	LOG(("curl can fetch\n"));
3616 sourcerer 176
	return true; //let's lie a bit
3584 sourcerer 177
}
178
 
179
/**
180
 * Start fetching data for the given URL.
181
 *
182
 * The function returns immediately. The fetch may be queued for later
183
 * processing.
184
 *
185
 * A pointer to an opaque struct curl_fetch_info is returned, which can be
186
 * passed to fetch_abort() to abort the fetch at any time. Returns 0 if memory
187
 * is exhausted (or some other fatal error occurred).
188
 *
189
 * The caller must supply a callback function which is called when anything
190
 * interesting happens. The callback function is first called with msg
191
 * FETCH_HEADER, with the header in data, then one or more times
192
 * with FETCH_DATA with some data for the url, and finally with
193
 * FETCH_FINISHED. Alternatively, FETCH_ERROR indicates an error occurred:
194
 * data contains an error message. FETCH_REDIRECT may replace the FETCH_HEADER,
195
 * FETCH_DATA, FETCH_FINISHED sequence if the server sends a replacement URL.
196
 *
197
 * Some private data can be passed as the last parameter to fetch_start, and
198
 * callbacks will contain this.
199
 */
200
 
3616 sourcerer 201
void * fetch_curl_setup (struct fetch *fetchh,
202
		 nsurl *url,
203
		 bool only_2xx,
204
		 bool downgrade_tls,
205
		 const char *post_urlenc,
3584 sourcerer 206
		 const struct fetch_multipart_data *post_multipart,
207
		 const char **headers)
208
{
209
 
3616 sourcerer 210
	LOG(("curl setup\n"));
211
 
212
	struct fetch_curl_context *ctx;
213
	int i;
3584 sourcerer 214
 
3616 sourcerer 215
	ctx = calloc(1, sizeof(*ctx));
216
	if (ctx == NULL)
217
		return NULL;
3584 sourcerer 218
 
3620 sourcerer 219
	//ctx->path = url_to_path(nsurl_access(url));
220
	char *zz;
221
	int pr;
222
	nsurl_get(url, NSURL_WITH_FRAGMENT, &zz, &pr);
223
 
224
	ctx->path = zz;
3616 sourcerer 225
	if (ctx->path == NULL) {
226
		free(ctx);
227
		return NULL;
228
	}
3584 sourcerer 229
 
3616 sourcerer 230
	ctx->url = nsurl_ref(url);
3584 sourcerer 231
 
232
 
3616 sourcerer 233
	ctx->fetchh = fetchh;
3584 sourcerer 234
 
3616 sourcerer 235
	RING_INSERT(ring, ctx);
3584 sourcerer 236
 
3616 sourcerer 237
	return ctx;
3584 sourcerer 238
}
239
 
240
 
241
/**
3616 sourcerer 242
 * Dispatch a single job
3584 sourcerer 243
 */
3616 sourcerer 244
bool fetch_curl_start(void *vfetch)
3584 sourcerer 245
{
3616 sourcerer 246
LOG(("curl start\n"));
247
	return true;
3584 sourcerer 248
}
249
 
250
 
251
 
252
 
253
 
254
 
255
/**
3616 sourcerer 256
 * Abort a fetch.
3584 sourcerer 257
 */
258
 
3616 sourcerer 259
void fetch_curl_abort(void *ctx)
3584 sourcerer 260
{
3616 sourcerer 261
	struct fetch_curl_context *c = ctx;
262
 
263
	/* To avoid the poll loop having to deal with the fetch context
264
	 * disappearing from under it, we simply flag the abort here.
265
	 * The poll loop itself will perform the appropriate cleanup.
266
	 */
267
	c->aborted = true;
3584 sourcerer 268
}
269
 
270
 
271
/**
3616 sourcerer 272
 * Free a fetch structure and associated resources.
3584 sourcerer 273
 */
274
 
3616 sourcerer 275
void fetch_curl_free(void *ctx)
3584 sourcerer 276
{
3616 sourcerer 277
	struct fetch_curl_context *c = ctx;
278
	nsurl_unref(c->url);
279
	free(c->path);
280
	RING_REMOVE(ring, c);
281
	free(ctx);
3584 sourcerer 282
}
283
 
3616 sourcerer 284
static inline bool fetch_curl_send_callback(const fetch_msg *msg,
285
		struct fetch_curl_context *ctx)
286
{
287
	ctx->locked = true;
288
	fetch_send_callback(msg, ctx->fetchh);
289
	ctx->locked = false;
3584 sourcerer 290
 
3616 sourcerer 291
	return ctx->aborted;
292
}
3584 sourcerer 293
 
3616 sourcerer 294
static bool fetch_curl_send_header(struct fetch_curl_context *ctx,
295
		const char *fmt, ...)
3584 sourcerer 296
{
3616 sourcerer 297
	fetch_msg msg;
298
	char header[64];
299
	va_list ap;
3584 sourcerer 300
 
3616 sourcerer 301
	va_start(ap, fmt);
3584 sourcerer 302
 
3616 sourcerer 303
	vsnprintf(header, sizeof header, fmt, ap);
3584 sourcerer 304
 
3616 sourcerer 305
	va_end(ap);
3584 sourcerer 306
 
3616 sourcerer 307
	msg.type = FETCH_HEADER;
308
	msg.data.header_or_data.buf = (const uint8_t *) header;
309
	msg.data.header_or_data.len = strlen(header);
310
	fetch_curl_send_callback(&msg, ctx);
3584 sourcerer 311
 
3616 sourcerer 312
	return ctx->aborted;
313
}
3584 sourcerer 314
 
3616 sourcerer 315
static void fetch_curl_process_error(struct fetch_curl_context *ctx, int code)
3584 sourcerer 316
{
3616 sourcerer 317
	fetch_msg msg;
318
	char buffer[1024];
319
	const char *title;
320
	char key[8];
3584 sourcerer 321
 
3616 sourcerer 322
	/* content is going to return error code */
323
	fetch_set_http_code(ctx->fetchh, code);
3584 sourcerer 324
 
3616 sourcerer 325
	/* content type */
326
	if (fetch_curl_send_header(ctx, "Content-Type: text/html"))
327
		goto fetch_file_process_error_aborted;
3584 sourcerer 328
 
3616 sourcerer 329
	snprintf(key, sizeof key, "HTTP%03d", code);
330
	title = messages_get(key);
3584 sourcerer 331
 
3616 sourcerer 332
	snprintf(buffer, sizeof buffer, "%s"
333
			"

%s

"
334
			"

Error %d while fetching file %s

",
335
			title, title, code, nsurl_access(ctx->url));
3584 sourcerer 336
 
3616 sourcerer 337
	msg.type = FETCH_DATA;
338
	msg.data.header_or_data.buf = (const uint8_t *) buffer;
339
	msg.data.header_or_data.len = strlen(buffer);
340
	if (fetch_curl_send_callback(&msg, ctx))
341
		goto fetch_file_process_error_aborted;
3584 sourcerer 342
 
3616 sourcerer 343
	msg.type = FETCH_FINISHED;
344
	fetch_curl_send_callback(&msg, ctx);
345
 
346
fetch_file_process_error_aborted:
347
	return;
3584 sourcerer 348
}
349
 
350
 
3620 sourcerer 351
int is_pid(int k)
352
{
353
	int error;
354
asm volatile ("int $0x40":"=a"(error):"a"(18), "b"(21), "c"(k));
355
return error;
356
}
357
 
358
 
359
int kill_pid(int k)
360
{
361
	int error;
362
asm volatile ("int $0x40":"=a"(error):"a"(18), "b"(18), "c"(k));
363
return error;
364
}
365
 
3616 sourcerer 366
static void fetch_curl_process(struct fetch_curl_context *ctx) {
367
 
3620 sourcerer 368
	int pid=execl ("/sys/network/downloader", ctx->path, 0);
369
 
370
 
371
 
372
//	while (is_pid(pid)) {
373
	kill_pid(pid);
374
//	}
375
 
376
	pid=execl ("/sys/network/downloader", ctx->path, 0);
377
 
378
	char ps[255];
379
	sprintf(ps, "pid %d", pid);
380
	execl ("/sys/network/@notify", ps, 0);
381
 
382
 
383
	while (is_pid(pid));
384
 
385
 
386
	sprintf(ps, "Yay! Finished");
387
	execl ("/sys/network/@notify", ps, 0);
388
 
389
 
390
	/*
391
	char pzz[255];
392
	sprintf(pzz, "Pid is %d", pid);
393
	execl ("/sys/@notify", pzz, 0); */
394
	//int status;
395
	//waitpid(pid, &status, 0);
396
 
397
 
3616 sourcerer 398
	fetch_msg msg;
3620 sourcerer 399
	//const char * buf = "

Hello, file fetcher!

";
3584 sourcerer 400
 
3620 sourcerer 401
 FILE *infile;
402
  infile = fopen("/sys/.download", "rb");
403
 
404
  if (infile == NULL) {
405
    printf("file does not exist.\n");
406
    return -1;
407
  }
408
 
409
  fseek(infile, 0, SEEK_END);
410
  size_t file_size = ftell(infile);
411
  rewind(infile);
412
 
413
  char *buffer = (char*)malloc(file_size * sizeof(char));
414
  if (buffer == NULL) {
415
    fclose(infile);
416
    printf("Error allocating %d bytes.\n", file_size * sizeof(char));
417
    return -1;
418
  }
419
  size_t bytes_read = fread(buffer, sizeof(char), file_size, infile);
420
  if (bytes_read != file_size) {
421
    printf("Have read only %d bytes of %d.\n", bytes_read, file_size);
422
    free(buffer);
423
    fclose(infile);
424
    return -1;
425
  }
426
  fclose(infile);
427
 
428
 
429
 
430
 
3616 sourcerer 431
/* fetch is going to be successful */
432
	fetch_set_http_code(ctx->fetchh, 200);
3584 sourcerer 433
 
3616 sourcerer 434
	/* Any callback can result in the fetch being aborted.
435
	 * Therefore, we _must_ check for this after _every_ call to
436
	 * fetch_file_send_callback().
437
	 */
3584 sourcerer 438
 
3624 sourcerer 439
	__menuet__debug_out(fetch_filetype(ctx->path));
440
	__menuet__debug_out("\n");
441
 
442
	if (fetch_curl_send_header(ctx, "Content-Type: %s",
443
			fetch_filetype(ctx->path)))
3616 sourcerer 444
		goto fetch_file_process_aborted;
3584 sourcerer 445
 
3616 sourcerer 446
 
447
	/* main data loop */
3584 sourcerer 448
 
3616 sourcerer 449
		msg.type = FETCH_DATA;
3620 sourcerer 450
		msg.data.header_or_data.buf = (const uint8_t *) buffer;
451
		msg.data.header_or_data.len = file_size;
3616 sourcerer 452
		fetch_curl_send_callback(&msg, ctx);
453
 
454
 
3584 sourcerer 455
 
3616 sourcerer 456
	if (ctx->aborted == false) {
457
		msg.type = FETCH_FINISHED;
458
		fetch_curl_send_callback(&msg, ctx);
459
	}
3584 sourcerer 460
 
3616 sourcerer 461
fetch_file_process_aborted:
462
return;
3584 sourcerer 463
 
464
}
465
 
3616 sourcerer 466
 
3584 sourcerer 467
/**
3616 sourcerer 468
 * Do some work on current fetches.
3584 sourcerer 469
 *
3616 sourcerer 470
 * Must be called regularly to make progress on fetches.
3584 sourcerer 471
 */
472
 
3616 sourcerer 473
void fetch_curl_poll(lwc_string *scheme_ignored)
3584 sourcerer 474
{
3616 sourcerer 475
	LOG(("curl poll\n"));
476
 
477
	struct fetch_curl_context *c, *next;
3584 sourcerer 478
 
3616 sourcerer 479
	if (ring == NULL) return;
3584 sourcerer 480
 
3616 sourcerer 481
	/* Iterate over ring, processing each pending fetch */
482
	c = ring;
483
	do {
484
		/* Ignore fetches that have been flagged as locked.
485
		 * This allows safe re-entrant calls to this function.
486
		 * Re-entrancy can occur if, as a result of a callback,
487
		 * the interested party causes fetch_poll() to be called
488
		 * again.
489
		 */
490
		if (c->locked == true) {
491
			next = c->r_next;
492
			continue;
493
		}
3584 sourcerer 494
 
3616 sourcerer 495
		/* Only process non-aborted fetches */
496
		if (c->aborted == false) {
497
			/* file fetches can be processed in one go */
498
			fetch_curl_process(c);
499
		}
3584 sourcerer 500
 
3616 sourcerer 501
		/* Compute next fetch item at the last possible moment as
502
		 * processing this item may have added to the ring.
503
		 */
504
		next = c->r_next;
3584 sourcerer 505
 
3616 sourcerer 506
		fetch_remove_from_queues(c->fetchh);
507
		fetch_free(c->fetchh);
508
 
509
		/* Advance to next ring entry, exiting if we've reached
510
		 * the start of the ring or the ring has become empty
511
		 */
512
	} while ( (c = next) != ring && ring != NULL);
513
 
3584 sourcerer 514
}
515