Subversion Repositories Kolibri OS

Rev

Rev 4364 | 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,2007 Daniel Silverstone 
3
 * Copyright 2007 James Bursa 
4
 * Copyright 2003 Phil Mellor 
5
 *
6
 * This file is part of NetSurf, http://www.netsurf-browser.org/
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
 * Active fetches are held in the circular linked list ::fetch_ring. There may
25
 * be at most ::option_max_fetchers_per_host active requests per Host: header.
26
 * There may be at most ::option_max_fetchers active requests overall. Inactive
27
 * fetchers are stored in the ::queue_ring waiting for use.
28
 */
29
 
30
#include 
31
#include 
32
#include 
33
#include 
34
#include 
35
#include 
36
 
37
#include 
38
 
39
#include "utils/config.h"
40
#include "content/fetch.h"
41
#include "content/fetchers/resource.h"
42
#include "content/fetchers/about.h"
43
#include "content/fetchers/curl.h"
44
#include "content/fetchers/data.h"
45
#include "content/fetchers/file.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/nsurl.h"
52
#include "utils/utils.h"
53
#include "utils/ring.h"
54
 
55
/* Define this to turn on verbose fetch logging */
56
#undef DEBUG_FETCH_VERBOSE
57
 
58
bool fetch_active;	/**< Fetches in progress, please call fetch_poll(). */
59
 
60
/** Information about a fetcher for a given scheme. */
61
typedef struct scheme_fetcher_s {
62
	lwc_string *scheme_name;		/**< The scheme. */
63
	fetcher_can_fetch can_fetch;		/**< Ensure an URL can be fetched. */
64
	fetcher_setup_fetch setup_fetch;	/**< Set up a fetch. */
65
	fetcher_start_fetch start_fetch;	/**< Start a fetch. */
66
	fetcher_abort_fetch abort_fetch;	/**< Abort a fetch. */
67
	fetcher_free_fetch free_fetch;		/**< Free a fetch. */
68
	fetcher_poll_fetcher poll_fetcher;	/**< Poll this fetcher. */
69
	fetcher_finalise finaliser;		/**< Clean up this fetcher. */
70
	int refcount;				/**< When zero, clean up the fetcher. */
71
	struct scheme_fetcher_s *next_fetcher;	/**< Next fetcher in the list. */
72
	struct scheme_fetcher_s *prev_fetcher;  /**< Prev fetcher in the list. */
73
} scheme_fetcher;
74
 
75
static scheme_fetcher *fetchers = NULL;
76
 
77
/** Information for a single fetch. */
78
struct fetch {
79
	fetch_callback callback;/**< Callback function. */
80
	nsurl *url;		/**< URL. */
81
	nsurl *referer;		/**< Referer URL. */
82
	bool send_referer;	/**< Valid to send the referer */
83
	bool verifiable;	/**< Transaction is verifiable */
84
	void *p;		/**< Private data for callback. */
85
	lwc_string *host;	/**< Host part of URL, interned */
86
	long http_code;		/**< HTTP response code, or 0. */
87
	scheme_fetcher *ops;	/**< Fetcher operations for this fetch,
88
				     NULL if not set. */
89
	void *fetcher_handle;	/**< The handle for the fetcher. */
90
	bool fetch_is_active;	/**< This fetch is active. */
91
	struct fetch *r_prev;	/**< Previous active fetch in ::fetch_ring. */
92
	struct fetch *r_next;	/**< Next active fetch in ::fetch_ring. */
93
};
94
 
95
static struct fetch *fetch_ring = 0;	/**< Ring of active fetches. */
96
static struct fetch *queue_ring = 0;	/**< Ring of queued fetches */
97
 
98
#define fetch_ref_fetcher(F) F->refcount++
99
static void fetch_unref_fetcher(scheme_fetcher *fetcher);
100
static void fetch_dispatch_jobs(void);
101
static bool fetch_choose_and_dispatch(void);
102
static bool fetch_dispatch_job(struct fetch *fetch);
103
 
104
/* Static lwc_strings */
105
static lwc_string *fetch_http_lwc;
106
static lwc_string *fetch_https_lwc;
107
 
108
 
109
/**
110
 * Initialise the fetcher.
111
 */
112
 
