| /* |
| * Copyright (c) 2015, Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "core/loader/FrameFetchContext.h" |
| |
| #include <memory> |
| #include "core/dom/Document.h" |
| #include "core/frame/FrameOwner.h" |
| #include "core/frame/FrameTypes.h" |
| #include "core/frame/LocalFrameView.h" |
| #include "core/frame/Settings.h" |
| #include "core/html/HTMLIFrameElement.h" |
| #include "core/loader/DocumentLoader.h" |
| #include "core/loader/EmptyClients.h" |
| #include "core/loader/SubresourceFilter.h" |
| #include "core/page/Page.h" |
| #include "core/testing/DummyPageHolder.h" |
| #include "platform/loader/fetch/FetchInitiatorInfo.h" |
| #include "platform/loader/fetch/FetchInitiatorTypeNames.h" |
| #include "platform/loader/fetch/ResourceLoaderOptions.h" |
| #include "platform/loader/fetch/ResourceRequest.h" |
| #include "platform/loader/fetch/ResourceTimingInfo.h" |
| #include "platform/loader/fetch/UniqueIdentifier.h" |
| #include "platform/loader/testing/MockResource.h" |
| #include "platform/weborigin/KURL.h" |
| #include "platform/weborigin/SecurityViolationReportingPolicy.h" |
| #include "public/platform/WebAddressSpace.h" |
| #include "public/platform/WebCachePolicy.h" |
| #include "public/platform/WebDocumentSubresourceFilter.h" |
| #include "public/platform/WebInsecureRequestPolicy.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace blink { |
| |
| using Checkpoint = ::testing::StrictMock<testing::MockFunction<void(int)>>; |
| |
| class StubLocalFrameClientWithParent final : public EmptyLocalFrameClient { |
| public: |
| static StubLocalFrameClientWithParent* Create(Frame* parent) { |
| return new StubLocalFrameClientWithParent(parent); |
| } |
| |
| DEFINE_INLINE_VIRTUAL_TRACE() { |
| visitor->Trace(parent_); |
| EmptyLocalFrameClient::Trace(visitor); |
| } |
| |
| Frame* Parent() const override { return parent_.Get(); } |
| |
| private: |
| explicit StubLocalFrameClientWithParent(Frame* parent) : parent_(parent) {} |
| |
| Member<Frame> parent_; |
| }; |
| |
| class MockLocalFrameClient : public EmptyLocalFrameClient { |
| public: |
| MockLocalFrameClient() : EmptyLocalFrameClient() {} |
| MOCK_METHOD1(DidDisplayContentWithCertificateErrors, void(const KURL&)); |
| MOCK_METHOD2(DispatchDidLoadResourceFromMemoryCache, |
| void(const ResourceRequest&, const ResourceResponse&)); |
| MOCK_METHOD0(UserAgent, String()); |
| MOCK_METHOD0(MayUseClientLoFiForImageRequests, bool()); |
| MOCK_METHOD0(IsClientLoFiActiveForFrame, bool()); |
| }; |
| |
| class FixedPolicySubresourceFilter : public WebDocumentSubresourceFilter { |
| public: |
| FixedPolicySubresourceFilter(LoadPolicy policy, int* filtered_load_counter) |
| : policy_(policy), filtered_load_counter_(filtered_load_counter) {} |
| |
| LoadPolicy GetLoadPolicy(const WebURL& resource_url, |
| WebURLRequest::RequestContext) override { |
| return policy_; |
| } |
| |
| LoadPolicy GetLoadPolicyForWebSocketConnect(const WebURL& url) override { |
| return policy_; |
| } |
| |
| void ReportDisallowedLoad() override { ++*filtered_load_counter_; } |
| |
| bool ShouldLogToConsole() override { return false; } |
| |
| private: |
| const LoadPolicy policy_; |
| int* filtered_load_counter_; |
| }; |
| |
| class FrameFetchContextTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| dummy_page_holder = DummyPageHolder::Create(IntSize(500, 500)); |
| dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(1.0); |
| document = &dummy_page_holder->GetDocument(); |
| fetch_context = |
| static_cast<FrameFetchContext*>(&document->Fetcher()->Context()); |
| owner = DummyFrameOwner::Create(); |
| FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get()); |
| } |
| |
| void TearDown() override { |
| if (child_frame) |
| child_frame->Detach(FrameDetachType::kRemove); |
| } |
| |
| FrameFetchContext* CreateChildFrame() { |
| child_client = StubLocalFrameClientWithParent::Create(document->GetFrame()); |
| child_frame = LocalFrame::Create( |
| child_client.Get(), *document->GetFrame()->GetPage(), owner.Get()); |
| child_frame->SetView( |
| LocalFrameView::Create(*child_frame, IntSize(500, 500))); |
| child_frame->Init(); |
| child_document = child_frame->GetDocument(); |
| FrameFetchContext* child_fetch_context = static_cast<FrameFetchContext*>( |
| &child_frame->Loader().GetDocumentLoader()->Fetcher()->Context()); |
| FrameFetchContext::ProvideDocumentToContext(*child_fetch_context, |
| child_document.Get()); |
| return child_fetch_context; |
| } |
| |
| std::unique_ptr<DummyPageHolder> dummy_page_holder; |
| // We don't use the DocumentLoader directly in any tests, but need to keep it |
| // around as long as the ResourceFetcher and Document live due to indirect |
| // usage. |
| Persistent<Document> document; |
| Persistent<FrameFetchContext> fetch_context; |
| |
| Persistent<StubLocalFrameClientWithParent> child_client; |
| Persistent<LocalFrame> child_frame; |
| Persistent<Document> child_document; |
| Persistent<DummyFrameOwner> owner; |
| }; |
| |
| class FrameFetchContextSubresourceFilterTest : public FrameFetchContextTest { |
| protected: |
| void SetUp() override { |
| FrameFetchContextTest::SetUp(); |
| filtered_load_callback_counter_ = 0; |
| } |
| |
| void TearDown() override { |
| document->Loader()->SetSubresourceFilter(nullptr); |
| FrameFetchContextTest::TearDown(); |
| } |
| |
| int GetFilteredLoadCallCount() const { |
| return filtered_load_callback_counter_; |
| } |
| |
| void SetFilterPolicy(WebDocumentSubresourceFilter::LoadPolicy policy) { |
| document->Loader()->SetSubresourceFilter(SubresourceFilter::Create( |
| *document, WTF::MakeUnique<FixedPolicySubresourceFilter>( |
| policy, &filtered_load_callback_counter_))); |
| } |
| |
| ResourceRequestBlockedReason CanRequest() { |
| return CanRequestInternal(SecurityViolationReportingPolicy::kReport); |
| } |
| |
| ResourceRequestBlockedReason CanRequestPreload() { |
| return CanRequestInternal( |
| SecurityViolationReportingPolicy::kSuppressReporting); |
| } |
| |
| private: |
| ResourceRequestBlockedReason CanRequestInternal( |
| SecurityViolationReportingPolicy reporting_policy) { |
| KURL input_url(kParsedURLString, "http://example.com/"); |
| ResourceRequest resource_request(input_url); |
| resource_request.SetFetchCredentialsMode( |
| WebURLRequest::kFetchCredentialsModeOmit); |
| ResourceLoaderOptions options; |
| return fetch_context->CanRequest( |
| Resource::kImage, resource_request, input_url, options, |
| reporting_policy, FetchParameters::kUseDefaultOriginRestrictionForType); |
| } |
| |
| int filtered_load_callback_counter_; |
| }; |
| |
| // This test class sets up a mock frame loader client. |
| class FrameFetchContextMockedLocalFrameClientTest |
| : public FrameFetchContextTest { |
| protected: |
| void SetUp() override { |
| url = KURL(NullURL(), "https://example.test/foo"); |
| main_resource_url = KURL(NullURL(), "https://www.example.test"); |
| client = new ::testing::NiceMock<MockLocalFrameClient>(); |
| dummy_page_holder = |
| DummyPageHolder::Create(IntSize(500, 500), nullptr, client); |
| dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(1.0); |
| document = &dummy_page_holder->GetDocument(); |
| document->SetURL(main_resource_url); |
| fetch_context = |
| static_cast<FrameFetchContext*>(&document->Fetcher()->Context()); |
| owner = DummyFrameOwner::Create(); |
| FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get()); |
| } |
| |
| KURL url; |
| KURL main_resource_url; |
| |
| Persistent<testing::NiceMock<MockLocalFrameClient>> client; |
| }; |
| |
| class FrameFetchContextModifyRequestTest : public FrameFetchContextTest { |
| public: |
| FrameFetchContextModifyRequestTest() |
| : example_origin(SecurityOrigin::Create( |
| KURL(kParsedURLString, "https://example.test/"))), |
| secure_origin(SecurityOrigin::Create( |
| KURL(kParsedURLString, "https://secureorigin.test/image.png"))) {} |
| |
| protected: |
| void ExpectUpgrade(const char* input, const char* expected) { |
| ExpectUpgrade(input, WebURLRequest::kRequestContextScript, |
| WebURLRequest::kFrameTypeNone, expected); |
| } |
| |
| void ExpectUpgrade(const char* input, |
| WebURLRequest::RequestContext request_context, |
| WebURLRequest::FrameType frame_type, |
| const char* expected) { |
| KURL input_url(kParsedURLString, input); |
| KURL expected_url(kParsedURLString, expected); |
| |
| ResourceRequest resource_request(input_url); |
| resource_request.SetRequestContext(request_context); |
| resource_request.SetFrameType(frame_type); |
| |
| fetch_context->ModifyRequestForCSP(resource_request); |
| |
| EXPECT_EQ(expected_url.GetString(), resource_request.Url().GetString()); |
| EXPECT_EQ(expected_url.Protocol(), resource_request.Url().Protocol()); |
| EXPECT_EQ(expected_url.Host(), resource_request.Url().Host()); |
| EXPECT_EQ(expected_url.Port(), resource_request.Url().Port()); |
| EXPECT_EQ(expected_url.HasPort(), resource_request.Url().HasPort()); |
| EXPECT_EQ(expected_url.GetPath(), resource_request.Url().GetPath()); |
| } |
| |
| void ExpectUpgradeInsecureRequestHeader(const char* input, |
| WebURLRequest::FrameType frame_type, |
| bool should_prefer) { |
| KURL input_url(kParsedURLString, input); |
| |
| ResourceRequest resource_request(input_url); |
| resource_request.SetRequestContext(WebURLRequest::kRequestContextScript); |
| resource_request.SetFrameType(frame_type); |
| |
| fetch_context->ModifyRequestForCSP(resource_request); |
| |
| EXPECT_EQ( |
| should_prefer ? String("1") : String(), |
| resource_request.HttpHeaderField(HTTPNames::Upgrade_Insecure_Requests)); |
| |
| // Calling modifyRequestForCSP more than once shouldn't affect the |
| // header. |
| if (should_prefer) { |
| fetch_context->ModifyRequestForCSP(resource_request); |
| EXPECT_EQ("1", resource_request.HttpHeaderField( |
| HTTPNames::Upgrade_Insecure_Requests)); |
| } |
| } |
| |
| void ExpectSetRequiredCSPRequestHeader( |
| const char* input, |
| WebURLRequest::FrameType frame_type, |
| const AtomicString& expected_required_csp) { |
| KURL input_url(kParsedURLString, input); |
| ResourceRequest resource_request(input_url); |
| resource_request.SetRequestContext(WebURLRequest::kRequestContextScript); |
| resource_request.SetFrameType(frame_type); |
| |
| fetch_context->ModifyRequestForCSP(resource_request); |
| |
| EXPECT_EQ(expected_required_csp, |
| resource_request.HttpHeaderField(HTTPNames::Sec_Required_CSP)); |
| } |
| |
| void SetFrameOwnerBasedOnFrameType(WebURLRequest::FrameType frame_type, |
| HTMLIFrameElement* iframe, |
| const AtomicString& potential_value) { |
| if (frame_type != WebURLRequest::kFrameTypeNested) { |
| document->GetFrame()->SetOwner(nullptr); |
| return; |
| } |
| |
| iframe->setAttribute(HTMLNames::cspAttr, potential_value); |
| document->GetFrame()->SetOwner(iframe); |
| } |
| |
| RefPtr<SecurityOrigin> example_origin; |
| RefPtr<SecurityOrigin> secure_origin; |
| }; |
| |
| TEST_F(FrameFetchContextModifyRequestTest, UpgradeInsecureResourceRequests) { |
| struct TestCase { |
| const char* original; |
| const char* upgraded; |
| } tests[] = { |
| {"http://example.test/image.png", "https://example.test/image.png"}, |
| {"http://example.test:80/image.png", |
| "https://example.test:443/image.png"}, |
| {"http://example.test:1212/image.png", |
| "https://example.test:1212/image.png"}, |
| |
| {"https://example.test/image.png", "https://example.test/image.png"}, |
| {"https://example.test:80/image.png", |
| "https://example.test:80/image.png"}, |
| {"https://example.test:1212/image.png", |
| "https://example.test:1212/image.png"}, |
| |
| {"ftp://example.test/image.png", "ftp://example.test/image.png"}, |
| {"ftp://example.test:21/image.png", "ftp://example.test:21/image.png"}, |
| {"ftp://example.test:1212/image.png", |
| "ftp://example.test:1212/image.png"}, |
| }; |
| |
| FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get()); |
| document->SetInsecureRequestPolicy(kUpgradeInsecureRequests); |
| |
| for (const auto& test : tests) { |
| document->InsecureNavigationsToUpgrade()->clear(); |
| |
| // We always upgrade for FrameTypeNone and FrameTypeNested. |
| ExpectUpgrade(test.original, WebURLRequest::kRequestContextScript, |
| WebURLRequest::kFrameTypeNone, test.upgraded); |
| ExpectUpgrade(test.original, WebURLRequest::kRequestContextScript, |
| WebURLRequest::kFrameTypeNested, test.upgraded); |
| |
| // We do not upgrade for FrameTypeTopLevel or FrameTypeAuxiliary... |
| ExpectUpgrade(test.original, WebURLRequest::kRequestContextScript, |
| WebURLRequest::kFrameTypeTopLevel, test.original); |
| ExpectUpgrade(test.original, WebURLRequest::kRequestContextScript, |
| WebURLRequest::kFrameTypeAuxiliary, test.original); |
| |
| // unless the request context is RequestContextForm. |
| ExpectUpgrade(test.original, WebURLRequest::kRequestContextForm, |
| WebURLRequest::kFrameTypeTopLevel, test.upgraded); |
| ExpectUpgrade(test.original, WebURLRequest::kRequestContextForm, |
| WebURLRequest::kFrameTypeAuxiliary, test.upgraded); |
| |
| // Or unless the host of the resource is in the document's |
| // InsecureNavigationsSet: |
| document->AddInsecureNavigationUpgrade( |
| example_origin->Host().Impl()->GetHash()); |
| ExpectUpgrade(test.original, WebURLRequest::kRequestContextScript, |
| WebURLRequest::kFrameTypeTopLevel, test.upgraded); |
| ExpectUpgrade(test.original, WebURLRequest::kRequestContextScript, |
| WebURLRequest::kFrameTypeAuxiliary, test.upgraded); |
| } |
| } |
| |
| TEST_F(FrameFetchContextModifyRequestTest, |
| DoNotUpgradeInsecureResourceRequests) { |
| FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get()); |
| document->SetSecurityOrigin(secure_origin); |
| document->SetInsecureRequestPolicy(kLeaveInsecureRequestsAlone); |
| |
| ExpectUpgrade("http://example.test/image.png", |
| "http://example.test/image.png"); |
| ExpectUpgrade("http://example.test:80/image.png", |
| "http://example.test:80/image.png"); |
| ExpectUpgrade("http://example.test:1212/image.png", |
| "http://example.test:1212/image.png"); |
| |
| ExpectUpgrade("https://example.test/image.png", |
| "https://example.test/image.png"); |
| ExpectUpgrade("https://example.test:80/image.png", |
| "https://example.test:80/image.png"); |
| ExpectUpgrade("https://example.test:1212/image.png", |
| "https://example.test:1212/image.png"); |
| |
| ExpectUpgrade("ftp://example.test/image.png", "ftp://example.test/image.png"); |
| ExpectUpgrade("ftp://example.test:21/image.png", |
| "ftp://example.test:21/image.png"); |
| ExpectUpgrade("ftp://example.test:1212/image.png", |
| "ftp://example.test:1212/image.png"); |
| } |
| |
| TEST_F(FrameFetchContextModifyRequestTest, SendUpgradeInsecureRequestHeader) { |
| struct TestCase { |
| const char* to_request; |
| WebURLRequest::FrameType frame_type; |
| bool should_prefer; |
| } tests[] = { |
| {"http://example.test/page.html", WebURLRequest::kFrameTypeAuxiliary, |
| true}, |
| {"http://example.test/page.html", WebURLRequest::kFrameTypeNested, true}, |
| {"http://example.test/page.html", WebURLRequest::kFrameTypeNone, false}, |
| {"http://example.test/page.html", WebURLRequest::kFrameTypeTopLevel, |
| true}, |
| {"https://example.test/page.html", WebURLRequest::kFrameTypeAuxiliary, |
| true}, |
| {"https://example.test/page.html", WebURLRequest::kFrameTypeNested, true}, |
| {"https://example.test/page.html", WebURLRequest::kFrameTypeNone, false}, |
| {"https://example.test/page.html", WebURLRequest::kFrameTypeTopLevel, |
| true}}; |
| |
| // This should work correctly both when the FrameFetchContext has a Document, |
| // and when it doesn't (e.g. during main frame navigations), so run through |
| // the tests both before and after providing a document to the context. |
| for (const auto& test : tests) { |
| document->SetInsecureRequestPolicy(kLeaveInsecureRequestsAlone); |
| ExpectUpgradeInsecureRequestHeader(test.to_request, test.frame_type, |
| test.should_prefer); |
| |
| document->SetInsecureRequestPolicy(kUpgradeInsecureRequests); |
| ExpectUpgradeInsecureRequestHeader(test.to_request, test.frame_type, |
| test.should_prefer); |
| } |
| |
| FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get()); |
| |
| for (const auto& test : tests) { |
| document->SetInsecureRequestPolicy(kLeaveInsecureRequestsAlone); |
| ExpectUpgradeInsecureRequestHeader(test.to_request, test.frame_type, |
| test.should_prefer); |
| |
| document->SetInsecureRequestPolicy(kUpgradeInsecureRequests); |
| ExpectUpgradeInsecureRequestHeader(test.to_request, test.frame_type, |
| test.should_prefer); |
| } |
| } |
| |
| TEST_F(FrameFetchContextModifyRequestTest, SendRequiredCSPHeader) { |
| struct TestCase { |
| const char* to_request; |
| WebURLRequest::FrameType frame_type; |
| } tests[] = { |
| {"https://example.test/page.html", WebURLRequest::kFrameTypeAuxiliary}, |
| {"https://example.test/page.html", WebURLRequest::kFrameTypeNested}, |
| {"https://example.test/page.html", WebURLRequest::kFrameTypeNone}, |
| {"https://example.test/page.html", WebURLRequest::kFrameTypeTopLevel}}; |
| |
| HTMLIFrameElement* iframe = HTMLIFrameElement::Create(*document); |
| const AtomicString& required_csp = AtomicString("default-src 'none'"); |
| const AtomicString& another_required_csp = AtomicString("default-src 'self'"); |
| |
| for (const auto& test : tests) { |
| SetFrameOwnerBasedOnFrameType(test.frame_type, iframe, required_csp); |
| ExpectSetRequiredCSPRequestHeader( |
| test.to_request, test.frame_type, |
| test.frame_type == WebURLRequest::kFrameTypeNested ? required_csp |
| : g_null_atom); |
| |
| SetFrameOwnerBasedOnFrameType(test.frame_type, iframe, |
| another_required_csp); |
| ExpectSetRequiredCSPRequestHeader( |
| test.to_request, test.frame_type, |
| test.frame_type == WebURLRequest::kFrameTypeNested |
| ? another_required_csp |
| : g_null_atom); |
| } |
| } |
| |
| // Tests that PopulateResourceRequest() checks report-only CSP headers, so that |
| // any violations are reported before the request is modified. |
| TEST_F(FrameFetchContextTest, PopulateResourceRequestChecksReportOnlyCSP) { |
| ContentSecurityPolicy* policy = document->GetContentSecurityPolicy(); |
| policy->DidReceiveHeader( |
| "upgrade-insecure-requests; script-src https://foo.test", |
| kContentSecurityPolicyHeaderTypeEnforce, |
| kContentSecurityPolicyHeaderSourceHTTP); |
| policy->DidReceiveHeader("script-src https://bar.test", |
| kContentSecurityPolicyHeaderTypeReport, |
| kContentSecurityPolicyHeaderSourceHTTP); |
| KURL url(NullURL(), "http://baz.test"); |
| ResourceRequest resource_request(url); |
| resource_request.SetRequestContext(WebURLRequest::kRequestContextScript); |
| resource_request.SetFetchCredentialsMode( |
| WebURLRequest::kFetchCredentialsModeOmit); |
| ResourceLoaderOptions options; |
| fetch_context->PopulateResourceRequest( |
| url, Resource::kScript, ClientHintsPreferences(), |
| FetchParameters::ResourceWidth(), options, |
| SecurityViolationReportingPolicy::kReport, resource_request); |
| EXPECT_EQ(1u, policy->violation_reports_sent_.size()); |
| // Check that the resource was upgraded to a secure URL. |
| EXPECT_EQ(KURL(NullURL(), "https://baz.test"), resource_request.Url()); |
| } |
| |
| class FrameFetchContextHintsTest : public FrameFetchContextTest { |
| public: |
| FrameFetchContextHintsTest() {} |
| |
| protected: |
| void ExpectHeader(const char* input, |
| const char* header_name, |
| bool is_present, |
| const char* header_value, |
| float width = 0) { |
| ClientHintsPreferences hints_preferences; |
| |
| FetchParameters::ResourceWidth resource_width; |
| if (width > 0) { |
| resource_width.width = width; |
| resource_width.is_set = true; |
| } |
| |
| KURL input_url(kParsedURLString, input); |
| ResourceRequest resource_request(input_url); |
| |
| fetch_context->AddClientHintsIfNecessary(hints_preferences, resource_width, |
| resource_request); |
| |
| EXPECT_EQ(is_present ? String(header_value) : String(), |
| resource_request.HttpHeaderField(header_name)); |
| } |
| }; |
| |
| TEST_F(FrameFetchContextHintsTest, MonitorDeviceRAMHints) { |
| ExpectHeader("http://www.example.com/1.gif", "device-ram", false, ""); |
| ClientHintsPreferences preferences; |
| preferences.SetShouldSendDeviceRAM(true); |
| document->GetClientHintsPreferences().UpdateFrom(preferences); |
| MemoryCoordinator::SetPhysicalMemoryMBForTesting(4096); |
| ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "4"); |
| MemoryCoordinator::SetPhysicalMemoryMBForTesting(2048); |
| ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "2"); |
| MemoryCoordinator::SetPhysicalMemoryMBForTesting(64385); |
| ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "64"); |
| MemoryCoordinator::SetPhysicalMemoryMBForTesting(768); |
| ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "0.75"); |
| ExpectHeader("http://www.example.com/1.gif", "DPR", false, ""); |
| ExpectHeader("http://www.example.com/1.gif", "Width", false, ""); |
| ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", false, ""); |
| } |
| |
| TEST_F(FrameFetchContextHintsTest, MonitorDPRHints) { |
| ExpectHeader("http://www.example.com/1.gif", "DPR", false, ""); |
| ClientHintsPreferences preferences; |
| preferences.SetShouldSendDPR(true); |
| document->GetClientHintsPreferences().UpdateFrom(preferences); |
| ExpectHeader("http://www.example.com/1.gif", "DPR", true, "1"); |
| dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(2.5); |
| ExpectHeader("http://www.example.com/1.gif", "DPR", true, "2.5"); |
| ExpectHeader("http://www.example.com/1.gif", "Width", false, ""); |
| ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", false, ""); |
| } |
| |
| TEST_F(FrameFetchContextHintsTest, MonitorResourceWidthHints) { |
| ExpectHeader("http://www.example.com/1.gif", "Width", false, ""); |
| ClientHintsPreferences preferences; |
| preferences.SetShouldSendResourceWidth(true); |
| document->GetClientHintsPreferences().UpdateFrom(preferences); |
| ExpectHeader("http://www.example.com/1.gif", "Width", true, "500", 500); |
| ExpectHeader("http://www.example.com/1.gif", "Width", true, "667", 666.6666); |
| ExpectHeader("http://www.example.com/1.gif", "DPR", false, ""); |
| dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(2.5); |
| ExpectHeader("http://www.example.com/1.gif", "Width", true, "1250", 500); |
| ExpectHeader("http://www.example.com/1.gif", "Width", true, "1667", 666.6666); |
| } |
| |
| TEST_F(FrameFetchContextHintsTest, MonitorViewportWidthHints) { |
| ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", false, ""); |
| ClientHintsPreferences preferences; |
| preferences.SetShouldSendViewportWidth(true); |
| document->GetClientHintsPreferences().UpdateFrom(preferences); |
| ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", true, "500"); |
| dummy_page_holder->GetFrameView().SetLayoutSizeFixedToFrameSize(false); |
| dummy_page_holder->GetFrameView().SetLayoutSize(IntSize(800, 800)); |
| ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", true, "800"); |
| ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", true, "800", |
| 666.6666); |
| ExpectHeader("http://www.example.com/1.gif", "DPR", false, ""); |
| } |
| |
| TEST_F(FrameFetchContextHintsTest, MonitorAllHints) { |
| ExpectHeader("http://www.example.com/1.gif", "device-ram", false, ""); |
| ExpectHeader("http://www.example.com/1.gif", "DPR", false, ""); |
| ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", false, ""); |
| ExpectHeader("http://www.example.com/1.gif", "Width", false, ""); |
| |
| ClientHintsPreferences preferences; |
| preferences.SetShouldSendDeviceRAM(true); |
| preferences.SetShouldSendDPR(true); |
| preferences.SetShouldSendResourceWidth(true); |
| preferences.SetShouldSendViewportWidth(true); |
| MemoryCoordinator::SetPhysicalMemoryMBForTesting(4096); |
| document->GetClientHintsPreferences().UpdateFrom(preferences); |
| ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "4"); |
| ExpectHeader("http://www.example.com/1.gif", "DPR", true, "1"); |
| ExpectHeader("http://www.example.com/1.gif", "Width", true, "400", 400); |
| ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", true, "500"); |
| } |
| |
| TEST_F(FrameFetchContextHintsTest, ClientHintsDeviceRAM) { |
| EXPECT_EQ(0.125, FrameFetchContext::ClientHintsDeviceRAM(128)); // 128MB |
| EXPECT_EQ(0.25, FrameFetchContext::ClientHintsDeviceRAM(256)); // 256MB |
| EXPECT_EQ(0.5, FrameFetchContext::ClientHintsDeviceRAM(510)); // <512MB |
| EXPECT_EQ(0.5, FrameFetchContext::ClientHintsDeviceRAM(512)); // 512MB |
| EXPECT_EQ(0.5, FrameFetchContext::ClientHintsDeviceRAM(640)); // 512+128MB |
| EXPECT_EQ(0.75, FrameFetchContext::ClientHintsDeviceRAM(768)); // 512+256MB |
| EXPECT_EQ(1, FrameFetchContext::ClientHintsDeviceRAM(1000)); // <1GB |
| EXPECT_EQ(1, FrameFetchContext::ClientHintsDeviceRAM(1024)); // 1GB |
| EXPECT_EQ(1.5, FrameFetchContext::ClientHintsDeviceRAM(1536)); // 1.5GB |
| EXPECT_EQ(2, FrameFetchContext::ClientHintsDeviceRAM(2000)); // <2GB |
| EXPECT_EQ(2, FrameFetchContext::ClientHintsDeviceRAM(2048)); // 2GB |
| EXPECT_EQ(3, FrameFetchContext::ClientHintsDeviceRAM(3000)); // <3GB |
| EXPECT_EQ(4, FrameFetchContext::ClientHintsDeviceRAM(5120)); // 5GB |
| EXPECT_EQ(8, FrameFetchContext::ClientHintsDeviceRAM(8192)); // 8GB |
| EXPECT_EQ(16, FrameFetchContext::ClientHintsDeviceRAM(16384)); // 16GB |
| EXPECT_EQ(32, FrameFetchContext::ClientHintsDeviceRAM(32768)); // 32GB |
| EXPECT_EQ(64, FrameFetchContext::ClientHintsDeviceRAM(64385)); // <64GB |
| } |
| |
| TEST_F(FrameFetchContextTest, MainResourceCachePolicy) { |
| // Default case |
| ResourceRequest request("http://www.example.com"); |
| EXPECT_EQ(WebCachePolicy::kUseProtocolCachePolicy, |
| fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // Post |
| ResourceRequest post_request("http://www.example.com"); |
| post_request.SetHTTPMethod(HTTPNames::POST); |
| EXPECT_EQ( |
| WebCachePolicy::kValidatingCacheData, |
| fetch_context->ResourceRequestCachePolicy( |
| post_request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // Re-post |
| document->Loader()->SetLoadType(kFrameLoadTypeBackForward); |
| EXPECT_EQ( |
| WebCachePolicy::kReturnCacheDataDontLoad, |
| fetch_context->ResourceRequestCachePolicy( |
| post_request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // FrameLoadTypeReload |
| document->Loader()->SetLoadType(kFrameLoadTypeReload); |
| EXPECT_EQ(WebCachePolicy::kValidatingCacheData, |
| fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // Conditional request |
| document->Loader()->SetLoadType(kFrameLoadTypeStandard); |
| ResourceRequest conditional("http://www.example.com"); |
| conditional.SetHTTPHeaderField(HTTPNames::If_Modified_Since, "foo"); |
| EXPECT_EQ( |
| WebCachePolicy::kValidatingCacheData, |
| fetch_context->ResourceRequestCachePolicy( |
| conditional, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // FrameLoadTypeReloadBypassingCache |
| document->Loader()->SetLoadType(kFrameLoadTypeReloadBypassingCache); |
| EXPECT_EQ(WebCachePolicy::kBypassingCache, |
| fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // FrameLoadTypeReloadBypassingCache with a conditional request |
| document->Loader()->SetLoadType(kFrameLoadTypeReloadBypassingCache); |
| EXPECT_EQ( |
| WebCachePolicy::kBypassingCache, |
| fetch_context->ResourceRequestCachePolicy( |
| conditional, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // FrameLoadTypeReloadBypassingCache with a post request |
| document->Loader()->SetLoadType(kFrameLoadTypeReloadBypassingCache); |
| EXPECT_EQ( |
| WebCachePolicy::kBypassingCache, |
| fetch_context->ResourceRequestCachePolicy( |
| post_request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // Set up a child frame |
| FrameFetchContext* child_fetch_context = CreateChildFrame(); |
| |
| // Child frame as part of back/forward |
| document->Loader()->SetLoadType(kFrameLoadTypeBackForward); |
| EXPECT_EQ(WebCachePolicy::kReturnCacheDataElseLoad, |
| child_fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // Child frame as part of reload |
| document->Loader()->SetLoadType(kFrameLoadTypeReload); |
| EXPECT_EQ(WebCachePolicy::kUseProtocolCachePolicy, |
| child_fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // Child frame as part of reload bypassing cache |
| document->Loader()->SetLoadType(kFrameLoadTypeReloadBypassingCache); |
| EXPECT_EQ(WebCachePolicy::kBypassingCache, |
| child_fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| |
| // Per-frame bypassing reload, but parent load type is different. |
| // This is not the case users can trigger through user interfaces, but for |
| // checking code correctness and consistency. |
| document->Loader()->SetLoadType(kFrameLoadTypeReload); |
| child_frame->Loader().GetDocumentLoader()->SetLoadType( |
| kFrameLoadTypeReloadBypassingCache); |
| EXPECT_EQ(WebCachePolicy::kBypassingCache, |
| child_fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMainResource, FetchParameters::kNoDefer)); |
| } |
| |
| TEST_F(FrameFetchContextTest, SubResourceCachePolicy) { |
| // Reset load event state: if the load event is finished, we ignore the |
| // DocumentLoader load type. |
| document->open(); |
| ASSERT_FALSE(document->LoadEventFinished()); |
| |
| // Default case |
| ResourceRequest request("http://www.example.com/mock"); |
| EXPECT_EQ(WebCachePolicy::kUseProtocolCachePolicy, |
| fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMock, FetchParameters::kNoDefer)); |
| |
| // FrameLoadTypeReload should not affect sub-resources |
| document->Loader()->SetLoadType(kFrameLoadTypeReload); |
| EXPECT_EQ(WebCachePolicy::kUseProtocolCachePolicy, |
| fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMock, FetchParameters::kNoDefer)); |
| |
| // Conditional request |
| document->Loader()->SetLoadType(kFrameLoadTypeStandard); |
| ResourceRequest conditional("http://www.example.com/mock"); |
| conditional.SetHTTPHeaderField(HTTPNames::If_Modified_Since, "foo"); |
| EXPECT_EQ(WebCachePolicy::kValidatingCacheData, |
| fetch_context->ResourceRequestCachePolicy( |
| conditional, Resource::kMock, FetchParameters::kNoDefer)); |
| |
| // FrameLoadTypeReloadBypassingCache |
| document->Loader()->SetLoadType(kFrameLoadTypeReloadBypassingCache); |
| EXPECT_EQ(WebCachePolicy::kBypassingCache, |
| fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMock, FetchParameters::kNoDefer)); |
| |
| // FrameLoadTypeReloadBypassingCache with a conditional request |
| document->Loader()->SetLoadType(kFrameLoadTypeReloadBypassingCache); |
| EXPECT_EQ(WebCachePolicy::kBypassingCache, |
| fetch_context->ResourceRequestCachePolicy( |
| conditional, Resource::kMock, FetchParameters::kNoDefer)); |
| |
| // Back/forward navigation |
| document->Loader()->SetLoadType(kFrameLoadTypeBackForward); |
| EXPECT_EQ(WebCachePolicy::kReturnCacheDataElseLoad, |
| fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kMock, FetchParameters::kNoDefer)); |
| |
| // Back/forward navigation with a conditional request |
| document->Loader()->SetLoadType(kFrameLoadTypeBackForward); |
| EXPECT_EQ(WebCachePolicy::kReturnCacheDataElseLoad, |
| fetch_context->ResourceRequestCachePolicy( |
| conditional, Resource::kMock, FetchParameters::kNoDefer)); |
| } |
| |
| TEST_F(FrameFetchContextTest, SetFirstPartyCookieAndRequestorOrigin) { |
| struct TestCase { |
| const char* document_url; |
| bool document_sandboxed; |
| const char* requestor_origin; // "" => null |
| WebURLRequest::FrameType frame_type; |
| const char* serialized_origin; // "" => null |
| } cases[] = { |
| // No document origin => unique request origin |
| {"", false, "", WebURLRequest::kFrameTypeNone, "null"}, |
| {"", true, "", WebURLRequest::kFrameTypeNone, "null"}, |
| |
| // Document origin => request origin |
| {"http://example.test", false, "", WebURLRequest::kFrameTypeNone, |
| "http://example.test"}, |
| {"http://example.test", true, "", WebURLRequest::kFrameTypeNone, |
| "http://example.test"}, |
| |
| // If the request already has a requestor origin, then |
| // 'SetFirstPartyCookieAndRequestorOrigin' leaves it alone: |
| {"http://example.test", false, "http://not-example.test", |
| WebURLRequest::kFrameTypeNone, "http://not-example.test"}, |
| {"http://example.test", true, "http://not-example.test", |
| WebURLRequest::kFrameTypeNone, "http://not-example.test"}, |
| }; |
| |
| int index = 0; |
| for (const auto& test : cases) { |
| SCOPED_TRACE(::testing::Message() << index++ << " " << test.document_url |
| << " => " << test.serialized_origin); |
| // Set up a new document to ensure sandbox flags are cleared: |
| dummy_page_holder = DummyPageHolder::Create(IntSize(500, 500)); |
| dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(1.0); |
| document = &dummy_page_holder->GetDocument(); |
| fetch_context = |
| static_cast<FrameFetchContext*>(&document->Fetcher()->Context()); |
| FrameFetchContext::ProvideDocumentToContext(*fetch_context, document.Get()); |
| |
| // Setup the test: |
| document->SetURL(KURL(kParsedURLString, test.document_url)); |
| document->SetSecurityOrigin(SecurityOrigin::Create(document->Url())); |
| |
| if (test.document_sandboxed) |
| document->EnforceSandboxFlags(kSandboxOrigin); |
| |
| ResourceRequest request("http://example.test/"); |
| request.SetFrameType(test.frame_type); |
| if (strlen(test.requestor_origin) > 0) { |
| request.SetRequestorOrigin(SecurityOrigin::Create( |
| KURL(kParsedURLString, test.requestor_origin))); |
| } |
| |
| // Compare the populated |requestorOrigin| against |test.serializedOrigin| |
| fetch_context->SetFirstPartyCookieAndRequestorOrigin(request); |
| if (strlen(test.serialized_origin) == 0) { |
| EXPECT_TRUE(!request.RequestorOrigin()); |
| } else { |
| EXPECT_EQ(String(test.serialized_origin), |
| request.RequestorOrigin()->ToString()); |
| } |
| |
| EXPECT_EQ(document->FirstPartyForCookies(), request.FirstPartyForCookies()); |
| } |
| } |
| |
| // Tests if "Save-Data" header is correctly added on the first load and reload. |
| TEST_F(FrameFetchContextTest, EnableDataSaver) { |
| Settings* settings = document->GetFrame()->GetSettings(); |
| settings->SetDataSaverEnabled(true); |
| ResourceRequest resource_request("http://www.example.com"); |
| fetch_context->AddAdditionalRequestHeaders(resource_request, |
| kFetchMainResource); |
| EXPECT_EQ("on", resource_request.HttpHeaderField("Save-Data")); |
| |
| // Subsequent call to addAdditionalRequestHeaders should not append to the |
| // save-data header. |
| fetch_context->AddAdditionalRequestHeaders(resource_request, |
| kFetchMainResource); |
| EXPECT_EQ("on", resource_request.HttpHeaderField("Save-Data")); |
| } |
| |
| // Tests if "Save-Data" header is not added when the data saver is disabled. |
| TEST_F(FrameFetchContextTest, DisabledDataSaver) { |
| ResourceRequest resource_request("http://www.example.com"); |
| fetch_context->AddAdditionalRequestHeaders(resource_request, |
| kFetchMainResource); |
| EXPECT_EQ(String(), resource_request.HttpHeaderField("Save-Data")); |
| } |
| |
| // Tests if reload variants can reflect the current data saver setting. |
| TEST_F(FrameFetchContextTest, ChangeDataSaverConfig) { |
| Settings* settings = document->GetFrame()->GetSettings(); |
| settings->SetDataSaverEnabled(true); |
| ResourceRequest resource_request("http://www.example.com"); |
| fetch_context->AddAdditionalRequestHeaders(resource_request, |
| kFetchMainResource); |
| EXPECT_EQ("on", resource_request.HttpHeaderField("Save-Data")); |
| |
| settings->SetDataSaverEnabled(false); |
| document->Loader()->SetLoadType(kFrameLoadTypeReload); |
| fetch_context->AddAdditionalRequestHeaders(resource_request, |
| kFetchMainResource); |
| EXPECT_EQ(String(), resource_request.HttpHeaderField("Save-Data")); |
| |
| settings->SetDataSaverEnabled(true); |
| fetch_context->AddAdditionalRequestHeaders(resource_request, |
| kFetchMainResource); |
| EXPECT_EQ("on", resource_request.HttpHeaderField("Save-Data")); |
| |
| settings->SetDataSaverEnabled(false); |
| document->Loader()->SetLoadType(kFrameLoadTypeReload); |
| fetch_context->AddAdditionalRequestHeaders(resource_request, |
| kFetchMainResource); |
| EXPECT_EQ(String(), resource_request.HttpHeaderField("Save-Data")); |
| } |
| |
| // Tests that the embedder gets correct notification when a resource is loaded |
| // from the memory cache. |
| TEST_F(FrameFetchContextMockedLocalFrameClientTest, |
| DispatchDidLoadResourceFromMemoryCache) { |
| ResourceRequest resource_request(url); |
| resource_request.SetRequestContext(WebURLRequest::kRequestContextImage); |
| resource_request.SetFetchCredentialsMode( |
| WebURLRequest::kFetchCredentialsModeOmit); |
| Resource* resource = MockResource::Create(resource_request); |
| EXPECT_CALL(*client, |
| DispatchDidLoadResourceFromMemoryCache( |
| ::testing::AllOf( |
| ::testing::Property(&ResourceRequest::Url, url), |
| ::testing::Property(&ResourceRequest::GetFrameType, |
| WebURLRequest::kFrameTypeNone), |
| ::testing::Property(&ResourceRequest::GetRequestContext, |
| WebURLRequest::kRequestContextImage)), |
| ResourceResponse())); |
| fetch_context->DispatchDidLoadResourceFromMemoryCache( |
| CreateUniqueIdentifier(), resource_request, resource->GetResponse()); |
| } |
| |
| // Tests that when a resource with certificate errors is loaded from the memory |
| // cache, the embedder is notified. |
| TEST_F(FrameFetchContextMockedLocalFrameClientTest, |
| MemoryCacheCertificateError) { |
| ResourceRequest resource_request(url); |
| resource_request.SetRequestContext(WebURLRequest::kRequestContextImage); |
| resource_request.SetFetchCredentialsMode( |
| WebURLRequest::kFetchCredentialsModeOmit); |
| ResourceResponse response; |
| response.SetURL(url); |
| response.SetHasMajorCertificateErrors(true); |
| Resource* resource = MockResource::Create(resource_request); |
| resource->SetResponse(response); |
| EXPECT_CALL(*client, DidDisplayContentWithCertificateErrors(url)); |
| fetch_context->DispatchDidLoadResourceFromMemoryCache( |
| CreateUniqueIdentifier(), resource_request, resource->GetResponse()); |
| } |
| |
| TEST_F(FrameFetchContextSubresourceFilterTest, Filter) { |
| SetFilterPolicy(WebDocumentSubresourceFilter::kDisallow); |
| |
| EXPECT_EQ(ResourceRequestBlockedReason::kSubresourceFilter, CanRequest()); |
| EXPECT_EQ(1, GetFilteredLoadCallCount()); |
| |
| EXPECT_EQ(ResourceRequestBlockedReason::kSubresourceFilter, CanRequest()); |
| EXPECT_EQ(2, GetFilteredLoadCallCount()); |
| |
| EXPECT_EQ(ResourceRequestBlockedReason::kSubresourceFilter, |
| CanRequestPreload()); |
| EXPECT_EQ(2, GetFilteredLoadCallCount()); |
| |
| EXPECT_EQ(ResourceRequestBlockedReason::kSubresourceFilter, CanRequest()); |
| EXPECT_EQ(3, GetFilteredLoadCallCount()); |
| } |
| |
| TEST_F(FrameFetchContextSubresourceFilterTest, Allow) { |
| SetFilterPolicy(WebDocumentSubresourceFilter::kAllow); |
| |
| EXPECT_EQ(ResourceRequestBlockedReason::kNone, CanRequest()); |
| EXPECT_EQ(0, GetFilteredLoadCallCount()); |
| |
| EXPECT_EQ(ResourceRequestBlockedReason::kNone, CanRequestPreload()); |
| EXPECT_EQ(0, GetFilteredLoadCallCount()); |
| } |
| |
| TEST_F(FrameFetchContextSubresourceFilterTest, WouldDisallow) { |
| SetFilterPolicy(WebDocumentSubresourceFilter::kWouldDisallow); |
| |
| EXPECT_EQ(ResourceRequestBlockedReason::kNone, CanRequest()); |
| EXPECT_EQ(0, GetFilteredLoadCallCount()); |
| |
| EXPECT_EQ(ResourceRequestBlockedReason::kNone, CanRequestPreload()); |
| EXPECT_EQ(0, GetFilteredLoadCallCount()); |
| } |
| |
| TEST_F(FrameFetchContextTest, AddAdditionalRequestHeadersWhenDetached) { |
| const KURL document_url(NullURL(), "https://www2.example.com/fuga/hoge.html"); |
| const String origin = "https://www2.example.com"; |
| ResourceRequest request(KURL(NullURL(), "https://localhost/")); |
| request.SetHTTPMethod("PUT"); |
| |
| Settings* settings = document->GetFrame()->GetSettings(); |
| settings->SetDataSaverEnabled(true); |
| document->SetSecurityOrigin(SecurityOrigin::Create(KURL(NullURL(), origin))); |
| document->SetURL(document_url); |
| document->SetReferrerPolicy(kReferrerPolicyOrigin); |
| document->SetAddressSpace(kWebAddressSpacePublic); |
| |
| dummy_page_holder = nullptr; |
| |
| EXPECT_FALSE(request.IsExternalRequest()); |
| |
| fetch_context->AddAdditionalRequestHeaders(request, kFetchSubresource); |
| |
| EXPECT_EQ(origin, request.HttpHeaderField(HTTPNames::Origin)); |
| EXPECT_EQ(String(origin + "/"), request.HttpHeaderField(HTTPNames::Referer)); |
| EXPECT_EQ(String(), request.HttpHeaderField("Save-Data")); |
| EXPECT_TRUE(request.IsExternalRequest()); |
| } |
| |
| TEST_F(FrameFetchContextTest, ResourceRequestCachePolicyWhenDetached) { |
| ResourceRequest request(KURL(NullURL(), "https://localhost/")); |
| |
| dummy_page_holder = nullptr; |
| |
| EXPECT_EQ(WebCachePolicy::kUseProtocolCachePolicy, |
| fetch_context->ResourceRequestCachePolicy( |
| request, Resource::kRaw, FetchParameters::kNoDefer)); |
| } |
| |
| TEST_F(FrameFetchContextTest, DispatchDidChangePriorityWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DispatchDidChangeResourcePriority(2, kResourceLoadPriorityLow, |
| 3); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextMockedLocalFrameClientTest, |
| PrepareRequestWhenDetached) { |
| Checkpoint checkpoint; |
| |
| EXPECT_CALL(checkpoint, Call(1)); |
| EXPECT_CALL(*client, UserAgent()).WillOnce(testing::Return(String("hi"))); |
| EXPECT_CALL(checkpoint, Call(2)); |
| |
| checkpoint.Call(1); |
| dummy_page_holder = nullptr; |
| checkpoint.Call(2); |
| |
| ResourceRequest request(KURL(NullURL(), "https://localhost/")); |
| fetch_context->PrepareRequest(request, |
| FetchContext::RedirectType::kNotForRedirect); |
| |
| EXPECT_EQ("hi", request.HttpHeaderField(HTTPNames::User_Agent)); |
| } |
| |
| TEST_F(FrameFetchContextTest, DispatchWillSendRequestWhenDetached) { |
| ResourceRequest request(KURL(NullURL(), "https://www.example.com/")); |
| ResourceResponse response; |
| FetchInitiatorInfo initiator_info; |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DispatchWillSendRequest(1, request, response, initiator_info); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, |
| DispatchDidLoadResourceFromMemoryCacheWhenDetached) { |
| ResourceRequest request(KURL(NullURL(), "https://www.example.com/")); |
| ResourceResponse response; |
| FetchInitiatorInfo initiator_info; |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DispatchDidLoadResourceFromMemoryCache(8, request, response); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, DispatchDidReceiveResponseWhenDetached) { |
| ResourceRequest request(KURL(NullURL(), "https://www.example.com/")); |
| request.SetFetchCredentialsMode(WebURLRequest::kFetchCredentialsModeOmit); |
| Resource* resource = MockResource::Create(request); |
| ResourceResponse response; |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DispatchDidReceiveResponse( |
| 3, response, WebURLRequest::kFrameTypeTopLevel, |
| WebURLRequest::kRequestContextFetch, resource, |
| FetchContext::ResourceResponseType::kNotFromMemoryCache); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, DispatchDidReceiveDataWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DispatchDidReceiveData(3, "abcd", 4); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, DispatchDidReceiveEncodedDataWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DispatchDidReceiveEncodedData(8, 9); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, DispatchDidDownloadDataWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DispatchDidDownloadData(4, 7, 9); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, DispatchDidFinishLoadingWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DispatchDidFinishLoading(4, 0.3, 8, 10); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, DispatchDidFailWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DispatchDidFail(8, ResourceError(), 5, false); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, ShouldLoadNewResourceWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| EXPECT_FALSE(fetch_context->ShouldLoadNewResource(Resource::kImage)); |
| EXPECT_FALSE(fetch_context->ShouldLoadNewResource(Resource::kRaw)); |
| EXPECT_FALSE(fetch_context->ShouldLoadNewResource(Resource::kScript)); |
| EXPECT_FALSE(fetch_context->ShouldLoadNewResource(Resource::kMainResource)); |
| } |
| |
| TEST_F(FrameFetchContextTest, RecordLoadingActivityWhenDetached) { |
| ResourceRequest request(KURL(NullURL(), "https://www.example.com/")); |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->RecordLoadingActivity(4, request, Resource::kRaw, |
| FetchInitiatorTypeNames::xmlhttprequest); |
| // Should not crash. |
| |
| fetch_context->RecordLoadingActivity(8, request, Resource::kRaw, |
| FetchInitiatorTypeNames::document); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, DidLoadResourceWhenDetached) { |
| ResourceRequest request(KURL(NullURL(), "https://www.example.com/")); |
| request.SetFetchCredentialsMode(WebURLRequest::kFetchCredentialsModeOmit); |
| Resource* resource = MockResource::Create(request); |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->DidLoadResource(resource); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, AddResourceTimingWhenDetached) { |
| RefPtr<ResourceTimingInfo> info = |
| ResourceTimingInfo::Create("type", 0.3, false); |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->AddResourceTiming(*info); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, AllowImageWhenDetached) { |
| KURL url(NullURL(), "https://www.example.com/"); |
| |
| dummy_page_holder = nullptr; |
| |
| EXPECT_TRUE(fetch_context->AllowImage(true, url)); |
| EXPECT_TRUE(fetch_context->AllowImage(false, url)); |
| } |
| |
| TEST_F(FrameFetchContextTest, IsControlledByServiceWorkerWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| EXPECT_FALSE(fetch_context->IsControlledByServiceWorker()); |
| } |
| |
| TEST_F(FrameFetchContextTest, IsMainFrameWhenDetached) { |
| FetchContext* child_fetch_context = CreateChildFrame(); |
| |
| EXPECT_TRUE(fetch_context->IsMainFrame()); |
| EXPECT_FALSE(child_fetch_context->IsMainFrame()); |
| |
| dummy_page_holder = nullptr; |
| |
| EXPECT_TRUE(fetch_context->IsMainFrame()); |
| EXPECT_FALSE(child_fetch_context->IsMainFrame()); |
| } |
| |
| TEST_F(FrameFetchContextTest, DefersLoadingWhenDetached) { |
| EXPECT_FALSE(fetch_context->DefersLoading()); |
| } |
| |
| TEST_F(FrameFetchContextTest, IsLoadCompleteWhenDetached_1) { |
| document->open(); |
| EXPECT_FALSE(fetch_context->IsLoadComplete()); |
| |
| dummy_page_holder = nullptr; |
| |
| EXPECT_TRUE(fetch_context->IsLoadComplete()); |
| } |
| |
| TEST_F(FrameFetchContextTest, IsLoadCompleteWhenDetached_2) { |
| EXPECT_TRUE(fetch_context->IsLoadComplete()); |
| |
| dummy_page_holder = nullptr; |
| |
| EXPECT_TRUE(fetch_context->IsLoadComplete()); |
| } |
| |
| TEST_F(FrameFetchContextTest, PageDismissalEventBeingDispatchedWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| EXPECT_FALSE(fetch_context->PageDismissalEventBeingDispatched()); |
| } |
| |
| TEST_F(FrameFetchContextTest, UpdateTimingInfoForIFrameNavigationWhenDetached) { |
| RefPtr<ResourceTimingInfo> info = |
| ResourceTimingInfo::Create("type", 0.3, false); |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->UpdateTimingInfoForIFrameNavigation(info.Get()); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, SendImagePingWhenDetached) { |
| KURL url(NullURL(), "https://www.example.com/"); |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->SendImagePing(url); |
| // Should not crash. Nothing should be sent. |
| } |
| |
| TEST_F(FrameFetchContextTest, AddConsoleMessageWhenDetached) { |
| dummy_page_holder = nullptr; |
| |
| fetch_context->AddConsoleMessage("foobar"); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, GetSecurityOriginWhenDetached) { |
| RefPtr<SecurityOrigin> origin = |
| SecurityOrigin::Create(KURL(NullURL(), "https://www.example.com")); |
| document->SetSecurityOrigin(origin); |
| |
| dummy_page_holder = nullptr; |
| EXPECT_EQ(origin.Get(), fetch_context->GetSecurityOrigin()); |
| } |
| |
| TEST_F(FrameFetchContextTest, PopulateResourceRequestWhenDetached) { |
| KURL url(NullURL(), "https://www.example.com/"); |
| ResourceRequest request(url); |
| request.SetFetchCredentialsMode(WebURLRequest::kFetchCredentialsModeOmit); |
| |
| ClientHintsPreferences client_hints_preferences; |
| client_hints_preferences.SetShouldSendDeviceRAM(true); |
| client_hints_preferences.SetShouldSendDPR(true); |
| client_hints_preferences.SetShouldSendResourceWidth(true); |
| client_hints_preferences.SetShouldSendViewportWidth(true); |
| |
| FetchParameters::ResourceWidth resource_width; |
| ResourceLoaderOptions options; |
| |
| document->GetClientHintsPreferences().SetShouldSendDeviceRAM(true); |
| document->GetClientHintsPreferences().SetShouldSendDPR(true); |
| document->GetClientHintsPreferences().SetShouldSendResourceWidth(true); |
| document->GetClientHintsPreferences().SetShouldSendViewportWidth(true); |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->PopulateResourceRequest( |
| url, Resource::kRaw, client_hints_preferences, resource_width, options, |
| SecurityViolationReportingPolicy::kReport, request); |
| // Should not crash. |
| } |
| |
| TEST_F(FrameFetchContextTest, |
| SetFirstPartyCookieAndRequestorOriginWhenDetached) { |
| KURL url(NullURL(), "https://www.example.com/hoge/fuga"); |
| ResourceRequest request(url); |
| KURL document_url(NullURL(), "https://www2.example.com/foo/bar"); |
| RefPtr<SecurityOrigin> origin = SecurityOrigin::Create(document_url); |
| |
| document->SetSecurityOrigin(origin); |
| document->SetURL(document_url); |
| |
| dummy_page_holder = nullptr; |
| |
| fetch_context->SetFirstPartyCookieAndRequestorOrigin(request); |
| |
| EXPECT_EQ(document_url, request.FirstPartyForCookies()); |
| EXPECT_EQ(origin, request.RequestorOrigin()); |
| } |
| |
| TEST_F(FrameFetchContextTest, ArchiveWhenDetached) { |
| FetchContext* child_fetch_context = CreateChildFrame(); |
| |
| dummy_page_holder = nullptr; |
| child_frame->Detach(FrameDetachType::kRemove); |
| child_frame = nullptr; |
| |
| EXPECT_EQ(nullptr, child_fetch_context->Archive()); |
| } |
| |
| // Tests if "Intervention" header is added for frame with Client Lo-Fi enabled. |
| TEST_F(FrameFetchContextMockedLocalFrameClientTest, |
| ClientLoFiInterventionHeader) { |
| // Verify header not added if Lo-Fi not active. |
| EXPECT_CALL(*client, IsClientLoFiActiveForFrame()) |
| .WillRepeatedly(testing::Return(false)); |
| ResourceRequest resource_request("http://www.example.com/style.css"); |
| fetch_context->AddAdditionalRequestHeaders(resource_request, |
| kFetchMainResource); |
| EXPECT_EQ(g_null_atom, resource_request.HttpHeaderField("Intervention")); |
| |
| // Verify header is added if Lo-Fi is active. |
| EXPECT_CALL(*client, IsClientLoFiActiveForFrame()) |
| .WillRepeatedly(testing::Return(true)); |
| fetch_context->AddAdditionalRequestHeaders(resource_request, |
| kFetchSubresource); |
| EXPECT_EQ( |
| "<https://www.chromestatus.com/features/6072546726248448>; " |
| "level=\"warning\"", |
| resource_request.HttpHeaderField("Intervention")); |
| |
| // Verify appended to an existing "Intervention" header value. |
| ResourceRequest resource_request2("http://www.example.com/getad.js"); |
| resource_request2.SetHTTPHeaderField("Intervention", |
| "<https://otherintervention.org>"); |
| fetch_context->AddAdditionalRequestHeaders(resource_request2, |
| kFetchSubresource); |
| EXPECT_EQ( |
| "<https://otherintervention.org>, " |
| "<https://www.chromestatus.com/features/6072546726248448>; " |
| "level=\"warning\"", |
| resource_request2.HttpHeaderField("Intervention")); |
| } |
| |
| } // namespace blink |