Commit 4cbcb461 authored by Felix Bruns's avatar Felix Bruns Committed by Marshall Greenblatt
Browse files

Add 'UR_FLAG_DISABLE_CACHE' and support for equivalent 'Cache-Control: no-store' (issue #2283)

parent 602c1631
......@@ -1261,38 +1261,47 @@ typedef enum {
// If set the request will fail if it cannot be served from the cache (or some
// equivalent local store). Setting this value is equivalent to specifying the
// "Cache-Control: only-if-cached" request header. Setting this value in
// combination with UR_FLAG_SKIP_CACHE will cause the request to fail.
// combination with UR_FLAG_SKIP_CACHE or UR_FLAG_DISABLE_CACHE will cause the
// request to fail.
///
UR_FLAG_ONLY_FROM_CACHE = 1 << 1,
///
// If set the cache will not be used at all. Setting this value is equivalent
// to specifying the "Cache-Control: no-store" request header. Setting this
// value in combination with UR_FLAG_ONLY_FROM_CACHE will cause the request to
// fail.
///
UR_FLAG_DISABLE_CACHE = 1 << 2,
///
// If set user name, password, and cookies may be sent with the request, and
// cookies may be saved from the response.
///
UR_FLAG_ALLOW_STORED_CREDENTIALS = 1 << 2,
UR_FLAG_ALLOW_STORED_CREDENTIALS = 1 << 3,
///
// If set upload progress events will be generated when a request has a body.
///
UR_FLAG_REPORT_UPLOAD_PROGRESS = 1 << 3,
UR_FLAG_REPORT_UPLOAD_PROGRESS = 1 << 4,
///
// If set the CefURLRequestClient::OnDownloadData method will not be called.
///
UR_FLAG_NO_DOWNLOAD_DATA = 1 << 4,
UR_FLAG_NO_DOWNLOAD_DATA = 1 << 5,
///
// If set 5XX redirect errors will be propagated to the observer instead of
// automatically re-tried. This currently only applies for requests
// originated in the browser process.
///
UR_FLAG_NO_RETRY_ON_5XX = 1 << 5,
UR_FLAG_NO_RETRY_ON_5XX = 1 << 6,
///
// If set 3XX responses will cause the fetch to halt immediately rather than
// continue through the redirect.
///
UR_FLAG_STOP_ON_REDIRECT = 1 << 6,
UR_FLAG_STOP_ON_REDIRECT = 1 << 7,
} cef_urlrequest_flags_t;
///
......
......@@ -48,11 +48,13 @@ const char kReferrerLowerCase[] = "referer";
const char kContentTypeLowerCase[] = "content-type";
const char kCacheControlLowerCase[] = "cache-control";
const char kCacheControlDirectiveNoCacheLowerCase[] = "no-cache";
const char kCacheControlDirectiveNoStoreLowerCase[] = "no-store";
const char kCacheControlDirectiveOnlyIfCachedLowerCase[] = "only-if-cached";
const char kApplicationFormURLEncoded[] = "application/x-www-form-urlencoded";
// Mask of values that configure the cache policy.
const int kURCachePolicyMask = (UR_FLAG_SKIP_CACHE | UR_FLAG_ONLY_FROM_CACHE);
const int kURCachePolicyMask =
(UR_FLAG_SKIP_CACHE | UR_FLAG_ONLY_FROM_CACHE | UR_FLAG_DISABLE_CACHE);
// A subclass of net::UploadBytesElementReader that keeps the associated
// UploadElement alive until the request completes.
......@@ -142,6 +144,9 @@ int GetCacheControlHeaderPolicy(CefRequest::HeaderMap headerMap) {
} else if (base::LowerCaseEqualsASCII(
piece, kCacheControlDirectiveOnlyIfCachedLowerCase)) {
flags |= UR_FLAG_ONLY_FROM_CACHE;
} else if (base::LowerCaseEqualsASCII(
piece, kCacheControlDirectiveNoStoreLowerCase)) {
flags |= UR_FLAG_DISABLE_CACHE;
}
}
}
......@@ -151,12 +156,17 @@ int GetCacheControlHeaderPolicy(CefRequest::HeaderMap headerMap) {
// Convert cef_urlrequest_flags_t to blink::WebCachePolicy.
blink::mojom::FetchCacheMode GetFetchCacheMode(int ur_flags) {
if ((ur_flags & kURCachePolicyMask) == kURCachePolicyMask) {
const bool skip_cache{ur_flags & UR_FLAG_SKIP_CACHE};
const bool only_from_cache{ur_flags & UR_FLAG_ONLY_FROM_CACHE};
const bool disable_cache{ur_flags & UR_FLAG_DISABLE_CACHE};
if (only_from_cache && (skip_cache || disable_cache)) {
return blink::mojom::FetchCacheMode::kUnspecifiedForceCacheMiss;
} else if (ur_flags & UR_FLAG_SKIP_CACHE) {
} else if (skip_cache) {
return blink::mojom::FetchCacheMode::kBypassCache;
} else if (ur_flags & UR_FLAG_ONLY_FROM_CACHE) {
} else if (only_from_cache) {
return blink::mojom::FetchCacheMode::kOnlyIfCached;
} else if (disable_cache) {
return blink::mojom::FetchCacheMode::kNoStore;
}
return blink::mojom::FetchCacheMode::kDefault;
}
......@@ -756,6 +766,9 @@ void CefRequestImpl::Get(net::URLFetcher& fetcher,
if (flags & UR_FLAG_ONLY_FROM_CACHE) {
net_flags |= net::LOAD_ONLY_FROM_CACHE | net::LOAD_SKIP_CACHE_VALIDATION;
}
if (flags & UR_FLAG_DISABLE_CACHE) {
net_flags |= net::LOAD_DISABLE_CACHE;
}
if (!(flags & UR_FLAG_ALLOW_STORED_CREDENTIALS)) {
net_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA |
......
......@@ -72,6 +72,8 @@ enum RequestTestMode {
REQTEST_CACHE_ONLY_FAILURE_HEADER,
REQTEST_CACHE_ONLY_SUCCESS_FLAG,
REQTEST_CACHE_ONLY_SUCCESS_HEADER,
REQTEST_CACHE_DISABLE_FLAG,
REQTEST_CACHE_DISABLE_HEADER,
};
enum ContextTestMode {
......@@ -1086,6 +1088,10 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
SetupCacheOnlySuccessFlagTest, MultipleRunTest);
REGISTER_TEST(REQTEST_CACHE_ONLY_SUCCESS_HEADER,
SetupCacheOnlySuccessHeaderTest, MultipleRunTest);
REGISTER_TEST(REQTEST_CACHE_DISABLE_FLAG, SetupCacheDisableFlagTest,
MultipleRunTest);
REGISTER_TEST(REQTEST_CACHE_DISABLE_HEADER, SetupCacheDisableHeaderTest,
MultipleRunTest);
}
void Destroy() {
......@@ -1466,11 +1472,49 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
SetupCacheShared("CacheSkipFlagTest.html", true);
// Skip the cache despite the the Cache-Control response header.
// This will not read from the cache, but still write to the cache.
settings_.request->SetFlags(UR_FLAG_SKIP_CACHE);
// Send multiple requests. All should be received.
// Send multiple requests. The 1st request will be handled normally,
// but not result in any reads from the cache. The 2nd request will
// expect a cached response and the 3nd request will skip the cache
// again.
settings_.expected_send_count = 3;
settings_.expected_receive_count = 3;
settings_.expected_receive_count = 2;
settings_.setup_next_request =
base::Bind(&RequestTestRunner::SetupCacheSkipFlagTestNext, this);
complete_callback.Run();
}
void SetupCacheSkipFlagTestNext(int next_send_count,
const base::Closure& complete_callback) {
// Recreate the request object because the existing object will now be
// read-only.
EXPECT_TRUE(settings_.request->IsReadOnly());
SetupCacheShared("CacheSkipFlagTest.html", true);
// Expect a cached response.
settings_.expect_response_was_cached = true;
settings_.setup_next_request =
base::Bind(&RequestTestRunner::SetupCacheSkipFlagTestLast, this);
complete_callback.Run();
}
void SetupCacheSkipFlagTestLast(int next_send_count,
const base::Closure& complete_callback) {
// Recreate the request object because the existing object will now be
// read-only.
EXPECT_TRUE(settings_.request->IsReadOnly());
SetupCacheShared("CacheSkipFlagTest.html", true);
// Skip the cache despite the the Cache-Control response header.
settings_.request->SetFlags(UR_FLAG_SKIP_CACHE);
// Expect the cache to be skipped.
settings_.expect_response_was_cached = false;
settings_.setup_next_request.Reset();
complete_callback.Run();
}
......@@ -1479,13 +1523,51 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
SetupCacheShared("CacheSkipHeaderTest.html", true);
// Skip the cache despite the the Cache-Control response header.
// This will not read from the cache, but still write to the cache.
CefRequest::HeaderMap headerMap;
headerMap.insert(std::make_pair(kCacheControlHeader, "no-cache"));
settings_.request->SetHeaderMap(headerMap);
// Send multiple requests. All should be received.
// Send multiple requests. The 1st request will be handled normally,
// but not result in any reads from the cache. The 2nd request will
// expect a cached response and the 3nd request will skip the cache
// again.
settings_.expected_send_count = 3;
settings_.expected_receive_count = 3;
settings_.expected_receive_count = 2;
settings_.setup_next_request =
base::Bind(&RequestTestRunner::SetupCacheSkipHeaderTestNext, this);
complete_callback.Run();
}
void SetupCacheSkipHeaderTestNext(int next_send_count,
const base::Closure& complete_callback) {
// Recreate the request object because the existing object will now be
// read-only.
EXPECT_TRUE(settings_.request->IsReadOnly());
SetupCacheShared("CacheSkipHeaderTest.html", true);
// Expect a cached response.
settings_.expect_response_was_cached = true;
settings_.setup_next_request =
base::Bind(&RequestTestRunner::SetupCacheSkipHeaderTestLast, this);
complete_callback.Run();
}
void SetupCacheSkipHeaderTestLast(int next_send_count,
const base::Closure& complete_callback) {
// Recreate the request object because the existing object will now be
// read-only.
EXPECT_TRUE(settings_.request->IsReadOnly());
SetupCacheShared("CacheSkipHeaderTest.html", true);
// Skip the cache despite the the Cache-Control response header.
settings_.request->SetFlags(UR_FLAG_SKIP_CACHE);
// Expect the cache to be skipped.
settings_.expect_response_was_cached = false;
settings_.setup_next_request.Reset();
complete_callback.Run();
}
......@@ -1592,6 +1674,86 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
complete_callback.Run();
}
void SetupCacheDisableFlagTest(const base::Closure& complete_callback) {
SetupCacheShared("CacheDisableFlagTest.html", true);
// Disable the cache despite the the Cache-Control response header.
settings_.request->SetFlags(UR_FLAG_DISABLE_CACHE);
// Send multiple requests. The 1st request will be handled normally,
// but not result in any reads from or writes to the cache.
// Therefore all following requests that are set to be only handled
// from the cache should fail.
settings_.expected_send_count = 3;
settings_.expected_receive_count = 1;
settings_.setup_next_request =
base::Bind(&RequestTestRunner::SetupCacheDisableFlagTestNext, this);
complete_callback.Run();
}
void SetupCacheDisableFlagTestNext(int next_send_count,
const base::Closure& complete_callback) {
// Recreate the request object because the existing object will now be
// read-only.
EXPECT_TRUE(settings_.request->IsReadOnly());
SetupCacheShared("CacheDisableFlagTest.html", true);
// Only handle from the cache.
settings_.request->SetFlags(UR_FLAG_ONLY_FROM_CACHE);
// The request is expected to fail.
settings_.SetRequestFailureExpected(ERR_CACHE_MISS);
// The following requests will use the same setup, so no more callbacks
// are required.
settings_.setup_next_request.Reset();
complete_callback.Run();
}
void SetupCacheDisableHeaderTest(const base::Closure& complete_callback) {
SetupCacheShared("CacheDisableHeaderTest.html", true);
// Disable the cache despite the the Cache-Control response header.
CefRequest::HeaderMap headerMap;
headerMap.insert(std::make_pair(kCacheControlHeader, "no-store"));
settings_.request->SetHeaderMap(headerMap);
// Send multiple requests. The 1st request will be handled normally,
// but not result in any reads from or writes to the cache.
// Therefore all following requests that are set to be only handled
// from the cache should fail.
settings_.expected_send_count = 3;
settings_.expected_receive_count = 1;
settings_.setup_next_request =
base::Bind(&RequestTestRunner::SetupCacheDisableHeaderTestNext, this);
complete_callback.Run();
}
void SetupCacheDisableHeaderTestNext(int next_send_count,
const base::Closure& complete_callback) {
// Recreate the request object because the existing object will now be
// read-only.
EXPECT_TRUE(settings_.request->IsReadOnly());
SetupCacheShared("CacheDisableHeaderTest.html", true);
// Only handle from the cache.
CefRequest::HeaderMap headerMap;
headerMap.insert(std::make_pair(kCacheControlHeader, "only-if-cached"));
settings_.request->SetHeaderMap(headerMap);
// The request is expected to fail.
settings_.SetRequestFailureExpected(ERR_CACHE_MISS);
// The following requests will use the same setup, so no more callbacks
// are required.
settings_.setup_next_request.Reset();
complete_callback.Run();
}
// Send a request. |complete_callback| will be executed on request completion.
void SendRequest(
const RequestClient::RequestCompleteCallback& complete_callback) {
......@@ -2337,6 +2499,10 @@ REQ_TEST_SET(ContextOnDiskServer, CONTEXT_ONDISK, true);
REQTEST_CACHE_ONLY_SUCCESS_FLAG, context_mode, true, true) \
REQ_TEST(BrowserGETCacheOnlySuccessHeader##suffix, \
REQTEST_CACHE_ONLY_SUCCESS_HEADER, context_mode, true, true) \
REQ_TEST(BrowserGETCacheDisableFlag##suffix, REQTEST_CACHE_DISABLE_FLAG, \
context_mode, true, true); \
REQ_TEST(BrowserGETCacheDisableHeader##suffix, REQTEST_CACHE_DISABLE_HEADER, \
context_mode, true, true); \
REQ_TEST(RendererGETCacheWithControl##suffix, REQTEST_CACHE_WITH_CONTROL, \
context_mode, false, true); \
REQ_TEST(RendererGETCacheWithoutControl##suffix, \
......@@ -2352,7 +2518,11 @@ REQ_TEST_SET(ContextOnDiskServer, CONTEXT_ONDISK, true);
REQ_TEST(RendererGETCacheOnlySuccessFlag##suffix, \
REQTEST_CACHE_ONLY_SUCCESS_FLAG, context_mode, false, true); \
REQ_TEST(RendererGETCacheOnlySuccessHeader##suffix, \
REQTEST_CACHE_ONLY_SUCCESS_HEADER, context_mode, false, true)
REQTEST_CACHE_ONLY_SUCCESS_HEADER, context_mode, false, true) \
REQ_TEST(RendererGETCacheDisableFlag##suffix, REQTEST_CACHE_DISABLE_FLAG, \
context_mode, false, true); \
REQ_TEST(RendererGETCacheDisableHeader##suffix, \
REQTEST_CACHE_DISABLE_HEADER, context_mode, false, true);
REQ_TEST_CACHE_SET(ContextGlobalServer, CONTEXT_GLOBAL);
REQ_TEST_CACHE_SET(ContextInMemoryServer, CONTEXT_INMEMORY);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment