Add support for <link rel=preconnect>
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Sep 2017 17:05:26 +0000 (17:05 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Sep 2017 17:05:26 +0000 (17:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177474
<rdar://problem/33141380>

Reviewed by Alex Christensen.

Source/WebCore:

Add support for <link rel=preconnect>:
- https://w3c.github.io/resource-hints/#preconnect

It is currently only enabled for WK2 on MacOS High Sierra+
and iOS 11+.

Tests: fast/dom/HTMLLinkElement/preconnect-support.html
       http/tests/preconnect/link-rel-preconnect-http.html
       http/tests/preconnect/link-rel-preconnect-https.html

* bindings/js/JSDOMExceptionHandling.h:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateCallbackHeaderContent):
* bindings/scripts/IDLAttributes.json:
* dom/Document.cpp:
(WebCore::Document::addConsoleMessage):
(WebCore::Document::setConsoleMessageListener):
* dom/Document.h:
* dom/StringCallback.idl:
* html/DOMTokenList.cpp:
(WebCore::DOMTokenList::DOMTokenList):
(WebCore::DOMTokenList::supports):
* html/DOMTokenList.h:
(WebCore::DOMTokenList::DOMTokenList):
* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::relList):
* html/HTMLIFrameElement.cpp:
(WebCore::HTMLIFrameElement::sandbox):
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::parseAttribute):
(WebCore::HTMLLinkElement::relList):
* html/LinkRelAttribute.cpp:
(WebCore::LinkRelAttribute::LinkRelAttribute):
(WebCore::LinkRelAttribute::isSupported):
* html/LinkRelAttribute.h:
* html/parser/HTMLPreloadScanner.cpp:
(WebCore::TokenPreloadScanner::StartTagScanner::processAttribute):
* loader/LinkLoader.cpp:
(WebCore::LinkLoader::loadLinksFromHeader):
(WebCore::LinkLoader::loadLink):
* loader/LoaderStrategy.h:
* page/Settings.in:
* testing/Internals.cpp:
(WebCore::Internals::Internals):
(WebCore::Internals::setConsoleMessageListener):
* testing/Internals.h:
* testing/Internals.idl:

Source/WebCore/PAL:

Add new CFNetwork SPI for preconnecting.

* pal/spi/cf/CFNetworkSPI.h:

Source/WebKit:

Add support for <link rel=preconnect>:
- https://w3c.github.io/resource-hints/#preconnect

Also add corresponding native private API.

* NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::preconnectTo):
(WebKit::NetworkConnectionToWebProcess::didFinishPreconnection):
* NetworkProcess/NetworkConnectionToWebProcess.h:
* NetworkProcess/NetworkConnectionToWebProcess.messages.in:
* NetworkProcess/NetworkDataTask.cpp:
(WebKit::NetworkDataTask::create):
* NetworkProcess/NetworkLoadParameters.h:
* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::preconnectTo):
* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
* NetworkProcess/PreconnectTask.cpp: Added.
(WebKit::PreconnectTask::PreconnectTask):
(WebKit::PreconnectTask::~PreconnectTask):
(WebKit::PreconnectTask::willPerformHTTPRedirection):
(WebKit::PreconnectTask::didReceiveChallenge):
(WebKit::PreconnectTask::didReceiveResponseNetworkSession):
(WebKit::PreconnectTask::didReceiveData):
(WebKit::PreconnectTask::didCompleteWithError):
(WebKit::PreconnectTask::didSendData):
(WebKit::PreconnectTask::wasBlocked):
(WebKit::PreconnectTask::cannotShowURL):
(WebKit::PreconnectTask::didFinish):
* NetworkProcess/PreconnectTask.h: Copied from Source/WebKit/NetworkProcess/NetworkLoadParameters.h.
* NetworkProcess/cocoa/NetworkDataTaskCocoa.h:
* NetworkProcess/cocoa/NetworkDataTaskCocoa.mm:
(WebKit::NetworkDataTaskCocoa::NetworkDataTaskCocoa):
* Shared/WebCoreArgumentCoders.h:
* Shared/WebPreferencesDefinitions.h:
* UIProcess/API/C/WKContext.cpp:
(WKContextPreconnectToServer):
* UIProcess/API/C/WKContextPrivate.h:
* UIProcess/API/Cocoa/WKProcessPool.mm:
(-[WKProcessPool _preconnectToServer:]):
* UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::preconnectToServer):
* UIProcess/WebProcessPool.h:
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/Network/NetworkProcessConnection.cpp:
(WebKit::NetworkProcessConnection::didFinishPreconnection):
* WebProcess/Network/NetworkProcessConnection.h:
* WebProcess/Network/NetworkProcessConnection.messages.in:
* WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::WebLoaderStrategy::networkProcessCrashed):
(WebKit::generateLoadIdentifier):
(WebKit::WebLoaderStrategy::startPingLoad):
(WebKit::WebLoaderStrategy::preconnectTo):
(WebKit::WebLoaderStrategy::didFinishPreconnection):
* WebProcess/Network/WebLoaderStrategy.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::updatePreferences):
* config.h:

Source/WebKitLegacy:

* WebCoreSupport/WebResourceLoadScheduler.cpp:
(WebResourceLoadScheduler::preconnectTo):
* WebCoreSupport/WebResourceLoadScheduler.h:

LayoutTests:

* fast/dom/HTMLLinkElement/preconnect-support-expected.txt: Added.
* fast/dom/HTMLLinkElement/preconnect-support.html: Added.
* http/tests/preconnect/link-rel-preconnect-http-expected.txt: Added.
* http/tests/preconnect/link-rel-preconnect-http.html: Added.
* http/tests/preconnect/link-rel-preconnect-https-expected.txt: Added.
* http/tests/preconnect/link-rel-preconnect-https.html: Added.
Add layout test coverage.

* platform/mac-elcapitan-wk2/fast/dom/HTMLLinkElement/preconnect-support-expected.txt: Added.
* platform/mac-wk1/TestExpectations:
* platform/mac-wk1/fast/dom/HTMLLinkElement/preconnect-support-expected.txt: Added.
* platform/mac-wk2/TestExpectations:
Skip or land failure expectations for platforms where the feature is disabled.

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

67 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/HTMLLinkElement/preconnect-support-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/HTMLLinkElement/preconnect-support.html [new file with mode: 0644]
LayoutTests/http/tests/preconnect/link-rel-preconnect-http-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/preconnect/link-rel-preconnect-http.html [new file with mode: 0644]
LayoutTests/http/tests/preconnect/link-rel-preconnect-https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/preconnect/link-rel-preconnect-https.html [new file with mode: 0644]
LayoutTests/platform/mac-elcapitan-wk2/fast/dom/HTMLLinkElement/preconnect-support-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-sierra-wk2/fast/dom/HTMLLinkElement/preconnect-support-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk1/TestExpectations
LayoutTests/platform/mac-wk1/fast/dom/HTMLLinkElement/preconnect-support-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/spi/cf/CFNetworkSPI.h
Source/WebCore/bindings/js/JSDOMExceptionHandling.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/IDLAttributes.json
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/StringCallback.idl
Source/WebCore/html/DOMTokenList.cpp
Source/WebCore/html/DOMTokenList.h
Source/WebCore/html/HTMLAnchorElement.cpp
Source/WebCore/html/HTMLIFrameElement.cpp
Source/WebCore/html/HTMLLinkElement.cpp
Source/WebCore/html/LinkRelAttribute.cpp
Source/WebCore/html/LinkRelAttribute.h
Source/WebCore/html/parser/HTMLPreloadScanner.cpp
Source/WebCore/loader/LinkLoader.cpp
Source/WebCore/loader/LoaderStrategy.h
Source/WebCore/page/Settings.in
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
Source/WebKit/NetworkProcess/NetworkDataTask.cpp
Source/WebKit/NetworkProcess/NetworkLoadParameters.h
Source/WebKit/NetworkProcess/NetworkProcess.cpp
Source/WebKit/NetworkProcess/NetworkProcess.h
Source/WebKit/NetworkProcess/NetworkProcess.messages.in
Source/WebKit/NetworkProcess/PreconnectTask.cpp [new file with mode: 0644]
Source/WebKit/NetworkProcess/PreconnectTask.h [new file with mode: 0644]
Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h
Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
Source/WebKit/Shared/WebCoreArgumentCoders.h
Source/WebKit/Shared/WebPreferencesDefinitions.h
Source/WebKit/UIProcess/API/C/WKContext.cpp
Source/WebKit/UIProcess/API/C/WKContextPrivate.h
Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm
Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/UIProcess/WebProcessPool.h
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp
Source/WebKit/WebProcess/Network/NetworkProcessConnection.h
Source/WebKit/WebProcess/Network/NetworkProcessConnection.messages.in
Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
Source/WebKit/WebProcess/Network/WebLoaderStrategy.h
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/config.h
Source/WebKitLegacy/ChangeLog
Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.cpp
Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.h

index f76861f..a30d2cd 100644 (file)
@@ -1,3 +1,25 @@
+2017-09-28  Chris Dumez  <cdumez@apple.com>
+
+        Add support for <link rel=preconnect>
+        https://bugs.webkit.org/show_bug.cgi?id=177474
+        <rdar://problem/33141380>
+
+        Reviewed by Alex Christensen.
+
+        * fast/dom/HTMLLinkElement/preconnect-support-expected.txt: Added.
+        * fast/dom/HTMLLinkElement/preconnect-support.html: Added.
+        * http/tests/preconnect/link-rel-preconnect-http-expected.txt: Added.
+        * http/tests/preconnect/link-rel-preconnect-http.html: Added.
+        * http/tests/preconnect/link-rel-preconnect-https-expected.txt: Added.
+        * http/tests/preconnect/link-rel-preconnect-https.html: Added.
+        Add layout test coverage.
+
+        * platform/mac-elcapitan-wk2/fast/dom/HTMLLinkElement/preconnect-support-expected.txt: Added.
+        * platform/mac-wk1/TestExpectations:
+        * platform/mac-wk1/fast/dom/HTMLLinkElement/preconnect-support-expected.txt: Added.
+        * platform/mac-wk2/TestExpectations:
+        Skip or land failure expectations for platforms where the feature is disabled.
+
 2017-09-28  Ryan Haddad  <ryanhaddad@apple.com>
 
         Update TestExpectations for two http/tests/xmlhttprequest/response-* tests.