113
void fetch_init(void)
114
{
115
	fetch_curl_register();
116
	fetch_data_register();
117
	fetch_file_register();
118
	fetch_resource_register();
119
	fetch_about_register();
120
	fetch_active = false;
121
 
122
	if (lwc_intern_string("http", SLEN("http"), &fetch_http_lwc) !=
123
			lwc_error_ok) {
124
		die("Failed to initialise the fetch module "
125
				"(couldn't intern \"http\").");
126
	}
127
 
128
	if (lwc_intern_string("https", SLEN("https"), &fetch_https_lwc) !=
129
			lwc_error_ok) {
130
		die("Failed to initialise the fetch module "
131
				"(couldn't intern \"https\").");
132
	}
133
}
134
 
135
 
136
/**
137
 * Clean up for quit.
138
 *
139
 * Must be called before exiting.
140
 */
141
 
142
void fetch_quit(void)
143
{
144
	while (fetchers != NULL) {
145
		if (fetchers->refcount != 1) {
146
			LOG(("Fetcher for scheme %s still active?!",
147
					lwc_string_data(fetchers->scheme_name)));
148
			/* We shouldn't do this, but... */
149
			fetchers->refcount = 1;
150
		}
151
		fetch_unref_fetcher(fetchers);
152
	}
153
 
154
	lwc_string_unref(fetch_http_lwc);
155
	lwc_string_unref(fetch_https_lwc);
156
}
157
 
158
 
159
bool fetch_add_fetcher(lwc_string *scheme,
160
		  fetcher_initialise initialiser,
161
		  fetcher_can_fetch can_fetch,
162
		  fetcher_setup_fetch setup_fetch,
163
		  fetcher_start_fetch start_fetch,
164
		  fetcher_abort_fetch abort_fetch,
165
		  fetcher_free_fetch free_fetch,
166
		  fetcher_poll_fetcher poll_fetcher,
167
		  fetcher_finalise finaliser)
168
{
169
	scheme_fetcher *new_fetcher;
170
	if (!initialiser(scheme))
171
		return false;
172
	new_fetcher = malloc(sizeof(scheme_fetcher));
173
	if (new_fetcher == NULL) {
174
		finaliser(scheme);
175
		return false;
176
	}
177
	new_fetcher->scheme_name = scheme;
178
	new_fetcher->refcount = 0;
179
	new_fetcher->can_fetch = can_fetch;
180
	new_fetcher->setup_fetch = setup_fetch;
181
	new_fetcher->start_fetch = start_fetch;
182
	new_fetcher->abort_fetch = abort_fetch;
183
	new_fetcher->free_fetch = free_fetch;
184
	new_fetcher->poll_fetcher = poll_fetcher;
185
	new_fetcher->finaliser = finaliser;
186
	new_fetcher->next_fetcher = fetchers;
187
	fetchers = new_fetcher;
188
	fetch_ref_fetcher(new_fetcher);
189
	return true;
190
}
191
 
192
 
193
void fetch_unref_fetcher(scheme_fetcher *fetcher)
194
{
195
	if (--fetcher->refcount == 0) {
196
		fetcher->finaliser(fetcher->scheme_name);
197
		lwc_string_unref(fetcher->scheme_name);
198
		if (fetcher == fetchers) {
199
			fetchers = fetcher->next_fetcher;
200
			if (fetchers)
201
				fetchers->prev_fetcher = NULL;
202
		} else {
203
			fetcher->prev_fetcher->next_fetcher =
204
					fetcher->next_fetcher;
205
			if (fetcher->next_fetcher != NULL)
206
				fetcher->next_fetcher->prev_fetcher =
207
						fetcher->prev_fetcher;
208
		}
209
		free(fetcher);
210
	}
211
}
212
 
213
 
214
/**
215
 * Start fetching data for the given URL.
216
 *
217
 * The function returns immediately. The fetch may be queued for later
218
 * processing.
219
 *
220
 * A pointer to an opaque struct fetch is returned, which can be passed to
221
 * fetch_abort() to abort the fetch at any time. Returns 0 if memory is
222
 * exhausted (or some other fatal error occurred).
223
 *
224
 * The caller must supply a callback function which is called when anything
225
 * interesting happens. The callback function is first called with msg
226
 * FETCH_HEADER, with the header in data, then one or more times
227
 * with FETCH_DATA with some data for the url, and finally with
228
 * FETCH_FINISHED. Alternatively, FETCH_ERROR indicates an error occurred:
229
 * data contains an error message. FETCH_REDIRECT may replace the FETCH_HEADER,
230
 * FETCH_DATA, FETCH_FINISHED sequence if the server sends a replacement URL.
231
 *
232
 */
