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 2009 John-Mark Bell 
3
 *
4
 * This file is part of NetSurf, http://www.netsurf-browser.org/
5
 *
6
 * NetSurf is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; version 2 of the License.
9
 *
10
 * NetSurf is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see .
17
 */
18
 
19
/** \file
20
 * Low-level resource cache (implementation)
21
 */
22
 
23
#include 
24
#include 
25
#include 
26
 
27
#include 
28
 
29
#include "content/fetch.h"
30
#include "content/llcache.h"
31
#include "content/urldb.h"
32
#include "utils/log.h"
33
#include "utils/messages.h"
34
#include "utils/nsurl.h"
35
#include "utils/utils.h"
36
 
37
/** Define to enable tracing of llcache operations. */
38
#undef LLCACHE_TRACE
39
 
5043 ashmew2 40
#ifdef DBG
41
#undef DBG
42
#endif
43
//#define DBG(s) __menuet__debug_out(s) /* For the debug messages in BOARD */
44
#define DBG(s) LOG((s))            /* So that we see debug in Netsurf's LOG files */
45
 
46
 
3584 sourcerer 47
/** State of a low-level cache object fetch */
48
typedef enum {
49
	LLCACHE_FETCH_INIT,		/**< Initial state, before fetch */
50
	LLCACHE_FETCH_HEADERS,		/**< Fetching headers */
51
	LLCACHE_FETCH_DATA,		/**< Fetching object data */
52
	LLCACHE_FETCH_COMPLETE		/**< Fetch completed */
53
} llcache_fetch_state;
54
 
55
/** Type of low-level cache object */
56
typedef struct llcache_object llcache_object;
57
 
58
/** Handle to low-level cache object */
59
struct llcache_handle {
60
	llcache_object *object;		/**< Pointer to associated object */
61
 
62
	llcache_handle_callback cb;	/**< Client callback */
63
	void *pw;			/**< Client data */
64
 
65
	llcache_fetch_state state;	/**< Last known state of object fetch */
66
	size_t bytes;			/**< Last reported byte count */
67
};
68
 
69
/** Low-level cache object user record */
70
typedef struct llcache_object_user {
71
	llcache_handle *handle;		/**< Handle data for client */
72
 
73
	bool iterator_target;		/**< This is the an iterator target */
74
	bool queued_for_delete;		/**< This user is queued for deletion */
75
 
76
	struct llcache_object_user *prev;	/**< Previous in list */
77
	struct llcache_object_user *next;	/**< Next in list */
78
} llcache_object_user;
79
 
80
/** Low-level cache object fetch context */
81
typedef struct {
82
	uint32_t flags;			/**< Fetch flags */
83
	nsurl *referer;			/**< Referring URL, or NULL if none */
84
	llcache_post_data *post;	/**< POST data, or NULL for GET */
85
 
86
	struct fetch *fetch;		/**< Fetch handle for this object */
87
 
88
	llcache_fetch_state state;	/**< Current state of object fetch */
89
 
90
	uint32_t redirect_count;	/**< Count of redirects followed */
91
 
92
	bool tried_with_auth;		/**< Whether we've tried with auth */
93
 
94
	bool tried_with_tls_downgrade;	/**< Whether we've tried TLS <= 1.0 */
95
 
96
	bool outstanding_query;		/**< Waiting for a query response */
97
} llcache_fetch_ctx;
98
 
99
typedef enum {
100
	LLCACHE_VALIDATE_FRESH,		/**< Only revalidate if not fresh */
101
	LLCACHE_VALIDATE_ALWAYS,	/**< Always revalidate */
102
	LLCACHE_VALIDATE_ONCE		/**< Revalidate once only */
103
} llcache_validate;
104
 
105
/** Cache control data */
106
typedef struct {
107
	time_t req_time;	/**< Time of request */
108
	time_t res_time;	/**< Time of response */
109
	time_t date;		/**< Date: response header */
110
	time_t expires;		/**< Expires: response header */
111
#define INVALID_AGE -1
112
	int age;		/**< Age: response header */
113
	int max_age;		/**< Max-Age Cache-control parameter */
114
	llcache_validate no_cache;	/**< No-Cache Cache-control parameter */
115
	char *etag;		/**< Etag: response header */
116
	time_t last_modified;	/**< Last-Modified: response header */
117
} llcache_cache_control;
118
 
119
/** Representation of a fetch header */
120
typedef struct {
121
	char *name;		/**< Header name */
122
	char *value;		/**< Header value */
123
} llcache_header;
124
 
125
/** Low-level cache object */
126
/** \todo Consider whether a list is a sane container */
127
struct llcache_object {
128
	llcache_object *prev;		/**< Previous in list */
129
	llcache_object *next;		/**< Next in list */
130
 
131
	nsurl *url;			/**< Post-redirect URL for object */
132
	bool has_query;			/**< URL has a query segment */
133
 
134
	/** \todo We need a generic dynamic buffer object */
135
	uint8_t *source_data;		/**< Source data for object */
136
	size_t source_len;		/**< Byte length of source data */
137
	size_t source_alloc;		/**< Allocated size of source buffer */
138
 
139
	llcache_object_user *users;	/**< List of users */
140
 
141
	llcache_fetch_ctx fetch;	/**< Fetch context for object */
142
 
143
	llcache_cache_control cache;	/**< Cache control data for object */
144
	llcache_object *candidate;	/**< Object to use, if fetch determines
145
					 * that it is still fresh */
146
	uint32_t candidate_count;	/**< Count of objects this is a
147
					 * candidate for */
148
 
149
	llcache_header *headers;	/**< Fetch headers */
150
	size_t num_headers;		/**< Number of fetch headers */
151
};
152
 
153
struct llcache_s {
154
	/** Handler for fetch-related queries */
155
	llcache_query_callback query_cb;
156
 
157
	/** Data for fetch-related query handler */
158
	void *query_cb_pw;
159
 
160
	/** Head of the low-level cached object list */
161
	llcache_object *cached_objects;
162
 
163
	/** Head of the low-level uncached object list */
164
	llcache_object *uncached_objects;
165
 
166
	uint32_t limit;
167
};
168
 
169
/** low level cache state */
170
static struct llcache_s *llcache = NULL;
171
 
172
/* Static lwc_strings */
173
static lwc_string *llcache_file_lwc;
174
static lwc_string *llcache_about_lwc;
175
static lwc_string *llcache_resource_lwc;
176
 
177
/* forward referenced callback function */
178
static void llcache_fetch_callback(const fetch_msg *msg, void *p);
179
 
180
 
181
/******************************************************************************
182
 * Low-level cache internals						      *
183
 ******************************************************************************/
184
 
185
/**
186
 * Create a new object user
187
 *
188
 * \param cb	Callback routine
189
 * \param pw	Private data for callback
190
 * \param user	Pointer to location to receive result
191
 * \return NSERROR_OK on success, appropriate error otherwise
192
 */
193
static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
194
		llcache_object_user **user)
195
{
196
	llcache_handle *h;
197
	llcache_object_user *u;
198
 
199
	h = calloc(1, sizeof(llcache_handle));
200
	if (h == NULL)
201
		return NSERROR_NOMEM;
202
 
203
	u = calloc(1, sizeof(llcache_object_user));
204
	if (u == NULL) {
205
		free(h);
206
		return NSERROR_NOMEM;
207
	}
208
 
209
	h->cb = cb;
210
	h->pw = pw;
211
 
212
	u->handle = h;
213
 
214
#ifdef LLCACHE_TRACE
215
	LOG(("Created user %p (%p, %p, %p)", u, h, (void *) cb, pw));
216
#endif
217
 
218
	*user = u;
219
 
220
	return NSERROR_OK;
221
}
222
 
223
/**
224
 * Destroy an object user
225
 *
226
 * \param user	User to destroy
227
 * \return NSERROR_OK on success, appropriate error otherwise
228
 *
229
 * \pre User is not attached to an object
230
 */
231
static nserror llcache_object_user_destroy(llcache_object_user *user)
232
{
233
#ifdef LLCACHE_TRACE
234
	LOG(("Destroyed user %p", user));
235
#endif
236
 
237
	assert(user->next == NULL);
238
	assert(user->prev == NULL);
239
 
240
	if (user->handle != NULL)
241
		free(user->handle);
242
 
243
	free(user);
244
 
245
	return NSERROR_OK;
246
}
247
 
248
/**
249
 * Remove a user from a low-level cache object
250
 *
251
 * \param object  Object to remove user from
252
 * \param user	  User to remove
253
 * \return NSERROR_OK.
254
 */
255
static nserror llcache_object_remove_user(llcache_object *object,
256
		llcache_object_user *user)
257
{
258
	assert(user != NULL);
259
	assert(object != NULL);
260
	assert(object->users != NULL);
261
	assert(user->handle == NULL || user->handle->object == object);
262
	assert((user->prev != NULL) || (object->users == user));
263
 
264
	if (user == object->users)
265
		object->users = user->next;
266
	else
267
		user->prev->next = user->next;
268
 
269
	if (user->next != NULL)
270
		user->next->prev = user->prev;
271
 
272
	user->next = user->prev = NULL;
273
 
274
#ifdef LLCACHE_TRACE
275
	LOG(("Removing user %p from %p", user, object));
276
#endif
277
 
278
	return NSERROR_OK;
279
}
280
 
281
/**
282
 * Iterate the users of an object, calling their callbacks.
283
 *
284
 * \param object	The object to iterate
285
 * \param event		The event to pass to the callback.
286
 * \return NSERROR_OK on success, appropriate error otherwise.
287
 */
288
static nserror llcache_send_event_to_users(llcache_object *object,
289
					   llcache_event *event)
290
{
291
	nserror error = NSERROR_OK;
292
	llcache_object_user *user, *next_user;
293
 
294
	user = object->users;
295
	while (user != NULL) {
296
		user->iterator_target = true;
297
 
298
		error = user->handle->cb(user->handle, event,
299
					user->handle->pw);
300
 
301
		next_user = user->next;
302
 
303
		user->iterator_target = false;
304
 
305
		if (user->queued_for_delete) {
306
			llcache_object_remove_user(object, user);
307
			llcache_object_user_destroy(user);
308
		}
309
 
310
		if (error != NSERROR_OK)
311
			break;
312
 
313
		user = next_user;
314
	}
315
 
316
	return error;
317
}
318
 
319
/**
320
 * Create a new low-level cache object
321
 *
322
 * \param url	  URL of object to create
323
 * \param result  Pointer to location to receive result
324
 * \return NSERROR_OK on success, appropriate error otherwise
325
 */
326
static nserror llcache_object_new(nsurl *url, llcache_object **result)
327
{
328
	llcache_object *obj = calloc(1, sizeof(llcache_object));
329
	if (obj == NULL)
330
		return NSERROR_NOMEM;
331
 
332
#ifdef LLCACHE_TRACE
333
	LOG(("Created object %p (%s)", obj, nsurl_access(url)));
334
#endif
335
 
336
	obj->url = nsurl_ref(url);
337
 
338
	*result = obj;
339
 
340
	return NSERROR_OK;
341
}
342
 
343
/**
344
 * Clone a POST data object
345
 *
346
 * \param orig	 Object to clone
347
 * \param clone	 Pointer to location to receive clone
348
 * \return NSERROR_OK on success, appropriate error otherwise
349
 */
350
static nserror llcache_post_data_clone(const llcache_post_data *orig,
351
		llcache_post_data **clone)
