TEST(ImageResourceTest, CancelOnDetach) { KURL testURL(ParsedURLString, "http://www.test.com/cancelTest.html"); ScopedRegisteredURL scopedRegisteredURL(testURL); ResourceFetcher* fetcher = ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); // Emulate starting a real load. ImageResource* cachedImage = ImageResource::create(ResourceRequest(testURL)); cachedImage->setIdentifier(createUniqueIdentifier()); fetcher->startLoad(cachedImage); memoryCache()->add(cachedImage); Persistent<MockImageResourceClient> client = new MockImageResourceClient(cachedImage); EXPECT_EQ(Resource::Pending, cachedImage->getStatus()); // The load should still be alive, but a timer should be started to cancel the // load inside removeClient(). client->removeAsClient(); EXPECT_EQ(Resource::Pending, cachedImage->getStatus()); EXPECT_TRUE(memoryCache()->resourceForURL(testURL)); // Trigger the cancel timer, ensure the load was cancelled and the resource // was evicted from the cache. blink::testing::runPendingTasks(); EXPECT_EQ(Resource::LoadError, cachedImage->getStatus()); EXPECT_FALSE(memoryCache()->resourceForURL(testURL)); }
TEST(ImageResourceTest, CancelOnDetach) { KURL testURL(ParsedURLString, "http://www.test.com/cancelTest.html"); URLTestHelpers::registerMockedURLLoad(testURL, "cancelTest.html", "text/html"); ResourceFetcher* fetcher = ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); // Emulate starting a real load. ImageResource* cachedImage = ImageResource::create(ResourceRequest(testURL)); cachedImage->setIdentifier(createUniqueIdentifier()); fetcher->startLoad(cachedImage); memoryCache()->add(cachedImage); Persistent<MockImageResourceClient> client = new MockImageResourceClient(cachedImage); EXPECT_EQ(Resource::Pending, cachedImage->getStatus()); // The load should still be alive, but a timer should be started to cancel the load inside removeClient(). client->removeAsClient(); EXPECT_EQ(Resource::Pending, cachedImage->getStatus()); EXPECT_NE(reinterpret_cast<Resource*>(0), memoryCache()->resourceForURL(testURL)); // Trigger the cancel timer, ensure the load was cancelled and the resource was evicted from the cache. blink::testing::runPendingTasks(); EXPECT_EQ(Resource::LoadError, cachedImage->getStatus()); EXPECT_EQ(reinterpret_cast<Resource*>(0), memoryCache()->resourceForURL(testURL)); Platform::current()->getURLLoaderMockFactory()->unregisterURL(testURL); }
TEST_F(ResourceFetcherTest, Revalidate304) { KURL url(ParsedURLString, "http://127.0.0.1:8000/foo.html"); Resource* resource = RawResource::create(url, Resource::Raw); memoryCache()->add(resource); ResourceResponse response; response.setURL(url); response.setHTTPStatusCode(304); response.setHTTPHeaderField("etag", "1234567890"); resource->responseReceived(response, nullptr); resource->finish(); ResourceFetcher* fetcher = ResourceFetcher::create(ResourceFetcherTestMockFetchContext::create()); ResourceRequest resourceRequest(url); resourceRequest.setRequestContext(WebURLRequest::RequestContextInternal); FetchRequest fetchRequest = FetchRequest(resourceRequest, FetchInitiatorInfo()); Platform::current()->getURLLoaderMockFactory()->registerURL( url, WebURLResponse(), ""); Resource* newResource = RawResource::fetch(fetchRequest, fetcher); fetcher->stopFetching(); Platform::current()->getURLLoaderMockFactory()->unregisterURL(url); EXPECT_NE(resource, newResource); }
bool TextTrackLoader::load(const KURL& url, const String& crossOriginMode) { cancelLoad(); if (!m_client->shouldLoadCues(this)) return false; ASSERT(m_scriptExecutionContext->isDocument()); Document* document = toDocument(m_scriptExecutionContext); FetchRequest cueRequest(ResourceRequest(document->completeURL(url)), FetchInitiatorTypeNames::texttrack); if (!crossOriginMode.isNull()) { m_crossOriginMode = crossOriginMode; StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials; updateRequestForAccessControl(cueRequest.mutableResourceRequest(), document->securityOrigin(), allowCredentials); } else { // Cross-origin resources that are not suitably CORS-enabled may not load. if (!document->securityOrigin()->canRequest(url)) { corsPolicyPreventedLoad(); return false; } } ResourceFetcher* fetcher = document->fetcher(); m_cachedCueData = fetcher->requestTextTrack(cueRequest); if (m_cachedCueData) m_cachedCueData->addClient(this); m_client->cueLoadingStarted(this); return true; }
TEST_F(ResourceFetcherTest, RevalidateDeferedResourceFromTwoInitiators) { KURL url(ParsedURLString, "http://127.0.0.1:8000/font.woff"); ResourceResponse response; response.setURL(url); response.setHTTPStatusCode(200); response.setHTTPHeaderField(HTTPNames::ETag, "1234567890"); Platform::current()->getURLLoaderMockFactory()->registerURL( url, WrappedResourceResponse(response), ""); ResourceFetcherTestMockFetchContext* context = ResourceFetcherTestMockFetchContext::create(); ResourceFetcher* fetcher = ResourceFetcher::create(context); // Fetch to cache a resource. ResourceRequest request1(url); FetchRequest fetchRequest1 = FetchRequest(request1, FetchInitiatorInfo()); Resource* resource1 = FontResource::fetch(fetchRequest1, fetcher); ASSERT_TRUE(resource1); fetcher->startLoad(resource1); Platform::current()->getURLLoaderMockFactory()->serveAsynchronousRequests(); EXPECT_TRUE(resource1->isLoaded()); EXPECT_FALSE(resource1->errorOccurred()); // Set the context as it is on reloads. context->setLoadComplete(true); context->setCachePolicy(CachePolicyRevalidate); // Revalidate the resource. ResourceRequest request2(url); FetchRequest fetchRequest2 = FetchRequest(request2, FetchInitiatorInfo()); Resource* resource2 = FontResource::fetch(fetchRequest2, fetcher); ASSERT_TRUE(resource2); EXPECT_EQ(resource1, resource2); EXPECT_TRUE(resource2->isCacheValidator()); EXPECT_TRUE(resource2->stillNeedsLoad()); // Fetch the same resource again before actual load operation starts. ResourceRequest request3(url); FetchRequest fetchRequest3 = FetchRequest(request3, FetchInitiatorInfo()); Resource* resource3 = FontResource::fetch(fetchRequest3, fetcher); ASSERT_TRUE(resource3); EXPECT_EQ(resource2, resource3); EXPECT_TRUE(resource3->isCacheValidator()); EXPECT_TRUE(resource3->stillNeedsLoad()); // startLoad() can be called from any initiator. Here, call it from the // latter. fetcher->startLoad(resource3); Platform::current()->getURLLoaderMockFactory()->serveAsynchronousRequests(); EXPECT_TRUE(resource3->isLoaded()); EXPECT_FALSE(resource3->errorOccurred()); EXPECT_TRUE(resource2->isLoaded()); EXPECT_FALSE(resource2->errorOccurred()); memoryCache()->remove(resource1); }
bool TextTrackLoader::load(const KURL& url, const AtomicString& crossOriginMode) { cancelLoad(); FetchRequest cueRequest(ResourceRequest(m_document.completeURL(url)), FetchInitiatorTypeNames::texttrack); if (!crossOriginMode.isNull()) { cueRequest.setCrossOriginAccessControl(m_document.securityOrigin(), crossOriginMode); } else if (!m_document.securityOrigin()->canRequest(url)) { // Text track elements without 'crossorigin' set on the parent are "No CORS"; report error if not same-origin. corsPolicyPreventedLoad(m_document.securityOrigin(), url); return false; } ResourceFetcher* fetcher = m_document.fetcher(); setResource(fetcher->fetchRawResource(cueRequest)); return resource(); }
void SVGFontFaceUriElement::loadFont() { if (m_resource) m_resource->removeClient(this); const AtomicString& href = getAttribute(XLinkNames::hrefAttr); if (!href.isNull()) { ResourceFetcher* fetcher = document().fetcher(); FetchRequest request(ResourceRequest(document().completeURL(href)), localName()); m_resource = fetcher->fetchFont(request); if (m_resource) { m_resource->addClient(this); m_resource->beginLoadIfNeeded(fetcher); } } else { m_resource = 0; } }
void StyleRuleImport::requestStyleSheet() { if (!m_parentStyleSheet) return; Document* document = m_parentStyleSheet->singleOwnerDocument(); if (!document) return; ResourceFetcher* fetcher = document->fetcher(); if (!fetcher) return; KURL absURL; if (!m_parentStyleSheet->baseURL().isNull()) // use parent styleheet's URL as the base URL absURL = KURL(m_parentStyleSheet->baseURL(), m_strHref); else absURL = document->completeURL(m_strHref); // Check for a cycle in our import chain. If we encounter a stylesheet // in our parent chain with the same URL, then just bail. StyleSheetContents* rootSheet = m_parentStyleSheet; for (StyleSheetContents* sheet = m_parentStyleSheet; sheet; sheet = sheet->parentStyleSheet()) { if (equalIgnoringFragmentIdentifier(absURL, sheet->baseURL()) || equalIgnoringFragmentIdentifier(absURL, document->completeURL(sheet->originalURL()))) return; rootSheet = sheet; } FetchRequest request(ResourceRequest(absURL), FetchInitiatorTypeNames::css, m_parentStyleSheet->charset()); if (m_parentStyleSheet->isUserStyleSheet()) m_resource = fetcher->requestUserCSSStyleSheet(request); else m_resource = fetcher->requestCSSStyleSheet(request); if (m_resource) { // if the import rule is issued dynamically, the sheet may be // removed from the pending sheet count, so let the doc know // the sheet being imported is pending. if (m_parentStyleSheet && m_parentStyleSheet->loadCompleted() && rootSheet == m_parentStyleSheet) m_parentStyleSheet->startLoadingDynamicSheet(); m_loading = true; m_resource->addClient(&m_styleSheetClient); } }
TEST_F(ResourceFetcherTest, StartLoadAfterFrameDetach) { KURL secureURL(ParsedURLString, "https://secureorigin.test/image.png"); // Try to request a url. The request should fail, and a resource in an error // state should be returned, and no resource should be present in the cache. ResourceFetcher* fetcher = ResourceFetcher::create(nullptr); ResourceRequest resourceRequest(secureURL); resourceRequest.setRequestContext(WebURLRequest::RequestContextInternal); FetchRequest fetchRequest = FetchRequest(resourceRequest, FetchInitiatorInfo()); Resource* resource = RawResource::fetch(fetchRequest, fetcher); ASSERT_TRUE(resource); EXPECT_TRUE(resource->errorOccurred()); EXPECT_TRUE(resource->resourceError().isAccessCheck()); EXPECT_FALSE(memoryCache()->resourceForURL(secureURL)); // Start by calling startLoad() directly, rather than via requestResource(). // This shouldn't crash. fetcher->startLoad(RawResource::create(secureURL, Resource::Raw)); }
void CSSFontSelector::clearDocument() { if (!m_document) { ASSERT(!m_beginLoadingTimer.isActive()); ASSERT(m_fontsToBeginLoading.isEmpty()); return; } m_beginLoadingTimer.stop(); ResourceFetcher* fetcher = m_document->fetcher(); for (size_t i = 0; i < m_fontsToBeginLoading.size(); ++i) { // Balances incrementRequestCount() in beginLoadingFontSoon(). fetcher->decrementRequestCount(m_fontsToBeginLoading[i].get()); } m_fontsToBeginLoading.clear(); m_document = 0; }
void CSSFontSelector::beginLoadTimerFired(Timer<WebCore::CSSFontSelector>*) { Vector<ResourcePtr<FontResource> > fontsToBeginLoading; fontsToBeginLoading.swap(m_fontsToBeginLoading); // CSSFontSelector could get deleted via beginLoadIfNeeded() or loadDone() unless protected. RefPtr<CSSFontSelector> protect(this); ResourceFetcher* fetcher = m_document->fetcher(); for (size_t i = 0; i < fontsToBeginLoading.size(); ++i) { fontsToBeginLoading[i]->beginLoadIfNeeded(fetcher); // Balances incrementRequestCount() in beginLoadingFontSoon(). fetcher->decrementRequestCount(fontsToBeginLoading[i].get()); } // Ensure that if the request count reaches zero, the frame loader will know about it. fetcher->didLoadResource(0); // New font loads may be triggered by layout after the document load is complete but before we have dispatched // didFinishLoading for the frame. Make sure the delegate is always dispatched by checking explicitly. if (m_document && m_document->frame()) m_document->frame()->loader()->checkLoadComplete(); }
TEST_F(ResourceFetcherTest, LinkPreloadImageAndUse) { ResourceFetcher* fetcher = ResourceFetcher::create(ResourceFetcherTestMockFetchContext::create()); KURL url(ParsedURLString, "http://127.0.0.1:8000/foo.png"); URLTestHelpers::registerMockedURLLoad(url, testImageFilename, "image/png"); // Link preload preload scanner FetchRequest fetchRequestOriginal = FetchRequest(url, FetchInitiatorInfo()); fetchRequestOriginal.setLinkPreload(true); Resource* resource = ImageResource::fetch(fetchRequestOriginal, fetcher); ASSERT_TRUE(resource); EXPECT_TRUE(resource->isLinkPreload()); Platform::current()->getURLLoaderMockFactory()->serveAsynchronousRequests(); fetcher->preloadStarted(resource); // Image preload scanner FetchRequest fetchRequestPreloadScanner = FetchRequest(url, FetchInitiatorInfo()); Resource* imgPreloadScannerResource = ImageResource::fetch(fetchRequestPreloadScanner, fetcher); EXPECT_EQ(resource, imgPreloadScannerResource); EXPECT_FALSE(resource->isLinkPreload()); fetcher->preloadStarted(resource); // Image created by parser FetchRequest fetchRequest = FetchRequest(url, FetchInitiatorInfo()); Resource* newResource = ImageResource::fetch(fetchRequest, fetcher); Persistent<MockResourceClient> client = new MockResourceClient(newResource); EXPECT_EQ(resource, newResource); EXPECT_FALSE(resource->isLinkPreload()); // DCL reached fetcher->clearPreloads(ResourceFetcher::ClearSpeculativeMarkupPreloads); Platform::current()->getURLLoaderMockFactory()->unregisterURL(url); EXPECT_TRUE(memoryCache()->contains(resource)); EXPECT_FALSE(resource->isPreloaded()); }
TEST_F(ResourceFetcherTest, PreloadImageTwice) { ResourceFetcher* fetcher = ResourceFetcher::create(ResourceFetcherTestMockFetchContext::create()); KURL url(ParsedURLString, "http://127.0.0.1:8000/foo.png"); URLTestHelpers::registerMockedURLLoad(url, testImageFilename, "image/png"); FetchRequest fetchRequestOriginal = FetchRequest(url, FetchInitiatorInfo()); Resource* resource = ImageResource::fetch(fetchRequestOriginal, fetcher); ASSERT_TRUE(resource); Platform::current()->getURLLoaderMockFactory()->serveAsynchronousRequests(); fetcher->preloadStarted(resource); FetchRequest fetchRequest = FetchRequest(url, FetchInitiatorInfo()); Resource* newResource = ImageResource::fetch(fetchRequest, fetcher); EXPECT_EQ(resource, newResource); fetcher->preloadStarted(resource); fetcher->clearPreloads(ResourceFetcher::ClearAllPreloads); Platform::current()->getURLLoaderMockFactory()->unregisterURL(url); EXPECT_FALSE(memoryCache()->contains(resource)); EXPECT_FALSE(resource->isPreloaded()); }
TEST(ImageResourceTest, MultipartImage) { ResourceFetcher* fetcher = ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); KURL testURL(ParsedURLString, "http://www.test.com/cancelTest.html"); ScopedRegisteredURL scopedRegisteredURL(testURL); // Emulate starting a real load, but don't expect any "real" // WebURLLoaderClient callbacks. ImageResource* cachedImage = ImageResource::create(ResourceRequest(testURL)); cachedImage->setIdentifier(createUniqueIdentifier()); fetcher->startLoad(cachedImage); Persistent<MockImageResourceClient> client = new MockImageResourceClient(cachedImage); EXPECT_EQ(Resource::Pending, cachedImage->getStatus()); // Send the multipart response. No image or data buffer is created. Note that // the response must be routed through ResourceLoader to ensure the load is // flagged as multipart. ResourceResponse multipartResponse(KURL(), "multipart/x-mixed-replace", 0, nullAtom, String()); multipartResponse.setMultipartBoundary("boundary", strlen("boundary")); cachedImage->loader()->didReceiveResponse( nullptr, WrappedResourceResponse(multipartResponse), nullptr); EXPECT_FALSE(cachedImage->resourceBuffer()); EXPECT_FALSE(cachedImage->hasImage()); EXPECT_EQ(0, client->imageChangedCount()); EXPECT_FALSE(client->notifyFinishedCalled()); EXPECT_EQ("multipart/x-mixed-replace", cachedImage->response().mimeType()); const char firstPart[] = "--boundary\n" "Content-Type: image/svg+xml\n\n"; cachedImage->appendData(firstPart, strlen(firstPart)); // Send the response for the first real part. No image or data buffer is // created. EXPECT_FALSE(cachedImage->resourceBuffer()); EXPECT_FALSE(cachedImage->hasImage()); EXPECT_EQ(0, client->imageChangedCount()); EXPECT_FALSE(client->notifyFinishedCalled()); EXPECT_EQ("image/svg+xml", cachedImage->response().mimeType()); const char secondPart[] = "<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1'><rect " "width='1' height='1' fill='green'/></svg>\n"; // The first bytes arrive. The data buffer is created, but no image is // created. cachedImage->appendData(secondPart, strlen(secondPart)); EXPECT_TRUE(cachedImage->resourceBuffer()); EXPECT_FALSE(cachedImage->hasImage()); EXPECT_EQ(0, client->imageChangedCount()); EXPECT_FALSE(client->notifyFinishedCalled()); // Add a client to check an assertion error doesn't happen // (crbug.com/630983). Persistent<MockImageResourceClient> client2 = new MockImageResourceClient(cachedImage); EXPECT_EQ(0, client2->imageChangedCount()); EXPECT_FALSE(client2->notifyFinishedCalled()); const char thirdPart[] = "--boundary"; cachedImage->appendData(thirdPart, strlen(thirdPart)); ASSERT_TRUE(cachedImage->resourceBuffer()); EXPECT_EQ(strlen(secondPart) - 1, cachedImage->resourceBuffer()->size()); // This part finishes. The image is created, callbacks are sent, and the data // buffer is cleared. cachedImage->loader()->didFinishLoading(nullptr, 0.0, 0); EXPECT_TRUE(cachedImage->resourceBuffer()); EXPECT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); EXPECT_FALSE(cachedImage->getImage()->isNull()); EXPECT_EQ(1, cachedImage->getImage()->width()); EXPECT_EQ(1, cachedImage->getImage()->height()); EXPECT_EQ(1, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_EQ(1, client2->imageChangedCount()); EXPECT_TRUE(client2->notifyFinishedCalled()); }