diff --git a/LayoutTests/fast/dom/HTMLLinkElement/preconnect-support-expected.txt b/LayoutTests/fast/dom/HTMLLinkElement/preconnect-support-expected.txt
new file mode 100644 (file)
index 0000000..c5a3f5d
--- /dev/null
@@ -0,0 +1,12 @@
+Tests that Link's rel=preconnect is reported as supported.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS testLink.relList.length is 1
+PASS testLink.relList[0] is "preconnect"
+PASS testLink.relList.supports('preconnect') is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/HTMLLinkElement/preconnect-support.html b/LayoutTests/fast/dom/HTMLLinkElement/preconnect-support.html
new file mode 100644 (file)
index 0000000..b6cd312
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../resources/js-test.js"></script>
+</head>
+<body>
+<script>
+description("Tests that Link's rel=preconnect is reported as supported.");
+
+const testLink = document.createElement("link");
+testLink.rel = "preconnect";
+testLink.href = "http://localhost:8000";
+
+shouldBe("testLink.relList.length", "1");
+shouldBeEqualToString("testLink.relList[0]", "preconnect");
+shouldBeTrue("testLink.relList.supports('preconnect')");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/preconnect/link-rel-preconnect-http-expected.txt b/LayoutTests/http/tests/preconnect/link-rel-preconnect-http-expected.txt
new file mode 100644 (file)
index 0000000..6d0802f
--- /dev/null
@@ -0,0 +1,10 @@
+CONSOLE MESSAGE: Successfuly preconnected to http://localhost:8000/
+Tests that Link's rel=preconnect works as expected over HTTP.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/preconnect/link-rel-preconnect-http.html b/LayoutTests/http/tests/preconnect/link-rel-preconnect-http.html
new file mode 100644 (file)
index 0000000..0b1e432
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="/js-test-resources/js-test.js"></script>
+</head>
+<body>
+<script>
+description("Tests that Link's rel=preconnect works as expected over HTTP.");
+jsTestIsAsync = true;
+
+internals.setConsoleMessageListener(function() {
+    finishJSTest();
+});
+
+const testLink = document.createElement("link");
+testLink.rel = "preconnect";
+testLink.href = "http://localhost:8000";
+document.head.appendChild(testLink);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/preconnect/link-rel-preconnect-https-expected.txt b/LayoutTests/http/tests/preconnect/link-rel-preconnect-https-expected.txt
new file mode 100644 (file)
index 0000000..3c14e23
--- /dev/null
@@ -0,0 +1,10 @@
+CONSOLE MESSAGE: Failed to preconnect to https://localhost:8443/. Error: The certificate for this server is invalid. You might be connecting to a server that is pretending to be “localhost” which could put your confidential information at risk.
+Tests that Link's rel=preconnect works as expected over HTTPS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/preconnect/link-rel-preconnect-https.html b/LayoutTests/http/tests/preconnect/link-rel-preconnect-https.html
new file mode 100644 (file)
index 0000000..efd9400
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="/js-test-resources/js-test.js"></script>
+</head>
+<body>
+<script>
+description("Tests that Link's rel=preconnect works as expected over HTTPS.");
+jsTestIsAsync = true;
+
+internals.setConsoleMessageListener(function() {
+    finishJSTest();
+});
+
+const testLink = document.createElement("link");
+testLink.rel = "preconnect";
+testLink.href = "https://localhost:8443";
+document.head.appendChild(testLink);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-elcapitan-wk2/fast/dom/HTMLLinkElement/preconnect-support-expected.txt b/LayoutTests/platform/mac-elcapitan-wk2/fast/dom/HTMLLinkElement/preconnect-support-expected.txt
new file mode 100644 (file)
index 0000000..3a204d4
--- /dev/null
@@ -0,0 +1,13 @@
+Tests that Link's rel=preconnect is reported as supported.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS testLink.relList.length is 1
+PASS testLink.relList[0] is "preconnect"
+FAIL testLink.relList.supports('preconnect') should be true. Was false.
+PASS successfullyParsed is true
+Some tests failed.
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac-sierra-wk2/fast/dom/HTMLLinkElement/preconnect-support-expected.txt b/LayoutTests/platform/mac-sierra-wk2/fast/dom/HTMLLinkElement/preconnect-support-expected.txt
new file mode 100644 (file)
index 0000000..3a204d4
--- /dev/null
@@ -0,0 +1,13 @@
+Tests that Link's rel=preconnect is reported as supported.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS testLink.relList.length is 1
+PASS testLink.relList[0] is "preconnect"
+FAIL testLink.relList.supports('preconnect') should be true. Was false.
+PASS successfullyParsed is true
+Some tests failed.
+
+TEST COMPLETE
+
index 54fc4ef..65fac87 100644 (file)
@@ -403,6 +403,9 @@ fast/images/low-memory-decode.html [ Skip ]
 
 http/tests/workers/service [ Skip ]
 
+# Link preconnect is disabled on WebKit1 because it does not use NETWORK_SESSION.
+http/tests/preconnect [ Skip ]
+
 webkit.org/b/175345 fast/images/animated-gif-scrolling-crash.html [ Pass Timeout ]
 
 webkit.org/b/175554 [ Sierra ] fullscreen/full-screen-iframe-legacy.html [ Pass Failure ]
diff --git a/LayoutTests/platform/mac-wk1/fast/dom/HTMLLinkElement/preconnect-support-expected.txt b/LayoutTests/platform/mac-wk1/fast/dom/HTMLLinkElement/preconnect-support-expected.txt
new file mode 100644 (file)
index 0000000..3a204d4
--- /dev/null
@@ -0,0 +1,13 @@
+Tests that Link's rel=preconnect is reported as supported.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS testLink.relList.length is 1
+PASS testLink.relList[0] is "preconnect"
+FAIL testLink.relList.supports('preconnect') should be true. Was false.
+PASS successfullyParsed is true
+Some tests failed.
+
+TEST COMPLETE
+
index 07ab468..4da449a 100644 (file)
@@ -793,6 +793,9 @@ webkit.org/b/176122 media/video-controls-drop-and-restore-timeline.html [ Pass F
 # <rdar://problem/33555759>
 [ HighSierra+ ] http/tests/media/video-buffered-range-contains-currentTime.html [ Pass ImageOnlyFailure ]
 
+# Link preconnect is disabled on pre-High Sierra because the CFNetwork SPI is missing.
+[ ElCapitan Sierra ] http/tests/preconnect [ Skip ]
+
 webkit.org/b/176486 [ ElCapitan Debug ] imported/w3c/web-platform-tests/background-fetch/interfaces-worker.https.html [ Pass Failure ]
 
 webkit.org/b/171839 [ Debug ] tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html [ Pass Failure ]
index 14b0f30..fbc38b3 100644 (file)
@@ -1,3 +1,59 @@
+2017-09-28  Chris Dumez  <cdumez@apple.com>
+
+        Add support for <link rel=preconnect>
+        https://bugs.webkit.org/show_bug.cgi?id=177474
+        <rdar://problem/33141380>
+
+        Reviewed by Alex Christensen.
+
+        Add support for <link rel=preconnect>:
+        - https://w3c.github.io/resource-hints/#preconnect
+
+        It is currently only enabled for WK2 on MacOS High Sierra+
+        and iOS 11+.
+
+        Tests: fast/dom/HTMLLinkElement/preconnect-support.html
+               http/tests/preconnect/link-rel-preconnect-http.html
+               http/tests/preconnect/link-rel-preconnect-https.html
+
+        * bindings/js/JSDOMExceptionHandling.h:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateCallbackHeaderContent):
+        * bindings/scripts/IDLAttributes.json:
+        * dom/Document.cpp:
+        (WebCore::Document::addConsoleMessage):
+        (WebCore::Document::setConsoleMessageListener):
+        * dom/Document.h:
+        * dom/StringCallback.idl:
+        * html/DOMTokenList.cpp:
+        (WebCore::DOMTokenList::DOMTokenList):
+        (WebCore::DOMTokenList::supports):
+        * html/DOMTokenList.h:
+        (WebCore::DOMTokenList::DOMTokenList):
+        * html/HTMLAnchorElement.cpp:
+        (WebCore::HTMLAnchorElement::relList):
+        * html/HTMLIFrameElement.cpp:
+        (WebCore::HTMLIFrameElement::sandbox):
+        * html/HTMLLinkElement.cpp:
+        (WebCore::HTMLLinkElement::parseAttribute):
+        (WebCore::HTMLLinkElement::relList):
+        * html/LinkRelAttribute.cpp:
+        (WebCore::LinkRelAttribute::LinkRelAttribute):
+        (WebCore::LinkRelAttribute::isSupported):
+        * html/LinkRelAttribute.h:
+        * html/parser/HTMLPreloadScanner.cpp:
+        (WebCore::TokenPreloadScanner::StartTagScanner::processAttribute):
+        * loader/LinkLoader.cpp:
+        (WebCore::LinkLoader::loadLinksFromHeader):
+        (WebCore::LinkLoader::loadLink):
+        * loader/LoaderStrategy.h:
+        * page/Settings.in:
+        * testing/Internals.cpp:
+        (WebCore::Internals::Internals):
+        (WebCore::Internals::setConsoleMessageListener):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2017-09-28  Zalan Bujtas  <zalan@apple.com>
 
         AX: Defer RenderListBox selectionChanged event until after layout is done.
index 7e0dbb9..e636504 100644 (file)
@@ -1,3 +1,15 @@
+2017-09-28  Chris Dumez  <cdumez@apple.com>
+
+        Add support for <link rel=preconnect>
+        https://bugs.webkit.org/show_bug.cgi?id=177474
+        <rdar://problem/33141380>
+
+        Reviewed by Alex Christensen.
+
+        Add new CFNetwork SPI for preconnecting.
+
+        * pal/spi/cf/CFNetworkSPI.h:
+
 2017-09-27  Tim Horton  <timothy_horton@apple.com>
 
         Try to fix the Mac CMake build