352
{
353
	llcache_post_data *post_clone;
354
 
355
	post_clone = calloc(1, sizeof(llcache_post_data));
356
	if (post_clone == NULL)
357
		return NSERROR_NOMEM;
358
 
359
	post_clone->type = orig->type;
360
 
361
	/* Deep-copy the type-specific data */
362
	if (orig->type == LLCACHE_POST_URL_ENCODED) {
363
		post_clone->data.urlenc = strdup(orig->data.urlenc);
364
		if (post_clone->data.urlenc == NULL) {
365
			free(post_clone);
366
 
367
			return NSERROR_NOMEM;
368
		}
369
	} else {
370
		post_clone->data.multipart = fetch_multipart_data_clone(
371
				orig->data.multipart);
372
		if (post_clone->data.multipart == NULL) {
373
			free(post_clone);
374
 
375
			return NSERROR_NOMEM;
376
		}
377
	}
378
 
379
	*clone = post_clone;
380
 
381
	return NSERROR_OK;
382
}
383
 
384
/**
385
 * Split a fetch header into name and value
386
 *
387
 * \param data	 Header string
388
 * \param len	 Byte length of header
389
 * \param name	 Pointer to location to receive header name
390
 * \param value	 Pointer to location to receive header value
391
 * \return NSERROR_OK on success, appropriate error otherwise
392
 */
393
static nserror llcache_fetch_split_header(const uint8_t *data, size_t len,
394
		char **name, char **value)
395
{
396
	char *n, *v;
397
	const uint8_t *colon;
398
 
399
	/* Find colon */
400
	colon = (const uint8_t *) strchr((const char *) data, ':');
401
	if (colon == NULL) {
402
		/* Failed, assume a key with no value */
403
		n = strdup((const char *) data);
404
		if (n == NULL)
405
			return NSERROR_NOMEM;
406
 
407
		v = strdup("");
408
		if (v == NULL) {
409
			free(n);
410
			return NSERROR_NOMEM;
411
		}
412
	} else {
413
		/* Split header into name & value */
414
 
415
		/* Strip leading whitespace from name */
416
		while (data[0] == ' ' || data[0] == '\t' ||
417
				data[0] == '\r' || data[0] == '\n') {
418
			data++;
419
		}
420
 
421
		/* Strip trailing whitespace from name */
422
		while (colon > data && (colon[-1] == ' ' ||
423
				colon[-1] == '\t' || colon[-1] == '\r' ||
424
				colon[-1] == '\n'))
425
			colon--;
426
 
427
		n = strndup((const char *) data, colon - data);
428
		if (n == NULL)
429
			return NSERROR_NOMEM;
430
 
431
		/* Find colon again */
432
		while (*colon != ':') {
433
			colon++;
434
		}
435
 
436
		/* Skip over colon and any subsequent whitespace */
437
		do {
438
			colon++;
439
		} while (*colon == ' ' || *colon == '\t' ||
440
				*colon == '\r' || *colon == '\n');
441
 
442
		/* Strip trailing whitespace from value */
443
		while (len > 0 && (data[len - 1] == ' ' ||
444
				data[len - 1] == '\t' ||
445
				data[len - 1] == '\r' ||
446
				data[len - 1] == '\n')) {
447
			len--;
448
		}
449
 
450
		v = strndup((const char *) colon, len - (colon - data));
451
		if (v == NULL) {
452
			free(n);
453
			return NSERROR_NOMEM;
454
		}
455
	}
456
 
457
	*name = n;
458
	*value = v;
459
 
460
	return NSERROR_OK;
461
}
462
 
463
/**
464
 * Parse a fetch header
465
 *
466
 * \param object  Object to parse header for
467
 * \param data	  Header string
468
 * \param len	  Byte length of header
469
 * \param name	  Pointer to location to receive header name
470
 * \param value	  Pointer to location to receive header value
471
 * \return NSERROR_OK on success, appropriate error otherwise
472
 *
473
 * \note This function also has the side-effect of updating
474
 *	 the cache control data for the object if an interesting
475
 *	 header is encountered
476
 */
477
static nserror llcache_fetch_parse_header(llcache_object *object,
478
		const uint8_t *data, size_t len, char **name, char **value)
479
{
480
	nserror error;
481
 
482
	/* Set fetch response time if not already set */
483
	if (object->cache.res_time == 0)
484
		object->cache.res_time = time(NULL);
485
 
486
	/* Decompose header into name-value pair */
487
	error = llcache_fetch_split_header(data, len, name, value);
488
	if (error != NSERROR_OK)
489
		return error;
490
 
491
	/* Parse cache headers to populate cache control data */
492
#define SKIP_ST(p) while (*p != '\0' && (*p == ' ' || *p == '\t')) p++
493
 
494
	if (5 < len && strcasecmp(*name, "Date") == 0) {
495
		/* extract Date header */
5043 ashmew2 496
		/* TODO: object->cache.date = curl_getdate(*value, NULL); */
497
	  object->cache.date = (time_t) 12341234;
498
 
3584 sourcerer 499
	} else if (4 < len && strcasecmp(*name, "Age") == 0) {
500
		/* extract Age header */
501
		if ('0' <= **value && **value <= '9')
502
			object->cache.age = atoi(*value);
503
	} else if (8 < len && strcasecmp(*name, "Expires") == 0) {
504
		/* extract Expires header */
5043 ashmew2 505
	/* TODO: object->cache.expires = curl_getdate(*value, NULL); */
506
		object->cache.expires =  (time_t) 123412399;
3584 sourcerer 507
	} else if (14 < len && strcasecmp(*name, "Cache-Control") == 0) {
508
		/* extract and parse Cache-Control header */
509
		const char *start = *value;
510
		const char *comma = *value;
511
 
512
		while (*comma != '\0') {
513
			while (*comma != '\0' && *comma != ',')
514
				comma++;
515
 
516
			if (8 < comma - start && (strncasecmp(start,
517
					"no-cache", 8) == 0 ||
518
					strncasecmp(start, "no-store", 8) == 0))
519
				/* When we get a disk cache we should
520
				 * distinguish between these two */
521
				object->cache.no_cache = LLCACHE_VALIDATE_ALWAYS;
522
			else if (7 < comma - start &&
523
					strncasecmp(start, "max-age", 7) == 0) {
524
				/* Find '=' */
525
				while (start < comma && *start != '=')
526
					start++;
527
 
528
				/* Skip over it */
529
				start++;
530
 
531
				/* Skip whitespace */
532
				SKIP_ST(start);
533
 
534
				if (start < comma)
535
					object->cache.max_age = atoi(start);
536
			}
537
 
538
			if (*comma != '\0') {
539
				/* Skip past comma */
540
				comma++;
541
				/* Skip whitespace */
542
				SKIP_ST(comma);
543
			}
544
 
545
			/* Set start for next token */
546
			start = comma;
547
		}
548
	} else if (5 < len && strcasecmp(*name, "ETag") == 0) {
549
		/* extract ETag header */
550
		free(object->cache.etag);
551
		object->cache.etag = strdup(*value);
552
		if (object->cache.etag == NULL)
553
			return NSERROR_NOMEM;
554
	} else if (14 < len && strcasecmp(*name, "Last-Modified") == 0) {
555
		/* extract Last-Modified header */
5043 ashmew2 556
	  /* TODO object->cache.last_modified = curl_getdate(*value, NULL); */
557
	  object->cache.last_modified = (time_t) 12341230;
3584 sourcerer 558
	}
559
 
560
#undef SKIP_ST
561
 
562
	return NSERROR_OK;
563
}
564
 
565
/* Destroy headers */
566
static inline void llcache_destroy_headers(llcache_object *object)
567
{
568
	while (object->num_headers > 0) {
569
		object->num_headers--;
570
 
571
		free(object->headers[object->num_headers].name);
572
		free(object->headers[object->num_headers].value);
573
	}
574
	free(object->headers);
575
	object->headers = NULL;
576
}
577
 
578
/* Invalidate cache control data */
579
static inline void llcache_invalidate_cache_control_data(llcache_object *object)
580
{
581
	free(object->cache.etag);
582
	memset(&(object->cache), 0, sizeof(llcache_cache_control));
583
 
584
	object->cache.age = INVALID_AGE;
585
	object->cache.max_age = INVALID_AGE;
586
}
587
 
588
/**
589
 * Process a fetch header
590
 *
591
 * \param object  Object being fetched
592
 * \param data	  Header string
593
 * \param len	  Byte length of header
594
 * \return NSERROR_OK on success, appropriate error otherwise
595
 */
596
static nserror llcache_fetch_process_header(llcache_object *object,
597
		const uint8_t *data, size_t len)
598
{
599
	nserror error;
600
	char *name, *value;
601
	llcache_header *temp;
602
 
603
	/* The headers for multiple HTTP responses may be delivered to us if
604
	 * the fetch layer receives a 401 response for which it has
605
	 * authentication credentials. This will result in a silent re-request
606
	 * after which we'll receive the actual response headers for the
607
	 * object we want to fetch (assuming that the credentials were correct
608
	 * of course)
609
	 *
610
	 * Therefore, if the header is an HTTP response start marker, then we
611
	 * must discard any headers we've read so far, reset the cache data
612
	 * that we might have computed, and start again.
613
	 */
614
	/** \todo Properly parse the response line */
615
	if (strncmp((const char *) data, "HTTP/", SLEN("HTTP/")) == 0) {
616
		time_t req_time = object->cache.req_time;
617
 
618
		llcache_invalidate_cache_control_data(object);
619
 
620
		/* Restore request time, so we compute object's age correctly */
621
		object->cache.req_time = req_time;
622
 
623
		llcache_destroy_headers(object);
624
	}
625
 
626
	error = llcache_fetch_parse_header(object, data, len, &name, &value);
627
	if (error != NSERROR_OK)
628
		return error;
629
 
630
	/* Append header data to the object's headers array */
631
	temp = realloc(object->headers, (object->num_headers + 1) *
632
			sizeof(llcache_header));
633
	if (temp == NULL) {
634
		free(name);
635
		free(value);
636
		return NSERROR_NOMEM;
637
	}
638
 
639
	object->headers = temp;
640
 
641
	object->headers[object->num_headers].name = name;
642
	object->headers[object->num_headers].value = value;
643
 
644
	object->num_headers++;
645
 
646
	return NSERROR_OK;
647
}
648
 
649
/**
650
 * (Re)fetch an object
651
 *
652
 * \param object  Object to refetch
653
 * \return NSERROR_OK on success, appropriate error otherwise
654
 *
655
 * \pre The fetch parameters in object->fetch must be populated
656
 */
657
static nserror llcache_object_refetch(llcache_object *object)
658
{
659
	const char *urlenc = NULL;
660
	struct fetch_multipart_data *multipart = NULL;
661
	char **headers = NULL;
662
	int header_idx = 0;
663
 
664
	if (object->fetch.post != NULL) {
665
		if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED)
666
			urlenc = object->fetch.post->data.urlenc;
667
		else
668
			multipart = object->fetch.post->data.multipart;
669
	}
670
 
671
	/* Generate cache-control headers */
672
	headers = malloc(3 * sizeof(char *));
673
	if (headers == NULL)
674
		return NSERROR_NOMEM;
675
 
676
	if (object->cache.etag != NULL) {
677
		const size_t len = SLEN("If-None-Match: ") +
678
				strlen(object->cache.etag) + 1;
679
 
680
		headers[header_idx] = malloc(len);
681
		if (headers[header_idx] == NULL) {
682
			free(headers);
683
			return NSERROR_NOMEM;
684
		}
685
 
686
		snprintf(headers[header_idx], len, "If-None-Match: %s",
687
				object->cache.etag);
688
 
689
		header_idx++;
690
	}
691
	if (object->cache.date != 0) {
692
		/* Maximum length of an RFC 1123 date is 29 bytes */
693
		const size_t len = SLEN("If-Modified-Since: ") + 29 + 1;
694
 
695
		headers[header_idx] = malloc(len);
696
		if (headers[header_idx] == NULL) {
697
			while (--header_idx >= 0)
698
				free(headers[header_idx]);
699
			free(headers);
700
			return NSERROR_NOMEM;
701
		}
702
 
703
		snprintf(headers[header_idx], len, "If-Modified-Since: %s",
704
				rfc1123_date(object->cache.date));
705
 
706
		header_idx++;
707
	}