233
 
234
struct fetch * fetch_start(nsurl *url, nsurl *referer,
235
			   fetch_callback callback,
236
			   void *p, bool only_2xx, const char *post_urlenc,
237
			   const struct fetch_multipart_data *post_multipart,
238
			   bool verifiable, bool downgrade_tls,
239
			   const char *headers[])
240
{
241
	struct fetch *fetch;
242
	scheme_fetcher *fetcher = fetchers;
243
	lwc_string *scheme;
244
	bool match;
245
 
246
	fetch = malloc(sizeof (*fetch));
247
	if (fetch == NULL)
248
		return NULL;
249
 
250
	/* The URL we're fetching must have a scheme */
251
	scheme = nsurl_get_component(url, NSURL_SCHEME);
252
	assert(scheme != NULL);
253
 
254
#ifdef DEBUG_FETCH_VERBOSE
255
	LOG(("fetch %p, url '%s'", fetch, nsurl_access(url)));
256
#endif
257
 
258
	/* construct a new fetch structure */
259
	fetch->callback = callback;
260
	fetch->url = nsurl_ref(url);
261
	fetch->verifiable = verifiable;
262
	fetch->p = p;
263
	fetch->http_code = 0;
264
	fetch->r_prev = NULL;
265
	fetch->r_next = NULL;
266
	fetch->referer = NULL;
267
	fetch->send_referer = false;
268
	fetch->fetcher_handle = NULL;
269
	fetch->ops = NULL;
270
	fetch->fetch_is_active = false;
271
	fetch->host = nsurl_get_component(url, NSURL_HOST);
272
 
273
	if (referer != NULL) {
274
		lwc_string *ref_scheme;
275
		fetch->referer = nsurl_ref(referer);
276
 
277
		ref_scheme = nsurl_get_component(referer, NSURL_SCHEME);
278
		/* Not a problem if referer has no scheme */
279
 
280
		/* Determine whether to send the Referer header */
281
		if (nsoption_bool(send_referer) && ref_scheme != NULL) {
282
			/* User permits us to send the header
283
			 * Only send it if:
284
			 *    1) The fetch and referer schemes match
285
			 * or 2) The fetch is https and the referer is http
286
			 *
287
			 * This ensures that referer information is only sent
288
			 * across schemes in the special case of an https
289
			 * request from a page served over http. The inverse
290
			 * (https -> http) should not send the referer (15.1.3)
291
			 */
292
			bool match1;
293
			bool match2;
294
			if (lwc_string_isequal(scheme, ref_scheme, &match) != lwc_error_ok) {
295
				match = false;
296
			}
297
			if (lwc_string_isequal(scheme, fetch_https_lwc, &match1) != lwc_error_ok) {
298
				match1 = false;
299
			}
300
			if (lwc_string_isequal(ref_scheme, fetch_http_lwc, &match2) != lwc_error_ok) {
301
				match2= false;
302
			}
303
			if (match == true || (match1 == true && match2 == true))
304
				fetch->send_referer = true;
305
		}
306
		if (ref_scheme != NULL)
307
			lwc_string_unref(ref_scheme);
308
	}
309
 
310
	/* Pick the scheme ops */
311
	while (fetcher) {
312
		if ((lwc_string_isequal(fetcher->scheme_name, scheme,
313
				&match) == lwc_error_ok) && (match == true)) {
314
			fetch->ops = fetcher;
315
			break;
316
		}
317
		fetcher = fetcher->next_fetcher;
318
	}
319
 
320
	if (fetch->ops == NULL)
321
		goto failed;
322
 
323
	/* Got a scheme fetcher, try and set up the fetch */
324
	fetch->fetcher_handle = fetch->ops->setup_fetch(fetch, url,
325
					only_2xx, downgrade_tls,
326
					post_urlenc, post_multipart,
327
					headers);
328
 
329
	if (fetch->fetcher_handle == NULL)
330
		goto failed;
331
 
332
	/* Rah, got it, so ref the fetcher. */
333
	fetch_ref_fetcher(fetch->ops);
334
 
335
	/* these aren't needed past here */
336
	lwc_string_unref(scheme);
337
 
338
	/* Dump us in the queue and ask the queue to run. */
339
	RING_INSERT(queue_ring, fetch);
340
	fetch_dispatch_jobs();
341
 
342
	return fetch;
343
 
344
failed:
345
	lwc_string_unref(scheme);
346
 
347
	if (fetch->host != NULL)
348
		lwc_string_unref(fetch->host);
349
	if (fetch->url != NULL)
350
		nsurl_unref(fetch->url);
351
	if (fetch->referer != NULL)
352
		nsurl_unref(fetch->referer);
353
 
354
	free(fetch);
355
 
356
	return NULL;
357
}
358
 