index 3e5843e..681dbbb 100644 (file)
@@ -113,6 +113,12 @@ typedef void (^CFCachedURLResponseCallBackBlock)(CFCachedURLResponseRef);
 - (NSDictionary *)_timingData;
 @end
 
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000)
+@interface NSURLSessionTask (ResourceHints)
+@property (nonatomic, assign) BOOL _preconnect;
+@end
+#endif
+
 @interface NSHTTPCookie ()
 - (CFHTTPCookieRef)_CFHTTPCookie;
 + (CFArrayRef __nullable)_ns2cfCookies:(NSArray * __nullable)nsCookies CF_RETURNS_RETAINED;
index 2808c8f..e6d7531 100644 (file)
@@ -62,7 +62,7 @@ WEBCORE_EXPORT void throwSequenceTypeError(JSC::ExecState&, JSC::ThrowScope&);
 void throwTypeMismatchError(JSC::ExecState&, JSC::ThrowScope&);
 
 WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues);
-JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName);
+WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName);
 WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType);
 WEBCORE_EXPORT JSC::EncodedJSValue throwRequiredMemberTypeError(JSC::ExecState&, JSC::ThrowScope&, const char* memberName, const char* dictionaryName, const char* expectedType);
 JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::ExecState&, JSC::ThrowScope&, const char* interfaceName);
index 66243c5..c5a87c2 100644 (file)
@@ -5818,7 +5818,9 @@ sub GenerateCallbackHeaderContent
     $includesRef->{"<wtf/Forward.h>"} = 1;
     $includesRef->{"${name}.h"} = 1;
 
-    push(@$contentRef, "class $className final : public ${name} {\n");
+    my $exportMacro = GetExportMacroForJSClass($interfaceOrCallback);
+
+    push(@$contentRef, "class $exportMacro$className final : public ${name} {\n");
     push(@$contentRef, "public:\n");
 
     # The static create() method.
@@ -5875,7 +5877,7 @@ sub GenerateCallbackHeaderContent
     push(@$contentRef, "};\n\n");
 
     # toJS().
-    push(@$contentRef, "JSC::JSValue toJS(${name}&);\n");
+    push(@$contentRef, $exportMacro . "JSC::JSValue toJS(${name}&);\n");
     push(@$contentRef, "inline JSC::JSValue toJS(${name}* impl) { return impl ? toJS(*impl) : JSC::jsNull(); }\n\n");
 }
 
index 579a09a..7ce48e6 100644 (file)
             }
         },
         "ExportMacro": {
-            "contextsAllowed": ["interface", "dictionary", "enum"],
+            "contextsAllowed": ["interface", "dictionary", "enum", "callback-function"],
             "values": ["WEBCORE_EXPORT", "WEBCORE_TESTSUPPORT_EXPORT"]
         },
         "ExportToWrappedFunction": {
index f8a22d5..855fd19 100644 (file)
 #include "ShadowRoot.h"
 #include "SocketProvider.h"
 #include "StorageEvent.h"
+#include "StringCallback.h"
 #include "StyleProperties.h"
 #include "StyleResolveForDocument.h"
 #include "StyleResolver.h"
@@ -5611,6 +5612,9 @@ void Document::addConsoleMessage(MessageSource source, MessageLevel level, const
 
     if (Page* page = this->page())
         page->console().addMessage(source, level, message, requestIdentifier, this);
+
+    if (m_consoleMessageListener)
+        m_consoleMessageListener->scheduleCallback(*this, message);
 }
 
 void Document::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, RefPtr<Inspector::ScriptCallStack>&& callStack, JSC::ExecState* state, unsigned long requestIdentifier)
@@ -7340,4 +7344,9 @@ void Document::requestStorageAccess(Ref<DeferredPromise>&& passedPromise)
     promise->resolve<IDLBoolean>(false);
 }
 
+void Document::setConsoleMessageListener(RefPtr<StringCallback>&& listener)
+{
+    m_consoleMessageListener = listener;
+}
+
 } // namespace WebCore
index 7a5d1ae..0fbf106 100644 (file)
@@ -168,6 +168,7 @@ class SelectorQuery;
 class SelectorQueryCache;
 class SerializedScriptValue;
 class Settings;
+class StringCallback;
 class StyleResolver;
 class StyleSheet;
 class StyleSheetContents;
@@ -1359,6 +1360,8 @@ public:
     void requestStorageAccess(Ref<DeferredPromise>&& passedPromise);
     void setUserGrantsStorageAccessOverride(bool value) { m_grantStorageAccessOverride = value; }
 
+    WEBCORE_EXPORT void setConsoleMessageListener(RefPtr<StringCallback>&&); // For testing.
+
 protected:
     enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 };
     Document(Frame*, const URL&, unsigned = DefaultDocumentClass, unsigned constructionFlags = 0);
@@ -1808,6 +1811,7 @@ private:
     OrientationNotifier m_orientationNotifier;
     mutable PAL::SessionID m_sessionID;
     mutable RefPtr<PAL::Logger> m_logger;
+    RefPtr<StringCallback> m_consoleMessageListener;
 
     static bool hasEverCreatedAnAXObjectCache;
 