708
	headers[header_idx] = NULL;
709
 
710
	/* Reset cache control data */
711
	llcache_invalidate_cache_control_data(object);
712
	object->cache.req_time = time(NULL);
713
 
714
	/* Reset fetch state */
715
	object->fetch.state = LLCACHE_FETCH_INIT;
716
 
717
#ifdef LLCACHE_TRACE
718
	LOG(("Refetching %p", object));
719
#endif
720
 
721
	/* Kick off fetch */
722
	object->fetch.fetch = fetch_start(object->url, object->fetch.referer,
723
			llcache_fetch_callback, object,
724
			object->fetch.flags & LLCACHE_RETRIEVE_NO_ERROR_PAGES,
725
			urlenc, multipart,
726
			object->fetch.flags & LLCACHE_RETRIEVE_VERIFIABLE,
727
			object->fetch.tried_with_tls_downgrade,
728
			(const char **) headers);
729
 
730
	/* Clean up cache-control headers */
731
	while (--header_idx >= 0)
732
		free(headers[header_idx]);
733
	free(headers);
734
 
735
	/* Did we succeed in creating a fetch? */
736
	if (object->fetch.fetch == NULL)
737
		return NSERROR_NOMEM;
738
 
739
	return NSERROR_OK;
740
}
741
 
742
/**
743
 * Kick-off a fetch for an object
744
 *
745
 * \param object	  Object to fetch
746
 * \param flags		  Fetch flags
747
 * \param referer	  Referring URL, or NULL for none
748
 * \param post		  POST data, or NULL for GET
749
 * \param redirect_count  Number of redirects followed so far
750
 * \return NSERROR_OK on success, appropriate error otherwise
751
 *
752
 * \pre object::url must contain the URL to fetch
753
 * \pre If there is a freshness validation candidate,
754
 *	object::candidate and object::cache must be filled in
755
 * \pre There must not be a fetch in progress for \a object
756
 */
757
static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
758
		nsurl *referer, const llcache_post_data *post,
759
		uint32_t redirect_count)
760
{
761
	nserror error;
762
	nsurl *referer_clone = NULL;
763
	llcache_post_data *post_clone = NULL;
764
 
765
#ifdef LLCACHE_TRACE
766
	LOG(("Starting fetch for %p", object));
767
#endif
768
 
769
	if (post != NULL) {
770
		error = llcache_post_data_clone(post, &post_clone);
771
		if (error != NSERROR_OK)
772
			return error;
773
	}
774
 
775
	if (referer != NULL)
776
		referer_clone = nsurl_ref(referer);
777
 
778
	object->fetch.flags = flags;
779
	object->fetch.referer = referer_clone;
780
	object->fetch.post = post_clone;
781
	object->fetch.redirect_count = redirect_count;
782
 
783
	return llcache_object_refetch(object);
784
}
785
 
786
/**
787
 * Destroy a low-level cache object
788
 *
789
 * \param object  Object to destroy
790
 * \return NSERROR_OK on success, appropriate error otherwise
791
 *
792
 * \pre Object is detached from cache list
793
 * \pre Object has no users
794
 * \pre Object is not a candidate (i.e. object::candidate_count == 0)
795
 */
796
static nserror llcache_object_destroy(llcache_object *object)
797
{
798
	size_t i;
799
 
800
#ifdef LLCACHE_TRACE
801
	LOG(("Destroying object %p", object));
802
#endif
803
 
804
	nsurl_unref(object->url);
805
	free(object->source_data);
806
 
807
	if (object->fetch.fetch != NULL) {
808
		fetch_abort(object->fetch.fetch);
809
		object->fetch.fetch = NULL;
810
	}
811
 
812
	if (object->fetch.referer != NULL)
813
		nsurl_unref(object->fetch.referer);
814
 
815
	if (object->fetch.post != NULL) {
816
		if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED) {
817
			free(object->fetch.post->data.urlenc);
818
		} else {
819
			fetch_multipart_data_destroy(
820
					object->fetch.post->data.multipart);
821
		}
822
 
823
		free(object->fetch.post);
824
	}
825
 
826
	free(object->cache.etag);
827
 
828
	for (i = 0; i < object->num_headers; i++) {
829
		free(object->headers[i].name);
830
		free(object->headers[i].value);
831
	}
832
	free(object->headers);
833
 
834
	free(object);
835
 
836
	return NSERROR_OK;
837
}
838
 
839
/**
840
 * Add a low-level cache object to a cache list
841
 *
842
 * \param object  Object to add
843
 * \param list	  List to add to
844
 * \return NSERROR_OK
845
 */
846
static nserror llcache_object_add_to_list(llcache_object *object,
847
		llcache_object **list)
848
{
849
	object->prev = NULL;
850
	object->next = *list;
851
 
852
	if (*list != NULL)
853
		(*list)->prev = object;
854
	*list = object;
855
 
856
	return NSERROR_OK;
857
}
858
 
859
/**
860
 * Determine the remaining lifetime of a cache object using the
861
 *
862
 * \param object  Object to consider
863
 * \return True if object is still fresh, false otherwise
864
 */
865
static int
866
llcache_object_rfc2616_remaining_lifetime(const llcache_cache_control *cd)
867
{
868
	int current_age, freshness_lifetime;
869
	time_t now = time(NULL);
870
 
871
	/* Calculate staleness of cached object as per RFC 2616 13.2.3/13.2.4 */
872
	current_age = max(0, (cd->res_time - cd->date));
873
	current_age = max(current_age, (cd->age == INVALID_AGE) ? 0 : cd->age);
874
	current_age += cd->res_time - cd->req_time + now - cd->res_time;
875
 
876
	/* Determine freshness lifetime of this object */
877
	if (cd->max_age != INVALID_AGE)
878
		freshness_lifetime = cd->max_age;
879
	else if (cd->expires != 0)
880
		freshness_lifetime = cd->expires - cd->date;
881
	else if (cd->last_modified != 0)
882
		freshness_lifetime = (now - cd->last_modified) / 10;
883
	else
884
		freshness_lifetime = 0;
885
 
886
#ifdef LLCACHE_TRACE
887
	LOG(("%d:%d", freshness_lifetime, current_age));
888
#endif
889
 
890
	if ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
891
	    (freshness_lifetime > current_age)) {
892
		/* object was not forbidden from being returned from
893
		 * the cache unvalidated (i.e. the response contained
894
		 * a no-cache directive)
895
		 *
896
		 * The object current age is within the freshness lifetime.
897
		 */
898
		return freshness_lifetime - current_age;
899
	}
900
 
901
	return 0; /* object has no remaining lifetime */
902
}
903
 
904
/**
905
 * Determine if an object is still fresh
906
 *
907
 * \param object  Object to consider
908
 * \return True if object is still fresh, false otherwise
909
 */
910
static bool llcache_object_is_fresh(const llcache_object *object)
911
{
912
	int remaining_lifetime;
913
	const llcache_cache_control *cd = &object->cache;
914
 
915
	remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(cd);
916
 
917
#ifdef LLCACHE_TRACE
918
	LOG(("%p: (%d > 0 || %d != %d)", object,
919
	     remaining_lifetime,
920
	     object->fetch.state, LLCACHE_FETCH_COMPLETE));
921
#endif
922
 
923
	/* The object is fresh if:
924
	 * - it was not forbidden from being returned from the cache
925
	 *   unvalidated.
926
	 *
927
         * - it has remaining lifetime or still being fetched.
928
	 */
929
	return ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
930
		((remaining_lifetime > 0) ||
931
		 (object->fetch.state != LLCACHE_FETCH_COMPLETE)));
932
}
933
 
934
/**
935
 * Clone an object's cache data
936
 *
937
 * \param source       Source object containing cache data to clone
938
 * \param destination  Destination object to clone cache data into
939
 * \param deep	       Whether to deep-copy the data or not
940
 * \return NSERROR_OK on success, appropriate error otherwise
941
 *
942
 * \post If \a deep is false, then any pointers in \a source will be set to NULL
943
 */
944
static nserror llcache_object_clone_cache_data(llcache_object *source,
945
		llcache_object *destination, bool deep)
946
{
947
	/* ETag must be first, as it can fail when deep cloning */
948
	if (source->cache.etag != NULL) {
949
		char *etag = source->cache.etag;
950
 
951
		if (deep) {
952
			/* Copy the etag */
953
			etag = strdup(source->cache.etag);
954
			if (etag == NULL)
955
				return NSERROR_NOMEM;
956
		} else {
957
			/* Destination takes ownership */
958
			source->cache.etag = NULL;
959
		}
960
 
961
		if (destination->cache.etag != NULL)
962
			free(destination->cache.etag);
963
 
964
		destination->cache.etag = etag;
965
	}
966
 
967
	destination->cache.req_time = source->cache.req_time;
968
	destination->cache.res_time = source->cache.res_time;
969
 
970
	if (source->cache.date != 0)
971
		destination->cache.date = source->cache.date;
972
 
973
	if (source->cache.expires != 0)
974
		destination->cache.expires = source->cache.expires;
975
 
976
	if (source->cache.age != INVALID_AGE)
977
		destination->cache.age = source->cache.age;
978
 
979
	if (source->cache.max_age != INVALID_AGE)
980
		destination->cache.max_age = source->cache.max_age;
981
 
982
	if (source->cache.no_cache != LLCACHE_VALIDATE_FRESH)
983
		destination->cache.no_cache = source->cache.no_cache;
984
 
985
	if (source->cache.last_modified != 0)
986
		destination->cache.last_modified = source->cache.last_modified;
987
 
988
	return NSERROR_OK;
989
}
990
 
991
/**
992
 * Retrieve a potentially cached object
993
 *
994
 * \param url		  URL of object to retrieve
995
 * \param flags		  Fetch flags
996
 * \param referer	  Referring URL, or NULL if none
997
 * \param post		  POST data, or NULL for a GET request
998
 * \param redirect_count  Number of redirects followed so far
999
 * \param result	  Pointer to location to recieve retrieved object
1000
 * \return NSERROR_OK on success, appropriate error otherwise
1001
 */
1002
static nserror llcache_object_retrieve_from_cache(nsurl *url, uint32_t flags,
1003
		nsurl *referer, const llcache_post_data *post,
1004
		uint32_t redirect_count, llcache_object **result)