359
 
360
/**
361
 * Dispatch as many jobs as we have room to dispatch.
362
 */
363
void fetch_dispatch_jobs(void)
364
{
365
	int all_active, all_queued;
366
#ifdef DEBUG_FETCH_VERBOSE
367
	struct fetch *q;
368
	struct fetch *f;
369
#endif
370
 
371
	if (!queue_ring)
372
		return; /* Nothing to do, the queue is empty */
373
	RING_GETSIZE(struct fetch, queue_ring, all_queued);
374
	RING_GETSIZE(struct fetch, fetch_ring, all_active);
375
 
376
#ifdef DEBUG_FETCH_VERBOSE
377
	LOG(("queue_ring %i, fetch_ring %i", all_queued, all_active));
378
 
379
	q = queue_ring;
380
	if (q) {
381
		do {
382
			LOG(("queue_ring: %s", q->url));
383
			q = q->r_next;
384
		} while (q != queue_ring);
385
	}
386
	f = fetch_ring;
387
	if (f) {
388
		do {
389
			LOG(("fetch_ring: %s", f->url));
390
			f = f->r_next;
391
		} while (f != fetch_ring);
392
	}
393
#endif
394
 
395
	while ( all_queued && all_active < nsoption_int(max_fetchers) ) {
396
		/*LOG(("%d queued, %d fetching", all_queued, all_active));*/
397
		if (fetch_choose_and_dispatch()) {
398
			all_queued--;
399
			all_active++;
400
		} else {
401
			/* Either a dispatch failed or we ran out. Just stop */
402
			break;
403
		}
404
	}
405
	fetch_active = (all_active > 0);
406
#ifdef DEBUG_FETCH_VERBOSE
407
	LOG(("Fetch ring is now %d elements.", all_active));
408
	LOG(("Queue ring is now %d elements.", all_queued));
409
#endif
410
}
411
 
412
 
413
/**
414
 * Choose and dispatch a single job. Return false if we failed to dispatch
415
 * anything.
416
 *
417
 * We don't check the overall dispatch size here because we're not called unless
418
 * there is room in the fetch queue for us.
419
 */
420
bool fetch_choose_and_dispatch(void)
421
{
422
	bool same_host;
423
	struct fetch *queueitem;
424
	queueitem = queue_ring;
425
	do {
426
		/* We can dispatch the selected item if there is room in the
427
		 * fetch ring
428
		 */
429
		int countbyhost;
430
		RING_COUNTBYLWCHOST(struct fetch, fetch_ring, countbyhost,
431
				queueitem->host);
432
		if (countbyhost < nsoption_int(max_fetchers_per_host)) {
433
			/* We can dispatch this item in theory */
434
			return fetch_dispatch_job(queueitem);
435
		}
436
		/* skip over other items with the same host */
437
		same_host = true;
438
		while (same_host == true && queueitem->r_next != queue_ring) {
439
			if (lwc_string_isequal(queueitem->host,
440
					queueitem->r_next->host, &same_host) ==
441
					lwc_error_ok && same_host == true) {
442
				queueitem = queueitem->r_next;
443
			}
444
		}
445
		queueitem = queueitem->r_next;
446
	} while (queueitem != queue_ring);
447
	return false;
448
}
449
 
450
 
451
/**
452
 * Dispatch a single job
453
 */
454
bool fetch_dispatch_job(struct fetch *fetch)
455
{
456
	RING_REMOVE(queue_ring, fetch);
457
#ifdef DEBUG_FETCH_VERBOSE
458
	LOG(("Attempting to start fetch %p, fetcher %p, url %s", fetch,
459
			fetch->fetcher_handle, nsurl_access(fetch->url)));
460
#endif
461
	if (!fetch->ops->start_fetch(fetch->fetcher_handle)) {
462
		RING_INSERT(queue_ring, fetch); /* Put it back on the end of the queue */
463
		return false;
464
	} else {
465
		RING_INSERT(fetch_ring, fetch);
466
		fetch->fetch_is_active = true;
467
		return true;
468
	}
469
}
470
 
