1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/html/parser/CSSPreloadScanner.h"
#include "core/fetch/FetchContext.h"
#include "core/fetch/Resource.h"
#include "core/fetch/ResourceFetcher.h"
#include "core/frame/Settings.h"
#include "core/html/parser/HTMLResourcePreloader.h"
#include "core/testing/DummyPageHolder.h"
#include "platform/heap/Heap.h"
#include "platform/network/ResourceError.h"
#include "platform/network/ResourceRequest.h"
#include "platform/weborigin/KURL.h"
#include "testing/gtest/include/gtest/gtest.h"
#include <memory>
namespace blink {
namespace {
class MockHTMLResourcePreloader : public HTMLResourcePreloader {
WTF_MAKE_NONCOPYABLE(MockHTMLResourcePreloader);
public:
MockHTMLResourcePreloader(Document& document)
: HTMLResourcePreloader(document) {}
void preload(std::unique_ptr<PreloadRequest> preloadRequest,
const NetworkHintsInterface&) override {}
};
class PreloadRecordingCSSPreloaderResourceClient final
: public CSSPreloaderResourceClient {
public:
PreloadRecordingCSSPreloaderResourceClient(Resource* resource,
HTMLResourcePreloader* preloader)
: CSSPreloaderResourceClient(resource, preloader) {}
void fetchPreloads(PreloadRequestStream& preloads) override {
for (const auto& it : preloads)
m_preloadUrls.push_back(it->resourceURL());
CSSPreloaderResourceClient::fetchPreloads(preloads);
}
Vector<String> m_preloadUrls;
};
class CSSPreloadScannerTest : public ::testing::Test {};
} // namespace
TEST_F(CSSPreloadScannerTest, ScanFromResourceClient) {
std::unique_ptr<DummyPageHolder> dummyPageHolder =
DummyPageHolder::create(IntSize(500, 500));
dummyPageHolder->document().settings()->setCSSExternalScannerNoPreload(true);
MockHTMLResourcePreloader* preloader =
new MockHTMLResourcePreloader(dummyPageHolder->document());
KURL url(ParsedURLString, "http://127.0.0.1/foo.css");
CSSStyleSheetResource* resource =
CSSStyleSheetResource::createForTest(ResourceRequest(url), "utf-8");
resource->setStatus(Resource::Pending);
PreloadRecordingCSSPreloaderResourceClient* resourceClient =
new PreloadRecordingCSSPreloaderResourceClient(resource, preloader);
const char* data = "@import url('http://127.0.0.1/preload.css');";
resource->appendData(data, strlen(data));
EXPECT_EQ(Resource::PreloadNotReferenced, resource->getPreloadResult());
EXPECT_EQ(1u, resourceClient->m_preloadUrls.size());
EXPECT_EQ("http://127.0.0.1/preload.css",
resourceClient->m_preloadUrls.front());
}
// Regression test for crbug.com/608310 where the client is destroyed but was
// not removed from the resource's client list.
TEST_F(CSSPreloadScannerTest, DestroyClientBeforeDataSent) {
std::unique_ptr<DummyPageHolder> dummyPageHolder =
DummyPageHolder::create(IntSize(500, 500));
dummyPageHolder->document().settings()->setCSSExternalScannerNoPreload(true);
Persistent<MockHTMLResourcePreloader> preloader =
new MockHTMLResourcePreloader(dummyPageHolder->document());
KURL url(ParsedURLString, "http://127.0.0.1/foo.css");
Persistent<CSSStyleSheetResource> resource =
CSSStyleSheetResource::createForTest(ResourceRequest(url), "utf-8");
resource->setStatus(Resource::Pending);
new PreloadRecordingCSSPreloaderResourceClient(resource, preloader);
// Destroys the resourceClient.
ThreadState::current()->collectAllGarbage();
const char* data = "@import url('http://127.0.0.1/preload.css');";
// Should not crash.
resource->appendData(data, strlen(data));
}
// Regression test for crbug.com/646869 where the client's data is cleared
// before didAppendFirstData is called.
TEST_F(CSSPreloadScannerTest, DontReadFromClearedData) {
std::unique_ptr<DummyPageHolder> dummyPageHolder =
DummyPageHolder::create(IntSize(500, 500));
dummyPageHolder->document().settings()->setCSSExternalScannerNoPreload(true);
MockHTMLResourcePreloader* preloader =
new MockHTMLResourcePreloader(dummyPageHolder->document());
KURL url(ParsedURLString, "http://127.0.0.1/foo.css");
CSSStyleSheetResource* resource =
CSSStyleSheetResource::createForTest(ResourceRequest(url), "utf-8");
const char* data = "@import url('http://127.0.0.1/preload.css');";
resource->appendData(data, strlen(data));
ResourceError error(errorDomainBlinkInternal, 0, url.getString(), "");
resource->error(error);
// Should not crash.
PreloadRecordingCSSPreloaderResourceClient* resourceClient =
new PreloadRecordingCSSPreloaderResourceClient(resource, preloader);
EXPECT_EQ(0u, resourceClient->m_preloadUrls.size());
}
// Regression test for crbug.com/645331, where a resource client gets callbacks
// after the document is shutdown and we have no frame.
TEST_F(CSSPreloadScannerTest, DoNotExpectValidDocument) {
std::unique_ptr<DummyPageHolder> dummyPageHolder =
DummyPageHolder::create(IntSize(500, 500));
dummyPageHolder->document().settings()->setCSSExternalScannerNoPreload(true);
MockHTMLResourcePreloader* preloader =
new MockHTMLResourcePreloader(dummyPageHolder->document());
KURL url(ParsedURLString, "http://127.0.0.1/foo.css");
CSSStyleSheetResource* resource =
CSSStyleSheetResource::createForTest(ResourceRequest(url), "utf-8");
resource->setStatus(Resource::Pending);
PreloadRecordingCSSPreloaderResourceClient* resourceClient =
new PreloadRecordingCSSPreloaderResourceClient(resource, preloader);
dummyPageHolder->document().shutdown();
const char* data = "@import url('http://127.0.0.1/preload.css');";
resource->appendData(data, strlen(data));
// Do not expect to gather any preloads, as the document loader is invalid,
// which means we can't notify WebLoadingBehaviorData of the preloads.
EXPECT_EQ(0u, resourceClient->m_preloadUrls.size());
}
} // namespace blink
|