1005
{
1006
	nserror error;
1007
	llcache_object *obj, *newest = NULL;
1008
 
1009
#ifdef LLCACHE_TRACE
1010
	LOG(("Searching cache for %s (%x %s %p)", url, flags, referer, post));
1011
#endif
1012
 
1013
	/* Search for the most recently fetched matching object */
1014
	for (obj = llcache->cached_objects; obj != NULL; obj = obj->next) {
1015
 
1016
		if ((newest == NULL ||
1017
				obj->cache.req_time > newest->cache.req_time) &&
1018
				nsurl_compare(obj->url, url,
1019
						NSURL_COMPLETE) == true) {
1020
			newest = obj;
1021
		}
1022
	}
1023
 
1024
	if (newest != NULL && llcache_object_is_fresh(newest)) {
1025
		/* Found a suitable object, and it's still fresh, so use it */
1026
		obj = newest;
1027
 
1028
#ifdef LLCACHE_TRACE
1029
		LOG(("Found fresh %p", obj));
1030
#endif
1031
 
1032
		/* The client needs to catch up with the object's state.
1033
		 * This will occur the next time that llcache_poll is called.
1034
		 */
1035
	} else if (newest != NULL) {
1036
		/* Found a candidate object but it needs freshness validation */
1037
 
1038
		/* Create a new object */
1039
		error = llcache_object_new(url, &obj);
1040
		if (error != NSERROR_OK)
1041
			return error;
1042
 
1043
#ifdef LLCACHE_TRACE
1044
		LOG(("Found candidate %p (%p)", obj, newest));
1045
#endif
1046
 
1047
		/* Clone candidate's cache data */
1048
		error = llcache_object_clone_cache_data(newest, obj, true);
1049
		if (error != NSERROR_OK) {
1050
			llcache_object_destroy(obj);
1051
			return error;
1052
		}
1053
 
1054
		/* Record candidate, so we can fall back if it is still fresh */
1055
		newest->candidate_count++;
1056
		obj->candidate = newest;
1057
 
1058
		/* Attempt to kick-off fetch */
1059
		error = llcache_object_fetch(obj, flags, referer, post,
1060
				redirect_count);
1061
		if (error != NSERROR_OK) {
1062
			newest->candidate_count--;
1063
			llcache_object_destroy(obj);
1064
			return error;
1065
		}
1066
 
1067
		/* Add new object to cache */
1068
		llcache_object_add_to_list(obj, &llcache->cached_objects);
1069
	} else {
1070
		/* No object found; create a new one */
1071
		/* Create new object */
1072
		error = llcache_object_new(url, &obj);
1073
		if (error != NSERROR_OK)
1074
			return error;
1075
 
1076
#ifdef LLCACHE_TRACE
1077
		LOG(("Not found %p", obj));
1078
#endif
1079
 
1080
		/* Attempt to kick-off fetch */
1081
		error = llcache_object_fetch(obj, flags, referer, post,
1082
				redirect_count);
1083
		if (error != NSERROR_OK) {
1084
			llcache_object_destroy(obj);
1085
			return error;
1086
		}
1087
 
1088
		/* Add new object to cache */
1089
		llcache_object_add_to_list(obj, &llcache->cached_objects);
1090
	}
1091
 
1092
	*result = obj;
1093
 
1094
	return NSERROR_OK;
1095
}
1096
 
1097
/**
1098
 * Retrieve an object from the cache, fetching it if necessary.
1099
 *
1100
 * \param url		  URL of object to retrieve
1101
 * \param flags		  Fetch flags
1102
 * \param referer	  Referring URL, or NULL if none
1103
 * \param post		  POST data, or NULL for a GET request
1104
 * \param redirect_count  Number of redirects followed so far
1105
 * \param result	  Pointer to location to recieve retrieved object
1106
 * \return NSERROR_OK on success, appropriate error otherwise
1107
 */
1108
static nserror llcache_object_retrieve(nsurl *url, uint32_t flags,
1109
		nsurl *referer, const llcache_post_data *post,
1110
		uint32_t redirect_count, llcache_object **result)
1111
{
1112
	nserror error;
1113
	llcache_object *obj;
1114
	bool has_query;
1115
	nsurl *defragmented_url;
1116
 
1117
#ifdef LLCACHE_TRACE
1118
	LOG(("Retrieve %s (%x, %s, %p)", url, flags, referer, post));
1119
#endif
1120
 
1121
	/**
1122
	 * Caching Rules:
1123
	 *
1124
	 * 1) Forced fetches are never cached
1125
	 * 2) POST requests are never cached
1126
	 */
1127
 
1128
	/* Look for a query segment */
1129
	has_query = nsurl_has_component(url, NSURL_QUERY);
1130
 
1131
	/* Get rid of any url fragment */
1132
	if (nsurl_has_component(url, NSURL_FRAGMENT)) {
1133
		error = nsurl_defragment(url, &defragmented_url);
1134
		if (error != NSERROR_OK)
1135
			return error;
1136
	} else {
1137
		defragmented_url = nsurl_ref(url);
1138
	}
1139
 
1140
	if (flags & LLCACHE_RETRIEVE_FORCE_FETCH || post != NULL) {
1141
		/* Create new object */
1142
		error = llcache_object_new(defragmented_url, &obj);
1143
		if (error != NSERROR_OK) {
1144
			nsurl_unref(defragmented_url);
1145
			return error;
1146
		}
1147
 
1148
		/* Attempt to kick-off fetch */
1149
		error = llcache_object_fetch(obj, flags, referer, post,
1150
				redirect_count);
1151
		if (error != NSERROR_OK) {
1152
			llcache_object_destroy(obj);
1153
			nsurl_unref(defragmented_url);
1154
			return error;
1155
		}
1156
 
1157
		/* Add new object to uncached list */
1158
		llcache_object_add_to_list(obj, &llcache->uncached_objects);
1159
	} else {
1160
		error = llcache_object_retrieve_from_cache(defragmented_url,
1161
				flags, referer, post, redirect_count, &obj);
1162
		if (error != NSERROR_OK) {
1163
			nsurl_unref(defragmented_url);
1164
			return error;
1165
		}
1166
 
1167
		/* Returned object is already in the cached list */
1168
	}
1169
 
1170
	obj->has_query = has_query;
1171
 
1172
#ifdef LLCACHE_TRACE
1173
	LOG(("Retrieved %p", obj));
1174
#endif
1175
 
1176
	*result = obj;
1177
 
1178
	nsurl_unref(defragmented_url);
1179
 
1180
	return NSERROR_OK;
1181
}
1182
 
1183
/**
1184
 * Add a user to a low-level cache object
1185
 *
1186
 * \param object  Object to add user to
1187
 * \param user	  User to add
1188
 * \return NSERROR_OK.
1189
 */
1190
static nserror llcache_object_add_user(llcache_object *object,
1191
		llcache_object_user *user)
1192
{
1193
	assert(user->next == NULL);
1194
	assert(user->prev == NULL);
1195
 
1196
	user->handle->object = object;
1197
 
1198
	user->prev = NULL;
1199
	user->next = object->users;
1200
 
1201
	if (object->users != NULL)
1202
		object->users->prev = user;
1203
	object->users = user;
1204
 
1205
#ifdef LLCACHE_TRACE
1206
	LOG(("Adding user %p to %p", user, object));
1207
#endif
1208
 
1209
	return NSERROR_OK;
1210
}
1211
 
1212
/**
1213
 * Handle FETCH_REDIRECT event
1214
 *
1215
 * \param object       Object being redirected
1216
 * \param target       Target of redirect (may be relative)
1217
 * \param replacement  Pointer to location to receive replacement object
1218
 * \return NSERROR_OK on success, appropriate error otherwise
1219
 */
1220
static nserror llcache_fetch_redirect(llcache_object *object, const char *target,
1221
		llcache_object **replacement)
1222
{
1223
	nserror error;
1224
	llcache_object *dest;
1225
	llcache_object_user *user, *next;
1226
	const llcache_post_data *post = object->fetch.post;
1227
	nsurl *url;
1228
	lwc_string *scheme;
1229
	lwc_string *object_scheme;
1230
	bool match;
1231
	/* Extract HTTP response code from the fetch object */
1232
	long http_code = fetch_http_code(object->fetch.fetch);
1233
 
1234
	/* Abort fetch for this object */
1235
	fetch_abort(object->fetch.fetch);
1236
	object->fetch.fetch = NULL;
1237
 
1238
	/* Invalidate the cache control data */
1239
	llcache_invalidate_cache_control_data(object);
1240
 
1241
	/* And mark it complete */
1242
	object->fetch.state = LLCACHE_FETCH_COMPLETE;
1243
 
1244
	/* Forcibly stop redirecting if we've followed too many redirects */
1245
#define REDIRECT_LIMIT 10
1246
	if (object->fetch.redirect_count > REDIRECT_LIMIT) {
1247
		llcache_event event;
1248
 
1249
		LOG(("Too many nested redirects"));
1250
 
1251
		event.type = LLCACHE_EVENT_ERROR;
1252
		event.data.msg = messages_get("BadRedirect");
1253
 
1254
		return llcache_send_event_to_users(object, &event);
1255
	}
1256
#undef REDIRECT_LIMIT
1257
 
1258
	/* Make target absolute */
1259
	error = nsurl_join(object->url, target, &url);
1260
	if (error != NSERROR_OK)
1261
		return error;
1262
 
1263
	/* Reject attempts to redirect from unvalidated to validated schemes
1264
	 * A "validated" scheme is one over which we have some guarantee that
1265
	 * the source is trustworthy. */
1266
	object_scheme = nsurl_get_component(object->url, NSURL_SCHEME);
1267
	scheme = nsurl_get_component(url, NSURL_SCHEME);
1268
 
1269
	/* resource: and about: are allowed to redirect anywhere */
1270
	if ((lwc_string_isequal(object_scheme, llcache_resource_lwc,
1271
			&match) == lwc_error_ok && match == false) &&
1272
	    (lwc_string_isequal(object_scheme, llcache_about_lwc,
1273
			&match) == lwc_error_ok && match == false)) {
1274
		/* file, about and resource are not valid redirect targets */
1275
		if ((lwc_string_isequal(object_scheme, llcache_file_lwc,
1276
				&match) == lwc_error_ok && match == true) ||
1277
		    (lwc_string_isequal(object_scheme, llcache_about_lwc,
1278
				&match) == lwc_error_ok && match == true) ||
1279
		    (lwc_string_isequal(object_scheme, llcache_resource_lwc,
1280
				&match) == lwc_error_ok && match == true)) {
1281
			lwc_string_unref(object_scheme);
1282
			lwc_string_unref(scheme);
1283
			nsurl_unref(url);
1284
			return NSERROR_OK;
1285
		}
1286
	}
1287
 
1288
	lwc_string_unref(scheme);
1289
	lwc_string_unref(object_scheme);
1290
 
1291
	/* Bail out if we've no way of handling this URL */
1292
	if (fetch_can_fetch(url) == false) {
1293
		nsurl_unref(url);
1294
		return NSERROR_OK;
1295
	}
1296
 
1297
	if (http_code == 301 || http_code == 302 || http_code == 303) {
1298
		/* 301, 302, 303 redirects are all unconditional GET requests */
1299
		post = NULL;
1300
	} else if (http_code != 307 || post != NULL) {
1301
		/** \todo 300, 305, 307 with POST */
1302
		nsurl_unref(url);
1303
		return NSERROR_OK;
1304
	}
1305
 
1306
	/* Attempt to fetch target URL */
1307
	error = llcache_object_retrieve(url, object->fetch.flags,
1308
			object->fetch.referer, post,
1309
			object->fetch.redirect_count + 1, &dest);
1310
 
1311
	/* No longer require url */
1312
	nsurl_unref(url);
1313
 
1314
	if (error != NSERROR_OK)
1315
		return error;
1316
 
1317
	/* Move user(s) to replacement object */
1318
	for (user = object->users; user != NULL; user = next) {
1319
		next = user->next;
1320
 
1321
		llcache_object_remove_user(object, user);
1322
		llcache_object_add_user(dest, user);
1323
	}
1324
 
1325
	/* Dest is now our object */
1326
	*replacement = dest;
1327
 
1328
	return NSERROR_OK;
1329
}
1330
 
1331
/**
1332
 * Update an object's cache state
1333
 *
1334
 * \param object  Object to update cache for
1335
 * \return NSERROR_OK.
1336
 */
1337
static nserror llcache_object_cache_update(llcache_object *object)
1338
{
1339
	if (object->cache.date == 0)
1340
		object->cache.date = time(NULL);
1341
 
1342
	return NSERROR_OK;
1343
}
1344
 
1345
/**
1346
 * Handle FETCH_NOTMODIFIED event
1347
 *
1348
 * \param object       Object to process
1349
 * \param replacement  Pointer to location to receive replacement object
1350
 * \return NSERROR_OK.
1351
 */
