TEST(LinkHeaderTest, Double) { struct DoubleTestCase { const char* headerValue; const char* url; const char* rel; bool valid; const char* url2; const char* rel2; bool valid2; } cases[] = { {"<ybg.css>; rel=stylesheet, <simple.css>; rel=stylesheet", "ybg.css", "stylesheet", true, "simple.css", "stylesheet", true}, }; for (auto& testCase : cases) { LinkHeaderSet headerSet(testCase.headerValue); LinkHeader& header1 = headerSet[0]; LinkHeader& header2 = headerSet[1]; ASSERT_STREQ(testCase.url, header1.url().ascii().data()); ASSERT_STREQ(testCase.rel, header1.rel().ascii().data()); ASSERT_EQ(testCase.valid, header1.valid()); ASSERT_STREQ(testCase.url2, header2.url().ascii().data()); ASSERT_STREQ(testCase.rel2, header2.rel().ascii().data()); ASSERT_EQ(testCase.valid2, header2.valid()); } }
bool LinkLoader::loadLinkFromHeader(const String& headerValue, const KURL& baseURL, Document* document, const NetworkHintsInterface& networkHintsInterface, CanLoadResources canLoadResources) { if (!document) return false; LinkHeaderSet headerSet(headerValue); for (auto& header : headerSet) { if (!header.valid() || header.url().isEmpty() || header.rel().isEmpty()) return false; LinkRelAttribute relAttribute(header.rel()); KURL url(baseURL, header.url()); if (canLoadResources != OnlyLoadResources) { if (RuntimeEnabledFeatures::linkHeaderEnabled()) dnsPrefetchIfNeeded(relAttribute, url, *document, networkHintsInterface, LinkCalledFromHeader); if (RuntimeEnabledFeatures::linkPreconnectEnabled()) preconnectIfNeeded(relAttribute, url, *document, header.crossOrigin(), networkHintsInterface, LinkCalledFromHeader); } if (canLoadResources != DoNotLoadResources) { bool errorOccurred = false; if (RuntimeEnabledFeatures::linkPreloadEnabled()) preloadIfNeeded(relAttribute, url, *document, header.as(), header.mimeType(), header.crossOrigin(), LinkCalledFromHeader, errorOccurred); } // TODO(yoav): Add more supported headers as needed. } return true; }
TEST(LinkHeaderTest, CrossOrigin) { struct TestCase { const char* headerValue; const char* url; const char* rel; const CrossOriginAttributeValue crossorigin; bool valid; } cases[] = { {"<http://whatever.com>; rel=preconnect", "http://whatever.com", "preconnect", CrossOriginAttributeNotSet, true}, {"<http://whatever.com>; rel=preconnect; crossorigin=", "http://whatever.com", "preconnect", CrossOriginAttributeAnonymous, true}, {"<http://whatever.com>; rel=preconnect; crossorigin", "http://whatever.com", "preconnect", CrossOriginAttributeAnonymous, true}, {"<http://whatever.com>; rel=preconnect; crossorigin=anonymous", "http://whatever.com", "preconnect", CrossOriginAttributeAnonymous, true}, {"<http://whatever.com>; rel=preconnect; crossorigin=use-credentials", "http://whatever.com", "preconnect", CrossOriginAttributeUseCredentials, true}, {"<http://whatever.com>; rel=preconnect; crossorigin=whatever", "http://whatever.com", "preconnect", CrossOriginAttributeAnonymous, true}, }; // Test the cases with a single header for (auto& testCase : cases) { LinkHeaderSet headerSet(testCase.headerValue); LinkHeader& header = headerSet[0]; ASSERT_STREQ(testCase.url, header.url().ascii().data()); ASSERT_STREQ(testCase.rel, header.rel().ascii().data()); ASSERT_EQ(testCase.crossorigin, header.crossOrigin()); ASSERT_EQ(testCase.valid, header.valid()); } }
void LinkLoader::loadLinksFromHeader(const String& headerValue, const KURL& baseURL, Document* document, const NetworkHintsInterface& networkHintsInterface, CanLoadResources canLoadResources, ViewportDescriptionWrapper* viewportDescriptionWrapper) { if (!document || headerValue.isEmpty()) return; LinkHeaderSet headerSet(headerValue); for (auto& header : headerSet) { if (!header.valid() || header.url().isEmpty() || header.rel().isEmpty()) continue; LinkRelAttribute relAttribute(header.rel()); KURL url(baseURL, header.url()); if (canLoadResources != OnlyLoadResources) { if (RuntimeEnabledFeatures::linkHeaderEnabled()) dnsPrefetchIfNeeded(relAttribute, url, *document, networkHintsInterface, LinkCalledFromHeader); if (RuntimeEnabledFeatures::linkPreconnectEnabled()) preconnectIfNeeded(relAttribute, url, *document, crossOriginAttributeValue(header.crossOrigin()), networkHintsInterface, LinkCalledFromHeader); } if (canLoadResources != DoNotLoadResources) { bool errorOccurred = false; if (RuntimeEnabledFeatures::linkPreloadEnabled()) { ViewportDescription* viewportDescription = (viewportDescriptionWrapper && viewportDescriptionWrapper->set) ? &(viewportDescriptionWrapper->description) : nullptr; preloadIfNeeded(relAttribute, url, *document, header.as(), header.mimeType(), header.media(), crossOriginAttributeValue(header.crossOrigin()), LinkCalledFromHeader, errorOccurred, viewportDescription); } } // TODO(yoav): Add more supported headers as needed. } }
void LinkLoader::loadLinksFromHeader( const String& headerValue, const KURL& baseURL, Document* document, const NetworkHintsInterface& networkHintsInterface, CanLoadResources canLoadResources, MediaPreloadPolicy mediaPolicy, ViewportDescriptionWrapper* viewportDescriptionWrapper) { if (!document || headerValue.isEmpty()) return; LinkHeaderSet headerSet(headerValue); for (auto& header : headerSet) { if (!header.valid() || header.url().isEmpty() || header.rel().isEmpty()) continue; if (mediaPolicy == OnlyLoadMedia && header.media().isEmpty()) continue; if (mediaPolicy == OnlyLoadNonMedia && !header.media().isEmpty()) continue; LinkRelAttribute relAttribute(header.rel()); KURL url(baseURL, header.url()); // Sanity check to avoid re-entrancy here. if (url == baseURL) continue; if (canLoadResources != OnlyLoadResources) { dnsPrefetchIfNeeded(relAttribute, url, *document, networkHintsInterface, LinkCalledFromHeader); preconnectIfNeeded(relAttribute, url, *document, crossOriginAttributeValue(header.crossOrigin()), networkHintsInterface, LinkCalledFromHeader); } if (canLoadResources != DoNotLoadResources) { bool errorOccurred = false; ViewportDescription* viewportDescription = (viewportDescriptionWrapper && viewportDescriptionWrapper->set) ? &(viewportDescriptionWrapper->description) : nullptr; preloadIfNeeded(relAttribute, url, *document, header.as(), header.mimeType(), header.media(), crossOriginAttributeValue(header.crossOrigin()), LinkCalledFromHeader, errorOccurred, viewportDescription, ReferrerPolicyDefault); } if (relAttribute.isServiceWorker()) { UseCounter::count(*document, UseCounter::LinkHeaderServiceWorker); } // TODO(yoav): Add more supported headers as needed. } }
bool LinkLoader::loadLinkFromHeader(const String& headerValue, Document* document) { if (!document) return false; LinkHeaderSet headerSet(headerValue); for (auto& header : headerSet) { if (!header.valid() || header.url().isEmpty() || header.rel().isEmpty()) return false; LinkRelAttribute relAttribute(header.rel()); KURL url = document->completeURL(header.url()); if (RuntimeEnabledFeatures::linkHeaderEnabled()) dnsPrefetchIfNeeded(relAttribute, url, *document); if (RuntimeEnabledFeatures::linkPreconnectEnabled()) preconnectIfNeeded(relAttribute, url, *document, header.crossOrigin()); // FIXME: Add more supported headers as needed. } return true; }
TEST(LinkHeaderTest, Single) { struct TestCase { const char* headerValue; const char* url; const char* rel; bool valid; } cases[] = { {"</images/cat.jpg>; rel=prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>;rel=prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg> ;rel=prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg> ; rel=prefetch", "/images/cat.jpg", "prefetch", true}, {"< /images/cat.jpg> ; rel=prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg > ; rel=prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg wutwut> ; rel=prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg wutwut \t > ; rel=prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>; rel=prefetch ", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>; Rel=prefetch ", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>; Rel=PReFetCh ", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>; rel=prefetch; rel=somethingelse", "/images/cat.jpg", "prefetch", true}, {" </images/cat.jpg>; rel=prefetch ", "/images/cat.jpg", "prefetch", true}, {"\t </images/cat.jpg>; rel=prefetch ", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>\t\t ; \trel=prefetch \t ", "/images/cat.jpg", "prefetch", true}, {"\f</images/cat.jpg>\t\t ; \trel=prefetch \t ", "", "", false}, {"</images/cat.jpg>; rel= prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>; rel =prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>; rel pel=prefetch", "/images/cat.jpg", "", false}, {"< /images/cat.jpg>", "/images/cat.jpg", "", true}, {"</images/cat.jpg>; rel =", "/images/cat.jpg", "", false}, {"</images/cat.jpg>; wut=sup; rel =prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>; wut=sup ; rel =prefetch", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>; wut=sup ; rel =prefetch \t ;", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg> wut=sup ; rel =prefetch \t ;", "/images/cat.jpg", "", false}, {"< /images/cat.jpg", "", "", false}, {"< http://wut.com/ sdfsdf ?sd>; rel=dns-prefetch", "http://wut.com/", "dns-prefetch", true}, {"< http://wut.com/%20%20%3dsdfsdf?sd>; rel=dns-prefetch", "http://wut.com/%20%20%3dsdfsdf?sd", "dns-prefetch", true}, {"< http://wut.com/dfsdf?sdf=ghj&wer=rty>; rel=prefetch", "http://wut.com/dfsdf?sdf=ghj&wer=rty", "prefetch", true}, {"< http://wut.com/dfsdf?sdf=ghj&wer=rty>;;;;; rel=prefetch", "http://wut.com/dfsdf?sdf=ghj&wer=rty", "", false}, {"</images/cat.jpg>; anchor=foo; rel=prefetch;", "/images/cat.jpg", "", false}, {"</images/cat.jpg>; rel=prefetch;anchor=foo ", "/images/cat.jpg", "prefetch", false}, {"</images/cat.jpg>; anchor='foo'; rel=prefetch;", "/images/cat.jpg", "", false}, {"</images/cat.jpg>; rel=prefetch;anchor='foo' ", "/images/cat.jpg", "prefetch", false}, {"</images/cat.jpg>; rel=prefetch;anchor='' ", "/images/cat.jpg", "prefetch", false}, {"</images/cat.jpg>; rel=prefetch;", "/images/cat.jpg", "prefetch", true}, {"</images/cat.jpg>; rel=prefetch ;", "/images/cat.jpg", "prefetch", true}, {"</images/ca,t.jpg>; rel=prefetch ;", "/images/ca,t.jpg", "prefetch", true}, {"<simple.css>; rel=stylesheet; title=\"title with a DQUOTE and backslash\"", "simple.css", "stylesheet", true}, {"<simple.css>; rel=stylesheet; title=\"title with a DQUOTE \\\" and backslash: \\\"", "simple.css", "stylesheet", false}, {"<simple.css>; title=\"title with a DQUOTE \\\" and backslash: \"; rel=stylesheet; ", "simple.css", "stylesheet", true}, {"<simple.css>; title=\'title with a DQUOTE \\\' and backslash: \'; rel=stylesheet; ", "simple.css", "stylesheet", true}, {"<simple.css>; title=\"title with a DQUOTE \\\" and ;backslash,: \"; rel=stylesheet; ", "simple.css", "stylesheet", true}, {"<simple.css>; title=\"title with a DQUOTE \' and ;backslash,: \"; rel=stylesheet; ", "simple.css", "stylesheet", true}, {"<simple.css>; title=\"\"; rel=stylesheet; ", "simple.css", "stylesheet", true}, {"<simple.css>; title=\"\"; rel=\"stylesheet\"; ", "simple.css", "stylesheet", true}, {"<simple.css>; rel=stylesheet; title=\"", "simple.css", "stylesheet", false}, {"<simple.css>; rel=stylesheet; title=\"\"", "simple.css", "stylesheet", true}, {"<simple.css>; rel=\"stylesheet\"; title=\"", "simple.css", "stylesheet", false}, {"<simple.css>; rel=\";style,sheet\"; title=\"", "simple.css", ";style,sheet", false}, {"<simple.css>; rel=\"bla'sdf\"; title=\"", "simple.css", "bla'sdf", false}, {"<simple.css>; rel=\"\"; title=\"\"", "simple.css", "", true}, {"<simple.css>; rel=''; title=\"\"", "simple.css", "", true}, {"<simple.css>; rel='prefetch", "simple.css", "", false}, {"<simple.css>; rel=\"prefetch", "simple.css", "", false}, {"<simple.css>; rel=\"", "simple.css", "", false}, }; // Test the cases with a single header for (auto& testCase : cases) { LinkHeaderSet headerSet(testCase.headerValue); LinkHeader& header = headerSet[0]; ASSERT_STREQ(testCase.url, header.url().ascii().data()); ASSERT_STREQ(testCase.rel, header.rel().ascii().data()); ASSERT_EQ(testCase.valid, header.valid()); } }