Link preload HTMLPreloadScanner support
authoryoav@yoav.ws <yoav@yoav.ws@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 May 2017 21:55:25 +0000 (21:55 +0000)
committeryoav@yoav.ws <yoav@yoav.ws@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 May 2017 21:55:25 +0000 (21:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170747

Reviewed by Youenn Fablet.

Source/WebCore:

Test: http/tests/preload/preloadscanner_download_resources.html

* html/parser/HTMLPreloadScanner.cpp:
(WebCore::TokenPreloadScanner::StartTagScanner::StartTagScanner): Initialize link preload flag.
(WebCore::TokenPreloadScanner::StartTagScanner::createPreloadRequest): Create a request only if the type is known (so ignore
preloads with unknown type).
(WebCore::TokenPreloadScanner::StartTagScanner::processAttribute): Add handling for link preload and the `as` attribute.
(WebCore::TokenPreloadScanner::StartTagScanner::relAttributeIsStyleSheet): Get LinkRelAttribute as input.
(WebCore::TokenPreloadScanner::StartTagScanner::resourceType): Return an std::optional, in case the preload type is unknown.
(WebCore::TokenPreloadScanner::StartTagScanner::shouldPreload): Return true for the link preload case.
* loader/cache/CachedResourceLoader.cpp:
(WebCore::CachedResourceLoader::preload): Return the resource rather than a nullptr if it's already in m_preloads.

LayoutTests:

* http/tests/preload/preloadscanner_download_resources-expected.txt: Added.
* http/tests/preload/preloadscanner_download_resources.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@216143 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/http/tests/preload/preloadscanner_download_resources-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/preload/preloadscanner_download_resources.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/html/parser/HTMLPreloadScanner.cpp
Source/WebCore/loader/cache/CachedResourceLoader.cpp

index 4660ce1..93be7ec 100644 (file)
@@ -1,3 +1,13 @@
+2017-05-03  Yoav Weiss  <yoav@yoav.ws>
+
+        Link preload HTMLPreloadScanner support
+        https://bugs.webkit.org/show_bug.cgi?id=170747
+
+        Reviewed by Youenn Fablet.
+
+        * http/tests/preload/preloadscanner_download_resources-expected.txt: Added.
+        * http/tests/preload/preloadscanner_download_resources.html: Added.
+
 2017-05-03  Ryan Haddad  <ryanhaddad@apple.com>
 
         Mark http/tests/preload/single_download_preload.html as flaky.
diff --git a/LayoutTests/http/tests/preload/preloadscanner_download_resources-expected.txt b/LayoutTests/http/tests/preload/preloadscanner_download_resources-expected.txt
new file mode 100644 (file)
index 0000000..942f401
--- /dev/null
@@ -0,0 +1,12 @@
+PASS internals.isPreloaded('../resources/dummy.js'); is true
+PASS internals.isPreloaded('../resources/dummy.css'); is true
+PASS internals.isPreloaded('../resources/square.png'); is true
+PASS internals.isPreloaded('../resources/Ahem.ttf'); is true
+PASS internals.isPreloaded('../resources/test.mp4'); is true
+PASS internals.isPreloaded('../security/resources/captions.vtt'); is true
+PASS internals.isPreloaded('../resources/dummy.xml?badvalue'); is false
+PASS internals.isPreloaded('../resources/dummy.xml'); is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/preload/preloadscanner_download_resources.html b/LayoutTests/http/tests/preload/preloadscanner_download_resources.html
new file mode 100644 (file)
index 0000000..8bfb52e
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<script src="/js-test-resources/js-test.js"></script>
+<script src="http://127.0.0.1:8000/resources/slow-script.pl?delay=800"></script>
+<div id=result></div>
+<script>
+    if (window.testRunner)
+        testRunner.dumpAsText();
+    (function () {
+         if (!window.internals) {
+            document.getElementById("result").innerHTML = "This test needs to be run in the TestRunner environment, since it relies on the `internals` interface.";
+            return;
+        }
+        shouldBeTrue("internals.isPreloaded('../resources/dummy.js');");
+        shouldBeTrue("internals.isPreloaded('../resources/dummy.css');");
+        shouldBeTrue("internals.isPreloaded('../resources/square.png');");
+        shouldBeTrue("internals.isPreloaded('../resources/Ahem.ttf');");
+        shouldBeTrue("internals.isPreloaded('../resources/test.mp4');");
+        shouldBeTrue("internals.isPreloaded('../security/resources/captions.vtt');");
+        shouldBeFalse("internals.isPreloaded('../resources/dummy.xml?badvalue');");
+        shouldBeTrue("internals.isPreloaded('../resources/dummy.xml');");
+        document.write("<!" + "--");
+    })();
+</script>
+<link rel=preload href="../resources/dummy.js" as=script>
+<link rel=preload href="../resources/dummy.css" as=style>
+<link rel=preload href="../resources/square.png" as=image>
+<link rel=preload href="../resources/Ahem.ttf" as=font crossorigin>
+<link rel=preload href="../resources/test.mp4" as=media>
+<link rel=preload href="../security/resources/captions.vtt" as=track>
+<link rel=preload href="../resources/dummy.xml?badvalue" as=foobarxmlthing>
+<link rel=preload href="../resources/dummy.xml">
index cb9125b..467d3e5 100644 (file)
@@ -1,3 +1,23 @@
+2017-05-03  Yoav Weiss  <yoav@yoav.ws>
+
+        Link preload HTMLPreloadScanner support
+        https://bugs.webkit.org/show_bug.cgi?id=170747
+
+        Reviewed by Youenn Fablet.
+
+        Test: http/tests/preload/preloadscanner_download_resources.html
+
+        * html/parser/HTMLPreloadScanner.cpp:
+        (WebCore::TokenPreloadScanner::StartTagScanner::StartTagScanner): Initialize link preload flag.
+        (WebCore::TokenPreloadScanner::StartTagScanner::createPreloadRequest): Create a request only if the type is known (so ignore
+        preloads with unknown type).
+        (WebCore::TokenPreloadScanner::StartTagScanner::processAttribute): Add handling for link preload and the `as` attribute.
+        (WebCore::TokenPreloadScanner::StartTagScanner::relAttributeIsStyleSheet): Get LinkRelAttribute as input.
+        (WebCore::TokenPreloadScanner::StartTagScanner::resourceType): Return an std::optional, in case the preload type is unknown.
+        (WebCore::TokenPreloadScanner::StartTagScanner::shouldPreload): Return true for the link preload case.
+        * loader/cache/CachedResourceLoader.cpp:
+        (WebCore::CachedResourceLoader::preload): Return the resource rather than a nullptr if it's already in m_preloads.
+
 2017-05-03  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         YouTube user agent quirk breaks new YouTube
index 2022bd2..91968dc 100644 (file)
@@ -33,6 +33,7 @@
 #include "HTMLSrcsetParser.h"
 #include "HTMLTokenizer.h"
 #include "InputTypeNames.h"
+#include "LinkLoader.h"
 #include "LinkRelAttribute.h"
 #include "MediaList.h"
 #include "MediaQueryEvaluator.h"
@@ -100,6 +101,7 @@ public:
     explicit StartTagScanner(TagId tagId, float deviceScaleFactor = 1.0)
         : m_tagId(tagId)
         , m_linkIsStyleSheet(false)
+        , m_linkIsPreload(false)
         , m_metaIsViewport(false)
         , m_inputIsImage(false)
         , m_deviceScaleFactor(deviceScaleFactor)
@@ -144,7 +146,10 @@ public:
         if (!shouldPreload())
             return nullptr;
 
-        auto request = std::make_unique<PreloadRequest>(initiatorFor(m_tagId), m_urlToLoad, predictedBaseURL, resourceType(), m_mediaAttribute, m_moduleScript);
+        auto type = resourceType();
+        if (!type)
+            return nullptr;
+        auto request = std::make_unique<PreloadRequest>(initiatorFor(m_tagId), m_urlToLoad, predictedBaseURL, type.value(), m_mediaAttribute, m_moduleScript);
         request->setCrossOriginMode(m_crossOriginMode);
         request->setNonce(m_nonceAttribute);
 
@@ -220,9 +225,11 @@ private:
         case TagId::Link:
             if (match(attributeName, hrefAttr))
                 setUrlToLoad(attributeValue);
-            else if (match(attributeName, relAttr))
-                m_linkIsStyleSheet = relAttributeIsStyleSheet(attributeValue);
-            else if (match(attributeName, mediaAttr))
+            else if (match(attributeName, relAttr)) {
+                LinkRelAttribute parsedAttribute { attributeValue };
+                m_linkIsStyleSheet = relAttributeIsStyleSheet(parsedAttribute);
+                m_linkIsPreload = parsedAttribute.isLinkPreload;
+            } else if (match(attributeName, mediaAttr))
                 m_mediaAttribute = attributeValue;
             else if (match(attributeName, charsetAttr))
                 m_charset = attributeValue;
@@ -230,6 +237,8 @@ private:
                 m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeValue);
             else if (match(attributeName, nonceAttr))
                 m_nonceAttribute = attributeValue;
