diff options
Diffstat (limited to 'content/llcache.c')
-rw-r--r-- | content/llcache.c | 217 |
1 files changed, 161 insertions, 56 deletions
diff --git a/content/llcache.c b/content/llcache.c index c1ddea54c..32c7449d2 100644 --- a/content/llcache.c +++ b/content/llcache.c @@ -47,6 +47,7 @@ #include "utils/utils.h" #include "utils/time.h" #include "utils/http.h" +#include "utils/nsoption.h" #include "netsurf/misc.h" #include "desktop/gui_internal.h" @@ -115,7 +116,7 @@ typedef struct { bool tried_with_auth; /**< Whether we've tried with auth */ - bool tried_with_tls_downgrade; /**< Whether we've tried TLS <= 1.0 */ + bool tried_with_tls_downgrade; /**< Whether we've tried TLS 1.2 */ bool tainted_tls; /**< Whether the TLS transport is tainted */ } llcache_fetch_ctx; @@ -807,6 +808,87 @@ static nserror llcache_fetch_process_header(llcache_object *object, } /** + * construct a Referer header appropriate for the request + * + * \param url The url being navigated to + * \param referer The referring url + * \param header_out A pointer to receive the header. The buffer must + * be freed by the caller. + * \return NSERROR_OK and \a header_out updated on success else error code + */ +static nserror get_referer_header(nsurl *url, nsurl *referer, char **header_out) +{ + nserror res = NSERROR_INVALID; + lwc_string *ref_scheme; + lwc_string *scheme; + bool match; + bool match1; + bool match2; + char *header; + + /* Determine whether to send the Referer header */ + if (!nsoption_bool(send_referer)) { + return NSERROR_INVALID; + } + + scheme = nsurl_get_component(url, NSURL_SCHEME); + if (scheme == NULL) { + return NSERROR_BAD_URL; + } + + ref_scheme = nsurl_get_component(referer, NSURL_SCHEME); + if (ref_scheme == NULL) { + /* referer has no scheme so no header */ + lwc_string_unref(scheme); + return NSERROR_INVALID; + } + + /* User permits us to send the header + * Only send it if: + * 1) The fetch and referer schemes match + * or 2) The fetch is https and the referer is http + * + * This ensures that referer information is only sent + * across schemes in the special case of an https + * request from a page served over http. The inverse + * (https -> http) should not send the referer (15.1.3) + */ + if (lwc_string_isequal(scheme, ref_scheme, + &match) != lwc_error_ok) { + match = false; + } + if (lwc_string_isequal(scheme, corestring_lwc_https, + &match1) != lwc_error_ok) { + match1 = false; + } + if (lwc_string_isequal(ref_scheme, corestring_lwc_http, + &match2) != lwc_error_ok) { + match2 = false; + } + if (match == true || (match1 == true && match2 == true)) { + const size_t len = SLEN("Referer: ") + + nsurl_length(referer) + 1; + + header = malloc(len); + if (header == NULL) { + res = NSERROR_NOMEM; + } else { + snprintf(header, len, "Referer: %s", + nsurl_access(referer)); + + *header_out = header; + res = NSERROR_OK; + } + } + + + lwc_string_unref(scheme); + lwc_string_unref(ref_scheme); + + return res; +} + +/** * (Re)fetch an object * * Sets up headers and attempts to start an actual fetch from the @@ -834,12 +916,13 @@ static nserror llcache_object_refetch(llcache_object *object) } } - /* Generate cache-control headers */ - headers = malloc(3 * sizeof(char *)); + /* Generate headers */ + headers = malloc(4 * sizeof(char *)); if (headers == NULL) { return NSERROR_NOMEM; } + /* cache-control header for etag */ if (object->cache.etag != NULL) { const size_t len = SLEN("If-None-Match: ") + strlen(object->cache.etag) + 1; @@ -856,6 +939,7 @@ static nserror llcache_object_refetch(llcache_object *object) header_idx++; } + /* cache-control header for modification time */ if (object->cache.last_modified != 0) { /* Maximum length of an RFC 1123 date is 29 bytes */ const size_t len = SLEN("If-Modified-Since: ") + 29 + 1; @@ -873,6 +957,15 @@ static nserror llcache_object_refetch(llcache_object *object) header_idx++; } + + /* Referer header */ + if (object->fetch.referer != NULL) { + if (get_referer_header(object->url, + object->fetch.referer, + &headers[header_idx]) == NSERROR_OK) { + header_idx++; + } + } headers[header_idx] = NULL; /* Reset cache control data */ @@ -1830,7 +1923,7 @@ llcache_object_retrieve_from_cache(nsurl *url, llcache_object *obj, *newest = NULL; NSLOG(llcache, DEBUG, - "Searching cache for %s flags:%x referer:%s post:%p", + "Searching cache for %s flags:%"PRIx32" referer:%s post:%p", nsurl_access(url), flags, referer==NULL?"":nsurl_access(referer), post); @@ -2007,7 +2100,7 @@ llcache_object_retrieve(nsurl *url, nsurl *defragmented_url; bool uncachable = false; - NSLOG(llcache, DEBUG, "Retrieve %s (%x, %s, %p)", nsurl_access(url), flags, + NSLOG(llcache, DEBUG, "Retrieve %s (%"PRIx32", %s, %p)", nsurl_access(url), flags, referer==NULL?"":nsurl_access(referer), post); @@ -2114,10 +2207,17 @@ static nserror llcache_hsts_transform_url(nsurl *url, nsurl **result, 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 */ + /* Non-HTTP fetch: no transform required */ + if (lwc_string_caseless_isequal(scheme, corestring_lwc_https, + &match) == lwc_error_ok && match) { + /* HTTPS: ask urldb if HSTS is enabled */ + *hsts_in_use = urldb_get_hsts_enabled(url); + } else { + /* Anything else: no HSTS */ + *hsts_in_use = false; + } lwc_string_unref(scheme); *result = nsurl_ref(url); - *hsts_in_use = false; return error; } lwc_string_unref(scheme); @@ -2873,7 +2973,7 @@ static void llcache_persist(void *p) total_bandwidth = (total_written * 1000) / total_elapsed; NSLOG(llcache, DEBUG, - "Wrote %"PRIssizet" bytes in %lums bw:%lu %s", + "Wrote %"PRIsizet" bytes in %lums bw:%lu %s", written, elapsed, (written * 1000) / elapsed, nsurl_access(lst[idx]->url) ); @@ -2941,7 +3041,7 @@ static void llcache_persist(void *p) llcache->total_elapsed += total_elapsed; NSLOG(llcache, DEBUG, - "writeout size:%"PRIssizet" time:%lu bandwidth:%lubytes/s", + "writeout size:%"PRIsizet" time:%lu bandwidth:%lubytes/s", total_written, total_elapsed, total_bandwidth); NSLOG(llcache, DEBUG, "Rescheduling writeout in %dms", next); @@ -3571,6 +3671,46 @@ total_object_size(llcache_object *object) return tot; } +/** + * Catch up the cache users with state changes from fetchers. + * + * \param ignored We ignore this because all our state comes from llcache. + */ +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 invalidate all_caught_up and reschedule via + * llcache_users_not_caught_up() + */ + llcache->all_caught_up = true; + + /* Catch new users up with state of objects */ + for (object = llcache->cached_objects; object != NULL; + object = object->next) { + llcache_object_notify_users(object); + } + + for (object = llcache->uncached_objects; object != NULL; + object = object->next) { + llcache_object_notify_users(object); + } +} + +/** + * Ask for ::llcache_catch_up_all_users to be scheduled ASAP to pump the + * user state machines. + */ +static void llcache_users_not_caught_up(void) +{ + if (llcache->all_caught_up) { + llcache->all_caught_up = false; + guit->misc->schedule(0, llcache_catch_up_all_users, NULL); + } +} + + /****************************************************************************** * Public API * ******************************************************************************/ @@ -3680,7 +3820,7 @@ void llcache_clean(bool purge) llcache_size -= object->source_len; NSLOG(llcache, DEBUG, - "Freeing source data for %p len:%"PRIssizet, + "Freeing source data for %p len:%"PRIsizet, object, object->source_len); } } @@ -3699,7 +3839,7 @@ void llcache_clean(bool purge) (object->store_state == LLCACHE_STATE_DISC) && (object->source_data == NULL)) { NSLOG(llcache, DEBUG, - "discarding backed object len:%"PRIssizet" age:%ld (%p) %s", + "discarding backed object len:%"PRIsizet" age:%ld (%p) %s", object->source_len, (long)(time(NULL) - object->last_used), object, @@ -3729,7 +3869,7 @@ void llcache_clean(bool purge) (object->fetch.fetch == NULL) && (object->store_state == LLCACHE_STATE_RAM)) { NSLOG(llcache, DEBUG, - "discarding fresh object len:%"PRIssizet" age:%ld (%p) %s", + "discarding fresh object len:%"PRIsizet" age:%ld (%p) %s", object->source_len, (long)(time(NULL) - object->last_used), object, @@ -3743,7 +3883,7 @@ void llcache_clean(bool purge) } } - NSLOG(llcache, DEBUG, "Size: %u (limit: %u)", llcache_size, limit); + NSLOG(llcache, DEBUG, "Size: %"PRIu32" (limit: %"PRIu32")", llcache_size, limit); } /* Exported interface documented in content/llcache.h */ @@ -3764,7 +3904,7 @@ llcache_initialise(const struct llcache_parameters *prm) llcache->all_caught_up = true; NSLOG(llcache, INFO, - "llcache initialising with a limit of %d bytes", + "llcache initialising with a limit of %"PRIu32" bytes", llcache->limit); /* backing store initialisation */ @@ -3843,51 +3983,16 @@ void llcache_finalise(void) llcache = NULL; } -/** - * Catch up the cache users with state changes from fetchers. - * - * \param ignored We ignore this because all our state comes from llcache. - */ -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 invalidate all_caught_up and reschedule via - * llcache_users_not_caught_up() - */ - llcache->all_caught_up = true; - - /* Catch new users up with state of objects */ - for (object = llcache->cached_objects; object != NULL; - object = object->next) { - llcache_object_notify_users(object); - } - - for (object = llcache->uncached_objects; object != NULL; - object = object->next) { - llcache_object_notify_users(object); - } -} - -/** - * Ask for ::llcache_catch_up_all_users to be scheduled ASAP to pump the - * user state machines. - */ -static void llcache_users_not_caught_up(void) -{ - if (llcache->all_caught_up) { - llcache->all_caught_up = false; - guit->misc->schedule(0, llcache_catch_up_all_users, NULL); - } -} /* Exported interface documented in content/llcache.h */ -nserror llcache_handle_retrieve(nsurl *url, uint32_t flags, - nsurl *referer, const llcache_post_data *post, - llcache_handle_callback cb, void *pw, - llcache_handle **result) +nserror +llcache_handle_retrieve(nsurl *url, + uint32_t flags, + nsurl *referer, + const llcache_post_data *post, + llcache_handle_callback cb, void *pw, + llcache_handle **result) { nserror error; llcache_object_user *user; |