1352
static nserror llcache_fetch_notmodified(llcache_object *object,
1353
		llcache_object **replacement)
1354
{
1355
	/* There may be no candidate if the server erroneously responded
1356
	 * to an unconditional request with a 304 Not Modified response.
1357
	 * In this case, we simply retain the initial object, having
1358
	 * invalidated it and marked it as complete.
1359
	 */
1360
	if (object->candidate != NULL) {
1361
		llcache_object_user *user, *next;
1362
 
1363
		/* Move user(s) to candidate content */
1364
		for (user = object->users; user != NULL; user = next) {
1365
			next = user->next;
1366
 
1367
			llcache_object_remove_user(object, user);
1368
			llcache_object_add_user(object->candidate, user);
1369
		}
1370
 
1371
		/* Candidate is no longer a candidate for us */
1372
		object->candidate->candidate_count--;
1373
 
1374
		/* Clone our cache control data into the candidate */
1375
		llcache_object_clone_cache_data(object, object->candidate,
1376
				false);
1377
		/* Bring candidate's cache data up to date */
1378
		llcache_object_cache_update(object->candidate);
1379
		/* Revert no-cache to normal, if required */
1380
		if (object->candidate->cache.no_cache ==
1381
				LLCACHE_VALIDATE_ONCE) {
1382
			object->candidate->cache.no_cache =
1383
				LLCACHE_VALIDATE_FRESH;
1384
		}
1385
 
1386
		/* Candidate is now our object */
1387
		*replacement = object->candidate;
1388
		object->candidate = NULL;
1389
	} else {
1390
		/* There was no candidate: retain object */
1391
		*replacement = object;
1392
	}
1393
 
1394
	/* Ensure fetch has stopped */
1395
	fetch_abort(object->fetch.fetch);
1396
	object->fetch.fetch = NULL;
1397
 
1398
	/* Invalidate our cache-control data */
1399
	llcache_invalidate_cache_control_data(object);
1400
 
1401
	/* Mark it complete */
1402
	object->fetch.state = LLCACHE_FETCH_COMPLETE;
1403
 
1404
	/* Old object will be flushed from the cache on the next poll */
1405
 
1406
	return NSERROR_OK;
1407
}
1408
 
1409
/**
1410
 * Process a chunk of fetched data
1411
 *
1412
 * \param object  Object being fetched
1413
 * \param data	  Data to process
1414
 * \param len	  Byte length of data
1415
 * \return NSERROR_OK on success, appropriate error otherwise.
1416
 */
1417
static nserror llcache_fetch_process_data(llcache_object *object, const uint8_t *data,
1418
		size_t len)
1419
{
1420
	/* Resize source buffer if it's too small */
1421
	if (object->source_len + len >= object->source_alloc) {
1422
		const size_t new_len = object->source_len + len + 64 * 1024;
1423
		uint8_t *temp = realloc(object->source_data, new_len);
1424
		if (temp == NULL)
1425
			return NSERROR_NOMEM;
1426
 
1427
		object->source_data = temp;
1428
		object->source_alloc = new_len;
1429
	}
1430
 
1431
	/* Append this data chunk to source buffer */
1432
	memcpy(object->source_data + object->source_len, data, len);
1433
	object->source_len += len;
1434
 
1435
	return NSERROR_OK;
1436
}
1437
 
1438
/**
1439
 * Handle a query response
1440
 *
1441
 * \param proceed  Whether to proceed with fetch
1442
 * \param cbpw	   Our context for query
1443
 * \return NSERROR_OK on success, appropriate error otherwise
1444
 */
1445
static nserror llcache_query_handle_response(bool proceed, void *cbpw)
1446
{
1447
	llcache_event event;
1448
	llcache_object *object = cbpw;
1449
 
1450
	object->fetch.outstanding_query = false;
1451
 
1452
	/* Refetch, using existing fetch parameters, if client allows us to */
1453
	if (proceed)
1454
		return llcache_object_refetch(object);
1455
 
1456
	/* Invalidate cache-control data */
1457
	llcache_invalidate_cache_control_data(object);
1458
 
1459
	/* Mark it complete */
1460
	object->fetch.state = LLCACHE_FETCH_COMPLETE;
1461
 
1462
	/* Inform client(s) that object fetch failed */
1463
	event.type = LLCACHE_EVENT_ERROR;
1464
	/** \todo More appropriate error message */
1465
	event.data.msg = messages_get("FetchFailed");
1466
 
1467
	return llcache_send_event_to_users(object, &event);
1468
}
1469
 
1470
/**
1471
 * Handle an authentication request
1472
 *
1473
 * \param object  Object being fetched
1474
 * \param realm	  Authentication realm
1475
 * \return NSERROR_OK on success, appropriate error otherwise.
1476
 */
1477
static nserror llcache_fetch_auth(llcache_object *object, const char *realm)
1478
{
1479
	const char *auth;
1480
	nserror error = NSERROR_OK;
1481
 
1482
	/* Abort fetch for this object */
1483
	fetch_abort(object->fetch.fetch);
1484
	object->fetch.fetch = NULL;
1485
 
1486
	/* Invalidate cache-control data */
1487
	llcache_invalidate_cache_control_data(object);
1488
 
1489
	/* Destroy headers */
1490
	llcache_destroy_headers(object);
1491
 
1492
	/* If there was no realm, then default to the URL */
1493
	/** \todo If there was no WWW-Authenticate header, use response body */
1494
	if (realm == NULL)
1495
		realm = nsurl_access(object->url);
1496
 
1497
	auth = urldb_get_auth_details(object->url, realm);
1498
 
1499
	if (auth == NULL || object->fetch.tried_with_auth == true) {
1500
		/* No authentication details, or tried what we had, so ask */
1501
		object->fetch.tried_with_auth = false;
1502
 
1503
		if (llcache->query_cb != NULL) {
1504
			llcache_query query;
1505
 
1506
			/* Emit query for authentication details */
1507
			query.type = LLCACHE_QUERY_AUTH;
1508
			query.url = object->url;
1509
			query.data.auth.realm = realm;
1510
 
1511
			object->fetch.outstanding_query = true;
1512
 
1513
			error = llcache->query_cb(&query, llcache->query_cb_pw,
1514
					llcache_query_handle_response, object);
1515
		} else {
1516
			llcache_event event;
1517
 
1518
			/* Mark object complete */
1519
			object->fetch.state = LLCACHE_FETCH_COMPLETE;
1520
 
1521
			/* Inform client(s) that object fetch failed */
1522
			event.type = LLCACHE_EVENT_ERROR;
1523
			/** \todo More appropriate error message */
1524
			event.data.msg = messages_get("FetchFailed");
1525
 
1526
			error = llcache_send_event_to_users(object, &event);
1527
		}
1528
	} else {
1529
		/* Flag that we've tried to refetch with credentials, so
1530
		 * that if the fetch fails again, we ask the user again */
1531
		object->fetch.tried_with_auth = true;
1532
		error = llcache_object_refetch(object);
1533
	}
1534
 
1535
	return error;
1536
}
1537
 
1538
/**
1539
 * Handle a TLS certificate verification failure
1540
 *
1541
 * \param object  Object being fetched
1542
 * \param certs	  Certificate chain
1543
 * \param num	  Number of certificates in chain
1544
 * \return NSERROR_OK on success, appropriate error otherwise
1545
 */
1546
static nserror llcache_fetch_cert_error(llcache_object *object,
1547
		const struct ssl_cert_info *certs, size_t num)
1548
{
1549
	nserror error = NSERROR_OK;
1550
 
1551
	/* Fetch has been stopped, and destroyed. Invalidate object's pointer */
1552
	object->fetch.fetch = NULL;
1553
 
1554
	/* Invalidate cache-control data */
1555
	llcache_invalidate_cache_control_data(object);
1556
 
1557
	if (llcache->query_cb != NULL) {
1558
		llcache_query query;
1559
 
1560
		/* Emit query for TLS */
1561
		query.type = LLCACHE_QUERY_SSL;
1562
		query.url = object->url;
1563
		query.data.ssl.certs = certs;
1564
		query.data.ssl.num = num;
1565
 
1566
		object->fetch.outstanding_query = true;
1567
 
1568
		error = llcache->query_cb(&query, llcache->query_cb_pw,
1569
				llcache_query_handle_response, object);
1570
	} else {
1571
		llcache_event event;
1572
 
1573
		/* Mark object complete */
1574
		object->fetch.state = LLCACHE_FETCH_COMPLETE;
1575
 
1576
		/* Inform client(s) that object fetch failed */
1577
		event.type = LLCACHE_EVENT_ERROR;
1578
		/** \todo More appropriate error message */
1579
		event.data.msg = messages_get("FetchFailed");
1580
 
1581
		error = llcache_send_event_to_users(object, &event);
1582
	}
1583
 
1584
	return error;
1585
}
1586
 
1587
/**
1588
 * Handle a TLS connection setup failure
1589
 *
1590
 * \param object  Object being fetched
1591
 * \return NSERROR_OK on success, appropriate error otherwise
1592
 */
1593
static nserror llcache_fetch_ssl_error(llcache_object *object)
1594
{
1595
	nserror error = NSERROR_OK;
1596
 
1597
	/* Fetch has been stopped, and destroyed. Invalidate object's pointer */
1598
	object->fetch.fetch = NULL;
1599
 
1600
	/* Invalidate cache-control data */
1601
	llcache_invalidate_cache_control_data(object);
1602
 
1603
	if (object->fetch.tried_with_tls_downgrade == true) {
1604
		/* Have already tried to downgrade, so give up */
1605
		llcache_event event;
1606
 
1607
		/* Mark object complete */
1608
		object->fetch.state = LLCACHE_FETCH_COMPLETE;
1609
 
1610
		/* Inform client(s) that object fetch failed */
1611
		event.type = LLCACHE_EVENT_ERROR;
1612
		/** \todo More appropriate error message */
1613
		event.data.msg = messages_get("FetchFailed");
1614
 
1615
		error = llcache_send_event_to_users(object, &event);
1616
	} else {
1617
		/* Flag that we've tried to downgrade, so that if the
1618
		 * fetch fails again, we give up */
1619
		object->fetch.tried_with_tls_downgrade = true;
1620
		error = llcache_object_refetch(object);
1621
	}
1622
 
1623
	return error;
1624
}
1625
 
1626
/**
1627
 * Handler for fetch events
1628
 *
1629
 * \param msg	     Fetch event
1630
 * \param p	     Our private data
1631
 */