471
 
472
/**
473
 * Abort a fetch.
474
 */
475
 
476
void fetch_abort(struct fetch *f)
477
{
478
	assert(f);
479
#ifdef DEBUG_FETCH_VERBOSE
480
	LOG(("fetch %p, fetcher %p, url '%s'", f, f->fetcher_handle,
481
			nsurl_access(f->url)));
482
#endif
483
	f->ops->abort_fetch(f->fetcher_handle);
484
}
485
 
486
 
487
/**
488
 * Free a fetch structure and associated resources.
489
 */
490
 
491
void fetch_free(struct fetch *f)
492
{
493
#ifdef DEBUG_FETCH_VERBOSE
494
	LOG(("Freeing fetch %p, fetcher %p", f, f->fetcher_handle));
495
#endif
496
	f->ops->free_fetch(f->fetcher_handle);
497
	fetch_unref_fetcher(f->ops);
498
	nsurl_unref(f->url);
499
	if (f->referer != NULL)
500
		nsurl_unref(f->referer);
501
	if (f->host != NULL)
502
		lwc_string_unref(f->host);
503
        free(f);
504
}
505
 
506
 
507
/**
508
 * Do some work on current fetches.
509
 *
510
 * Must be called regularly to make progress on fetches.
511
 */
512
 
513
void fetch_poll(void)
514
{
515
	scheme_fetcher *fetcher = fetchers;
516
	scheme_fetcher *next_fetcher;
517
 
518
	fetch_dispatch_jobs();
519
 
520
	if (!fetch_active)
521
		return; /* No point polling, there's no fetch active. */
522
	while (fetcher != NULL) {
523
		next_fetcher = fetcher->next_fetcher;
524
		if (fetcher->poll_fetcher != NULL) {
525
			/* LOG(("Polling fetcher for %s",
526
			   lwc_string_data(fetcher->scheme_name))); */
527
			fetcher->poll_fetcher(fetcher->scheme_name);
528
		}
529
		fetcher = next_fetcher;
530
	}
531
}
532
 
533
 
534
/**
535
 * Check if a URL's scheme can be fetched.
536
 *
537
 * \param  url  URL to check
538
 * \return  true if the scheme is supported
539
 */
540
 
541
bool fetch_can_fetch(const nsurl *url)
542
{
543
	scheme_fetcher *fetcher = fetchers;
544
	bool match;
545
	lwc_string *scheme = nsurl_get_component(url, NSURL_SCHEME);
546
 
547
	while (fetcher != NULL) {
548
		if (lwc_string_isequal(fetcher->scheme_name, scheme, &match) == lwc_error_ok && match == true) {
549
			break;
550
		}
551
 
552
		fetcher = fetcher->next_fetcher;
553
	}
554
 
555
	lwc_string_unref(scheme);
556
 
557
	return fetcher == NULL ? false : fetcher->can_fetch(url);
558
}
559
 
560
 
561
/**
562
 * Change the callback function for a fetch.
563
 */
564
 
565
void fetch_change_callback(struct fetch *fetch,
566
			   fetch_callback callback,
567
			   void *p)
568
{
569
	assert(fetch);
570
	fetch->callback = callback;
571
	fetch->p = p;
572
}
573
 
574
 
575
/**
576
 * Get the HTTP response code.
577
 */
578
 
579
long fetch_http_code(struct fetch *fetch)
580
{
581
	return fetch->http_code;
582
}
583
 
584
/**
585
 * Determine if a fetch was verifiable
586
 *
587
 * \param fetch  Fetch to consider
588
 * \return Verifiable status of fetch
589
 */
590
bool fetch_get_verifiable(struct fetch *fetch)
591
{
592
	assert(fetch);
593
 
594
	return fetch->verifiable;
595
}
596
 
597
/**
598
 * Clone a linked list of fetch_multipart_data.
599
 *
600
 * \param list  List to clone
601
 * \return Pointer to head of cloned list, or NULL on failure
602
 */
603
struct fetch_multipart_data *fetch_multipart_data_clone(
604
		const struct fetch_multipart_data *list)
