Subversion Repositories Kolibri OS

Rev

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