1632
static void llcache_fetch_callback(const fetch_msg *msg, void *p)
1633
{
1634
	nserror error = NSERROR_OK;
1635
	llcache_object *object = p;
1636
	llcache_event event;
5043 ashmew2 1637
	/* DBG("Inside llcache_fetch_callback\n"); */
3584 sourcerer 1638
 
1639
#ifdef LLCACHE_TRACE
1640
	LOG(("Fetch event %d for %p", msg->type, object));
1641
#endif
5043 ashmew2 1642
	if(!msg)
1643
	  LOG(("msg is NULL in llcache_fetch_callback\n"));
3584 sourcerer 1644
 
1645
	switch (msg->type) {
1646
	case FETCH_HEADER:
5043 ashmew2 1647
	  /* DBG("FETCH_HEADER in llcache\n"); */
3584 sourcerer 1648
		/* Received a fetch header */
1649
		object->fetch.state = LLCACHE_FETCH_HEADERS;
1650
 
1651
		error = llcache_fetch_process_header(object,
1652
				msg->data.header_or_data.buf,
1653
				msg->data.header_or_data.len);
1654
		break;
1655
 
1656
	/* 3xx responses */
1657
	case FETCH_REDIRECT:
1658
		/* Request resulted in a redirect */
5043 ashmew2 1659
	  /* DBG("FETCH_REDIRECT in llcache\n"); */
3584 sourcerer 1660
		/* Release candidate, if any */
1661
		if (object->candidate != NULL) {
1662
			object->candidate->candidate_count--;
1663
			object->candidate = NULL;
1664
		}
1665
 
1666
		error = llcache_fetch_redirect(object,
1667
				msg->data.redirect, &object);
1668
		break;
1669
	case FETCH_NOTMODIFIED:
1670
		/* Conditional request determined that cached object is fresh */
5043 ashmew2 1671
	  	  /* DBG("FETCH_NOTMODIFIED in llcache\n"); */
3584 sourcerer 1672
		error = llcache_fetch_notmodified(object, &object);
1673
		break;
1674
 
1675
	/* Normal 2xx state machine */
1676
	case FETCH_DATA:
5043 ashmew2 1677
	  	  /* DBG("FETCH_DATA in llcache\n"); */
3584 sourcerer 1678
		/* Received some data */
1679
		if (object->fetch.state != LLCACHE_FETCH_DATA) {
1680
			/* On entry into this state, check if we need to
1681
			 * invalidate the cache control data. We are guaranteed
1682
			 * to have received all response headers.
1683
			 *
1684
			 * There are two cases in which we want to suppress
1685
			 * cacheing of an object:
1686
			 *
1687
			 * 1) The HTTP response code is not 200 or 203
1688
			 * 2) The request URI had a query string and the
1689
			 *    response headers did not provide an explicit
1690
			 *    object expiration time.
1691
			 */
1692
			long http_code = fetch_http_code(object->fetch.fetch);
1693
 
1694
			if ((http_code != 200 && http_code != 203) ||
1695
				(object->has_query &&
1696
				(object->cache.max_age == INVALID_AGE &&
1697
					object->cache.expires == 0))) {
1698
				/* Invalidate cache control data */
1699
				llcache_invalidate_cache_control_data(object);
1700
			}
1701
 
1702
			/* Release candidate, if any */
1703
			if (object->candidate != NULL) {
1704
				object->candidate->candidate_count--;
1705
				object->candidate = NULL;
1706
			}
1707
		}
1708
 
1709
		object->fetch.state = LLCACHE_FETCH_DATA;
1710
 
1711
		error = llcache_fetch_process_data(object,
1712
				msg->data.header_or_data.buf,
1713
				msg->data.header_or_data.len);
1714
		break;
1715
	case FETCH_FINISHED:
1716
		/* Finished fetching */
1717
	{
1718
		uint8_t *temp;
1719
 
5043 ashmew2 1720
		/* DBG("FETCH_FINISHED in llcache\n"); */
3584 sourcerer 1721
		object->fetch.state = LLCACHE_FETCH_COMPLETE;
1722
		object->fetch.fetch = NULL;
1723
 
1724
		/* Shrink source buffer to required size */
1725
		temp = realloc(object->source_data,
1726
				object->source_len);
1727
		/* If source_len is 0, then temp may be NULL */
1728
		if (temp != NULL || object->source_len == 0) {
1729
			object->source_data = temp;
1730
			object->source_alloc = object->source_len;
1731
		}
1732
 
1733
		llcache_object_cache_update(object);
1734
	}
1735
		break;
1736
 
1737
	/* Out-of-band information */
1738
	case FETCH_ERROR:
1739
		/* An error occurred while fetching */
1740
		/* The fetch has has already been cleaned up by the fetcher */
5043 ashmew2 1741
	  	  /* DBG("FETCH_ERROR in llcache\n"); */
3584 sourcerer 1742
		object->fetch.state = LLCACHE_FETCH_COMPLETE;
1743
		object->fetch.fetch = NULL;
1744
 
1745
		/* Release candidate, if any */
1746
		if (object->candidate != NULL) {
1747
			object->candidate->candidate_count--;
1748
			object->candidate = NULL;
1749
		}
1750
 
1751
		/* Invalidate cache control data */
1752
		llcache_invalidate_cache_control_data(object);
1753
 
1754
		/** \todo Consider using errorcode for something */
1755
 
1756
		event.type = LLCACHE_EVENT_ERROR;
1757
		event.data.msg = msg->data.error;
1758
 
1759
		error = llcache_send_event_to_users(object, &event);
1760
 
1761
		break;
1762
	case FETCH_PROGRESS:
5043 ashmew2 1763
	  	  /* DBG("FETCH_PROGRESS in llcache\n"); */
3584 sourcerer 1764
		/* Progress update */
1765
		event.type = LLCACHE_EVENT_PROGRESS;
1766
		event.data.msg = msg->data.progress;
1767
 
1768
		error = llcache_send_event_to_users(object, &event);
1769
 
1770
		break;
1771
 
1772
	/* Events requiring action */
1773
	case FETCH_AUTH:
5043 ashmew2 1774
	  	  /* DBG("FETCH_AUTH\n"); */
3584 sourcerer 1775
		/* Need Authentication */
1776
 
1777
		/* Release candidate, if any */
1778
		if (object->candidate != NULL) {
1779
			object->candidate->candidate_count--;
1780
			object->candidate = NULL;
1781
		}
1782
 
1783
		error = llcache_fetch_auth(object, msg->data.auth.realm);
1784
		break;
1785
	case FETCH_CERT_ERR:
1786
		/* Something went wrong when validating TLS certificates */
5043 ashmew2 1787
	  /* DBG("FETCH_CERT_ERR\n"); */
3584 sourcerer 1788
		/* Release candidate, if any */
1789
		if (object->candidate != NULL) {
1790
			object->candidate->candidate_count--;
1791
			object->candidate = NULL;
1792
		}
1793
 
1794
		error = llcache_fetch_cert_error(object,
1795
				msg->data.cert_err.certs,
1796
				msg->data.cert_err.num_certs);
1797
		break;
1798
	case FETCH_SSL_ERR:
1799
		/* TLS connection setup failed */
5043 ashmew2 1800
	  /* DBG("FETCH_SSL_ERR\n"); */
3584 sourcerer 1801
		/* Release candidate, if any */
1802
		if (object->candidate != NULL) {
1803
			object->candidate->candidate_count--;
1804
			object->candidate = NULL;
1805
		}
1806
 
1807
		error = llcache_fetch_ssl_error(object);
1808
		break;
1809
	}
1810
 
1811
	/* Deal with any errors reported by event handlers */
1812
	if (error != NSERROR_OK) {
5043 ashmew2 1813
	  /* DBG("Error is not NSERROR_OK!\n"); */
3584 sourcerer 1814
		if (object->fetch.fetch != NULL) {
1815
			fetch_abort(object->fetch.fetch);
1816
			object->fetch.fetch = NULL;
1817
 
1818
			/* Invalidate cache control data */
1819
			llcache_invalidate_cache_control_data(object);
1820
 
1821
			object->fetch.state = LLCACHE_FETCH_COMPLETE;
1822
		}
5043 ashmew2 1823
		/* DBG("Returning llc_f_cb. (err != NS_OK)\n"); */
3584 sourcerer 1824
		return;
1825
	}
5043 ashmew2 1826
	/* DBG("Returning from llc_f_cb.(err = NS_OK)\n"); */
3584 sourcerer 1827
}
1828
 
1829
/**
1830
 * Find a user of a low-level cache object
1831
 *
1832
 * \param handle  External cache handle to search for
1833
 * \return Pointer to corresponding user, or NULL if not found
1834
 */
1835
static llcache_object_user *llcache_object_find_user(const llcache_handle *handle)
1836
{
1837
	llcache_object_user *user;
1838
 
1839
	assert(handle->object != NULL);
1840
 
1841
	for (user = handle->object->users; user != NULL; user = user->next) {
1842
		if (user->handle == handle)
1843
			break;
1844
	}
1845
 
1846
	return user;
1847
}
1848
 
1849
/**
1850
 * Remove a low-level cache object from a cache list
1851
 *
1852
 * \param object  Object to remove
1853
 * \param list	  List to remove from
1854
 * \return NSERROR_OK
1855
 */
1856
static nserror llcache_object_remove_from_list(llcache_object *object,
1857
		llcache_object **list)
1858
{
1859
	if (object == *list)
1860
		*list = object->next;
1861
	else
1862
		object->prev->next = object->next;
1863
 
1864
	if (object->next != NULL)
1865
		object->next->prev = object->prev;
1866
 
1867
	return NSERROR_OK;
1868
}
1869
 
1870
/**
1871
 * Determine if a low-level cache object resides in a given list
1872
 *
1873
 * \param object  Object to search for
1874
 * \param list	  List to search in
1875
 * \return True if object resides in list, false otherwise
1876
 */
1877
static bool llcache_object_in_list(const llcache_object *object,
1878
		const llcache_object *list)
1879
{
1880
	while (list != NULL) {
1881
		if (list == object)
1882
			break;
1883
 
1884
		list = list->next;
1885
	}
1886
 
1887
	return list != NULL;
1888
}
1889
 
1890
/**
1891
 * Notify users of an object's current state
1892
 *
1893
 * \param object  Object to notify users about
1894
 * \return NSERROR_OK on success, appropriate error otherwise
1895
 */
