summaryrefslogtreecommitdiff
path: root/content/llcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'content/llcache.c')
-rw-r--r--content/llcache.c379
1 files changed, 254 insertions, 125 deletions
diff --git a/content/llcache.c b/content/llcache.c
index eb300534d..29b42a1c0 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -52,16 +52,6 @@
#include "content/backing_store.h"
#include "content/urldb.h"
-/** Define to enable tracing of llcache operations. */
-#undef LLCACHE_TRACE
-//#define LLCACHE_TRACE 1
-
-#ifdef LLCACHE_TRACE
-#define LLCACHE_LOG(x...) LOG(x)
-#else
-#define LLCACHE_LOG(x...) ((void) 0)
-#endif
-
/**
* State of a low-level cache object fetch.
*/
@@ -96,7 +86,7 @@ struct llcache_handle {
typedef struct llcache_object_user {
llcache_handle *handle; /**< Handle data for client */
- bool iterator_target; /**< This is the an iterator target */
+ bool iterator_target; /**< This is the iterator target */
bool queued_for_delete; /**< This user is queued for deletion */
struct llcache_object_user *prev; /**< Previous in list */
@@ -119,11 +109,15 @@ typedef struct {
uint32_t retries_remaining; /**< Number of times to retry on timeout */
+ bool hsts_in_use; /**< Whether HSTS applies to this fetch */
+
bool tried_with_auth; /**< Whether we've tried with auth */
bool tried_with_tls_downgrade; /**< Whether we've tried TLS <= 1.0 */
bool outstanding_query; /**< Waiting for a query response */
+
+ bool tainted_tls; /**< Whether the TLS transport is tainted */
} llcache_fetch_ctx;
/**
@@ -136,7 +130,7 @@ typedef enum {
} llcache_validate;
/**
- * cache control value for invalid age.
+ * Cache control value for invalid age.
*/
#define INVALID_AGE -1
@@ -160,7 +154,7 @@ typedef struct {
char *value; /**< Header value */
} llcache_header;
-/** Current status of objects data */
+/** Current status of an object's data */
typedef enum {
LLCACHE_STATE_RAM = 0, /**< source data is stored in RAM only */
LLCACHE_STATE_DISC, /**< source data is stored on disc */
@@ -201,7 +195,7 @@ struct llcache_object {
/* Instrumentation. These elements are strictly for information
* to improve the cache performance and to provide performance
- * metrics. The values are non-authorative and must not be used to
+ * metrics. The values are non-authoritative and must not be used to
* determine object lifetime etc.
*/
time_t last_used; /**< time the last user was removed from the object */
@@ -316,7 +310,8 @@ static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
u->handle = h;
- LLCACHE_LOG("Created user %p (%p, %p, %p)", u, h, (void *) cb, pw);
+ NSLOG(llcache, DEBUG,
+ "Created user %p (%p, %p, %p)", u, h, (void *) cb, pw);
*user = u;
@@ -333,7 +328,7 @@ static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
*/
static nserror llcache_object_user_destroy(llcache_object_user *user)
{
- LLCACHE_LOG("Destroyed user %p", user);
+ NSLOG(llcache, DEBUG, "Destroyed user %p", user);
assert(user->next == NULL);
assert(user->prev == NULL);
@@ -377,7 +372,7 @@ static nserror llcache_object_remove_user(llcache_object *object,
object->last_used = time(NULL);
}
- LLCACHE_LOG("Removing user %p from %p", user, object);
+ NSLOG(llcache, DEBUG, "Removing user %p from %p", user, object);
return NSERROR_OK;
}
@@ -433,7 +428,7 @@ static nserror llcache_object_new(nsurl *url, llcache_object **result)
if (obj == NULL)
return NSERROR_NOMEM;
- LLCACHE_LOG("Created object %p (%s)", obj, nsurl_access(url));
+ NSLOG(llcache, DEBUG, "Created object %p (%s)", obj, nsurl_access(url));
obj->url = nsurl_ref(url);
@@ -800,7 +795,7 @@ static nserror llcache_fetch_process_header(llcache_object *object,
/**
* (Re)fetch an object
*
- * sets up headers and attempts to start an actual fetch from the
+ * Sets up headers and attempts to start an actual fetch from the
* fetchers system updating the llcache object with the new fetch on
* successful start.
*
@@ -874,7 +869,7 @@ static nserror llcache_object_refetch(llcache_object *object)
/* Reset fetch state */
object->fetch.state = LLCACHE_FETCH_INIT;
- LLCACHE_LOG("Re-fetching %p", object);
+ NSLOG(llcache, DEBUG, "Re-fetching %p", object);
/* Kick off fetch */
res = fetch_start(object->url,
@@ -911,17 +906,18 @@ static nserror llcache_object_refetch(llcache_object *object)
* \param referer Referring URL, or NULL for none
* \param post POST data, or NULL for GET
* \param redirect_count Number of redirects followed so far
+ * \param hsts_in_use Whether HSTS applies to this fetch
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
nsurl *referer, const llcache_post_data *post,
- uint32_t redirect_count)
+ uint32_t redirect_count, bool hsts_in_use)
{
nserror error;
nsurl *referer_clone = NULL;
llcache_post_data *post_clone = NULL;
- LLCACHE_LOG("Starting fetch for %p", object);
+ NSLOG(llcache, DEBUG, "Starting fetch for %p", object);
if (post != NULL) {
error = llcache_post_data_clone(post, &post_clone);
@@ -937,6 +933,7 @@ static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
object->fetch.post = post_clone;
object->fetch.redirect_count = redirect_count;
object->fetch.retries_remaining = llcache->fetch_attempts;
+ object->fetch.hsts_in_use = hsts_in_use;
return llcache_object_refetch(object);
}
@@ -955,8 +952,8 @@ static nserror llcache_object_destroy(llcache_object *object)
{
size_t i;
- LLCACHE_LOG("Destroying object %p, %s", object,
- nsurl_access(object->url));
+ NSLOG(llcache, DEBUG, "Destroying object %p, %s", object,
+ nsurl_access(object->url));
if (object->source_data != NULL) {
if (object->store_state == LLCACHE_STATE_DISC) {
@@ -1038,16 +1035,17 @@ llcache_object_rfc2616_remaining_lifetime(const llcache_cache_control *cd)
current_age += cd->res_time - cd->req_time + now - cd->res_time;
/* Determine freshness lifetime of this object */
- if (cd->max_age != INVALID_AGE)
+ if (cd->max_age != INVALID_AGE) {
freshness_lifetime = cd->max_age;
- else if (cd->expires != 0)
+ } else if (cd->expires != 0) {
freshness_lifetime = cd->expires - cd->date;
- else if (cd->last_modified != 0)
+ } else if (cd->last_modified != 0) {
freshness_lifetime = (now - cd->last_modified) / 10;
- else
+ } else {
freshness_lifetime = 0;
+ }
- /* LLCACHE_LOG("%d:%d", freshness_lifetime, current_age); */
+ NSLOG(llcache, DEBUG, "%d:%d", freshness_lifetime, current_age);
if ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
(freshness_lifetime > current_age)) {
@@ -1076,7 +1074,7 @@ static bool llcache_object_is_fresh(const llcache_object *object)
remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(cd);
- LLCACHE_LOG("%p: (%d > 0 || %d != %d)", object,
+ NSLOG(llcache, DEBUG, "%p: (%d > 0 || %d != %d)", object,
remaining_lifetime,
object->fetch.state, LLCACHE_FETCH_COMPLETE);
@@ -1173,14 +1171,14 @@ llcache_object_remove_from_list(llcache_object *object, llcache_object **list)
/**
* Retrieve source data for an object from persistent store if necessary.
*
- * If an objects source data has been placed in the persistent store
- * and the in memory copy released this will attempt to retrieve the
- * source data.
+ * If an object's source data has been placed in the persistent store
+ * and there is no in-memory copy, then attempt to retrieve the source
+ * data.
*
* \param object the object to operate on.
* \return appropriate error code.
*/
-static nserror llcache_persist_retrieve(llcache_object *object)
+static nserror llcache_retrieve_persisted_data(llcache_object *object)
{
/* ensure the source data is present if necessary */
if ((object->source_data != NULL) ||
@@ -1199,7 +1197,7 @@ static nserror llcache_persist_retrieve(llcache_object *object)
}
/**
- * Generate a serialised version of an objects metadata
+ * Generate a serialised version of an object's metadata
*
* The metadata includes object headers.
*
@@ -1322,7 +1320,7 @@ llcache_serialise_metadata(llcache_object *object,
datasize -= use;
}
- LLCACHE_LOG("Filled buffer with %d spare", datasize);
+ NSLOG(llcache, DEBUG, "Filled buffer with %d spare", datasize);
*data_out = data;
*datasize_out = allocsize - datasize;
@@ -1331,19 +1329,19 @@ llcache_serialise_metadata(llcache_object *object,
overflow:
/* somehow we overflowed the buffer - hth? */
- LOG("Overflowed metadata buffer");
+ NSLOG(llcache, INFO, "Overflowed metadata buffer");
free(data);
return NSERROR_INVALID;
operror:
/* output error */
- LOG("Output error");
+ NSLOG(llcache, INFO, "Output error");
free(data);
return NSERROR_INVALID;
}
/**
- * Deserialisation of an objects metadata.
+ * Deserialisation of an object's metadata.
*
* Attempt to retrieve and deserialise the metadata for an object from
* the backing store.
@@ -1369,12 +1367,12 @@ llcache_process_metadata(llcache_object *object)
size_t source_length;
time_t request_time;
- time_t reponse_time;
+ time_t response_time;
time_t completion_time;
size_t num_headers;
size_t hloop;
- LOG("Retrieving metadata");
+ NSLOG(llcache, INFO, "Retrieving metadata");
/* attempt to retrieve object metadata from the backing store */
res = guit->llcache->fetch(object->url,
@@ -1385,7 +1383,7 @@ llcache_process_metadata(llcache_object *object)
return res;
}
- LOG("Processing retrieved data");
+ NSLOG(llcache, INFO, "Processing retrieved data");
/* metadata line 1 is the url the metadata referrs to */
line = 1;
@@ -1408,8 +1406,8 @@ llcache_process_metadata(llcache_object *object)
* by simply skipping caching of this object.
*/
- LOG("Got metadata for %s instead of %s",
- nsurl_access(metadataurl), nsurl_access(object->url));
+ NSLOG(llcache, INFO, "Got metadata for %s instead of %s",
+ nsurl_access(metadataurl), nsurl_access(object->url));
nsurl_unref(metadataurl);
@@ -1420,7 +1418,7 @@ llcache_process_metadata(llcache_object *object)
nsurl_unref(metadataurl);
- /* metadata line 2 is the objects length */
+ /* metadata line 2 is the object's length */
line = 2;
ln += lnsize + 1;
lnsize = strlen(ln);
@@ -1446,7 +1444,7 @@ llcache_process_metadata(llcache_object *object)
ln += lnsize + 1;
lnsize = strlen(ln);
- res = nsc_snptimet(ln, lnsize, &reponse_time);
+ res = nsc_snptimet(ln, lnsize, &response_time);
if (res != NSERROR_OK)
goto format_error;
@@ -1493,7 +1491,7 @@ llcache_process_metadata(llcache_object *object)
object->source_alloc = metadatalen;
object->cache.req_time = request_time;
- object->cache.res_time = reponse_time;
+ object->cache.res_time = response_time;
object->cache.fin_time = completion_time;
/* object stored in backing store */
@@ -1502,7 +1500,9 @@ llcache_process_metadata(llcache_object *object)
return NSERROR_OK;
format_error:
- LOG("metadata error on line %d error code %d\n", line, res);
+ NSLOG(llcache, INFO,
+ "metadata error on line %d error code %d\n",
+ line, res);
guit->llcache->release(object->url, BACKING_STORE_META);
return res;
@@ -1520,7 +1520,7 @@ format_error:
* cache else appropriate error code.
*/
static nserror
-llcache_object_fetch_persistant(llcache_object *object,
+llcache_object_fetch_persistent(llcache_object *object,
uint32_t flags,
nsurl *referer,
const llcache_post_data *post,
@@ -1570,6 +1570,7 @@ llcache_object_fetch_persistant(llcache_object *object,
* \param referer Referring URL, or NULL if none
* \param post POST data, or NULL for a GET request
* \param redirect_count Number of redirects followed so far
+ * \param hsts_in_use Whether HSTS applies to this fetch
* \param result Pointer to location to receive retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
*/
@@ -1579,12 +1580,13 @@ llcache_object_retrieve_from_cache(nsurl *url,
nsurl *referer,
const llcache_post_data *post,
uint32_t redirect_count,
+ bool hsts_in_use,
llcache_object **result)
{
nserror error;
llcache_object *obj, *newest = NULL;
- LLCACHE_LOG("Searching cache for %s flags:%x referer:%s post:%p",
+ NSLOG(llcache, DEBUG, "Searching cache for %s flags:%x referer:%s post:%p",
nsurl_access(url), flags,
referer==NULL?"":nsurl_access(referer), post);
@@ -1603,16 +1605,16 @@ llcache_object_retrieve_from_cache(nsurl *url,
* pull from persistent store.
*/
if (newest == NULL) {
- LLCACHE_LOG("No viable object found in llcache");
+ NSLOG(llcache, DEBUG, "No viable object found in llcache");
error = llcache_object_new(url, &obj);
if (error != NSERROR_OK)
return error;
/* attempt to retrieve object from persistent store */
- error = llcache_object_fetch_persistant(obj, flags, referer, post, redirect_count);
+ error = llcache_object_fetch_persistent(obj, flags, referer, post, redirect_count);
if (error == NSERROR_OK) {
- LLCACHE_LOG("retrieved object from persistent store");
+ NSLOG(llcache, DEBUG, "retrieved object from persistent store");
/* set newest object from persistent store which
* will cause the normal object handling to be used.
@@ -1630,14 +1632,14 @@ llcache_object_retrieve_from_cache(nsurl *url,
if ((newest != NULL) && (llcache_object_is_fresh(newest))) {
/* Found a suitable object, and it's still fresh */
- LLCACHE_LOG("Found fresh %p", newest);
+ NSLOG(llcache, DEBUG, "Found fresh %p", newest);
/* The client needs to catch up with the object's state.
* This will occur the next time that llcache_poll is called.
*/
/* ensure the source data is present */
- error = llcache_persist_retrieve(newest);
+ error = llcache_retrieve_persisted_data(newest);
if (error == NSERROR_OK) {
/* source data was successfully retrieved from
* persistent store
@@ -1651,7 +1653,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
* failed, destroy cache object and fall though to
* cache miss to re-fetch
*/
- LLCACHE_LOG("Persistent retrieval failed for %p", newest);
+ NSLOG(llcache, DEBUG, "Persistent retrieval failed for %p", newest);
llcache_object_remove_from_list(newest, &llcache->cached_objects);
llcache_object_destroy(newest);
@@ -1664,7 +1666,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
/* Found a candidate object but it needs freshness validation */
/* ensure the source data is present */
- error = llcache_persist_retrieve(newest);
+ error = llcache_retrieve_persisted_data(newest);
if (error == NSERROR_OK) {
/* Create a new object */
@@ -1672,7 +1674,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
if (error != NSERROR_OK)
return error;
- LLCACHE_LOG("Found candidate %p (%p)", obj, newest);
+ NSLOG(llcache, DEBUG, "Found candidate %p (%p)", obj, newest);
/* Clone candidate's cache data */
error = llcache_object_clone_cache_data(newest, obj, true);
@@ -1687,7 +1689,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
/* Attempt to kick-off fetch */
error = llcache_object_fetch(obj, flags, referer, post,
- redirect_count);
+ redirect_count, hsts_in_use);
if (error != NSERROR_OK) {
newest->candidate_count--;
llcache_object_destroy(obj);
@@ -1702,7 +1704,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
return NSERROR_OK;
}
- LLCACHE_LOG("Persistent retrieval failed for %p", newest);
+ NSLOG(llcache, DEBUG, "Persistent retrieval failed for %p", newest);
/* retrieval of source data from persistent store
* failed, destroy cache object and fall though to
@@ -1719,7 +1721,8 @@ llcache_object_retrieve_from_cache(nsurl *url,
}
/* Attempt to kick-off fetch */
- error = llcache_object_fetch(obj, flags, referer, post, redirect_count);
+ error = llcache_object_fetch(obj, flags, referer, post,
+ redirect_count, hsts_in_use);
if (error != NSERROR_OK) {
llcache_object_destroy(obj);
return error;
@@ -1741,6 +1744,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
* \param referer Referring URL, or NULL if none
* \param post POST data, or NULL for a GET request
* \param redirect_count Number of redirects followed so far
+ * \param hsts_in_use Whether HSTS applies to this fetch
* \param result Pointer to location to receive retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
*/
@@ -1750,6 +1754,7 @@ llcache_object_retrieve(nsurl *url,
nsurl *referer,
const llcache_post_data *post,
uint32_t redirect_count,
+ bool hsts_in_use,
llcache_object **result)
{
nserror error;
@@ -1757,7 +1762,7 @@ llcache_object_retrieve(nsurl *url,
nsurl *defragmented_url;
bool uncachable = false;
- LLCACHE_LOG("Retrieve %s (%x, %s, %p)", nsurl_access(url), flags,
+ NSLOG(llcache, DEBUG, "Retrieve %s (%x, %s, %p)", nsurl_access(url), flags,
referer==NULL?"":nsurl_access(referer), post);
@@ -1804,7 +1809,7 @@ llcache_object_retrieve(nsurl *url,
/* Attempt to kick-off fetch */
error = llcache_object_fetch(obj, flags, referer, post,
- redirect_count);
+ redirect_count, hsts_in_use);
if (error != NSERROR_OK) {
llcache_object_destroy(obj);
nsurl_unref(defragmented_url);
@@ -1815,7 +1820,8 @@ llcache_object_retrieve(nsurl *url,
llcache_object_add_to_list(obj, &llcache->uncached_objects);
} else {
error = llcache_object_retrieve_from_cache(defragmented_url,
- flags, referer, post, redirect_count, &obj);
+ flags, referer, post, redirect_count,
+ hsts_in_use, &obj);
if (error != NSERROR_OK) {
nsurl_unref(defragmented_url);
return error;
@@ -1824,7 +1830,7 @@ llcache_object_retrieve(nsurl *url,
/* Returned object is already in the cached list */
}
- LLCACHE_LOG("Retrieved %p", obj);
+ NSLOG(llcache, DEBUG, "Retrieved %p", obj);
*result = obj;
@@ -1857,7 +1863,87 @@ static nserror llcache_object_add_user(llcache_object *object,
object->users->prev = user;
object->users = user;
- LLCACHE_LOG("Adding user %p to %p", user, object);
+ NSLOG(llcache, DEBUG, "Adding user %p to %p", user, object);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Transform a request-URI based on HSTS policy
+ *
+ * \param url URL to transform
+ * \param result Pointer to location to receive transformed URL
+ * \param hsts_in_use Pointer to location to receive HSTS in-use flag
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_hsts_transform_url(nsurl *url, nsurl **result,
+ bool *hsts_in_use)
+{
+ lwc_string *scheme = NULL;
+ bool match;
+ nserror error = NSERROR_OK;
+
+ scheme = nsurl_get_component(url, NSURL_SCHEME);
+ if (lwc_string_caseless_isequal(scheme, corestring_lwc_http,
+ &match) != lwc_error_ok || match == false) {
+ /* Non-HTTP fetch: ignore */
+ lwc_string_unref(scheme);
+ *result = nsurl_ref(url);
+ *hsts_in_use = false;
+ return error;
+ }
+ lwc_string_unref(scheme);
+
+ if (urldb_get_hsts_enabled(url)) {
+ /* Only need to force HTTPS. If original port was explicitly
+ * specified as 80, nsurl_create/join will remove it (as
+ * it's redundant) */
+ error = nsurl_replace_scheme(url, corestring_lwc_https,
+ result);
+ *hsts_in_use = (error == NSERROR_OK);
+ } else {
+ *result = nsurl_ref(url);
+ *hsts_in_use = false;
+ }
+
+ return error;
+}
+
+/**
+ * Update HSTS policy for target domain.
+ *
+ * \param object Newly-fetched cache object
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_hsts_update_policy(llcache_object *object)
+{
+ size_t i;
+ lwc_string *scheme = NULL;
+ bool match = false;
+
+ scheme = nsurl_get_component(object->url, NSURL_SCHEME);
+ if (lwc_string_caseless_isequal(scheme, corestring_lwc_https,
+ &match) != lwc_error_ok || match == false) {
+ /* Non-HTTPS fetch: ignore */
+ lwc_string_unref(scheme);
+ return NSERROR_OK;
+ }
+ lwc_string_unref(scheme);
+
+ if (object->fetch.tainted_tls) {
+ /* Transport is tainted: ignore */
+ return NSERROR_OK;
+ }
+
+ for (i = 0; i < object->num_headers; i++) {
+ if (strcasecmp("Strict-Transport-Security",
+ object->headers[i].name) == 0) {
+ urldb_set_hsts_policy(object->url,
+ object->headers[i].value);
+ /* Only process the first one we find */
+ break;
+ }
+ }
return NSERROR_OK;
}
@@ -1877,10 +1963,10 @@ static nserror llcache_fetch_redirect(llcache_object *object,
llcache_object *dest;
llcache_object_user *user, *next;
const llcache_post_data *post = object->fetch.post;
- nsurl *url;
+ nsurl *url, *hsts_url;
lwc_string *scheme;
lwc_string *object_scheme;
- bool match;
+ bool match, hsts_in_use;
/* Extract HTTP response code from the fetch object */
long http_code = fetch_http_code(object->fetch.fetch);
llcache_event event;
@@ -1895,10 +1981,12 @@ static nserror llcache_fetch_redirect(llcache_object *object,
/* And mark it complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
+ (void) llcache_hsts_update_policy(object);
+
/* Forcibly stop redirecting if we've followed too many redirects */
#define REDIRECT_LIMIT 10
if (object->fetch.redirect_count > REDIRECT_LIMIT) {
- LOG("Too many nested redirects");
+ NSLOG(llcache, INFO, "Too many nested redirects");
event.type = LLCACHE_EVENT_ERROR;
event.data.msg = messages_get("BadRedirect");
@@ -1912,15 +2000,23 @@ static nserror llcache_fetch_redirect(llcache_object *object,
if (error != NSERROR_OK)
return error;
+ /* Perform HSTS transform */
+ error = llcache_hsts_transform_url(url, &hsts_url, &hsts_in_use);
+ if (error != NSERROR_OK) {
+ nsurl_unref(url);
+ return error;
+ }
+ nsurl_unref(url);
+
/* Inform users of redirect */
event.type = LLCACHE_EVENT_REDIRECT;
event.data.redirect.from = object->url;
- event.data.redirect.to = url;
+ event.data.redirect.to = hsts_url;
error = llcache_send_event_to_users(object, &event);
if (error != NSERROR_OK) {
- nsurl_unref(url);
+ nsurl_unref(hsts_url);
return error;
}
@@ -1928,7 +2024,7 @@ static nserror llcache_fetch_redirect(llcache_object *object,
* A "validated" scheme is one over which we have some guarantee that
* the source is trustworthy. */
object_scheme = nsurl_get_component(object->url, NSURL_SCHEME);
- scheme = nsurl_get_component(url, NSURL_SCHEME);
+ scheme = nsurl_get_component(hsts_url, NSURL_SCHEME);
/* resource: and about: are allowed to redirect anywhere */
if ((lwc_string_isequal(object_scheme, corestring_lwc_resource,
@@ -1944,7 +2040,7 @@ static nserror llcache_fetch_redirect(llcache_object *object,
&match) == lwc_error_ok && match == true)) {
lwc_string_unref(object_scheme);
lwc_string_unref(scheme);
- nsurl_unref(url);
+ nsurl_unref(hsts_url);
return NSERROR_OK;
}
}
@@ -1953,8 +2049,8 @@ static nserror llcache_fetch_redirect(llcache_object *object,
lwc_string_unref(object_scheme);
/* Bail out if we've no way of handling this URL */
- if (fetch_can_fetch(url) == false) {
- nsurl_unref(url);
+ if (fetch_can_fetch(hsts_url) == false) {
+ nsurl_unref(hsts_url);
return NSERROR_OK;
}
@@ -1963,17 +2059,18 @@ static nserror llcache_fetch_redirect(llcache_object *object,
post = NULL;
} else if (http_code != 307 || post != NULL) {
/** \todo 300, 305, 307 with POST */
- nsurl_unref(url);
+ nsurl_unref(hsts_url);
return NSERROR_OK;
}
/* Attempt to fetch target URL */
- error = llcache_object_retrieve(url, object->fetch.flags,
+ error = llcache_object_retrieve(hsts_url, object->fetch.flags,
object->fetch.referer, post,
- object->fetch.redirect_count + 1, &dest);
+ object->fetch.redirect_count + 1,
+ hsts_in_use, &dest);
/* No longer require url */
- nsurl_unref(url);
+ nsurl_unref(hsts_url);
if (error != NSERROR_OK)
return error;
@@ -2065,6 +2162,8 @@ static nserror llcache_fetch_notmodified(llcache_object *object,
/* Mark it complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
+ (void) llcache_hsts_update_policy(object);
+
/* Old object will be flushed from the cache on the next poll */
return NSERROR_OK;
@@ -2259,7 +2358,11 @@ static nserror llcache_fetch_cert_error(llcache_object *object,
/* Invalidate cache-control data */
llcache_invalidate_cache_control_data(object);
- if (llcache->query_cb != NULL) {
+ /* Consider the TLS transport tainted */
+ object->fetch.tainted_tls = true;
+
+ /* Only give the user a chance if HSTS isn't in use for this fetch */
+ if (object->fetch.hsts_in_use == false && llcache->query_cb != NULL) {
llcache_query query;
/* Emit query for TLS */
@@ -2309,7 +2412,13 @@ static nserror llcache_fetch_ssl_error(llcache_object *object)
/* Invalidate cache-control data */
llcache_invalidate_cache_control_data(object);
- if (object->fetch.tried_with_tls_downgrade == true) {
+ /* Consider the TLS transport tainted */
+ object->fetch.tainted_tls = true;
+
+ /* Make no attempt to downgrade if HSTS is in use
+ * (i.e. assume server does TLS properly) */
+ if (object->fetch.hsts_in_use ||
+ object->fetch.tried_with_tls_downgrade) {
/* Have already tried to downgrade, so give up */
llcache_event event;
@@ -2493,8 +2602,10 @@ static void llcache_persist_slowcheck(void *p)
total_bandwidth = (llcache->total_written * 1000) / llcache->total_elapsed;
if (total_bandwidth < llcache->minimum_bandwidth) {
- LOG("Current bandwidth %" PRIu64 " less than minimum %" PRIsizet,
- total_bandwidth, llcache->minimum_bandwidth);
+ NSLOG(llcache, INFO,
+ "Current bandwidth %"PRIu64" less than minimum %"PRIsizet,
+ total_bandwidth,
+ llcache->minimum_bandwidth);
guit->llcache->finalise();
}
}
@@ -2524,7 +2635,7 @@ static void llcache_persist(void *p)
ret = build_candidate_list(&lst, &lst_count);
if (ret != NSERROR_OK) {
- LLCACHE_LOG("Unable to construct candidate list for persistent writeout");
+ NSLOG(llcache, DEBUG, "Unable to construct candidate list for persistent writeout");
return;
}
@@ -2542,7 +2653,7 @@ static void llcache_persist(void *p)
total_elapsed += elapsed;
total_bandwidth = (total_written * 1000) / total_elapsed;
- LLCACHE_LOG("Wrote %zd bytes in %lums bw:%lu %s",
+ NSLOG(llcache, DEBUG, "Wrote %zd bytes in %lums bw:%lu %s",
written, elapsed, (written * 1000) / elapsed,
nsurl_access(lst[idx]->url) );
@@ -2550,7 +2661,7 @@ static void llcache_persist(void *p)
* (bandwidth) for this run being exceeded.
*/
if (total_elapsed > llcache->time_quantum) {
- LOG("Overran timeslot");
+ NSLOG(llcache, INFO, "Overran timeslot");
/* writeout has exhausted the available time.
* Either the writeout is slow or the last
* object was very large.
@@ -2609,10 +2720,10 @@ static void llcache_persist(void *p)
llcache->total_written += total_written;
llcache->total_elapsed += total_elapsed;
- LLCACHE_LOG("writeout size:%zd time:%lu bandwidth:%lubytes/s",
+ NSLOG(llcache, DEBUG, "writeout size:%zd time:%lu bandwidth:%lubytes/s",
total_written, total_elapsed, total_bandwidth);
- LLCACHE_LOG("Rescheduling writeout in %dms", next);
+ NSLOG(llcache, DEBUG, "Rescheduling writeout in %dms", next);
guit->misc->schedule(next, llcache_persist, NULL);
}
@@ -2629,7 +2740,7 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
llcache_object *object = p;
llcache_event event;
- LLCACHE_LOG("Fetch event %d for %p", msg->type, object);
+ NSLOG(llcache, DEBUG, "Fetch event %d for %p", msg->type, object);
switch (msg->type) {
case FETCH_HEADER:
@@ -2688,6 +2799,8 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
/* record when the fetch finished */
object->cache.fin_time = time(NULL);
+ (void) llcache_hsts_update_policy(object);
+
guit->misc->schedule(5000, llcache_persist, NULL);
}
break;
@@ -2702,9 +2815,7 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
error = llcache_object_refetch(object);
break;
}
- /* Otherwise fall through to error, setting the message to
- * a timeout
- */
+ /* Fall through */
case FETCH_ERROR:
/* An error occurred while fetching */
/* The fetch has has already been cleaned up by the fetcher */
@@ -2853,10 +2964,7 @@ static nserror llcache_object_notify_users(llcache_object *object)
nserror error;
llcache_object_user *user, *next_user;
llcache_event event;
-
-#ifdef LLCACHE_TRACE
bool emitted_notify = false;
-#endif
/**
* State transitions and event emission for users.
@@ -2917,17 +3025,20 @@ static nserror llcache_object_notify_users(llcache_object *object)
* continue is used)
*/
-#ifdef LLCACHE_TRACE
if (handle->state != objstate) {
if (emitted_notify == false) {
- LOG("Notifying users of %p", object);
+ NSLOG(llcache, DEBUG,
+ "Notifying users of %p",
+ object);
emitted_notify = true;
}
- LOG("User %p state: %d Object state: %d", user,
- handle->state, objstate);
+ NSLOG(llcache, DEBUG,
+ "User %p state: %d Object state: %d",
+ user,
+ handle->state,
+ objstate);
}
-#endif
/* User: INIT, Obj: HEADERS, DATA, COMPLETE => User->HEADERS */
if (handle->state == LLCACHE_FETCH_INIT &&
@@ -3184,7 +3295,7 @@ void llcache_clean(bool purge)
int remaining_lifetime;
uint32_t limit;
- LLCACHE_LOG("Attempting cache clean");
+ NSLOG(llcache, DEBUG, "Attempting cache clean");
/* If the cache is being purged set the size limit to zero. */
if (purge) {
@@ -3204,7 +3315,7 @@ void llcache_clean(bool purge)
(object->candidate_count == 0) &&
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false)) {
- LLCACHE_LOG("Discarding uncachable object with no users (%p) %s",
+ NSLOG(llcache, DEBUG, "Discarding uncachable object with no users (%p) %s",
object, nsurl_access(object->url));
llcache_object_remove_from_list(object,
@@ -3231,7 +3342,7 @@ void llcache_clean(bool purge)
(object->fetch.outstanding_query == false) &&
(remaining_lifetime <= 0)) {
/* object is stale */
- LLCACHE_LOG("discarding stale cacheable object with no "
+ NSLOG(llcache, DEBUG, "discarding stale cacheable object with no "
"users or pending fetches (%p) %s",
object, nsurl_access(object->url));
@@ -3277,7 +3388,7 @@ void llcache_clean(bool purge)
llcache_size -= object->source_len;
- LLCACHE_LOG("Freeing source data for %p len:%zd",
+ NSLOG(llcache, DEBUG, "Freeing source data for %p len:%zd",
object,
object->source_len);
}
@@ -3297,12 +3408,12 @@ void llcache_clean(bool purge)
(object->fetch.outstanding_query == false) &&
(object->store_state == LLCACHE_STATE_DISC) &&
(object->source_data == NULL)) {
- LLCACHE_LOG("discarding backed object len:%zd "
- "age:%d (%p) %s",
- object->source_len,
- time(NULL) - object->last_used,
- object,
- nsurl_access(object->url));
+ NSLOG(llcache, DEBUG,
+ "discarding backed object len:%zd age:%ld (%p) %s",
+ object->source_len,
+ (long)(time(NULL) - object->last_used),
+ object,
+ nsurl_access(object->url));
llcache_size -= total_object_size(object);
@@ -3328,11 +3439,12 @@ void llcache_clean(bool purge)
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false) &&
(object->store_state == LLCACHE_STATE_RAM)) {
- LLCACHE_LOG("discarding fresh object len:%zd age:%d (%p) %s",
- object->source_len,
- time(NULL) - object->last_used,
- object,
- nsurl_access(object->url));
+ NSLOG(llcache, DEBUG,
+ "discarding fresh object len:%zd age:%ld (%p) %s",
+ object->source_len,
+ (long)(time(NULL) - object->last_used),
+ object,
+ nsurl_access(object->url));
llcache_size -= object->source_len + sizeof(*object);
@@ -3342,7 +3454,7 @@ void llcache_clean(bool purge)
}
}
- LLCACHE_LOG("Size: %u (limit: %u)", llcache_size, limit);
+ NSLOG(llcache, DEBUG, "Size: %u (limit: %u)", llcache_size, limit);
}
/* Exported interface documented in content/llcache.h */
@@ -3364,7 +3476,9 @@ llcache_initialise(const struct llcache_parameters *prm)
llcache->fetch_attempts = prm->fetch_attempts;
llcache->all_caught_up = true;
- LOG("llcache initialising with a limit of %d bytes", llcache->limit);
+ NSLOG(llcache, INFO,
+ "llcache initialising with a limit of %d bytes",
+ llcache->limit);
/* backing store initialisation */
return guit->llcache->initialise(&prm->store);
@@ -3427,10 +3541,11 @@ void llcache_finalise(void)
llcache->total_elapsed;
}
- LOG("Backing store wrote %"PRIu64" bytes in %"PRIu64" ms "
- "(average %"PRIu64" bytes/second)",
- llcache->total_written, llcache->total_elapsed,
- total_bandwidth);
+ NSLOG(llcache, INFO,
+ "Backing store wrote %"PRIu64" bytes in %"PRIu64" ms ""(average %"PRIu64" bytes/second)",
+ llcache->total_written,
+ llcache->total_elapsed,
+ total_bandwidth);
free(llcache);
llcache = NULL;
@@ -3446,8 +3561,8 @@ static void llcache_catch_up_all_users(void *ignored)
llcache_object *object;
/* Assume after this we'll be all caught up. If any user of a handle
- * defers then we'll end up set not caught up and we'll
- * reschedule at that point via llcache_users_not_caught_up()
+ * defers then we'll invalidate all_caught_up and reschedule via
+ * llcache_users_not_caught_up()
*/
llcache->all_caught_up = true;
@@ -3485,23 +3600,35 @@ nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
nserror error;
llcache_object_user *user;
llcache_object *object;
+ nsurl *hsts_url;
+ bool hsts_in_use;
+
+ /* Perform HSTS transform */
+ error = llcache_hsts_transform_url(url, &hsts_url, &hsts_in_use);
+ if (error != NSERROR_OK) {
+ return error;
+ }
/* Can we fetch this URL at all? */
- if (fetch_can_fetch(url) == false) {
+ if (fetch_can_fetch(hsts_url) == false) {
+ nsurl_unref(hsts_url);
return NSERROR_NO_FETCH_HANDLER;
}
/* Create a new object user */
error = llcache_object_user_new(cb, pw, &user);
if (error != NSERROR_OK) {
+ nsurl_unref(hsts_url);
return error;
}
/* Retrieve a suitable object from the cache,
* creating a new one if needed. */
- error = llcache_object_retrieve(url, flags, referer, post, 0, &object);
+ error = llcache_object_retrieve(hsts_url, flags, referer, post, 0,
+ hsts_in_use, &object);
if (error != NSERROR_OK) {
llcache_object_user_destroy(user);
+ nsurl_unref(hsts_url);
return error;
}
@@ -3513,6 +3640,8 @@ nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
/* Users exist which are now not caught up! */
llcache_users_not_caught_up();
+ nsurl_unref(hsts_url);
+
return NSERROR_OK;
}