+            else if (match(attributeName, asAttr))
+                m_asAttribute = attributeValue;
             break;
         case TagId::Input:
             if (match(attributeName, srcAttr))
@@ -252,9 +261,8 @@ private:
         }
     }
 
-    static bool relAttributeIsStyleSheet(const String& attributeValue)
+    static bool relAttributeIsStyleSheet(const LinkRelAttribute& parsedAttribute)
     {
-        LinkRelAttribute parsedAttribute { attributeValue };
         return parsedAttribute.isStyleSheet && !parsedAttribute.isAlternate && !parsedAttribute.iconType && !parsedAttribute.isDNSPrefetch;
     }
 
@@ -275,7 +283,7 @@ private:
         return m_charset;
     }
 
-    CachedResource::Type resourceType() const
+    std::optional<CachedResource::Type> resourceType() const
     {
         switch (m_tagId) {
         case TagId::Script:
@@ -286,8 +294,11 @@ private:
             ASSERT(m_tagId != TagId::Input || m_inputIsImage);
             return CachedResource::ImageResource;
         case TagId::Link:
-            ASSERT(m_linkIsStyleSheet);
-            return CachedResource::CSSStyleSheet;
+            if (m_linkIsStyleSheet)
+                return CachedResource::CSSStyleSheet;
+            if (m_linkIsPreload)
+                return LinkLoader::resourceTypeFromAsAttribute(m_asAttribute);
+            break;
         case TagId::Meta:
         case TagId::Unknown:
         case TagId::Style:
@@ -308,7 +319,7 @@ private:
         if (protocolIs(m_urlToLoad, "data") || protocolIs(m_urlToLoad, "about"))
             return false;
 
-        if (m_tagId == TagId::Link && !m_linkIsStyleSheet)
+        if (m_tagId == TagId::Link && !m_linkIsStyleSheet && !m_linkIsPreload)
             return false;
 
         if (m_tagId == TagId::Input && !m_inputIsImage)
@@ -325,9 +336,11 @@ private:
     String m_charset;
     String m_crossOriginMode;
     bool m_linkIsStyleSheet;
+    bool m_linkIsPreload;
     String m_mediaAttribute;
     String m_nonceAttribute;
     String m_metaContent;
+    String m_asAttribute;
     bool m_metaIsViewport;
     bool m_inputIsImage;
     float m_deviceScaleFactor;
index f54d041..1a5086f 100644 (file)
@@ -1222,17 +1222,16 @@ CachedResourceHandle<CachedResource> CachedResourceLoader::preload(CachedResourc
         request.setCharset(m_document->charset());
 
     CachedResourceHandle<CachedResource> resource = requestResource(type, WTFMove(request), ForPreload::Yes);
-    if (!resource || (m_preloads && m_preloads->contains(resource.get())))
-        return nullptr;
-    // Fonts need special treatment since just creating the resource doesn't trigger a load.
-    if (type == CachedResource::FontResource)
-        downcast<CachedFont>(resource.get())->beginLoadIfNeeded(*this);
-    resource->increasePreloadCount();
-
-    if (!m_preloads)
-        m_preloads = std::make_unique<ListHashSet<CachedResource*>>();
-    m_preloads->add(resource.get());
-
+    if (resource && (!m_preloads || !m_preloads->contains(resource.get()))) {
+        // Fonts need special treatment since just creating the resource doesn't trigger a load.
+        if (type == CachedResource::FontResource)
+            downcast<CachedFont>(resource.get())->beginLoadIfNeeded(*this);
+        resource->increasePreloadCount();
+
+        if (!m_preloads)
+            m_preloads = std::make_unique<ListHashSet<CachedResource*>>();
+        m_preloads->add(resource.get());
+    }
     return resource;
 }