1896
static nserror llcache_object_notify_users(llcache_object *object)
1897
{
1898
	nserror error;
1899
	llcache_object_user *user, *next_user;
1900
	llcache_event event;
1901
 
1902
#ifdef LLCACHE_TRACE
1903
	bool emitted_notify = false;
1904
#endif
1905
 
1906
	/**
1907
	 * State transitions and event emission for users.
1908
	 * Rows: user state. Cols: object state.
1909
	 *
1910
	 * User\Obj	INIT	HEADERS		DATA	COMPLETE
1911
	 * INIT		 -	   T		 T*	   T*
1912
	 * HEADERS	 -	   -		 T	   T*
1913
	 * DATA		 -	   -		 M	   T
1914
	 * COMPLETE	 -	   -		 -	   -
1915
	 *
1916
	 * T => transition user to object state
1917
	 * M => no transition required, but may need to emit event
1918
	 *
1919
	 * The transitions marked with an asterisk can be removed by moving
1920
	 * the user context into the subsequent state and then reevaluating.
1921
	 *
1922
	 * Events are issued as follows:
1923
	 *
1924
	 * HAD_HEADERS: on transition from HEADERS -> DATA state
1925
	 * HAD_DATA   : in DATA state, whenever there's new source data
1926
	 * DONE	      : on transition from DATA -> COMPLETE state
1927
	 */
1928
 
1929
	for (user = object->users; user != NULL; user = next_user) {
1930
		/* Emit necessary events to bring the user up-to-date */
1931
		llcache_handle *handle = user->handle;
1932
		const llcache_fetch_state objstate = object->fetch.state;
1933
 
1934
		/* Flag that this user is the current iteration target
1935
		 * in case the client attempts to destroy it underneath us */
1936
		user->iterator_target = true;
1937
 
1938
		/* A note on the computation of next_user:
1939
		 *
1940
		 * Within this loop, we may make a number of calls to
1941
		 * client code. Our contract with clients is that they
1942
		 * can do whatever they like from within their callback
1943
		 * handlers. This is so that we limit the pain of
1944
		 * reentrancy to this module alone.
1945
		 *
1946
		 * One of the things a client can do from within its
1947
		 * callback handler is to remove users from this object's
1948
		 * user list. In the common case, the user they attempt
1949
		 * to remove is the current iteration target, and we
1950
		 * already protect against that causing problems here.
1951
		 * However, no such protection exists if the client
1952
		 * attempts to remove other users from this object's
1953
		 * user list.
1954
		 *
1955
		 * Therefore, we cannot compute next_user up-front
1956
		 * and expect it to remain valid across calls to
1957
		 * client code (as the identity of the next user
1958
		 * in the list may change underneath us). Instead,
1959
		 * we must compute next_user at the point where we
1960
		 * are about to cause another iteration of this loop
1961
		 * (i.e. at the very end, and also at the points where
1962
		 * continue is used)
1963
		 */
1964
 
1965
#ifdef LLCACHE_TRACE
1966
		if (handle->state != objstate) {
1967
			if (emitted_notify == false) {
1968
				LOG(("Notifying users of %p", object));
1969
				emitted_notify = true;
1970
			}
1971
 
1972
			LOG(("User %p state: %d Object state: %d",
1973
					user, handle->state, objstate));
1974
		}
1975
#endif
1976
 
1977
		/* User: INIT, Obj: HEADERS, DATA, COMPLETE => User->HEADERS */
1978
		if (handle->state == LLCACHE_FETCH_INIT &&
1979
				objstate > LLCACHE_FETCH_INIT) {
1980
			handle->state = LLCACHE_FETCH_HEADERS;
1981
		}
1982
 
1983
		/* User: HEADERS, Obj: DATA, COMPLETE => User->DATA */
1984
		if (handle->state == LLCACHE_FETCH_HEADERS &&
1985
				objstate > LLCACHE_FETCH_HEADERS) {
1986
			handle->state = LLCACHE_FETCH_DATA;
1987
 
1988
			/* Emit HAD_HEADERS event */
1989
			event.type = LLCACHE_EVENT_HAD_HEADERS;
1990
 
1991
			error = handle->cb(handle, &event, handle->pw);
1992
 
1993
			if (user->queued_for_delete) {
1994
				next_user = user->next;
1995
				llcache_object_remove_user(object, user);
1996
				llcache_object_user_destroy(user);
1997
 
1998
				if (error != NSERROR_OK)
1999
					return error;
2000
 
2001
				continue;
2002
			} else if (error == NSERROR_NEED_DATA) {
2003
				/* User requested replay */
2004
				handle->state = LLCACHE_FETCH_HEADERS;
2005
 
2006
				/* Continue with the next user -- we'll
2007
				 * reemit the event next time round */
2008
				user->iterator_target = false;
2009
				next_user = user->next;
2010
				continue;
2011
			} else if (error != NSERROR_OK) {
2012
				user->iterator_target = false;
2013
				return error;
2014
			}
2015
		}
2016
 
2017
		/* User: DATA, Obj: DATA, COMPLETE, more source available */
2018
		if (handle->state == LLCACHE_FETCH_DATA &&
2019
				objstate >= LLCACHE_FETCH_DATA &&
2020
				object->source_len > handle->bytes) {
2021
			size_t orig_handle_read;
2022
 
2023
			/* Construct HAD_DATA event */
2024
			event.type = LLCACHE_EVENT_HAD_DATA;
2025
			event.data.data.buf =
2026
					object->source_data + handle->bytes;
2027
			event.data.data.len =
2028
					object->source_len - handle->bytes;
2029
 
2030
			/* Update record of last byte emitted */
2031
			if (object->fetch.flags &
2032
					LLCACHE_RETRIEVE_STREAM_DATA) {
2033
				/* Streaming, so reset to zero to
2034
				 * minimise amount of cached source data.
2035
				 * Additionally, we don't support replay
2036
				 * when streaming. */
2037
				orig_handle_read = 0;
2038
				handle->bytes = object->source_len = 0;
2039
			} else {
2040
				orig_handle_read = handle->bytes;
2041
				handle->bytes = object->source_len;
2042
			}
2043
 
2044
			/* Emit event */
2045
			error = handle->cb(handle, &event, handle->pw);
2046
			if (user->queued_for_delete) {
2047
				next_user = user->next;
2048
				llcache_object_remove_user(object, user);
2049
				llcache_object_user_destroy(user);
2050
 
2051
				if (error != NSERROR_OK)
2052
					return error;
2053
 
2054
				continue;
2055
			} else if (error == NSERROR_NEED_DATA) {
2056
				/* User requested replay */
2057
				handle->bytes = orig_handle_read;
2058
 
2059
				/* Continue with the next user -- we'll
2060
				 * reemit the data next time round */
2061
				user->iterator_target = false;
2062
				next_user = user->next;
2063
				continue;
2064
			} else if (error != NSERROR_OK) {
2065
				user->iterator_target = false;
2066
				return error;
2067
			}
2068
		}
2069
 
2070
		/* User: DATA, Obj: COMPLETE => User->COMPLETE */
2071
		if (handle->state == LLCACHE_FETCH_DATA &&
2072
				objstate > LLCACHE_FETCH_DATA) {
2073
			handle->state = LLCACHE_FETCH_COMPLETE;
2074
 
2075
			/* Emit DONE event */
2076
			event.type = LLCACHE_EVENT_DONE;
2077
 
2078
			error = handle->cb(handle, &event, handle->pw);
2079
			if (user->queued_for_delete) {
2080
				next_user = user->next;
2081
				llcache_object_remove_user(object, user);
2082
				llcache_object_user_destroy(user);
2083
 
2084
				if (error != NSERROR_OK)
2085
					return error;
2086
 
2087
				continue;
2088
			} else if (error == NSERROR_NEED_DATA) {
2089
				/* User requested replay */
2090
				handle->state = LLCACHE_FETCH_DATA;
2091
 
2092
				/* Continue with the next user -- we'll
2093
				 * reemit the event next time round */
2094
				user->iterator_target = false;
2095
				next_user = user->next;
2096
				continue;
2097
			} else if (error != NSERROR_OK) {
2098
				user->iterator_target = false;
2099
				return error;
2100
			}
2101
		}
2102
 
2103
		/* No longer the target of an iterator */
2104
		user->iterator_target = false;
2105
 
2106
		next_user = user->next;
2107
	}
2108
 
2109
	return NSERROR_OK;
2110
}
2111
 
2112
/**
2113
 * Make a snapshot of the current state of an llcache_object.
2114
 *
2115
 * This has the side-effect of the new object being non-cacheable,
2116
 * also not-fetching and not a candidate for any other object.
2117
 *
2118
 * Also note that this new object has no users and at least one
2119
 * should be assigned to it before llcache_clean is entered or it
2120
 * will be immediately cleaned up.
2121
 *
2122
 * \param object  The object to take a snapshot of
2123
 * \param snapshot  Pointer to receive snapshot of \a object
2124
 * \return NSERROR_OK on success, appropriate error otherwise
2125
 */
2126
static nserror llcache_object_snapshot(llcache_object *object,
2127
		llcache_object **snapshot)
2128
{
2129
	llcache_object *newobj;
2130
	nserror error;
2131
 
2132
	error = llcache_object_new(object->url, &newobj);
2133
 
2134
	if (error != NSERROR_OK)
2135
		return error;
2136
 
2137
	newobj->has_query = object->has_query;
2138
 
2139
	newobj->source_alloc = newobj->source_len = object->source_len;
2140
 
2141
	if (object->source_len > 0) {
2142
		newobj->source_data = malloc(newobj->source_alloc);
2143
		if (newobj->source_data == NULL) {
2144
			llcache_object_destroy(newobj);
2145
			return NSERROR_NOMEM;
2146
		}
2147
		memcpy(newobj->source_data, object->source_data,
2148
				newobj->source_len);
2149
	}
2150
 
2151
	if (object->num_headers > 0) {
2152
		newobj->headers = calloc(sizeof(llcache_header),
2153
				object->num_headers);
2154
		if (newobj->headers == NULL) {
2155
			llcache_object_destroy(newobj);
2156
			return NSERROR_NOMEM;
2157
		}
2158
		while (newobj->num_headers < object->num_headers) {
2159
			llcache_header *nh =
2160
					&(newobj->headers[newobj->num_headers]);
2161
			llcache_header *oh =
2162
					&(object->headers[newobj->num_headers]);
2163
			newobj->num_headers += 1;
2164
			nh->name = strdup(oh->name);
2165
			nh->value = strdup(oh->value);
2166
			if (nh->name == NULL || nh->value == NULL) {
2167
				llcache_object_destroy(newobj);
2168
				return NSERROR_NOMEM;
2169
			}
2170
		}
2171
	}
2172
 
2173
	newobj->fetch.state = LLCACHE_FETCH_COMPLETE;
2174
 
2175
	*snapshot = newobj;
2176
 
2177
	return NSERROR_OK;
2178
}
2179
 
2180
 
2181
/******************************************************************************
2182
 * Public API								      *
2183
 ******************************************************************************/
2184
 
2185
/**
2186
 * Attempt to clean the cache
2187
 */
2188
/* Exported interface documented in llcache.h */
2189
void llcache_clean(void)
2190
{
2191
	llcache_object *object, *next;
2192
	uint32_t llcache_size = 0;
2193
	int remaining_lifetime;
2194
 
2195
#ifdef LLCACHE_TRACE
2196
	LOG(("Attempting cache clean"));
2197
#endif
2198
 
2199
	/* Candidates for cleaning are (in order of priority):
2200
	 *
2201
	 * 1) Uncacheable objects with no users
2202
	 * 2) Stale cacheable objects with no users or pending fetches
2203
	 * 3) Fresh cacheable objects with no users or pending fetches
2204
	 */
2205
 
2206
	/* 1) Uncacheable objects with no users or fetches */
2207
	for (object = llcache->uncached_objects; object != NULL; object = next) {
2208
		next = object->next;
2209
 
2210
		/* The candidate count of uncacheable objects is always 0 */
2211
		if ((object->users == NULL) &&
2212
		    (object->candidate_count == 0) &&
2213
		    (object->fetch.fetch == NULL) &&
2214
		    (object->fetch.outstanding_query == false)) {
2215
#ifdef LLCACHE_TRACE
2216
			LOG(("Found victim %p", object));
2217
#endif
2218
			llcache_object_remove_from_list(object,
2219
					&llcache->uncached_objects);
2220
			llcache_object_destroy(object);
2221
		} else {
2222
			llcache_size += object->source_len + sizeof(*object);
2223
		}
2224
	}
2225
 
2226
	/* 2) Stale cacheable objects with no users or pending fetches */
2227
	for (object = llcache->cached_objects; object != NULL; object = next) {
2228
		next = object->next;
2229
 
2230
		remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(&object->cache);
2231
 
2232
		if ((object->users == NULL) &&
2233
		    (object->candidate_count == 0) &&
2234
		    (object->fetch.fetch == NULL) &&
2235
		    (object->fetch.outstanding_query == false)) {
2236
 
2237
			if (remaining_lifetime > 0) {
2238
				/* object is fresh */
2239
				llcache_size += object->source_len + sizeof(*object);
2240
			} else {
2241
				/* object is not fresh */
2242
#ifdef LLCACHE_TRACE
2243
				LOG(("Found stale cacheable object (%p) with no users or pending fetches", object));
2244
#endif
2245
				llcache_object_remove_from_list(object,
2246
						&llcache->cached_objects);
2247
				llcache_object_destroy(object);
2248
			}
2249
		} else {
2250
			llcache_size += object->source_len + sizeof(*object);
2251
		}
2252
	}
2253
 
2254
	/* 3) Fresh cacheable objects with no users or pending
2255
	 * fetches, only if the cache exceeds the configured size.
2256
	 */
2257
	if (llcache->limit < llcache_size) {
2258
		for (object = llcache->cached_objects; object != NULL;
2259
				object = next) {
2260
			next = object->next;
2261
 
2262
			if ((object->users == NULL) &&
2263
			    (object->candidate_count == 0) &&
2264
			    (object->fetch.fetch == NULL) &&
2265
			    (object->fetch.outstanding_query == false)) {
2266
#ifdef LLCACHE_TRACE
2267
				LOG(("Found victim %p", object));
2268
#endif
2269
				llcache_size -=
2270
					object->source_len + sizeof(*object);
2271
 
2272
				llcache_object_remove_from_list(object,
2273
						&llcache->cached_objects);
2274
				llcache_object_destroy(object);
2275
			}
2276
		}
2277
	}
2278
 
2279
#ifdef LLCACHE_TRACE
2280
	LOG(("Size: %u", llcache_size));
2281
#endif
2282
 
2283
}
2284
 
