Subversion Repositories Kolibri OS

Rev

Rev 4821 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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