605
{
606
	struct fetch_multipart_data *clone, *last = NULL;
607
	struct fetch_multipart_data *result = NULL;
608
 
609
	for (; list != NULL; list = list->next) {
610
		clone = malloc(sizeof(struct fetch_multipart_data));
611
		if (clone == NULL) {
612
			if (result != NULL)
613
				fetch_multipart_data_destroy(result);
614
 
615
			return NULL;
616
		}
617
 
618
		clone->file = list->file;
619
 
620
		clone->name = strdup(list->name);
621
		if (clone->name == NULL) {
622
			free(clone);
623
			if (result != NULL)
624
				fetch_multipart_data_destroy(result);
625
 
626
			return NULL;
627
		}
628
 
629
		clone->value = strdup(list->value);
630
		if (clone->value == NULL) {
631
			free(clone->name);
632
			free(clone);
633
			if (result != NULL)
634
				fetch_multipart_data_destroy(result);
635
 
636
			return NULL;
637
		}
638
 
639
		clone->next = NULL;
640
 
641
		if (result == NULL)
642
			result = clone;
643
		else
644
			last->next = clone;
645
 
646
		last = clone;
647
	}
648
 
649
	return result;
650
}
651
 
652
/**
653
 * Free a linked list of fetch_multipart_data.
654
 *
655
 * \param list Pointer to head of list to free
656
 */
657
void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
658
{
659
	struct fetch_multipart_data *next;
660
 
661
	for (; list != NULL; list = next) {
662
		next = list->next;
663
		free(list->name);
664
		free(list->value);
665
		free(list);
666
	}
667
}
668
 
669
void
670
fetch_send_callback(const fetch_msg *msg, struct fetch *fetch)
671
{
4821 ashmew2 672
	__menuet__debug_out("Inside fetch_send_callback\n");
673
 
3584 sourcerer 674
	fetch->callback(msg, fetch->p);
4821 ashmew2 675
	__menuet__debug_out("After fetch->callback \n");
3584 sourcerer 676
}
677
 
678
 
679
void fetch_remove_from_queues(struct fetch *fetch)
680
{
681
	int all_active, all_queued;
682
 
683
	/* Go ahead and free the fetch properly now */
684
#ifdef DEBUG_FETCH_VERBOSE
685
	LOG(("Fetch %p, fetcher %p can be freed", fetch, fetch->fetcher_handle));
686
#endif
687
 
688
	if (fetch->fetch_is_active) {
689
		RING_REMOVE(fetch_ring, fetch);
690
	} else {
691
		RING_REMOVE(queue_ring, fetch);
692
	}
693
 
694
	RING_GETSIZE(struct fetch, fetch_ring, all_active);
695
	RING_GETSIZE(struct fetch, queue_ring, all_queued);
696
 
697
	fetch_active = (all_active > 0);
698
 
699
#ifdef DEBUG_FETCH_VERBOSE
700
	LOG(("Fetch ring is now %d elements.", all_active));
701
	LOG(("Queue ring is now %d elements.", all_queued));
702
#endif
703
}
704
 
705
 
706
void
707
fetch_set_http_code(struct fetch *fetch, long http_code)
708
{
709
#ifdef DEBUG_FETCH_VERBOSE
710
	LOG(("Setting HTTP code to %ld", http_code));
711
#endif
712
	fetch->http_code = http_code;
713
}
714
 
715
const char *fetch_get_referer_to_send(struct fetch *fetch)
716
{
717
	if (fetch->send_referer)
718
		return nsurl_access(fetch->referer);
719
	return NULL;
720
}
721
 
722
void
723
fetch_set_cookie(struct fetch *fetch, const char *data)
724
{
725
	assert(fetch && data);
726
 
727
	/* If the fetch is unverifiable err on the side of caution and
728
	 * do not set the cookie */
729
 
730
	if (fetch->verifiable) {
731
		/* If the transaction's verifiable, we don't require
732
		 * that the request uri and the parent domain match,
733
		 * so don't pass in any referer/parent in this case. */
734
		urldb_set_cookie(data, fetch->url, NULL);
735
	} else if (fetch->referer != NULL) {
736
		/* Permit the cookie to be set if the fetch is unverifiable
737
		 * and the fetch URI domain matches the referer. */
738
		/** \todo Long-term, this needs to be replaced with a
739
		 * comparison against the origin fetch URI. In the case
740
		 * where a nested object requests a fetch, the origin URI
741
		 * is the nested object's parent URI, whereas the referer
742
		 * for the fetch will be the nested object's URI. */
743
		urldb_set_cookie(data, fetch->url, fetch->referer);
744
	}
745
}
746