2285
/* See llcache.h for documentation */
2286
nserror
2287
llcache_initialise(llcache_query_callback cb, void *pw, uint32_t llcache_limit)
2288
{
2289
	llcache = calloc(1, sizeof(struct llcache_s));
2290
	if (llcache == NULL) {
2291
		return NSERROR_NOMEM;
2292
	}
2293
 
2294
	llcache->query_cb = cb;
2295
	llcache->query_cb_pw = pw;
2296
	llcache->limit = llcache_limit;
2297
 
2298
	/* Create static scheme strings */
2299
	if (lwc_intern_string("file", SLEN("file"),
2300
			&llcache_file_lwc) != lwc_error_ok)
2301
		return NSERROR_NOMEM;
2302
 
2303
	if (lwc_intern_string("about", SLEN("about"),
2304
			&llcache_about_lwc) != lwc_error_ok)
2305
		return NSERROR_NOMEM;
2306
 
2307
	if (lwc_intern_string("resource", SLEN("resource"),
2308
			&llcache_resource_lwc) != lwc_error_ok)
2309
		return NSERROR_NOMEM;
2310
 
2311
	LOG(("llcache initialised with a limit of %d bytes", llcache_limit));
2312
 
2313
	return NSERROR_OK;
2314
}
2315
 
2316
/* See llcache.h for documentation */
2317
void llcache_finalise(void)
2318
{
2319
	llcache_object *object, *next;
2320
 
2321
	/* Clean uncached objects */
2322
	for (object = llcache->uncached_objects; object != NULL; object = next) {
2323
		llcache_object_user *user, *next_user;
2324
 
2325
		next = object->next;
2326
 
2327
		for (user = object->users; user != NULL; user = next_user) {
2328
			next_user = user->next;
2329
 
2330
			if (user->handle != NULL)
2331
				free(user->handle);
2332
 
2333
			free(user);
2334
		}
2335
 
2336
		/* Fetch system has already been destroyed */
2337
		object->fetch.fetch = NULL;
2338
 
2339
		llcache_object_destroy(object);
2340
	}
2341
 
2342
	/* Clean cached objects */
2343
	for (object = llcache->cached_objects; object != NULL; object = next) {
2344
		llcache_object_user *user, *next_user;
2345
 
2346
		next = object->next;
2347
 
2348
		for (user = object->users; user != NULL; user = next_user) {
2349
			next_user = user->next;
2350
 
2351
			if (user->handle != NULL)
2352
			       free(user->handle);
2353
 
2354
			free(user);
2355
		}
2356
 
2357
		/* Fetch system has already been destroyed */
2358
		object->fetch.fetch = NULL;
2359
 
2360
		llcache_object_destroy(object);
2361
	}
2362
 
2363
	/* Unref static scheme lwc strings */
2364
	lwc_string_unref(llcache_file_lwc);
2365
	lwc_string_unref(llcache_about_lwc);
2366
	lwc_string_unref(llcache_resource_lwc);
2367
 
2368
	free(llcache);
2369
	llcache = NULL;
2370
}
2371
 
2372
/* See llcache.h for documentation */
2373
nserror llcache_poll(void)
2374
{
2375
	llcache_object *object;
2376
	fetch_poll();
2377
 
2378
	/* Catch new users up with state of objects */
2379
	for (object = llcache->cached_objects; object != NULL;
2380
			object = object->next) {
2381
		llcache_object_notify_users(object);
2382
	}
2383
 
2384
	for (object = llcache->uncached_objects; object != NULL;
2385
			object = object->next) {
2386
		llcache_object_notify_users(object);
2387
	}
2388
 
2389
	return NSERROR_OK;
2390
}
2391
 
2392
/* See llcache.h for documentation */
2393
nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
2394
		nsurl *referer, const llcache_post_data *post,
2395
		llcache_handle_callback cb, void *pw,
2396
		llcache_handle **result)
2397
{
2398
	nserror error;
2399
	llcache_object_user *user;
2400
	llcache_object *object;
2401
 
2402
	/* Can we fetch this URL at all? */
2403
	if (fetch_can_fetch(url) == false)
2404
		return NSERROR_NO_FETCH_HANDLER;
2405
 
2406
	/* Create a new object user */
2407
	error = llcache_object_user_new(cb, pw, &user);
2408
	if (error != NSERROR_OK)
2409
		return error;
2410
 
2411
	/* Retrieve a suitable object from the cache,
2412
	 * creating a new one if needed. */
2413
	error = llcache_object_retrieve(url, flags, referer, post, 0, &object);
2414
	if (error != NSERROR_OK) {
2415
		llcache_object_user_destroy(user);
2416
		return error;
2417
	}
2418
 
2419
	/* Add user to object */
2420
	llcache_object_add_user(object, user);
2421
 
2422
	*result = user->handle;
2423
 
2424
	return NSERROR_OK;
2425
}
2426
 
2427
/* See llcache.h for documentation */
2428
nserror llcache_handle_change_callback(llcache_handle *handle,
2429
		llcache_handle_callback cb, void *pw)
2430
{
2431
	handle->cb = cb;
2432
	handle->pw = pw;
2433
 
2434
	return NSERROR_OK;
2435
}
2436
 
2437
/* See llcache.h for documentation */
2438
nserror llcache_handle_release(llcache_handle *handle)
2439
{
2440
	nserror error = NSERROR_OK;
2441
	llcache_object *object = handle->object;
2442
	llcache_object_user *user = llcache_object_find_user(handle);
2443
 
2444
	assert(user != NULL);
2445
 
2446
	if (user->iterator_target) {
2447
		/* Can't remove / delete user object if it's
2448
		 * the target of an iterator */
2449
		user->queued_for_delete = true;
2450
	} else {
2451
		/* Remove the user from the object and destroy it */
2452
		error = llcache_object_remove_user(object, user);
2453
		if (error == NSERROR_OK) {
2454
			error = llcache_object_user_destroy(user);
2455
		}
2456
	}
2457
 
2458
	return error;
2459
}
2460
 
2461
/* See llcache.h for documentation */
2462
nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result)
2463
{
2464
	nserror error;
2465
	llcache_object_user *newuser;
2466
 
2467
	error = llcache_object_user_new(handle->cb, handle->pw, &newuser);
2468
	if (error == NSERROR_OK) {
2469
		llcache_object_add_user(handle->object, newuser);
2470
		newuser->handle->state = handle->state;
2471
		*result = newuser->handle;
2472
	}
2473
 
2474
	return error;
2475
}
2476
 
2477
/* See llcache.h for documentation */
2478
nserror llcache_handle_abort(llcache_handle *handle)
2479
{
2480
	llcache_object_user *user = llcache_object_find_user(handle);
2481
	llcache_object *object = handle->object, *newobject;
2482
	nserror error = NSERROR_OK;
2483
	bool all_alone = true;
2484
 
2485
	/* Determine if we are the only user */
2486
	if (user->prev != NULL)
2487
		all_alone = false;
2488
	if (user->next != NULL)
2489
		all_alone = false;
2490
 
2491
	if (all_alone == false) {
2492
		/* We must snapshot this object */
2493
		error = llcache_object_snapshot(object, &newobject);
2494
		if (error != NSERROR_OK)
2495
			return error;
2496
 
2497
		/* Move across to the new object */
2498
		if (user->iterator_target) {
2499
			/* User is current iterator target, clone it */
2500
			llcache_object_user *newuser =
2501
					calloc(1, sizeof(llcache_object_user));
2502
			if (newuser == NULL) {
2503
				llcache_object_destroy(newobject);
2504
				return NSERROR_NOMEM;
2505
			}
2506
 
2507
			/* Move handle across to clone */
2508
			newuser->handle = user->handle;
2509
			user->handle = NULL;
2510
 
2511
			/* Mark user as needing deletion */
2512
			user->queued_for_delete = true;
2513
 
2514
			llcache_object_add_user(newobject, newuser);
2515
		} else {
2516
			llcache_object_remove_user(object, user);
2517
			llcache_object_add_user(newobject, user);
2518
		}
2519
 
2520
		/* Add new object to uncached list */
2521
		llcache_object_add_to_list(newobject,
2522
				&llcache->uncached_objects);
2523
	} else {
2524
		/* We're the only user, so abort any fetch in progress */
2525
		if (object->fetch.fetch != NULL) {
2526
			fetch_abort(object->fetch.fetch);
2527
			object->fetch.fetch = NULL;
2528
		}
2529
 
2530
		object->fetch.state = LLCACHE_FETCH_COMPLETE;
2531
 
2532
		/* Invalidate cache control data */
2533
		llcache_invalidate_cache_control_data(object);
2534
	}
2535
 
2536
	return error;
2537
}
2538
 
2539
/* See llcache.h for documentation */
2540
nserror llcache_handle_force_stream(llcache_handle *handle)
2541
{
2542
	llcache_object_user *user = llcache_object_find_user(handle);
2543
	llcache_object *object = handle->object;
2544
 
2545
	/* Cannot stream if there are multiple users */
2546
	if (user->prev != NULL || user->next != NULL)
2547
		return NSERROR_OK;
2548
 
2549
	/* Forcibly uncache this object */
2550
	if (llcache_object_in_list(object, llcache->cached_objects)) {
2551
		llcache_object_remove_from_list(object,
2552
				&llcache->cached_objects);
2553
		llcache_object_add_to_list(object, &llcache->uncached_objects);
2554
	}
2555
 
2556
	object->fetch.flags |= LLCACHE_RETRIEVE_STREAM_DATA;
2557
 
2558
	return NSERROR_OK;
2559
}
2560
 
2561
/* See llcache.h for documentation */
2562
nserror llcache_handle_invalidate_cache_data(llcache_handle *handle)
2563
{
2564
	if (handle->object != NULL && handle->object->fetch.fetch == NULL &&
2565
			handle->object->cache.no_cache ==
2566
				LLCACHE_VALIDATE_FRESH) {
2567
		handle->object->cache.no_cache = LLCACHE_VALIDATE_ONCE;
2568
	}
2569
 
2570
	return NSERROR_OK;
2571
}
2572
 
2573
/* See llcache.h for documentation */
2574
nsurl *llcache_handle_get_url(const llcache_handle *handle)
2575
{
2576
	return handle->object != NULL ? handle->object->url : NULL;
2577
}
2578
 
2579
/* See llcache.h for documentation */
2580
const uint8_t *llcache_handle_get_source_data(const llcache_handle *handle,
2581
		size_t *size)
2582
{
2583
	*size = handle->object != NULL ? handle->object->source_len : 0;
2584
 
2585
	return handle->object != NULL ? handle->object->source_data : NULL;
2586
}
2587
 
2588
/* See llcache.h for documentation */
2589
const char *llcache_handle_get_header(const llcache_handle *handle,
2590
		const char *key)
2591
{
2592
	const llcache_object *object = handle->object;
2593
	size_t i;
2594
 
2595
	if (object == NULL)
2596
		return NULL;
2597
 
2598
	/* About as trivial as possible */
2599
	for (i = 0; i < object->num_headers; i++) {
2600
		if (strcasecmp(key, object->headers[i].name) == 0)
2601
			return object->headers[i].value;
2602
	}
2603
 
2604
	return NULL;
2605
}
2606
 
2607
/* See llcache.h for documentation */
2608
bool llcache_handle_references_same_object(const llcache_handle *a,
2609
		const llcache_handle *b)
2610
{
2611
	return a->object == b->object;
2612
}
2613