index 5ccd31a..97591e1 100644 (file)
@@ -28,4 +28,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-callback StringCallback = void (DOMString data);
+[
+    ExportMacro=WEBCORE_TESTSUPPORT_EXPORT
+] callback StringCallback = void (DOMString data);
index 2555b68..7cab1b7 100644 (file)
@@ -35,7 +35,7 @@
 
 namespace WebCore {
 
-DOMTokenList::DOMTokenList(Element& element, const QualifiedName& attributeName, WTF::Function<bool(StringView)>&& isSupportedToken)
+DOMTokenList::DOMTokenList(Element& element, const QualifiedName& attributeName, IsSupportedTokenFunction&& isSupportedToken)
     : m_element(element)
     , m_attributeName(attributeName)
     , m_isSupportedToken(WTFMove(isSupportedToken))
@@ -191,7 +191,7 @@ ExceptionOr<bool> DOMTokenList::supports(StringView token)
 {
     if (!m_isSupportedToken)
         return Exception { TypeError };
-    return m_isSupportedToken(token);
+    return m_isSupportedToken(m_element.document(), token);
 }
 
 // https://dom.spec.whatwg.org/#dom-domtokenlist-value
index 21fb46f..d60d17c 100644 (file)
@@ -32,7 +32,8 @@ namespace WebCore {
 class DOMTokenList {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    DOMTokenList(Element&, const QualifiedName& attributeName, WTF::Function<bool(StringView)>&& isSupportedToken = { });
+    using IsSupportedTokenFunction = WTF::Function<bool(Document&, StringView)>;
+    DOMTokenList(Element&, const QualifiedName& attributeName, IsSupportedTokenFunction&& isSupportedToken = { });
 
     void associatedAttributeValueChanged(const AtomicString&);
 
@@ -73,7 +74,7 @@ private:
     bool m_inUpdateAssociatedAttributeFromTokens { false };
     bool m_tokensNeedUpdating { true };
     Vector<AtomicString> m_tokens;
-    WTF::Function<bool(StringView)> m_isSupportedToken;
+    IsSupportedTokenFunction m_isSupportedToken;
 };
 
 inline unsigned DOMTokenList::length() const
index cb1f1c9..4881c3d 100644 (file)
@@ -307,7 +307,7 @@ bool HTMLAnchorElement::hasRel(Relation relation) const
 DOMTokenList& HTMLAnchorElement::relList()
 {
     if (!m_relList) 
-        m_relList = std::make_unique<DOMTokenList>(*this, HTMLNames::relAttr, [](StringView token) {
+        m_relList = std::make_unique<DOMTokenList>(*this, HTMLNames::relAttr, [](Document&, StringView token) {
             return equalIgnoringASCIICase(token, "noreferrer") || equalIgnoringASCIICase(token, "noopener");
         });
     return *m_relList;
index d30322d..223e3b0 100644 (file)
@@ -51,7 +51,7 @@ Ref<HTMLIFrameElement> HTMLIFrameElement::create(const QualifiedName& tagName, D
 DOMTokenList& HTMLIFrameElement::sandbox()
 {
     if (!m_sandbox)
-        m_sandbox = std::make_unique<DOMTokenList>(*this, sandboxAttr, [](StringView token) {
+        m_sandbox = std::make_unique<DOMTokenList>(*this, sandboxAttr, [](Document&, StringView token) {
             return SecurityContext::isSupportedSandboxPolicy(token);
         });
     return *m_sandbox;
index e01b6e3..e7d0f7c 100644 (file)
@@ -156,7 +156,7 @@ void HTMLLinkElement::setDisabledState(bool disabled)
 void HTMLLinkElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
 {
     if (name == relAttr) {
-        m_relAttribute = LinkRelAttribute(value);
+        m_relAttribute = LinkRelAttribute(document(), value);
         if (m_relList)
             m_relList->associatedAttributeValueChanged(value);
         process();
@@ -498,8 +498,8 @@ void HTMLLinkElement::dispatchPendingEvent(LinkEventSender* eventSender)
 DOMTokenList& HTMLLinkElement::relList()
 {
     if (!m_relList) 
-        m_relList = std::make_unique<DOMTokenList>(*this, HTMLNames::relAttr, [](StringView token) {
-            return LinkRelAttribute::isSupported(token);
+        m_relList = std::make_unique<DOMTokenList>(*this, HTMLNames::relAttr, [](Document& document, StringView token) {
+            return LinkRelAttribute::isSupported(document, token);
         });
     return *m_relList;
 }
index 866afd8..572bdb3 100644 (file)
 #include "config.h"
 #include "LinkRelAttribute.h"
 
+#include "Document.h"
 #include "LinkIconType.h"
 #include "RuntimeEnabledFeatures.h"
+#include "Settings.h"
 #include <wtf/text/StringView.h>
 #include <wtf/text/WTFString.h>
 
@@ -44,7 +46,7 @@ LinkRelAttribute::LinkRelAttribute()
 }
 
 // Keep LinkRelAttribute::isSupported() in sync when updating this constructor.
-LinkRelAttribute::LinkRelAttribute(const String& rel)
+LinkRelAttribute::LinkRelAttribute(Document& document, const String& rel)
 {
     if (equalLettersIgnoringASCIICase(rel, "stylesheet"))
         isStyleSheet = true;
@@ -56,6 +58,8 @@ LinkRelAttribute::LinkRelAttribute(const String& rel)
         iconType = LinkIconType::TouchPrecomposedIcon;
     else if (equalLettersIgnoringASCIICase(rel, "dns-prefetch"))
         isDNSPrefetch = true;
+    else if (document.settings().linkPreconnectEnabled() && equalLettersIgnoringASCIICase(rel, "preconnect"))
+        isLinkPreconnect = true;
     else if (RuntimeEnabledFeatures::sharedFeatures().linkPreloadEnabled() && equalLettersIgnoringASCIICase(rel, "preload"))
         isLinkPreload = true;
     else if (equalLettersIgnoringASCIICase(rel, "alternate stylesheet") || equalLettersIgnoringASCIICase(rel, "stylesheet alternate")) {
@@ -87,7 +91,7 @@ LinkRelAttribute::LinkRelAttribute(const String& rel)
 }
 
 // https://html.spec.whatwg.org/#linkTypes
-bool LinkRelAttribute::isSupported(StringView attribute)
+bool LinkRelAttribute::isSupported(Document& document, StringView attribute)
 {
     static const char* const supportedAttributes[] = {
         "alternate", "dns-prefetch", "icon", "stylesheet", "apple-touch-icon", "apple-touch-icon-precomposed",
@@ -101,6 +105,9 @@ bool LinkRelAttribute::isSupported(StringView attribute)
             return true;
     }
 
+    if (document.settings().linkPreconnectEnabled() && equalIgnoringASCIICase(attribute, "preconnect"))
+        return true;
+
     if (RuntimeEnabledFeatures::sharedFeatures().linkPreloadEnabled() && equalIgnoringASCIICase(attribute, "preload"))
         return true;
 
index 8e26692..f12e986 100644 (file)
@@ -37,6 +37,7 @@
 
 namespace WebCore {
 
+class Document;
 enum class LinkIconType;
 
 struct LinkRelAttribute {
@@ -45,15 +46,16 @@ struct LinkRelAttribute {
     bool isAlternate { false };
     bool isDNSPrefetch { false };
     bool isLinkPreload { false };
+    bool isLinkPreconnect { false };
 #if ENABLE(LINK_PREFETCH)
     bool isLinkPrefetch { false };
     bool isLinkSubresource { false };
 #endif
 
     LinkRelAttribute();
-    explicit LinkRelAttribute(const String&);
+    LinkRelAttribute(Document&, const String&);
 
-    static bool isSupported(StringView);
+    static bool isSupported(Document&, StringView);
 };
 
 }
index 0601dc1..08d28cd 100644 (file)
@@ -232,7 +232,7 @@ private:
             if (match(attributeName, hrefAttr))
                 setUrlToLoad(attributeValue);
             else if (match(attributeName, relAttr)) {
-                LinkRelAttribute parsedAttribute { attributeValue };
+                LinkRelAttribute parsedAttribute { document, attributeValue };
                 m_linkIsStyleSheet = relAttributeIsStyleSheet(parsedAttribute);
                 m_linkIsPreload = parsedAttribute.isLinkPreload;
             } else if (match(attributeName, mediaAttr))
index 2b16132..9e3f2aa 100644 (file)
 #include "LinkHeader.h"
 #include "LinkPreloadResourceClients.h"
 #include "LinkRelAttribute.h"
+#include "LoaderStrategy.h"
 #include "MIMETypeRegistry.h"
 #include "MediaQueryEvaluator.h"
+#include "PlatformStrategies.h"
+#include "ResourceError.h"
 #include "RuntimeEnabledFeatures.h"
 #include "Settings.h"
 #include "StyleResolver.h"
@@ -102,7 +105,7 @@ void LinkLoader::loadLinksFromHeader(const String& headerValue, const URL& baseU
                 continue;
         }
 
-        LinkRelAttribute relAttribute(header.rel());
+        LinkRelAttribute relAttribute(document, header.rel());
         URL url(baseURL, header.url());
         // Sanity check to avoid re-entrancy here.
         if (equalIgnoringFragmentIdentifier(url, baseURL))
@@ -250,6 +253,22 @@ bool LinkLoader::loadLink(const LinkRelAttribute& relAttribute, const URL& href,
             document.frame()->loader().client().prefetchDNS(href.host());
     }
 
+    if (relAttribute.isLinkPreconnect && href.isValid() && href.protocolIsInHTTPFamily()) {
+        ASSERT(document.settings().linkPreconnectEnabled());
+        StoredCredentialsPolicy storageCredentialsPolicy = StoredCredentialsPolicy::Use;
+        if (equalIgnoringASCIICase(crossOrigin, "anonymous") && document.securityOrigin().canAccess(SecurityOrigin::create(href)))
+            storageCredentialsPolicy = StoredCredentialsPolicy::DoNotUse;
+        platformStrategies()->loaderStrategy()->preconnectTo(document.sessionID(), href, storageCredentialsPolicy, [weakDocument = document.createWeakPtr(), href](ResourceError error) {
+            if (!weakDocument)
+                return;
+
+            if (!error.isNull())
+                weakDocument->addConsoleMessage(MessageSource::Network, MessageLevel::Error, makeString(ASCIILiteral("Failed to preconnect to "), href.string(), ASCIILiteral(". Error: "), error.localizedDescription()));
+            else
+                weakDocument->addConsoleMessage(MessageSource::Network, MessageLevel::Info, makeString(ASCIILiteral("Successfuly preconnected to "), href.string()));
+        });
+    }
+
     if (m_client.shouldLoadLink()) {
         auto resourceClient = preloadIfNeeded(relAttribute, href, document, as, media, mimeType, crossOrigin, this);
         if (resourceClient)
index 53f3bfb..98bed84 100644 (file)
@@ -28,6 +28,7 @@
 #include "ResourceLoadPriority.h"
 #include "ResourceLoaderOptions.h"
 #include "StoredCredentialsPolicy.h"
+#include <pal/SessionID.h>
 #include <wtf/Forward.h>
 #include <wtf/SHA1.h>
 
@@ -67,6 +68,9 @@ public:
     using PingLoadCompletionHandler = WTF::Function<void(const ResourceError&)>;
     virtual void startPingLoad(Frame&, ResourceRequest&, const HTTPHeaderMap& originalRequestHeaders, const FetchOptions&, PingLoadCompletionHandler&& = { }) = 0;
 
+    using PreconnectCompletionHandler = WTF::Function<void(const ResourceError&)>;
+    virtual void preconnectTo(PAL::SessionID, const URL&, StoredCredentialsPolicy, PreconnectCompletionHandler&&) = 0;
+
     virtual void storeDerivedDataToCache(const SHA1::Digest& bodyKey, const String& type, const String& partition, WebCore::SharedBuffer&) = 0;
 
     virtual void setCaptureExtraNetworkLoadMetricsEnabled(bool) = 0;
index 9277c0a..d81526a 100644 (file)
@@ -291,6 +291,8 @@ langAttributeAwareFormControlUIEnabled initial=false
 
 subresourceIntegrityEnabled initial=true
 
+linkPreconnectEnabled initial=false
+
 beaconAPIEnabled initial=false
 
 constantPropertiesEnabled initial=false
index 8350976..bee580a 100644 (file)
 #include "SourceBuffer.h"
 #include "SpellChecker.h"
 #include "StaticNodeList.h"
+#include "StringCallback.h"
 #include "StyleRule.h"
 #include "StyleScope.h"
 #include "StyleSheetContents.h"
@@ -503,6 +504,8 @@ Internals::Internals(Document& document)
         setAutomaticLinkDetectionEnabled(false);
         setAutomaticTextReplacementEnabled(true);
     }
+
+    setConsoleMessageListener(nullptr);
 }
 
 Document* Internals::contextDocument() const
@@ -4177,4 +4180,12 @@ void Internals::cacheStorageEngineRepresentation(DOMPromiseDeferred<IDLDOMString
     });
 }
 
+void Internals::setConsoleMessageListener(RefPtr<StringCallback>&& listener)
+{
+    if (!contextDocument())
+        return;
+
+    contextDocument()->setConsoleMessageListener(WTFMove(listener));
+}
+
 } // namespace WebCore
index eb23c13..308e39f 100644 (file)
@@ -77,6 +77,7 @@ class RTCPeerConnection;
 class SVGSVGElement;
 class SerializedScriptValue;
 class SourceBuffer;
+class StringCallback;
 class StyleSheet;
 class TimeRanges;
 class TypeConversions;
@@ -603,6 +604,8 @@ public:
     void clearCacheStorageMemoryRepresentation(DOMPromiseDeferred<void>&&);
     void cacheStorageEngineRepresentation(DOMPromiseDeferred<IDLDOMString>&&);
 
+    void setConsoleMessageListener(RefPtr<StringCallback>&&);
+
 private:
     explicit Internals(Document&);
     Document* contextDocument() const;
index 658b179..c0c9cae 100644 (file)
@@ -548,5 +548,7 @@ enum EventThrottlingBehavior {
     Promise<void> clearCacheStorageMemoryRepresentation();
     Promise<DOMString> cacheStorageEngineRepresentation();
 
+    void setConsoleMessageListener(StringCallback callback);
+
     DOMString audioSessionCategory();
 };
index 89a5261..e24bc9a 100644 (file)
@@ -1,3 +1,71 @@
+2017-09-28  Chris Dumez  <cdumez@apple.com>
+
+        Add support for <link rel=preconnect>
+        https://bugs.webkit.org/show_bug.cgi?id=177474
+        <rdar://problem/33141380>
+
+        Reviewed by Alex Christensen.
+
+        Add support for <link rel=preconnect>:
+        - https://w3c.github.io/resource-hints/#preconnect
+
+        Also add corresponding native private API.
+
+        * NetworkProcess/NetworkConnectionToWebProcess.cpp:
+        (WebKit::NetworkConnectionToWebProcess::preconnectTo):
+        (WebKit::NetworkConnectionToWebProcess::didFinishPreconnection):
+        * NetworkProcess/NetworkConnectionToWebProcess.h:
+        * NetworkProcess/NetworkConnectionToWebProcess.messages.in:
+        * NetworkProcess/NetworkDataTask.cpp:
+        (WebKit::NetworkDataTask::create):
+        * NetworkProcess/NetworkLoadParameters.h:
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::preconnectTo):
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+        * NetworkProcess/PreconnectTask.cpp: Added.
+        (WebKit::PreconnectTask::PreconnectTask):
+        (WebKit::PreconnectTask::~PreconnectTask):
+        (WebKit::PreconnectTask::willPerformHTTPRedirection):
+        (WebKit::PreconnectTask::didReceiveChallenge):
+        (WebKit::PreconnectTask::didReceiveResponseNetworkSession):
+        (WebKit::PreconnectTask::didReceiveData):
+        (WebKit::PreconnectTask::didCompleteWithError):
+        (WebKit::PreconnectTask::didSendData):
+        (WebKit::PreconnectTask::wasBlocked):
+        (WebKit::PreconnectTask::cannotShowURL):
+        (WebKit::PreconnectTask::didFinish):
+        * NetworkProcess/PreconnectTask.h: Copied from Source/WebKit/NetworkProcess/NetworkLoadParameters.h.
+        * NetworkProcess/cocoa/NetworkDataTaskCocoa.h:
+        * NetworkProcess/cocoa/NetworkDataTaskCocoa.mm:
+        (WebKit::NetworkDataTaskCocoa::NetworkDataTaskCocoa):
+        * Shared/WebCoreArgumentCoders.h:
+        * Shared/WebPreferencesDefinitions.h:
+        * UIProcess/API/C/WKContext.cpp:
+        (WKContextPreconnectToServer):
+        * UIProcess/API/C/WKContextPrivate.h:
+        * UIProcess/API/Cocoa/WKProcessPool.mm:
+        (-[WKProcessPool _preconnectToServer:]):
+        * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::preconnectToServer):
+        * UIProcess/WebProcessPool.h:
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/Network/NetworkProcessConnection.cpp:
+        (WebKit::NetworkProcessConnection::didFinishPreconnection):
+        * WebProcess/Network/NetworkProcessConnection.h:
+        * WebProcess/Network/NetworkProcessConnection.messages.in:
+        * WebProcess/Network/WebLoaderStrategy.cpp:
+        (WebKit::WebLoaderStrategy::networkProcessCrashed):
+        (WebKit::generateLoadIdentifier):
+        (WebKit::WebLoaderStrategy::startPingLoad):
+        (WebKit::WebLoaderStrategy::preconnectTo):
+        (WebKit::WebLoaderStrategy::didFinishPreconnection):
+        * WebProcess/Network/WebLoaderStrategy.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::updatePreferences):
+        * config.h:
+
 2017-09-28  Zan Dobersek  <zdobersek@igalia.com>
 
         [Cairo] Remove the cairo_glyph_t complexity from GlyphBuffer
index 8f3569c..94ec00f 100644 (file)
 #include "NetworkResourceLoaderMessages.h"
 #include "NetworkSocketStream.h"
 #include "NetworkSocketStreamMessages.h"
+#include "PreconnectTask.h"
 #include "RemoteNetworkingContext.h"
 #include "SessionTracker.h"
 #include "WebCoreArgumentCoders.h"
+#include "WebErrors.h"
 #include "WebsiteDataStoreParameters.h"
 #include <WebCore/NetworkStorageSession.h>
 #include <WebCore/PingHandle.h>
@@ -289,6 +291,26 @@ void NetworkConnectionToWebProcess::prefetchDNS(const String& hostname)
     NetworkProcess::singleton().prefetchDNS(hostname);
 }
 
+void NetworkConnectionToWebProcess::preconnectTo(PAL::SessionID sessionID, uint64_t preconnectionIdentifier, const URL& url, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
+{
+#if ENABLE(SERVER_PRECONNECT)
+    new PreconnectTask(sessionID, url, storedCredentialsPolicy, [this, protectedThis = makeRef(*this), identifier = preconnectionIdentifier] (const ResourceError& error) {
+        didFinishPreconnection(identifier, error);
+    });
+#else
+    UNUSED_PARAM(storedCredentialsPolicy);
+    didFinishPreconnection(preconnectionIdentifier, internalError(url));
+#endif
+}
+
+void NetworkConnectionToWebProcess::didFinishPreconnection(uint64_t preconnectionIdentifier, const ResourceError& error)
+{
+    if (!m_connection->isValid())
+        return;
+
+    m_connection->send(Messages::NetworkProcessConnection::DidFinishPreconnection(preconnectionIdentifier, error), 0);
+}
+
 static NetworkStorageSession& storageSession(PAL::SessionID sessionID)
 {
     ASSERT(sessionID.isValid());
index cd28042..b10df58 100644 (file)
@@ -76,6 +76,8 @@ public:
 private:
     NetworkConnectionToWebProcess(IPC::Connection::Identifier);
 
+    void didFinishPreconnection(uint64_t preconnectionIdentifier, const WebCore::ResourceError&);
+
     // IPC::Connection::Client
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
     void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) override;
@@ -90,6 +92,7 @@ private:
     void performSynchronousLoad(const NetworkResourceLoadParameters&, Ref<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&&);
     void loadPing(NetworkResourceLoadParameters&&, WebCore::HTTPHeaderMap&& originalRequestHeaders);
     void prefetchDNS(const String&);
+    void preconnectTo(PAL::SessionID, uint64_t preconnectionIdentifier, const WebCore::URL&, WebCore::StoredCredentialsPolicy);
 
     void removeLoadIdentifier(ResourceLoadIdentifier);
     void setDefersLoading(ResourceLoadIdentifier, bool);
index abf0fcc..e85e973 100644 (file)
@@ -28,6 +28,7 @@ messages -> NetworkConnectionToWebProcess LegacyReceiver {
     RemoveLoadIdentifier(uint64_t resourceLoadIdentifier)
     SetDefersLoading(uint64_t resourceLoadIdentifier, bool defers)
     PrefetchDNS(String hostname)
+    PreconnectTo(PAL::SessionID sessionID, uint64_t preconnectionIdentifier, WebCore::URL url, enum WebCore::StoredCredentialsPolicy storedCredentialsPolicy);
 
     StartDownload(PAL::SessionID sessionID, WebKit::DownloadID downloadID, WebCore::ResourceRequest request, String suggestedName)
     ConvertMainResourceLoadToDownload(PAL::SessionID sessionID, uint64_t mainResourceLoadIdentifier, WebKit::DownloadID downloadID, WebCore::ResourceRequest request, WebCore::ResourceResponse response)
index 8054b47..bb7f175 100644 (file)
@@ -53,7 +53,7 @@ Ref<NetworkDataTask> NetworkDataTask::create(NetworkSession& session, NetworkDat
         return NetworkDataTaskBlob::create(session, client, parameters.request, parameters.contentSniffingPolicy, parameters.blobFileReferences);
 
 #if PLATFORM(COCOA)
-    return NetworkDataTaskCocoa::create(session, client, parameters.request, parameters.storedCredentialsPolicy, parameters.contentSniffingPolicy, parameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
+    return NetworkDataTaskCocoa::create(session, client, parameters.request, parameters.storedCredentialsPolicy, parameters.contentSniffingPolicy, parameters.shouldClearReferrerOnHTTPSToHTTPRedirect, parameters.shouldPreconnectOnly);
 #endif
 #if USE(SOUP)
     return NetworkDataTaskSoup::create(session, client, parameters.request, parameters.storedCredentialsPolicy, parameters.contentSniffingPolicy, parameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
index 1fbd2da..25aa505 100644 (file)
@@ -33,6 +33,8 @@
 
 namespace WebKit {
 
+enum class PreconnectOnly { No, Yes };
+
 class NetworkLoadParameters {
 public:
     uint64_t webPageID { 0 };
@@ -49,6 +51,7 @@ public:
 #if USE(NETWORK_SESSION)
     Vector<RefPtr<WebCore::BlobDataFileReference>> blobFileReferences;
 #endif
+    PreconnectOnly shouldPreconnectOnly { PreconnectOnly::No };
 };
 
 } // namespace WebKit
index 79e02cf..d46c6f3 100644 (file)
@@ -40,6 +40,7 @@
 #include "NetworkProcessProxyMessages.h"
 #include "NetworkResourceLoader.h"
 #include "NetworkSession.h"
+#include "PreconnectTask.h"
 #include "RemoteNetworkingContext.h"
 #include "SessionTracker.h"
 #include "StatisticsData.h"
@@ -725,6 +726,16 @@ String NetworkProcess::cacheStorageDirectory(PAL::SessionID sessionID) const
     return session->cacheStorageDirectory();
 }
 
+void NetworkProcess::preconnectTo(const WebCore::URL& url, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
+{
+#if ENABLE(SERVER_PRECONNECT)
+    new PreconnectTask(PAL::SessionID::defaultSessionID(), url, storedCredentialsPolicy);
+#else
+    UNUSED_PARAM(url);
+    UNUSED_PARAM(storedCredentialsPolicy);
+#endif
+}
+
 #if !PLATFORM(COCOA)
 void NetworkProcess::initializeProcess(const ChildProcessInitializationParameters&)
 {
index 14a522f..b9fa720 100644 (file)
@@ -54,6 +54,8 @@ class ProtectionSpace;
 class SecurityOrigin;
 struct SecurityOriginData;
 struct SoupNetworkProxySettings;
+enum class StoredCredentialsPolicy;
+class URL;
 }
 
 namespace WebKit {
@@ -137,6 +139,8 @@ public:
     Seconds loadThrottleLatency() const { return m_loadThrottleLatency; }
     String cacheStorageDirectory(PAL::SessionID) const;
 
+    void preconnectTo(const WebCore::URL&, WebCore::StoredCredentialsPolicy);
+
 private:
     NetworkProcess();
     ~NetworkProcess();
index 694e474..461f1c0 100644 (file)
@@ -82,6 +82,8 @@ messages -> NetworkProcess LegacyReceiver {
 
     DidGrantSandboxExtensionsToStorageProcessForBlobs(uint64_t requestID)
 
+    PreconnectTo(WebCore::URL url, enum WebCore::StoredCredentialsPolicy storedCredentialsPolicy);
+
 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
     UpdatePrevalentDomainsToPartitionOrBlockCookies(PAL::SessionID sessionID, Vector<String> domainsToPartition, Vector<String> domainsToBlock, Vector<String> domainsToNeitherPartitionNorBlock, bool shouldClearFirst)
     RemovePrevalentDomains(PAL::SessionID sessionID, Vector<String> domainsWithInteraction);
diff --git a/Source/WebKit/NetworkProcess/PreconnectTask.cpp b/Source/WebKit/NetworkProcess/PreconnectTask.cpp
new file mode 100644 (file)
index 0000000..ca89334
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "config.h"
+#include "PreconnectTask.h"
+
+#if ENABLE(SERVER_PRECONNECT)
+
+#include "AuthenticationManager.h"
+#include "Logging.h"
+#include "NetworkLoadParameters.h"
+#include "NetworkSession.h"
+#include "SessionTracker.h"
+#include "WebErrors.h"
+#include <WebCore/AuthenticationChallenge.h>
+#include <WebCore/ResourceError.h>
+
+#if PLATFORM(COCOA)
+#include "NetworkDataTaskCocoa.h"
+#endif
+
+namespace WebKit {
+
+using namespace WebCore;
+
+PreconnectTask::PreconnectTask(PAL::SessionID sessionID, const URL& url, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, WTF::CompletionHandler<void(const WebCore::ResourceError&)>&& completionHandler)
+    : m_completionHandler(WTFMove(completionHandler))
+    , m_timeoutTimer([this] { didFinish(ResourceError { String(), 0, m_task->firstRequest().url(), ASCIILiteral("Preconnection timed out"), ResourceError::Type::Timeout }); })
+{
+    auto* networkSession = SessionTracker::networkSession(sessionID);
+    ASSERT(networkSession);
+
+    RELEASE_LOG(Network, "%p - PreconnectTask::PreconnectTask()", this);
+    NetworkLoadParameters parameters;
+    parameters.request = ResourceRequest(url);
+    parameters.shouldPreconnectOnly = PreconnectOnly::Yes;
+    parameters.storedCredentialsPolicy = storedCredentialsPolicy;
+    m_task = NetworkDataTask::create(*networkSession, *this, parameters);
+    m_task->resume();
+
+    m_timeoutTimer.startOneShot(60000_s);
+}
+
+PreconnectTask::~PreconnectTask()
+{
+    ASSERT(m_task->client() == this);
+    m_task->clearClient();
+    m_task->cancel();
+}
+
+void PreconnectTask::willPerformHTTPRedirection(WebCore::ResourceResponse&&, WebCore::ResourceRequest&&, RedirectCompletionHandler&&)
+{
+    ASSERT_NOT_REACHED();
+}
+
+void PreconnectTask::didReceiveChallenge(const WebCore::AuthenticationChallenge& challenge, ChallengeCompletionHandler&& completionHandler)
+{
+    if (challenge.protectionSpace().authenticationScheme() == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
+        if (m_task && m_task->allowsSpecificHTTPSCertificateForHost(challenge))
+            completionHandler(AuthenticationChallengeDisposition::UseCredential, serverTrustCredential(challenge));
+        else
+            completionHandler(AuthenticationChallengeDisposition::RejectProtectionSpace, { });
+        return;
+    }
+    ASSERT_NOT_REACHED();
+}
+
+void PreconnectTask::didReceiveResponseNetworkSession(WebCore::ResourceResponse&&, ResponseCompletionHandler&&)
+{
+    ASSERT_NOT_REACHED();
+}
+
+void PreconnectTask::didReceiveData(Ref<WebCore::SharedBuffer>&&)
+{
+    ASSERT_NOT_REACHED();
+}
+
+void PreconnectTask::didCompleteWithError(const WebCore::ResourceError& error, const WebCore::NetworkLoadMetrics&)
+{
+    if (error.isNull())
+        RELEASE_LOG(Network, "%p - PreconnectTask::didComplete", this);
+    else
+        RELEASE_LOG(Network, "%p - PreconnectTask::didCompleteWithError, error_code: %d", this, error.errorCode());
+
+    didFinish(error);
+}
+
+void PreconnectTask::didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend)
+{
+    ASSERT_NOT_REACHED();
+}
+
+void PreconnectTask::wasBlocked()
+{
+    RELEASE_LOG(Network, "%p - PreconnectTask::wasBlocked()", this);
+    didFinish(blockedError(m_task->firstRequest()));
+}
+
+void PreconnectTask::cannotShowURL()
+{
+    RELEASE_LOG(Network, "%p - PreconnectTask::cannotShowURL()", this);
+    didFinish(cannotShowURLError(m_task->firstRequest()));
+}
+
+void PreconnectTask::didFinish(const ResourceError& error)
+{
+    if (m_completionHandler)
+        m_completionHandler(error);
+    delete this;
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(SERVER_PRECONNECT)
diff --git a/Source/WebKit/NetworkProcess/PreconnectTask.h b/Source/WebKit/NetworkProcess/PreconnectTask.h
new file mode 100644 (file)
index 0000000..bf9e395
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#pragma once
+
+#if ENABLE(SERVER_PRECONNECT)
+
+#include "NetworkDataTask.h"
+#include <WebCore/Timer.h>
+#include <wtf/CompletionHandler.h>
+
+namespace PAL {
+class SessionID;
+}
+
+namespace WebKit {
+
+class PreconnectTask final : private NetworkDataTaskClient {
+public:
+    explicit PreconnectTask(PAL::SessionID, const WebCore::URL&, WebCore::StoredCredentialsPolicy, WTF::CompletionHandler<void(const WebCore::ResourceError&)>&& completionHandler = { });
+    ~PreconnectTask();
+
+private:
+    // NetworkDataTaskClient.
+    void willPerformHTTPRedirection(WebCore::ResourceResponse&&, WebCore::ResourceRequest&&, RedirectCompletionHandler&&) final;
+    void didReceiveChallenge(const WebCore::AuthenticationChallenge&, ChallengeCompletionHandler&&) final;
+    void didReceiveResponseNetworkSession(WebCore::ResourceResponse&&, ResponseCompletionHandler&&) final;
+    void didReceiveData(Ref<WebCore::SharedBuffer>&&) final;
+    void didCompleteWithError(const WebCore::ResourceError&, const WebCore::NetworkLoadMetrics&) final;
+    void didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend) final;
+    void wasBlocked() final;
+    void cannotShowURL() final;
+
+    void didFinish(const WebCore::ResourceError&);
+
+    RefPtr<NetworkDataTask> m_task;
+    WTF::CompletionHandler<void(const WebCore::ResourceError&)> m_completionHandler;
+    WebCore::Timer m_timeoutTimer;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(SERVER_PRECONNECT)
index cdf4324..212a9a0 100644 (file)
@@ -28,6 +28,7 @@
 #if USE(NETWORK_SESSION)
 
 #include "NetworkDataTask.h"
+#include "NetworkLoadParameters.h"
 #include <WebCore/NetworkLoadMetrics.h>
 #include <wtf/RetainPtr.h>
 
@@ -40,9 +41,9 @@ class NetworkSessionCocoa;
 class NetworkDataTaskCocoa final : public NetworkDataTask {
     friend class NetworkSessionCocoa;
 public:
-    static Ref<NetworkDataTask> create(NetworkSession& session, NetworkDataTaskClient& client, const WebCore::ResourceRequest& request, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, WebCore::ContentSniffingPolicy shouldContentSniff, bool shouldClearReferrerOnHTTPSToHTTPRedirect)
+    static Ref<NetworkDataTask> create(NetworkSession& session, NetworkDataTaskClient& client, const WebCore::ResourceRequest& request, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, WebCore::ContentSniffingPolicy shouldContentSniff, bool shouldClearReferrerOnHTTPSToHTTPRedirect, PreconnectOnly shouldPreconnectOnly)
     {
-        return adoptRef(*new NetworkDataTaskCocoa(session, client, request, storedCredentialsPolicy, shouldContentSniff, shouldClearReferrerOnHTTPSToHTTPRedirect));
+        return adoptRef(*new NetworkDataTaskCocoa(session, client, request, storedCredentialsPolicy, shouldContentSniff, shouldClearReferrerOnHTTPSToHTTPRedirect, shouldPreconnectOnly));
     }
 
     ~NetworkDataTaskCocoa();
@@ -71,7 +72,7 @@ public:
     WebCore::NetworkLoadMetrics& networkLoadMetrics() { return m_networkLoadMetrics; }
 
 private:
-    NetworkDataTaskCocoa(NetworkSession&, NetworkDataTaskClient&, const WebCore::ResourceRequest&, WebCore::StoredCredentialsPolicy, WebCore::ContentSniffingPolicy, bool shouldClearReferrerOnHTTPSToHTTPRedirect);
+    NetworkDataTaskCocoa(NetworkSession&, NetworkDataTaskClient&, const WebCore::ResourceRequest&, WebCore::StoredCredentialsPolicy, WebCore::ContentSniffingPolicy, bool shouldClearReferrerOnHTTPSToHTTPRedirect, PreconnectOnly);
 
     bool tryPasswordBasedAuthentication(const WebCore::AuthenticationChallenge&, ChallengeCompletionHandler&);
 
index 997e0ee..dbbb100 100644 (file)
@@ -74,7 +74,7 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     return NSURLSessionTaskPriorityDefault;
 }
 
-NetworkDataTaskCocoa::NetworkDataTaskCocoa(NetworkSession& session, NetworkDataTaskClient& client, const WebCore::ResourceRequest& requestWithCredentials, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, WebCore::ContentSniffingPolicy shouldContentSniff, bool shouldClearReferrerOnHTTPSToHTTPRedirect)
+NetworkDataTaskCocoa::NetworkDataTaskCocoa(NetworkSession& session, NetworkDataTaskClient& client, const WebCore::ResourceRequest& requestWithCredentials, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, WebCore::ContentSniffingPolicy shouldContentSniff, bool shouldClearReferrerOnHTTPSToHTTPRedirect, PreconnectOnly shouldPreconnectOnly)
     : NetworkDataTask(session, client, requestWithCredentials, storedCredentialsPolicy, shouldClearReferrerOnHTTPSToHTTPRedirect)
 {
     if (m_scheduledFailureType != NoFailure)
@@ -128,6 +128,14 @@ NetworkDataTaskCocoa::NetworkDataTaskCocoa(NetworkSession& session, NetworkDataT
         LOG(NetworkSession, "%llu Creating NetworkDataTask with URL %s", [m_task taskIdentifier], nsRequest.URL.absoluteString.UTF8String);
     }
 
+    if (shouldPreconnectOnly == PreconnectOnly::Yes) {
+#if ENABLE(SERVER_PRECONNECT)
+        m_task.get()._preconnect = true;
+#else
+        ASSERT_NOT_REACHED();
+#endif
+    }
+
 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
     if (storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use) {
         String storagePartition = session.networkStorageSession().cookieStoragePartition(request);
index c9a820a..4ac01da 100644 (file)
@@ -39,6 +39,7 @@
 #include <WebCore/PaymentHeaders.h>
 #include <WebCore/RealtimeMediaSource.h>
 #include <WebCore/ScrollSnapOffsetsInfo.h>
+#include <WebCore/StoredCredentialsPolicy.h>
 
 namespace WTF {
 class MonotonicTime;
@@ -775,4 +776,12 @@ template<> struct EnumTraits<WebCore::MediaSelectionOption::Type> {
     >;
 };
 
+template <> struct EnumTraits<WebCore::StoredCredentialsPolicy> {
+    using values = EnumValues<
+        WebCore::StoredCredentialsPolicy,
+        WebCore::StoredCredentialsPolicy::DoNotUse,
+        WebCore::StoredCredentialsPolicy::Use
+    >;
+};
+
 } // namespace WTF
index c6820d8..83c6361 100644 (file)
 #define DEFAULT_HIDDEN_PAGE_CSS_ANIMATION_SUSPENSION_ENABLED false
 #endif
 
+#if ENABLE(SERVER_PRECONNECT)
+#define DEFAULT_LINK_PRECONNECT_ENABLED true
+#else
+#define DEFAULT_LINK_PRECONNECT_ENABLED false
+#endif
+
 #if PLATFORM(COCOA)
 #define DEFAULT_PDFPLUGIN_ENABLED true
 #else
     macro(DOMPasteAllowed, domPasteAllowed, Bool, bool, false, "", "") \
     macro(JavaScriptCanAccessClipboard, javaScriptCanAccessClipboard, Bool, bool, false, "", "") \
     macro(ShouldPrintBackgrounds, shouldPrintBackgrounds, Bool, bool, DEFAULT_SHOULD_PRINT_BACKGROUNDS, "", "") \
+    macro(LinkPreconnect, linkPreconnect, Bool, bool, DEFAULT_LINK_PRECONNECT_ENABLED, "", "") \
     macro(FullScreenEnabled, fullScreenEnabled, Bool, bool, false, "", "") \
     macro(AsynchronousSpellCheckingEnabled, asynchronousSpellCheckingEnabled, Bool, bool, false, "", "") \
     macro(WebSecurityEnabled, webSecurityEnabled, Bool, bool, true, "", "") \
index 78338ed..7048bbe 100644 (file)
@@ -407,6 +407,11 @@ void WKContextSetDiskCacheSpeculativeValidationEnabled(WKContextRef contextRef,
     toImpl(contextRef)->configuration().setDiskCacheSpeculativeValidationEnabled(value);
 }
 
+void WKContextPreconnectToServer(WKContextRef contextRef, WKURLRef serverURLRef)
+{
+    toImpl(contextRef)->preconnectToServer(URL(URL(), toWTFString(serverURLRef)));
+}
+
 WKCookieManagerRef WKContextGetCookieManager(WKContextRef contextRef)
 {
     return toAPI(toImpl(contextRef)->supplement<WebCookieManagerProxy>());
index 02f90b9..152d6da 100644 (file)
@@ -105,6 +105,8 @@ WK_EXPORT void WKContextSetMemoryCacheDisabled(WKContextRef, bool disabled);
 
 WK_EXPORT void WKContextSetFontWhitelist(WKContextRef, WKArrayRef);
 
+WK_EXPORT void WKContextPreconnectToServer(WKContextRef context, WKURLRef serverURL);
+
 WK_EXPORT WKProcessID WKContextGetNetworkProcessIdentifier(WKContextRef context);
 WK_EXPORT WKProcessID WKContextGetDatabaseProcessIdentifier(WKContextRef context);
 
index 1f5974d..1802307 100644 (file)
@@ -415,6 +415,11 @@ static NSDictionary *policiesHashMapToDictionary(const HashMap<String, HashMap<S
     return _processPool->processes().size();
 }
 
+- (void)_preconnectToServer:(NSURL *)serverURL
+{
+    _processPool->preconnectToServer(serverURL);
+}
+
 - (size_t)_pluginProcessCount
 {
 #if !PLATFORM(IOS)
index 07aae31..13fe59c 100644 (file)
@@ -87,6 +87,8 @@
 // Test only. Should be called before any web content processes are launched.
 + (void)_forceGameControllerFramework WK_API_AVAILABLE(macosx(10.13), ios(11.0));
 
+- (void)_preconnectToServer:(NSURL *)serverURL WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 @property (nonatomic, getter=_isCookieStoragePartitioningEnabled, setter=_setCookieStoragePartitioningEnabled:) BOOL _cookieStoragePartitioningEnabled WK_API_AVAILABLE(macosx(10.12.3), ios(10.3));
 
 @end
index acb9d56..2620863 100644 (file)
@@ -1157,6 +1157,14 @@ void WebProcessPool::setCanHandleHTTPSServerTrustEvaluation(bool value)
     }
 }
 
+void WebProcessPool::preconnectToServer(const URL& url)
+{
+    if (!url.isValid() || !url.protocolIsInHTTPFamily())
+        return;
+
+    ensureNetworkProcess().send(Messages::NetworkProcess::PreconnectTo(url, StoredCredentialsPolicy::Use), 0);
+}
+
 void WebProcessPool::registerURLSchemeAsLocal(const String& urlScheme)
 {
     m_schemesToRegisterAsLocal.add(urlScheme);
index e19f6df..ad5b0c6 100644 (file)
@@ -216,6 +216,7 @@ public:
     void registerURLSchemeAsDisplayIsolated(const String&);
     void registerURLSchemeAsCORSEnabled(const String&);
     void registerURLSchemeAsCachePartitioned(const String&);
+    void preconnectToServer(const WebCore::URL&);
 
     VisitedLinkStore& visitedLinkStore() { return m_visitedLinkStore.get(); }
 
index 6807e93..c28cc11 100644 (file)
                839902031BE9A02B000F3653 /* NetworkLoad.h in Headers */ = {isa = PBXBuildFile; fileRef = 839901FE1BE9A01B000F3653 /* NetworkLoad.h */; };
                839A2F311E2067450039057E /* HighPerformanceGraphicsUsageSampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 839A2F2F1E2067390039057E /* HighPerformanceGraphicsUsageSampler.cpp */; };
                839A2F321E2067450039057E /* HighPerformanceGraphicsUsageSampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 839A2F301E2067390039057E /* HighPerformanceGraphicsUsageSampler.h */; };
+               83A0ED341F747CCD003299EB /* PreconnectTask.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83A0ED331F747CC7003299EB /* PreconnectTask.cpp */; };
+               83A0ED351F747CCF003299EB /* PreconnectTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A0ED321F747CC6003299EB /* PreconnectTask.h */; };
                83BDCCB91AC5FDB6003F6441 /* NetworkCacheStatistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BDCCB81AC5FDB6003F6441 /* NetworkCacheStatistics.cpp */; };
                83BFAC421D96137C00433490 /* BlobDownloadClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BFAC401D96136000433490 /* BlobDownloadClient.h */; };
                83BFAC431D96137C00433490 /* BlobDownloadClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BFAC411D96136000433490 /* BlobDownloadClient.cpp */; };
                839901FF1BE9A01B000F3653 /* NetworkLoad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NetworkLoad.cpp; path = NetworkProcess/NetworkLoad.cpp; sourceTree = "<group>"; };
                839A2F2F1E2067390039057E /* HighPerformanceGraphicsUsageSampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HighPerformanceGraphicsUsageSampler.cpp; sourceTree = "<group>"; };
                839A2F301E2067390039057E /* HighPerformanceGraphicsUsageSampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HighPerformanceGraphicsUsageSampler.h; sourceTree = "<group>"; };
+               83A0ED321F747CC6003299EB /* PreconnectTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PreconnectTask.h; path = NetworkProcess/PreconnectTask.h; sourceTree = "<group>"; };
+               83A0ED331F747CC7003299EB /* PreconnectTask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PreconnectTask.cpp; path = NetworkProcess/PreconnectTask.cpp; sourceTree = "<group>"; };
                83BDCCB81AC5FDB6003F6441 /* NetworkCacheStatistics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheStatistics.cpp; sourceTree = "<group>"; };
                83BFAC401D96136000433490 /* BlobDownloadClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlobDownloadClient.h; path = NetworkProcess/Downloads/BlobDownloadClient.h; sourceTree = "<group>"; };
                83BFAC411D96136000433490 /* BlobDownloadClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BlobDownloadClient.cpp; path = NetworkProcess/Downloads/BlobDownloadClient.cpp; sourceTree = "<group>"; };
                                5C0B177F1E7C886700E9123C /* NetworkSocketStream.messages.in */,
                                462107D71F38DBD300DD7810 /* PingLoad.cpp */,
                                5CE85B1F1C88E6430070BFCE /* PingLoad.h */,
+                               83A0ED331F747CC7003299EB /* PreconnectTask.cpp */,
+                               83A0ED321F747CC6003299EB /* PreconnectTask.h */,
                                E1B78470163F24690007B692 /* RemoteNetworkingContext.h */,
                        );
                        name = NetworkProcess;
                                1A4A9F3312B844E2008FE984 /* PluginQuirks.h in Headers */,
                                7CD622781739D863005BD7FF /* PluginSandboxProfile.h in Headers */,
                                1A6FB7AF11E64B6800DB1371 /* PluginView.h in Headers */,
+                               83A0ED351F747CCF003299EB /* PreconnectTask.h in Headers */,
                                E1CC1B9012D7EADF00625838 /* PrintInfo.h in Headers */,
                                86F9536518FF58F5001DB2EF /* ProcessAssertion.h in Headers */,
                                BC1A7C581136E19C00FB7167 /* ProcessLauncher.h in Headers */,
                                7CD622771739D863005BD7FF /* PluginSandboxProfile.mm in Sources */,
                                BC82844D16B5081C00A278FE /* PluginServiceEntryPoint.mm in Sources */,
                                1A6FB7AE11E64B6800DB1371 /* PluginView.cpp in Sources */,
+                               83A0ED341F747CCD003299EB /* PreconnectTask.cpp in Sources */,
                                E18C92F412DB9E7100CF2AEB /* PrintInfo.cpp in Sources */,
                                E1CC1B9112D7EADF00625838 /* PrintInfoMac.mm in Sources */,
                                37716A5A195B910500EE8B1B /* ProcessAssertion.cpp in Sources */,
index 9624e29..38d53c9 100644 (file)
@@ -140,6 +140,11 @@ void NetworkProcessConnection::didFinishPingLoad(uint64_t pingLoadIdentifier, Re
     WebProcess::singleton().webLoaderStrategy().didFinishPingLoad(pingLoadIdentifier, WTFMove(error));
 }
 
+void NetworkProcessConnection::didFinishPreconnection(uint64_t preconnectionIdentifier, ResourceError&& error)
+{
+    WebProcess::singleton().webLoaderStrategy().didFinishPreconnection(preconnectionIdentifier, WTFMove(error));
+}
+
 #if ENABLE(SHAREABLE_RESOURCE)
 void NetworkProcessConnection::didCacheResource(const ResourceRequest& request, const ShareableResource::Handle& handle, PAL::SessionID sessionID)
 {
index c5344ea..deea7b0 100644 (file)
@@ -74,6 +74,7 @@ private:
 
     void didWriteBlobsToTemporaryFiles(uint64_t requestIdentifier, const Vector<String>& filenames);
     void didFinishPingLoad(uint64_t pingLoadIdentifier, WebCore::ResourceError&&);
+    void didFinishPreconnection(uint64_t preconnectionIdentifier, WebCore::ResourceError&&);
 
 #if ENABLE(SHAREABLE_RESOURCE)
     // Message handlers.
index 83ef2e6..287363e 100644 (file)
@@ -28,4 +28,5 @@ messages -> NetworkProcessConnection LegacyReceiver {
 
     DidWriteBlobsToTemporaryFiles(uint64_t requestIdentifier, Vector<String> filenames)
     DidFinishPingLoad(uint64_t pingLoadIdentifier, WebCore::ResourceError error)
+    DidFinishPreconnection(uint64_t preconnectionIdentifier, WebCore::ResourceError error)
 }
index ea7b17a..76f1866 100644 (file)
@@ -356,6 +356,10 @@ void WebLoaderStrategy::networkProcessCrashed()
     auto pingLoadCompletionHandlers = WTFMove(m_pingLoadCompletionHandlers);
     for (auto& pingLoadCompletionHandler : pingLoadCompletionHandlers.values())
         pingLoadCompletionHandler(internalError(URL()));
+
+    auto preconnectCompletionHandlers = WTFMove(m_preconnectCompletionHandlers);
+    for (auto& preconnectCompletionHandler : preconnectCompletionHandlers.values())
+        preconnectCompletionHandler(internalError(URL()));
 }
 
 void WebLoaderStrategy::loadResourceSynchronously(NetworkingContext* context, unsigned long resourceLoadIdentifier, const ResourceRequest& request, StoredCredentialsPolicy storedCredentialsPolicy, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
@@ -392,7 +396,7 @@ void WebLoaderStrategy::loadResourceSynchronously(NetworkingContext* context, un
     }
 }
 
-static uint64_t generatePingLoadIdentifier()
+static uint64_t generateLoadIdentifier()
 {
     static uint64_t identifier = 0;
     return ++identifier;
@@ -422,7 +426,7 @@ void WebLoaderStrategy::startPingLoad(Frame& frame, ResourceRequest& request, co
     }
     
     NetworkResourceLoadParameters loadParameters;
-    loadParameters.identifier = generatePingLoadIdentifier();
+    loadParameters.identifier = generateLoadIdentifier();
     loadParameters.request = request;
     loadParameters.sourceOrigin = &document->securityOrigin();
     loadParameters.sessionID = webPage ? webPage->sessionID() : PAL::SessionID::defaultSessionID();
@@ -459,6 +463,20 @@ void WebLoaderStrategy::didFinishPingLoad(uint64_t pingLoadIdentifier, ResourceE
         completionHandler(WTFMove(error));
 }
 
+void WebLoaderStrategy::preconnectTo(PAL::SessionID sessionID, const WebCore::URL& url, StoredCredentialsPolicy storedCredentialsPolicy, PreconnectCompletionHandler&& completionHandler)
+{
+    uint64_t preconnectionIdentifier = generateLoadIdentifier();
+    auto addResult = m_preconnectCompletionHandlers.add(preconnectionIdentifier, WTFMove(completionHandler));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+    WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::PreconnectTo(sessionID, preconnectionIdentifier, url, storedCredentialsPolicy), 0);
+}
+
+void WebLoaderStrategy::didFinishPreconnection(uint64_t preconnectionIdentifier, ResourceError&& error)
+{
+    if (auto completionHandler = m_preconnectCompletionHandlers.take(preconnectionIdentifier))
+        completionHandler(WTFMove(error));
+}
+
 void WebLoaderStrategy::storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer& data)
 {
 #if ENABLE(NETWORK_CACHE)
index 573028e..7256b5d 100644 (file)
@@ -62,6 +62,9 @@ public:
     void startPingLoad(WebCore::Frame&, WebCore::ResourceRequest&, const WebCore::HTTPHeaderMap& originalRequestHeaders, const WebCore::FetchOptions&, PingLoadCompletionHandler&&) final;
     void didFinishPingLoad(uint64_t pingLoadIdentifier, WebCore::ResourceError&&);
 
+    void preconnectTo(PAL::SessionID, const WebCore::URL&, WebCore::StoredCredentialsPolicy, PreconnectCompletionHandler&&) final;
+    void didFinishPreconnection(uint64_t preconnectionIdentifier, WebCore::ResourceError&&);
+
     void storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer&) final;
 
     void setCaptureExtraNetworkLoadMetricsEnabled(bool) final;
@@ -86,6 +89,7 @@ private:
     HashMap<unsigned long, RefPtr<WebResourceLoader>> m_webResourceLoaders;
     HashMap<unsigned long, WebURLSchemeTaskProxy*> m_urlSchemeTasks;
     HashMap<unsigned long, PingLoadCompletionHandler> m_pingLoadCompletionHandlers;
+    HashMap<unsigned long, PreconnectCompletionHandler> m_preconnectCompletionHandlers;
 };
 
 } // namespace WebKit
index 1ea7a3c..170edf7 100644 (file)
@@ -3090,6 +3090,7 @@ void WebPage::updatePreferences(const WebPreferencesStore& store)
     settings.setPaginateDuringLayoutEnabled(store.getBoolValueForKey(WebPreferencesKey::paginateDuringLayoutEnabledKey()));
     settings.setDOMPasteAllowed(store.getBoolValueForKey(WebPreferencesKey::domPasteAllowedKey()));
     settings.setJavaScriptCanAccessClipboard(store.getBoolValueForKey(WebPreferencesKey::javaScriptCanAccessClipboardKey()));
+    settings.setLinkPreconnectEnabled(store.getBoolValueForKey(WebPreferencesKey::linkPreconnectKey()));
     settings.setShouldPrintBackgrounds(store.getBoolValueForKey(WebPreferencesKey::shouldPrintBackgroundsKey()));
     settings.setWebSecurityEnabled(store.getBoolValueForKey(WebPreferencesKey::webSecurityEnabledKey()));
     settings.setAllowUniversalAccessFromFileURLs(store.getBoolValueForKey(WebPreferencesKey::allowUniversalAccessFromFileURLsKey()));
index e867f48..caf4fd7 100644 (file)
 #endif
 #endif
 
+#if USE(NETWORK_SESSION) && ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000))
+#ifndef ENABLE_SERVER_PRECONNECT
+#define ENABLE_SERVER_PRECONNECT 1
+#endif
+#endif
+
 #ifndef HAVE_SEC_ACCESS_CONTROL
 #if PLATFORM(IOS) || PLATFORM(MAC)
 #define HAVE_SEC_ACCESS_CONTROL 1
index f825036..c8180f3 100644 (file)
@@ -1,3 +1,15 @@
+2017-09-28  Chris Dumez  <cdumez@apple.com>
+
+        Add support for <link rel=preconnect>
+        https://bugs.webkit.org/show_bug.cgi?id=177474
+        <rdar://problem/33141380>
+
+        Reviewed by Alex Christensen.
+
+        * WebCoreSupport/WebResourceLoadScheduler.cpp:
+        (WebResourceLoadScheduler::preconnectTo):
+        * WebCoreSupport/WebResourceLoadScheduler.h:
+
 2017-09-26  Per Arne Vollan  <pvollan@apple.com>
 
         [Win] WebKitCOMAPI.h is not copied after build has finished.
index 4d2985d..7975bd3 100644 (file)
@@ -369,3 +369,7 @@ void WebResourceLoadScheduler::startPingLoad(Frame& frame, ResourceRequest& requ
     new PingHandle(frame.loader().networkingContext(), request, options.credentials != FetchOptions::Credentials::Omit, PingHandle::UsesAsyncCallbacks::No, options.redirect == FetchOptions::Redirect::Follow, WTFMove(completionHandler));
 }
 
+void WebResourceLoadScheduler::preconnectTo(PAL::SessionID, const URL&, StoredCredentialsPolicy, PreconnectCompletionHandler&&)
+{
+}
+
index 0e0c2de..ecfc1cf 100644 (file)
@@ -61,6 +61,8 @@ public:
 
     void startPingLoad(WebCore::Frame&, WebCore::ResourceRequest&, const WebCore::HTTPHeaderMap&, const WebCore::FetchOptions&, PingLoadCompletionHandler&&) final;
 
+    void preconnectTo(PAL::SessionID, const WebCore::URL&, WebCore::StoredCredentialsPolicy, PreconnectCompletionHandler&&) final;
+
     void storeDerivedDataToCache(const SHA1::Digest&, const String&, const String&, WebCore::SharedBuffer&) final { }
 
     void setCaptureExtraNetworkLoadMetricsEnabled(bool) final { }