Commit c1df0048 authored by Takeshi Yoshino's avatar Takeshi Yoshino Committed by Commit Bot

Stop reusing MemoryCache entries for requests with a different source origin.

ResourceFetcher/ResourceLoader now saves the result of the CORS check on
the Resource object. Though the result of the CORS check varies
depending on the source origin, reusing an existing resource fetched by
a different source origin is allowed by mistake.

This patch introduces a logic to prevent MemoryCache entries from being
reused for requests with a different source (requestor) origin by saving
the source origin on the Resource object and comparing that with the new
source origin in Resource::CanReuse(), so that the result of the CORS
check is reused only when the source origin is the same.

An alternative possibly-better approach is to isolate MemoryCache for
different origins by changing the cache identifier to take into account
the source origin of requests. However, to keep the patch small and fix
the issue quickly, this patch just prevents reuse.

Bug: 799477, 809350
Change-Id: Ib96c9e728abe969a53f3d80519118a83392067b4
Reviewed-on: https://chromium-review.googlesource.com/897040
Commit-Queue: Takeshi Yoshino <tyoshino@chromium.org>
Reviewed-by: default avatarTakashi Toyoshima <toyoshim@chromium.org>
Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537580}
parent d3562176
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
</body>
<script>
async_test(t => {
const img = document.createElement('img');
img.onload = t.step_func(() => {
const iframe = document.createElement('iframe');
window.onmessage = t.step_func_done(e => {
assert_equals(e.data, 'DONE');
});
iframe.src = 'http://{{domains[www1]}}:{{ports[http][0]}}/cors/resources/image-tainting-checker.sub.html';
document.body.appendChild(iframe);
});
img.src = '/images/blue-png-cachable.py';
document.body.appendChild(img);
}, 'An image resource that is same-origin to the top-level frame loaded in ' +
'the frame is not treated as same-origin for an iframe that is ' +
'cross-origin to the top-level frame, and therefore a canvas where the ' +
'image is drawn gets tainted.');
</script>
<!DOCTYPE html>
<body>
<canvas id="canvas"></canvas>
<script>
// Used by image-tainting-in-cross-origin-iframe.sub.html to check that an
// image resource loaded by the top level frame that is same-origin to the
// frame isn't treated as a same-origin resource in a cross-origin iframe.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = 'http://{{host}}:{{ports[http][0]}}/images/blue-png-cachable.py';
img.onload = () => {
ctx.drawImage(img, 0, 0);
try {
ctx.getImageData(0, 0, 1, 1);
parent.postMessage('FAIL: getImageData() didn\'t throw', '*');
} catch (e) {
parent.postMessage('DONE', '*');
}
};
</script>
</body>
import os
import time
def main(request, response):
"""Serves the contents in blue.png but with a Cache-Control header.
Emits a Cache-Control header with max-age set to 1h to allow the browser
cache the image. Used for testing behaviors involving caching logics.
"""
image_path = os.path.join(os.path.dirname(__file__), "blue.png")
response.headers.set("Cache-Control", "max-age=3600")
response.headers.set("Content-Type", "image/png")
response.content = open(image_path, mode='rb').read()
...@@ -174,7 +174,9 @@ ImageResource* ImageResource::Fetch(FetchParameters& params, ...@@ -174,7 +174,9 @@ ImageResource* ImageResource::Fetch(FetchParameters& params,
return resource; return resource;
} }
bool ImageResource::CanReuse(const FetchParameters& params) const { bool ImageResource::CanReuse(
const FetchParameters& params,
scoped_refptr<const SecurityOrigin> new_source_origin) const {
// If the image is a placeholder, but this fetch doesn't allow a // If the image is a placeholder, but this fetch doesn't allow a
// placeholder, then do not reuse this resource. // placeholder, then do not reuse this resource.
if (params.GetPlaceholderImageRequestType() != if (params.GetPlaceholderImageRequestType() !=
...@@ -182,7 +184,7 @@ bool ImageResource::CanReuse(const FetchParameters& params) const { ...@@ -182,7 +184,7 @@ bool ImageResource::CanReuse(const FetchParameters& params) const {
placeholder_option_ != PlaceholderOption::kDoNotReloadPlaceholder) placeholder_option_ != PlaceholderOption::kDoNotReloadPlaceholder)
return false; return false;
return Resource::CanReuse(params); return Resource::CanReuse(params, std::move(new_source_origin));
} }
bool ImageResource::CanUseCacheValidator() const { bool ImageResource::CanUseCacheValidator() const {
......
...@@ -78,7 +78,9 @@ class CORE_EXPORT ImageResource final ...@@ -78,7 +78,9 @@ class CORE_EXPORT ImageResource final
void AllClientsAndObserversRemoved() override; void AllClientsAndObserversRemoved() override;
bool CanReuse(const FetchParameters&) const override; bool CanReuse(
const FetchParameters&,
scoped_refptr<const SecurityOrigin> new_source_origin) const override;
bool CanUseCacheValidator() const override; bool CanUseCacheValidator() const override;
scoped_refptr<const SharedBuffer> ResourceBuffer() const override; scoped_refptr<const SharedBuffer> ResourceBuffer() const override;
......
...@@ -64,7 +64,7 @@ class MemoryCacheCorrectnessTest : public ::testing::Test { ...@@ -64,7 +64,7 @@ class MemoryCacheCorrectnessTest : public ::testing::Test {
MockResource* resource = MockResource::Create(request); MockResource* resource = MockResource::Create(request);
resource->SetResponse(response); resource->SetResponse(response);
resource->FinishForTest(); resource->FinishForTest();
GetMemoryCache()->Add(resource); AddResourceToMemoryCache(resource);
return resource; return resource;
} }
...@@ -76,10 +76,14 @@ class MemoryCacheCorrectnessTest : public ::testing::Test { ...@@ -76,10 +76,14 @@ class MemoryCacheCorrectnessTest : public ::testing::Test {
MockResource* resource = MockResource::Create(request); MockResource* resource = MockResource::Create(request);
resource->SetResponse(ResourceResponse(KURL(kResourceURL), "text/html")); resource->SetResponse(ResourceResponse(KURL(kResourceURL), "text/html"));
resource->FinishForTest(); resource->FinishForTest();
GetMemoryCache()->Add(resource); AddResourceToMemoryCache(resource);
return resource; return resource;
} }
void AddResourceToMemoryCache(Resource* resource) {
resource->SetSourceOrigin(security_origin_);
GetMemoryCache()->Add(resource);
}
// TODO(toyoshim): Consider to use MockResource for all tests instead of // TODO(toyoshim): Consider to use MockResource for all tests instead of
// RawResource. // RawResource.
RawResource* FetchRawResource() { RawResource* FetchRawResource() {
...@@ -102,8 +106,12 @@ class MemoryCacheCorrectnessTest : public ::testing::Test { ...@@ -102,8 +106,12 @@ class MemoryCacheCorrectnessTest : public ::testing::Test {
// Save the global memory cache to restore it upon teardown. // Save the global memory cache to restore it upon teardown.
global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create()); global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create());
fetcher_ = ResourceFetcher::Create( MockFetchContext* context =
MockFetchContext::Create(MockFetchContext::kShouldNotLoadNewResource)); MockFetchContext::Create(MockFetchContext::kShouldNotLoadNewResource);
security_origin_ = SecurityOrigin::CreateUnique();
context->SetSecurityOrigin(security_origin_);
fetcher_ = ResourceFetcher::Create(context);
} }
void TearDown() override { void TearDown() override {
GetMemoryCache()->EvictResources(); GetMemoryCache()->EvictResources();
...@@ -113,6 +121,7 @@ class MemoryCacheCorrectnessTest : public ::testing::Test { ...@@ -113,6 +121,7 @@ class MemoryCacheCorrectnessTest : public ::testing::Test {
} }
Persistent<MemoryCache> global_memory_cache_; Persistent<MemoryCache> global_memory_cache_;
scoped_refptr<const SecurityOrigin> security_origin_;
Persistent<ResourceFetcher> fetcher_; Persistent<ResourceFetcher> fetcher_;
ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler> ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
platform_; platform_;
...@@ -376,7 +385,7 @@ TEST_F(MemoryCacheCorrectnessTest, FreshWithFreshRedirect) { ...@@ -376,7 +385,7 @@ TEST_F(MemoryCacheCorrectnessTest, FreshWithFreshRedirect) {
first_resource->SetResponse(fresh200_response); first_resource->SetResponse(fresh200_response);
first_resource->FinishForTest(); first_resource->FinishForTest();
GetMemoryCache()->Add(first_resource); AddResourceToMemoryCache(first_resource);
AdvanceClock(500.); AdvanceClock(500.);
...@@ -414,7 +423,7 @@ TEST_F(MemoryCacheCorrectnessTest, FreshWithStaleRedirect) { ...@@ -414,7 +423,7 @@ TEST_F(MemoryCacheCorrectnessTest, FreshWithStaleRedirect) {
first_resource->SetResponse(fresh200_response); first_resource->SetResponse(fresh200_response);
first_resource->FinishForTest(); first_resource->FinishForTest();
GetMemoryCache()->Add(first_resource); AddResourceToMemoryCache(first_resource);
AdvanceClock(500.); AdvanceClock(500.);
...@@ -427,7 +436,7 @@ TEST_F(MemoryCacheCorrectnessTest, PostToSameURLTwice) { ...@@ -427,7 +436,7 @@ TEST_F(MemoryCacheCorrectnessTest, PostToSameURLTwice) {
request1.SetHTTPMethod(HTTPNames::POST); request1.SetHTTPMethod(HTTPNames::POST);
RawResource* resource1 = RawResource::CreateForTest(request1, Resource::kRaw); RawResource* resource1 = RawResource::CreateForTest(request1, Resource::kRaw);
resource1->SetStatus(ResourceStatus::kPending); resource1->SetStatus(ResourceStatus::kPending);
GetMemoryCache()->Add(resource1); AddResourceToMemoryCache(resource1);
ResourceRequest request2{KURL(kResourceURL)}; ResourceRequest request2{KURL(kResourceURL)};
request2.SetHTTPMethod(HTTPNames::POST); request2.SetHTTPMethod(HTTPNames::POST);
...@@ -467,7 +476,7 @@ TEST_F(MemoryCacheCorrectnessTest, 302RedirectNotImplicitlyFresh) { ...@@ -467,7 +476,7 @@ TEST_F(MemoryCacheCorrectnessTest, 302RedirectNotImplicitlyFresh) {
first_resource->SetResponse(fresh200_response); first_resource->SetResponse(fresh200_response);
first_resource->FinishForTest(); first_resource->FinishForTest();
GetMemoryCache()->Add(first_resource); AddResourceToMemoryCache(first_resource);
AdvanceClock(500.); AdvanceClock(500.);
...@@ -505,7 +514,7 @@ TEST_F(MemoryCacheCorrectnessTest, 302RedirectExplicitlyFreshMaxAge) { ...@@ -505,7 +514,7 @@ TEST_F(MemoryCacheCorrectnessTest, 302RedirectExplicitlyFreshMaxAge) {
first_resource->SetResponse(fresh200_response); first_resource->SetResponse(fresh200_response);
first_resource->FinishForTest(); first_resource->FinishForTest();
GetMemoryCache()->Add(first_resource); AddResourceToMemoryCache(first_resource);
AdvanceClock(500.); AdvanceClock(500.);
...@@ -544,7 +553,7 @@ TEST_F(MemoryCacheCorrectnessTest, 302RedirectExplicitlyFreshExpires) { ...@@ -544,7 +553,7 @@ TEST_F(MemoryCacheCorrectnessTest, 302RedirectExplicitlyFreshExpires) {
first_resource->SetResponse(fresh200_response); first_resource->SetResponse(fresh200_response);
first_resource->FinishForTest(); first_resource->FinishForTest();
GetMemoryCache()->Add(first_resource); AddResourceToMemoryCache(first_resource);
AdvanceClock(500.); AdvanceClock(500.);
......
...@@ -323,7 +323,9 @@ static bool IsCacheableHTTPMethod(const AtomicString& method) { ...@@ -323,7 +323,9 @@ static bool IsCacheableHTTPMethod(const AtomicString& method) {
method != "DELETE"; method != "DELETE";
} }
bool RawResource::CanReuse(const FetchParameters& new_fetch_parameters) const { bool RawResource::CanReuse(
const FetchParameters& new_fetch_parameters,
scoped_refptr<const SecurityOrigin> new_source_origin) const {
const ResourceRequest& new_request = const ResourceRequest& new_request =
new_fetch_parameters.GetResourceRequest(); new_fetch_parameters.GetResourceRequest();
...@@ -364,7 +366,7 @@ bool RawResource::CanReuse(const FetchParameters& new_fetch_parameters) const { ...@@ -364,7 +366,7 @@ bool RawResource::CanReuse(const FetchParameters& new_fetch_parameters) const {
return false; return false;
} }
return Resource::CanReuse(new_fetch_parameters); return Resource::CanReuse(new_fetch_parameters, std::move(new_source_origin));
} }
RawResourceClientStateChecker::RawResourceClientStateChecker() RawResourceClientStateChecker::RawResourceClientStateChecker()
......
...@@ -76,7 +76,9 @@ class PLATFORM_EXPORT RawResource final : public Resource { ...@@ -76,7 +76,9 @@ class PLATFORM_EXPORT RawResource final : public Resource {
} }
// Resource implementation // Resource implementation
bool CanReuse(const FetchParameters&) const override; bool CanReuse(
const FetchParameters&,
scoped_refptr<const SecurityOrigin> new_source_origin) const override;
bool WillFollowRedirect(const ResourceRequest&, bool WillFollowRedirect(const ResourceRequest&,
const ResourceResponse&) override; const ResourceResponse&) override;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "platform/loader/fetch/RawResource.h" #include "platform/loader/fetch/RawResource.h"
#include <memory>
#include "platform/SharedBuffer.h" #include "platform/SharedBuffer.h"
#include "platform/heap/Handle.h" #include "platform/heap/Handle.h"
#include "platform/loader/fetch/MemoryCache.h" #include "platform/loader/fetch/MemoryCache.h"
...@@ -38,6 +39,7 @@ ...@@ -38,6 +39,7 @@
#include "platform/scheduler/child/web_scheduler.h" #include "platform/scheduler/child/web_scheduler.h"
#include "platform/testing/TestingPlatformSupportWithMockScheduler.h" #include "platform/testing/TestingPlatformSupportWithMockScheduler.h"
#include "platform/testing/UnitTestHelpers.h" #include "platform/testing/UnitTestHelpers.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
#include "public/platform/WebThread.h" #include "public/platform/WebThread.h"
#include "public/platform/WebURL.h" #include "public/platform/WebURL.h"
...@@ -63,13 +65,18 @@ TEST_F(RawResourceTest, DontIgnoreAcceptForCacheReuse) { ...@@ -63,13 +65,18 @@ TEST_F(RawResourceTest, DontIgnoreAcceptForCacheReuse) {
ResourceRequest jpeg_request; ResourceRequest jpeg_request;
jpeg_request.SetHTTPAccept("image/jpeg"); jpeg_request.SetHTTPAccept("image/jpeg");
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUnique();
RawResource* jpeg_resource( RawResource* jpeg_resource(
RawResource::CreateForTest(jpeg_request, Resource::kRaw)); RawResource::CreateForTest(jpeg_request, Resource::kRaw));
jpeg_resource->SetSourceOrigin(source_origin);
ResourceRequest png_request; ResourceRequest png_request;
png_request.SetHTTPAccept("image/png"); png_request.SetHTTPAccept("image/png");
EXPECT_FALSE(jpeg_resource->CanReuse(FetchParameters(png_request))); EXPECT_FALSE(
jpeg_resource->CanReuse(FetchParameters(png_request), source_origin));
} }
class DummyClient final : public GarbageCollectedFinalized<DummyClient>, class DummyClient final : public GarbageCollectedFinalized<DummyClient>,
...@@ -209,12 +216,15 @@ TEST_F(RawResourceTest, RemoveClientDuringCallback) { ...@@ -209,12 +216,15 @@ TEST_F(RawResourceTest, RemoveClientDuringCallback) {
TEST_F(RawResourceTest, TEST_F(RawResourceTest,
CanReuseDevToolsEmulateNetworkConditionsClientIdHeader) { CanReuseDevToolsEmulateNetworkConditionsClientIdHeader) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUnique();
ResourceRequest request("data:text/html,"); ResourceRequest request("data:text/html,");
request.SetHTTPHeaderField( request.SetHTTPHeaderField(
HTTPNames::X_DevTools_Emulate_Network_Conditions_Client_Id, "Foo"); HTTPNames::X_DevTools_Emulate_Network_Conditions_Client_Id, "Foo");
Resource* raw = RawResource::CreateForTest(request, Resource::kRaw); Resource* raw = RawResource::CreateForTest(request, Resource::kRaw);
EXPECT_TRUE( raw->SetSourceOrigin(source_origin);
raw->CanReuse(FetchParameters(ResourceRequest("data:text/html,")))); EXPECT_TRUE(raw->CanReuse(FetchParameters(ResourceRequest("data:text/html,")),
source_origin));
} }
} // namespace blink } // namespace blink
...@@ -861,7 +861,9 @@ void Resource::FinishPendingClients() { ...@@ -861,7 +861,9 @@ void Resource::FinishPendingClients() {
DCHECK(clients_awaiting_callback_.IsEmpty() || scheduled); DCHECK(clients_awaiting_callback_.IsEmpty() || scheduled);
} }
bool Resource::CanReuse(const FetchParameters& params) const { bool Resource::CanReuse(
const FetchParameters& params,
scoped_refptr<const SecurityOrigin> new_source_origin) const {
const ResourceRequest& new_request = params.GetResourceRequest(); const ResourceRequest& new_request = params.GetResourceRequest();
const ResourceLoaderOptions& new_options = params.Options(); const ResourceLoaderOptions& new_options = params.Options();
...@@ -930,6 +932,13 @@ bool Resource::CanReuse(const FetchParameters& params) const { ...@@ -930,6 +932,13 @@ bool Resource::CanReuse(const FetchParameters& params) const {
return false; return false;
} }
DCHECK(source_origin_);
DCHECK(new_source_origin);
// Don't reuse an existing resource when the source origin is different.
if (!source_origin_->IsSameSchemeHostPort(new_source_origin.get()))
return false;
// securityOrigin has more complicated checks which callers are responsible // securityOrigin has more complicated checks which callers are responsible
// for. // for.
......
...@@ -292,6 +292,10 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>, ...@@ -292,6 +292,10 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>,
} }
String CacheIdentifier() const { return cache_identifier_; } String CacheIdentifier() const { return cache_identifier_; }
void SetSourceOrigin(scoped_refptr<const SecurityOrigin> source_origin) {
source_origin_ = source_origin;
}
virtual void DidSendData(unsigned long long /* bytesSent */, virtual void DidSendData(unsigned long long /* bytesSent */,
unsigned long long /* totalBytesToBeSent */) {} unsigned long long /* totalBytesToBeSent */) {}
virtual void DidDownloadData(int) {} virtual void DidDownloadData(int) {}
...@@ -308,7 +312,9 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>, ...@@ -308,7 +312,9 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>,
response_.SetDecodedBodyLength(value); response_.SetDecodedBodyLength(value);
} }
virtual bool CanReuse(const FetchParameters&) const; virtual bool CanReuse(
const FetchParameters&,
scoped_refptr<const SecurityOrigin> new_source_origin) const;
// If cache-aware loading is activated, this callback is called when the first // If cache-aware loading is activated, this callback is called when the first
// disk-cache-only request failed due to cache miss. After this callback, // disk-cache-only request failed due to cache miss. After this callback,
...@@ -448,9 +454,34 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>, ...@@ -448,9 +454,34 @@ class PLATFORM_EXPORT Resource : public GarbageCollectedFinalized<Resource>,
Type type_; Type type_;
ResourceStatus status_; ResourceStatus status_;
// A SecurityOrigin representing the origin from which the loading of the
// Resource was initiated. This is calculated and set by ResourceFetcher at
// the beginning of the loading.
//
// Unlike |security_origin| on |options_|, which:
// - holds a SecurityOrigin to override the FetchContext's SecurityOrigin
// (in case of e.g. that the script initiated the loading is in an isolated
// world)
// - may be modified during redirect as required by the CORS protocol
// this variable is stable after the loading has started.
//
// Used and should be used only for isolating resources for different origins
// in the MemoryCache.
//
// TODO(crbug.com/811669): Merge with some of the other SecurityOrigin
// variables.
scoped_refptr<const SecurityOrigin> source_origin_;
CORSStatus cors_status_; CORSStatus cors_status_;
Member<CachedMetadataHandlerImpl> cache_handler_; Member<CachedMetadataHandlerImpl> cache_handler_;
// Holds the SecurityOrigin obtained from the associated FetchContext.
// ResourceFetcher sets this at the beginning of loading. The override by
// specifying a SecurityOrigin in ResourceLoaderOptions doesn't affect this.
//
// TODO(crbug.com/811669): Merge this with |source_origin_|.
scoped_refptr<const SecurityOrigin> fetcher_security_origin_; scoped_refptr<const SecurityOrigin> fetcher_security_origin_;
Optional<ResourceError> error_; Optional<ResourceError> error_;
......
...@@ -468,10 +468,8 @@ Resource* ResourceFetcher::ResourceForStaticData( ...@@ -468,10 +468,8 @@ Resource* ResourceFetcher::ResourceForStaticData(
resource->SetCacheIdentifier(cache_identifier); resource->SetCacheIdentifier(cache_identifier);
resource->Finish(0.0, Context().GetLoadingTaskRunner().get()); resource->Finish(0.0, Context().GetLoadingTaskRunner().get());
if (ShouldResourceBeAddedToMemoryCache(params, resource) && if (!substitute_data.IsValid())
!substitute_data.IsValid()) { AddToMemoryCacheIfNeeded(params, resource);
GetMemoryCache()->Add(resource);
}
return resource; return resource;
} }
...@@ -864,8 +862,26 @@ void ResourceFetcher::InitializeRevalidation( ...@@ -864,8 +862,26 @@ void ResourceFetcher::InitializeRevalidation(
resource->SetRevalidatingRequest(revalidating_request); resource->SetRevalidatingRequest(revalidating_request);
} }
scoped_refptr<const SecurityOrigin> ResourceFetcher::GetSourceOrigin(
const ResourceLoaderOptions& options) const {
if (options.security_origin)
return options.security_origin;
return Context().GetSecurityOrigin();
}
void ResourceFetcher::AddToMemoryCacheIfNeeded(const FetchParameters& params,
Resource* resource) {
if (!ShouldResourceBeAddedToMemoryCache(params, resource))
return;
resource->SetSourceOrigin(GetSourceOrigin(params.Options()));
GetMemoryCache()->Add(resource);
}
Resource* ResourceFetcher::CreateResourceForLoading( Resource* ResourceFetcher::CreateResourceForLoading(
FetchParameters& params, const FetchParameters& params,
const ResourceFactory& factory) { const ResourceFactory& factory) {
const String cache_identifier = GetCacheIdentifier(); const String cache_identifier = GetCacheIdentifier();
DCHECK(!IsMainThread() || DCHECK(!IsMainThread() ||
...@@ -883,8 +899,7 @@ Resource* ResourceFetcher::CreateResourceForLoading( ...@@ -883,8 +899,7 @@ Resource* ResourceFetcher::CreateResourceForLoading(
} }
resource->SetCacheIdentifier(cache_identifier); resource->SetCacheIdentifier(cache_identifier);
if (ShouldResourceBeAddedToMemoryCache(params, resource)) AddToMemoryCacheIfNeeded(params, resource);
GetMemoryCache()->Add(resource);
return resource; return resource;
} }
...@@ -970,7 +985,7 @@ Resource* ResourceFetcher::MatchPreload(const FetchParameters& params, ...@@ -970,7 +985,7 @@ Resource* ResourceFetcher::MatchPreload(const FetchParameters& params,
return nullptr; return nullptr;
if (IsImageResourceDisallowedToBeReused(*resource) || if (IsImageResourceDisallowedToBeReused(*resource) ||
!resource->CanReuse(params)) !resource->CanReuse(params, GetSourceOrigin(params.Options())))
return nullptr; return nullptr;
if (!resource->MatchPreload(params, Context().GetLoadingTaskRunner().get())) if (!resource->MatchPreload(params, Context().GetLoadingTaskRunner().get()))
...@@ -993,12 +1008,15 @@ void ResourceFetcher::InsertAsPreloadIfNecessary(Resource* resource, ...@@ -993,12 +1008,15 @@ void ResourceFetcher::InsertAsPreloadIfNecessary(Resource* resource,
return; return;
} }
PreloadKey key(params.Url(), type); PreloadKey key(params.Url(), type);
if (preloads_.find(key) == preloads_.end()) { if (preloads_.find(key) != preloads_.end())
preloads_.insert(key, resource); return;
resource->MarkAsPreload();
if (preloaded_urls_for_test_) resource->SetSourceOrigin(GetSourceOrigin(params.Options()));
preloaded_urls_for_test_->insert(resource->Url().GetString());
} preloads_.insert(key, resource);
resource->MarkAsPreload();
if (preloaded_urls_for_test_)
preloaded_urls_for_test_->insert(resource->Url().GetString());
} }
bool ResourceFetcher::IsImageResourceDisallowedToBeReused( bool ResourceFetcher::IsImageResourceDisallowedToBeReused(
...@@ -1101,7 +1119,8 @@ ResourceFetcher::DetermineRevalidationPolicyInternal( ...@@ -1101,7 +1119,8 @@ ResourceFetcher::DetermineRevalidationPolicyInternal(
if (is_static_data) if (is_static_data)
return kUse; return kUse;
if (!existing_resource.CanReuse(fetch_params)) { if (!existing_resource.CanReuse(fetch_params,
GetSourceOrigin(fetch_params.Options()))) {
RESOURCE_LOADING_DVLOG(1) << "ResourceFetcher::DetermineRevalidationPolicy " RESOURCE_LOADING_DVLOG(1) << "ResourceFetcher::DetermineRevalidationPolicy "
"reloading due to Resource::CanReuse() " "reloading due to Resource::CanReuse() "
"returning false."; "returning false.";
......
...@@ -181,7 +181,12 @@ class PLATFORM_EXPORT ResourceFetcher ...@@ -181,7 +181,12 @@ class PLATFORM_EXPORT ResourceFetcher
ResourceFetcher(FetchContext*); ResourceFetcher(FetchContext*);
void InitializeRevalidation(ResourceRequest&, Resource*); void InitializeRevalidation(ResourceRequest&, Resource*);
Resource* CreateResourceForLoading(FetchParameters&, // When |security_origin| of the ResourceLoaderOptions is not a nullptr, it'll
// be used instead of the associated FetchContext's SecurityOrigin.
scoped_refptr<const SecurityOrigin> GetSourceOrigin(
const ResourceLoaderOptions&) const;
void AddToMemoryCacheIfNeeded(const FetchParameters&, Resource*);
Resource* CreateResourceForLoading(const FetchParameters&,
const ResourceFactory&); const ResourceFactory&);
void StorePerformanceTimingInitiatorInformation(Resource*); void StorePerformanceTimingInitiatorInformation(Resource*);
ResourceLoadPriority ComputeLoadPriority( ResourceLoadPriority ComputeLoadPriority(
......
...@@ -95,6 +95,12 @@ class ResourceFetcherTest : public ::testing::Test { ...@@ -95,6 +95,12 @@ class ResourceFetcherTest : public ::testing::Test {
protected: protected:
MockFetchContext* Context() { return platform_->Context(); } MockFetchContext* Context() { return platform_->Context(); }
void AddResourceToMemoryCache(
Resource* resource,
scoped_refptr<const SecurityOrigin> source_origin) {
resource->SetSourceOrigin(source_origin);
GetMemoryCache()->Add(resource);
}
ScopedTestingPlatformSupport<FetchTestingPlatformSupport> platform_; ScopedTestingPlatformSupport<FetchTestingPlatformSupport> platform_;
...@@ -144,9 +150,14 @@ TEST_F(ResourceFetcherTest, UseExistingResource) { ...@@ -144,9 +150,14 @@ TEST_F(ResourceFetcherTest, UseExistingResource) {
} }
TEST_F(ResourceFetcherTest, Vary) { TEST_F(ResourceFetcherTest, Vary) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUnique();
Context()->SetSecurityOrigin(source_origin);
KURL url("http://127.0.0.1:8000/foo.html"); KURL url("http://127.0.0.1:8000/foo.html");
Resource* resource = RawResource::CreateForTest(url, Resource::kRaw); Resource* resource = RawResource::CreateForTest(url, Resource::kRaw);
GetMemoryCache()->Add(resource); AddResourceToMemoryCache(resource, source_origin);
ResourceResponse response(url); ResourceResponse response(url);
response.SetHTTPStatusCode(200); response.SetHTTPStatusCode(200);
response.SetHTTPHeaderField(HTTPNames::Cache_Control, "max-age=3600"); response.SetHTTPHeaderField(HTTPNames::Cache_Control, "max-age=3600");
...@@ -202,11 +213,16 @@ TEST_F(ResourceFetcherTest, NavigationTimingInfo) { ...@@ -202,11 +213,16 @@ TEST_F(ResourceFetcherTest, NavigationTimingInfo) {
} }
TEST_F(ResourceFetcherTest, VaryOnBack) { TEST_F(ResourceFetcherTest, VaryOnBack) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUnique();
Context()->SetSecurityOrigin(source_origin);
ResourceFetcher* fetcher = ResourceFetcher::Create(Context()); ResourceFetcher* fetcher = ResourceFetcher::Create(Context());
KURL url("http://127.0.0.1:8000/foo.html"); KURL url("http://127.0.0.1:8000/foo.html");
Resource* resource = RawResource::CreateForTest(url, Resource::kRaw); Resource* resource = RawResource::CreateForTest(url, Resource::kRaw);
GetMemoryCache()->Add(resource); AddResourceToMemoryCache(resource, source_origin);
ResourceResponse response(url); ResourceResponse response(url);
response.SetHTTPStatusCode(200); response.SetHTTPStatusCode(200);
response.SetHTTPHeaderField(HTTPNames::Cache_Control, "max-age=3600"); response.SetHTTPHeaderField(HTTPNames::Cache_Control, "max-age=3600");
...@@ -253,7 +269,8 @@ class RequestSameResourceOnComplete ...@@ -253,7 +269,8 @@ class RequestSameResourceOnComplete
public: public:
explicit RequestSameResourceOnComplete(FetchParameters& params, explicit RequestSameResourceOnComplete(FetchParameters& params,
ResourceFetcher* fetcher) ResourceFetcher* fetcher)
: notify_finished_called_(false) { : notify_finished_called_(false),
source_origin_(fetcher->Context().GetSecurityOrigin()) {
MockResource::Fetch(params, fetcher, this); MockResource::Fetch(params, fetcher, this);
} }
...@@ -261,6 +278,7 @@ class RequestSameResourceOnComplete ...@@ -261,6 +278,7 @@ class RequestSameResourceOnComplete
EXPECT_EQ(GetResource(), resource); EXPECT_EQ(GetResource(), resource);
MockFetchContext* context = MockFetchContext* context =
MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource); MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
context->SetSecurityOrigin(source_origin_);
ResourceFetcher* fetcher2 = ResourceFetcher::Create(context); ResourceFetcher* fetcher2 = ResourceFetcher::Create(context);
ResourceRequest resource_request2(GetResource()->Url()); ResourceRequest resource_request2(GetResource()->Url());
resource_request2.SetCacheMode(mojom::FetchCacheMode::kValidateCache); resource_request2.SetCacheMode(mojom::FetchCacheMode::kValidateCache);
...@@ -280,15 +298,22 @@ class RequestSameResourceOnComplete ...@@ -280,15 +298,22 @@ class RequestSameResourceOnComplete
private: private:
bool notify_finished_called_; bool notify_finished_called_;
scoped_refptr<const SecurityOrigin> source_origin_;
}; };
TEST_F(ResourceFetcherTest, RevalidateWhileFinishingLoading) { TEST_F(ResourceFetcherTest, RevalidateWhileFinishingLoading) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUnique();
Context()->SetSecurityOrigin(source_origin);
KURL url("http://127.0.0.1:8000/foo.png"); KURL url("http://127.0.0.1:8000/foo.png");
ResourceResponse response(url); ResourceResponse response(url);
response.SetHTTPStatusCode(200); response.SetHTTPStatusCode(200);
response.SetHTTPHeaderField(HTTPNames::Cache_Control, "max-age=3600"); response.SetHTTPHeaderField(HTTPNames::Cache_Control, "max-age=3600");
response.SetHTTPHeaderField(HTTPNames::ETag, "1234567890"); response.SetHTTPHeaderField(HTTPNames::ETag, "1234567890");
RegisterMockedURLLoadWithCustomResponse(url, response); RegisterMockedURLLoadWithCustomResponse(url, response);
ResourceFetcher* fetcher1 = ResourceFetcher::Create(Context()); ResourceFetcher* fetcher1 = ResourceFetcher::Create(Context());
ResourceRequest request1(url); ResourceRequest request1(url);
request1.SetHTTPHeaderField(HTTPNames::Cache_Control, "no-cache"); request1.SetHTTPHeaderField(HTTPNames::Cache_Control, "no-cache");
...@@ -693,9 +718,14 @@ TEST_F(ResourceFetcherTest, SpeculativePreloadShouldBePromotedToLinkePreload) { ...@@ -693,9 +718,14 @@ TEST_F(ResourceFetcherTest, SpeculativePreloadShouldBePromotedToLinkePreload) {
} }
TEST_F(ResourceFetcherTest, Revalidate304) { TEST_F(ResourceFetcherTest, Revalidate304) {
scoped_refptr<const SecurityOrigin> source_origin =
SecurityOrigin::CreateUnique();
Context()->SetSecurityOrigin(source_origin);
KURL url("http://127.0.0.1:8000/foo.html"); KURL url("http://127.0.0.1:8000/foo.html");
Resource* resource = RawResource::CreateForTest(url, Resource::kRaw); Resource* resource = RawResource::CreateForTest(url, Resource::kRaw);
GetMemoryCache()->Add(resource); AddResourceToMemoryCache(resource, source_origin);
ResourceResponse response(url); ResourceResponse response(url);
response.SetHTTPStatusCode(304); response.SetHTTPStatusCode(304);
response.SetHTTPHeaderField("etag", "1234567890"); response.SetHTTPHeaderField("etag", "1234567890");
......
...@@ -371,7 +371,14 @@ class PLATFORM_EXPORT ResourceRequest final { ...@@ -371,7 +371,14 @@ class PLATFORM_EXPORT ResourceRequest final {
double timeout_interval_; // 0 is a magic value for platform default on double timeout_interval_; // 0 is a magic value for platform default on
// platforms that have one. // platforms that have one.
KURL site_for_cookies_; KURL site_for_cookies_;
// The SecurityOrigin specified by the ResourceLoaderOptions in case e.g.
// when the fetching was initiated in an isolated world. Set by
// ResourceFetcher but only when needed.
//
// TODO(crbug.com/811669): Merge with some of the other origin variables.
scoped_refptr<const SecurityOrigin> requestor_origin_; scoped_refptr<const SecurityOrigin> requestor_origin_;
AtomicString http_method_; AtomicString http_method_;
HTTPHeaderMap http_header_fields_; HTTPHeaderMap http_header_fields_;
scoped_refptr<EncodedFormData> http_body_; scoped_refptr<EncodedFormData> http_body_;
......
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