Diff
Modified: trunk/Source/WebCore/ChangeLog (277335 => 277336)
--- trunk/Source/WebCore/ChangeLog 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebCore/ChangeLog 2021-05-11 19:47:50 UTC (rev 277336)
@@ -1,3 +1,26 @@
+2021-05-11 Alex Christensen <[email protected]>
+
+ Add SPI to restrict networking to a set of hosts
+ https://bugs.webkit.org/show_bug.cgi?id=225426
+ <rdar://77571521>
+
+ Reviewed by Tim Horton.
+
+ In r259392 I added SPI to turn network access on and off, but a client needs finer grained control.
+ This uses the same infrastructure to add a set of hosts to allow. Setting it to nil (the default) allows all hosts,
+ but setting it to an empty set allows no network access. This accomplishes the same ability as the old SPI, so I'm deprecating it
+ with this as a replacement. The new ability to specify a finite number of hosts to allow creates a limited WKWebView.
+
+ * Modules/websockets/ThreadableWebSocketChannel.cpp:
+ (WebCore::ThreadableWebSocketChannel::validateURL):
+ * loader/ResourceLoadNotifier.cpp:
+ (WebCore::ResourceLoadNotifier::dispatchWillSendRequest):
+ * page/Page.cpp:
+ (WebCore::Page::allowsLoadFromURL const):
+ * page/Page.h:
+ (WebCore::Page::loadsFromNetwork const): Deleted.
+ * page/PageConfiguration.h:
+
2021-05-11 Megan Gardner <[email protected]>
Factor out find bounce layer
Modified: trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannel.cpp (277335 => 277336)
--- trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannel.cpp 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannel.cpp 2021-05-11 19:47:50 UTC (rev 277336)
@@ -89,7 +89,7 @@
{
ValidatedURL validatedURL { requestedURL, true };
if (auto* page = document.page()) {
- if (!page->loadsFromNetwork())
+ if (!page->allowsLoadFromURL(requestedURL))
return { };
#if ENABLE(CONTENT_EXTENSIONS)
if (auto* documentLoader = document.loader()) {
Modified: trunk/Source/WebCore/loader/ResourceLoadNotifier.cpp (277335 => 277336)
--- trunk/Source/WebCore/loader/ResourceLoadNotifier.cpp 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebCore/loader/ResourceLoadNotifier.cpp 2021-05-11 19:47:50 UTC (rev 277336)
@@ -137,7 +137,7 @@
if (!page->loadsSubresources()) {
if (!m_frame.isMainFrame() || (m_initialRequestIdentifier && *m_initialRequestIdentifier != identifier))
request = { };
- } else if (!page->loadsFromNetwork() && request.url().protocolIsInHTTPFamily())
+ } else if (!page->allowsLoadFromURL(request.url()))
request = { };
}
Modified: trunk/Source/WebCore/page/Page.cpp (277335 => 277336)
--- trunk/Source/WebCore/page/Page.cpp 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebCore/page/Page.cpp 2021-05-11 19:47:50 UTC (rev 277336)
@@ -305,8 +305,8 @@
, m_deviceOrientationUpdateProvider(WTFMove(pageConfiguration.deviceOrientationUpdateProvider))
#endif
, m_corsDisablingPatterns(WTFMove(pageConfiguration.corsDisablingPatterns))
+ , m_allowedNetworkHosts(WTFMove(pageConfiguration.allowedNetworkHosts))
, m_loadsSubresources(pageConfiguration.loadsSubresources)
- , m_loadsFromNetwork(pageConfiguration.loadsFromNetwork)
, m_shouldRelaxThirdPartyCookieBlocking(pageConfiguration.shouldRelaxThirdPartyCookieBlocking)
, m_httpsUpgradeEnabled(pageConfiguration.httpsUpgradeEnabled)
{
@@ -3299,6 +3299,15 @@
#endif
}
+bool Page::allowsLoadFromURL(const URL& url) const
+{
+ if (!m_allowedNetworkHosts)
+ return true;
+ if (!url.protocolIsInHTTPFamily() && !url.protocolIs("ws") && !url.protocolIs("wss"))
+ return true;
+ return m_allowedNetworkHosts->contains(url.host().toStringWithoutCopying());
+}
+
void Page::applicationWillResignActive()
{
#if ENABLE(VIDEO)
Modified: trunk/Source/WebCore/page/Page.h (277335 => 277336)
--- trunk/Source/WebCore/page/Page.h 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebCore/page/Page.h 2021-05-11 19:47:50 UTC (rev 277336)
@@ -794,7 +794,7 @@
bool isUtilityPage() const { return m_isUtilityPage; }
bool loadsSubresources() const { return m_loadsSubresources; }
- bool loadsFromNetwork() const { return m_loadsFromNetwork; }
+ bool allowsLoadFromURL(const URL&) const;
ShouldRelaxThirdPartyCookieBlocking shouldRelaxThirdPartyCookieBlocking() const { return m_shouldRelaxThirdPartyCookieBlocking; }
bool isLowPowerModeEnabled() const { return m_throttlingReasons.contains(ThrottlingReason::LowPowerMode); }
@@ -1142,9 +1142,9 @@
Vector<UserContentURLPattern> m_corsDisablingPatterns;
Vector<UserStyleSheet> m_userStyleSheetsPendingInjection;
+ Optional<HashSet<String>> m_allowedNetworkHosts;
bool m_isTakingSnapshotsForApplicationSuspension { false };
bool m_loadsSubresources { true };
- bool m_loadsFromNetwork { true };
bool m_canUseCredentialStorage { true };
ShouldRelaxThirdPartyCookieBlocking m_shouldRelaxThirdPartyCookieBlocking { ShouldRelaxThirdPartyCookieBlocking::No };
LoadSchedulingMode m_loadSchedulingMode { LoadSchedulingMode::Direct };
Modified: trunk/Source/WebCore/page/PageConfiguration.h (277335 => 277336)
--- trunk/Source/WebCore/page/PageConfiguration.h 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebCore/page/PageConfiguration.h 2021-05-11 19:47:50 UTC (rev 277336)
@@ -132,7 +132,7 @@
// FIXME: These should be all be Settings.
bool loadsSubresources { true };
- bool loadsFromNetwork { true };
+ Optional<HashSet<String>> allowedNetworkHosts;
bool userScriptsShouldWaitUntilNotification { true };
ShouldRelaxThirdPartyCookieBlocking shouldRelaxThirdPartyCookieBlocking { ShouldRelaxThirdPartyCookieBlocking::No };
bool httpsUpgradeEnabled { true };
Modified: trunk/Source/WebKit/ChangeLog (277335 => 277336)
--- trunk/Source/WebKit/ChangeLog 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebKit/ChangeLog 2021-05-11 19:47:50 UTC (rev 277336)
@@ -1,3 +1,33 @@
+2021-05-11 Alex Christensen <[email protected]>
+
+ Add SPI to restrict networking to a set of hosts
+ https://bugs.webkit.org/show_bug.cgi?id=225426
+ <rdar://77571521>
+
+ Reviewed by Tim Horton.
+
+ * Shared/WebPageCreationParameters.cpp:
+ (WebKit::WebPageCreationParameters::encode const):
+ (WebKit::WebPageCreationParameters::decode):
+ * Shared/WebPageCreationParameters.h:
+ * UIProcess/API/APIPageConfiguration.cpp:
+ (API::PageConfiguration::copy const):
+ * UIProcess/API/APIPageConfiguration.h:
+ (API::PageConfiguration::allowedNetworkHosts const):
+ (API::PageConfiguration::setAllowedNetworkHosts):
+ (API::PageConfiguration::loadsFromNetwork const): Deleted.
+ (API::PageConfiguration::setLoadsFromNetwork): Deleted.
+ * UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
+ (-[WKWebViewConfiguration _setLoadsFromNetwork:]):
+ (-[WKWebViewConfiguration _loadsFromNetwork]):
+ (-[WKWebViewConfiguration _setAllowedNetworkHosts:]):
+ (-[WKWebViewConfiguration _allowedNetworkHosts]):
+ * UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::creationParameters):
+ * WebProcess/WebPage/WebPage.cpp:
+ (WebKit::m_lastNavigationWasAppBound):
+
2021-05-11 Brent Fulgham <[email protected]>
[macOS] Extend access to 'com.apple.print.normalizerd' when canvas drawing is done in the WebContent process
Modified: trunk/Source/WebKit/Shared/WebPageCreationParameters.cpp (277335 => 277336)
--- trunk/Source/WebKit/Shared/WebPageCreationParameters.cpp 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebKit/Shared/WebPageCreationParameters.cpp 2021-05-11 19:47:50 UTC (rev 277336)
@@ -151,7 +151,7 @@
encoder << overriddenMediaType;
encoder << corsDisablingPatterns;
encoder << loadsSubresources;
- encoder << loadsFromNetwork;
+ encoder << allowedNetworkHosts;
encoder << userScriptsShouldWaitUntilNotification;
encoder << crossOriginAccessControlCheckEnabled;
encoder << processDisplayName;
@@ -509,11 +509,11 @@
return WTF::nullopt;
parameters.loadsSubresources = *loadsSubresources;
- Optional<bool> loadsFromNetwork;
- decoder >> loadsFromNetwork;
- if (!loadsFromNetwork)
+ Optional<Optional<HashSet<String>>> allowedNetworkHosts;
+ decoder >> allowedNetworkHosts;
+ if (!allowedNetworkHosts)
return WTF::nullopt;
- parameters.loadsFromNetwork = *loadsFromNetwork;
+ parameters.allowedNetworkHosts = *allowedNetworkHosts;
Optional<bool> userScriptsShouldWaitUntilNotification;
decoder >> userScriptsShouldWaitUntilNotification;
Modified: trunk/Source/WebKit/Shared/WebPageCreationParameters.h (277335 => 277336)
--- trunk/Source/WebKit/Shared/WebPageCreationParameters.h 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebKit/Shared/WebPageCreationParameters.h 2021-05-11 19:47:50 UTC (rev 277336)
@@ -222,7 +222,7 @@
Vector<String> corsDisablingPatterns;
bool userScriptsShouldWaitUntilNotification { true };
bool loadsSubresources { true };
- bool loadsFromNetwork { true };
+ Optional<HashSet<String>> allowedNetworkHosts;
bool crossOriginAccessControlCheckEnabled { true };
String processDisplayName;
Modified: trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp (277335 => 277336)
--- trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp 2021-05-11 19:47:50 UTC (rev 277336)
@@ -87,7 +87,7 @@
copy->m_processDisplayName = this->m_processDisplayName;
copy->m_loadsSubresources = this->m_loadsSubresources;
- copy->m_loadsFromNetwork = this->m_loadsFromNetwork;
+ copy->m_allowedNetworkHosts = this->m_allowedNetworkHosts;
#if ENABLE(APP_BOUND_DOMAINS)
copy->m_ignoresAppBoundDomains = this->m_ignoresAppBoundDomains;
copy->m_limitsNavigationsToAppBoundDomains = this->m_limitsNavigationsToAppBoundDomains;
Modified: trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h (277335 => 277336)
--- trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h 2021-05-11 19:47:50 UTC (rev 277336)
@@ -30,6 +30,7 @@
#include <wtf/Forward.h>
#include <wtf/GetPtr.h>
#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
#include <wtf/text/WTFString.h>
#if PLATFORM(IOS_FAMILY)
@@ -146,8 +147,8 @@
bool loadsSubresources() const { return m_loadsSubresources; }
void setLoadsSubresources(bool loads) { m_loadsSubresources = loads; }
- bool loadsFromNetwork() const { return m_loadsFromNetwork; }
- void setLoadsFromNetwork(bool loads) { m_loadsFromNetwork = loads; }
+ const Optional<HashSet<WTF::String>>& allowedNetworkHosts() const { return m_allowedNetworkHosts; }
+ void setAllowedNetworkHosts(Optional<HashSet<WTF::String>>&& hosts) { m_allowedNetworkHosts = WTFMove(hosts); }
#if ENABLE(APP_BOUND_DOMAINS)
bool ignoresAppBoundDomains() const { return m_ignoresAppBoundDomains; }
@@ -205,7 +206,7 @@
bool m_crossOriginAccessControlCheckEnabled { true };
WTF::String m_processDisplayName;
bool m_loadsSubresources { true };
- bool m_loadsFromNetwork { true };
+ Optional<HashSet<WTF::String>> m_allowedNetworkHosts;
#if ENABLE(APP_BOUND_DOMAINS)
bool m_ignoresAppBoundDomains { false };
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm (277335 => 277336)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm 2021-05-11 19:47:50 UTC (rev 277336)
@@ -952,14 +952,35 @@
- (void)_setLoadsFromNetwork:(BOOL)loads
{
- _pageConfiguration->setLoadsFromNetwork(loads);
+ _pageConfiguration->setAllowedNetworkHosts(loads ? WTF::nullopt : Optional<HashSet<String>> { HashSet<String> { } });
}
- (BOOL)_loadsFromNetwork
{
- return _pageConfiguration->loadsFromNetwork();
+ return _pageConfiguration->allowedNetworkHosts() == WTF::nullopt;
}
+- (void)_setAllowedNetworkHosts:(NSSet<NSString *> *)hosts
+{
+ if (!hosts)
+ return _pageConfiguration->setAllowedNetworkHosts(WTF::nullopt);
+ HashSet<String> set;
+ for (NSString *host in hosts)
+ set.add(host);
+ _pageConfiguration->setAllowedNetworkHosts(WTFMove(set));
+}
+
+- (NSSet<NSString *> *)_allowedNetworkHosts
+{
+ const auto& hosts = _pageConfiguration->allowedNetworkHosts();
+ if (!hosts)
+ return nil;
+ NSMutableSet<NSString *> *set = [NSMutableSet setWithCapacity:hosts->size()];
+ for (const auto& host : *hosts)
+ [set addObject:host];
+ return set;
+}
+
- (void)_setLoadsSubresources:(BOOL)loads
{
_pageConfiguration->setLoadsSubresources(loads);
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h (277335 => 277336)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h 2021-05-11 19:47:50 UTC (rev 277336)
@@ -79,7 +79,8 @@
@property (nonatomic, setter=_setDeferrableUserScriptsShouldWaitUntilNotification:) BOOL _deferrableUserScriptsShouldWaitUntilNotification WK_API_AVAILABLE(macos(11.0), ios(14.0));
@property (nonatomic, setter=_setCrossOriginAccessControlCheckEnabled:) BOOL _crossOriginAccessControlCheckEnabled WK_API_AVAILABLE(macos(11.0), ios(14.0));
-@property (nonatomic, setter=_setLoadsFromNetwork:) BOOL _loadsFromNetwork WK_API_AVAILABLE(macos(11.0), ios(14.0));
+@property (nonatomic, setter=_setLoadsFromNetwork:) BOOL _loadsFromNetwork WK_API_DEPRECATED_WITH_REPLACEMENT("_allowedNetworkHosts", macos(11.0, WK_MAC_TBA), ios(14.0, WK_IOS_TBA));
+@property (nonatomic, copy, setter=_setAllowedNetworkHosts:) NSSet<NSString *> *_allowedNetworkHosts WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
@property (nonatomic, setter=_setLoadsSubresources:) BOOL _loadsSubresources WK_API_AVAILABLE(macos(11.0), ios(14.0));
@property (nonatomic, setter=_setIgnoresAppBoundDomains:) BOOL _ignoresAppBoundDomains WK_API_AVAILABLE(macos(11.0), ios(14.0));
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (277335 => 277336)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2021-05-11 19:47:50 UTC (rev 277336)
@@ -8033,7 +8033,7 @@
parameters.overriddenMediaType = m_overriddenMediaType;
parameters.corsDisablingPatterns = corsDisablingPatterns();
parameters.userScriptsShouldWaitUntilNotification = m_configuration->userScriptsShouldWaitUntilNotification();
- parameters.loadsFromNetwork = m_configuration->loadsFromNetwork();
+ parameters.allowedNetworkHosts = m_configuration->allowedNetworkHosts();
parameters.loadsSubresources = m_configuration->loadsSubresources();
parameters.crossOriginAccessControlCheckEnabled = m_configuration->crossOriginAccessControlCheckEnabled();
parameters.hasResourceLoadClient = !!m_resourceLoadClient;
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (277335 => 277336)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2021-05-11 19:47:50 UTC (rev 277336)
@@ -605,7 +605,7 @@
pageConfiguration.userScriptsShouldWaitUntilNotification = parameters.userScriptsShouldWaitUntilNotification;
pageConfiguration.loadsSubresources = parameters.loadsSubresources;
- pageConfiguration.loadsFromNetwork = parameters.loadsFromNetwork;
+ pageConfiguration.allowedNetworkHosts = parameters.allowedNetworkHosts;
pageConfiguration.shouldRelaxThirdPartyCookieBlocking = parameters.shouldRelaxThirdPartyCookieBlocking;
pageConfiguration.httpsUpgradeEnabled = parameters.httpsUpgradeEnabled;
Modified: trunk/Tools/ChangeLog (277335 => 277336)
--- trunk/Tools/ChangeLog 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Tools/ChangeLog 2021-05-11 19:47:50 UTC (rev 277336)
@@ -1,3 +1,20 @@
+2021-05-11 Alex Christensen <[email protected]>
+
+ Add SPI to restrict networking to a set of hosts
+ https://bugs.webkit.org/show_bug.cgi?id=225426
+ <rdar://77571521>
+
+ Reviewed by Tim Horton.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/ContentRuleListNotification.mm:
+ (TEST):
+ (webSocketAcceptValue): Deleted.
+ * TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm:
+ * TestWebKitAPI/cocoa/HTTPServer.h:
+ (TestWebKitAPI::Connection::webSocketHandshake):
+ * TestWebKitAPI/cocoa/HTTPServer.mm:
+ (TestWebKitAPI::Connection::webSocketHandshake):
+
2021-05-11 Diego Pino Garcia <[email protected]>
[GTK] compositing/overflow/dynamic-composited-scrolling-status.html is failing
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ContentRuleListNotification.mm (277335 => 277336)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ContentRuleListNotification.mm 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ContentRuleListNotification.mm 2021-05-11 19:47:50 UTC (rev 277336)
@@ -43,10 +43,8 @@
#import <WebKit/_WKContentRuleListAction.h>
#import <WebKit/_WKWebsiteDataStoreConfiguration.h>
#import <wtf/RetainPtr.h>
-#import <wtf/SHA1.h>
#import <wtf/URL.h>
#import <wtf/cocoa/VectorCocoa.h>
-#import <wtf/text/Base64.h>
#import <wtf/text/WTFString.h>
static bool receivedNotification;
@@ -221,34 +219,11 @@
EXPECT_TRUE(expectedNotifications == notificationList);
}
-static String webSocketAcceptValue(const Vector<char>& request)
-{
- constexpr auto* keyHeaderField = "Sec-WebSocket-Key: ";
- const char* keyBegin = strnstr(request.data(), keyHeaderField, request.size()) + strlen(keyHeaderField);
- EXPECT_NOT_NULL(keyBegin);
- const char* keyEnd = strnstr(keyBegin, "\r\n", request.size() + (keyBegin - request.data()));
- EXPECT_NOT_NULL(keyEnd);
-
- constexpr auto* webSocketKeyGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- SHA1 sha1;
- sha1.addBytes(reinterpret_cast<const uint8_t*>(keyBegin), keyEnd - keyBegin);
- sha1.addBytes(reinterpret_cast<const uint8_t*>(webSocketKeyGUID), strlen(webSocketKeyGUID));
- SHA1::Digest hash;
- sha1.computeHash(hash);
- return base64Encode(hash.data(), SHA1::hashSize);
-}
-
TEST(ContentRuleList, ResourceTypes)
{
using namespace TestWebKitAPI;
HTTPServer webSocketServer([](Connection connection) {
- connection.receiveHTTPRequest([=](Vector<char>&& request) {
- connection.send(HTTPResponse(101, {
- { "Upgrade", "websocket" },
- { "Connection", "Upgrade" },
- { "Sec-WebSocket-Accept", webSocketAcceptValue(request) }
- }).serialize(HTTPResponse::IncludeContentLength::No));
- });
+ connection.webSocketHandshake();
});
auto serverPort = webSocketServer.port();
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm (277335 => 277336)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm 2021-05-11 19:47:50 UTC (rev 277336)
@@ -48,6 +48,7 @@
#import <wtf/Threading.h>
#import <wtf/Vector.h>
#import <wtf/WeakObjCPtr.h>
+#import <wtf/text/StringConcatenateNumbers.h>
#import <wtf/text/StringHash.h>
#import <wtf/text/WTFString.h>
@@ -1100,12 +1101,17 @@
TEST(URLSchemeHandler, LoadsFromNetwork)
{
- TestWebKitAPI::HTTPServer server({
+ using namespace TestWebKitAPI;
+ HTTPServer server({
{ "/", { {{ "Access-Control-Allow-Origin", "*" }}, "test content" } }
});
- bool loadSuccess = false;
- bool loadFail = false;
+ HTTPServer webSocketServer([](Connection connection) {
+ connection.webSocketHandshake();
+ });
+
+ Optional<bool> loadSuccess;
+ Optional<bool> webSocketSuccess;
bool done = false;
auto handler = adoptNS([TestURLSchemeHandler new]);
@@ -1114,50 +1120,139 @@
[configuration setURLSchemeHandler:handler.get() forURLScheme:@"test"];
[handler setStartURLSchemeTaskHandler:[&](WKWebView *, id<WKURLSchemeTask> task) {
- if ([task.request.URL.path isEqualToString:@"/main.html"]) {
- NSData *data = "" stringWithFormat:@"<script>"
- "fetch('http://127.0.0.1:%d/').then(()=>{"
- "fetch('/loadSuccess')"
+ NSString *path = task.request.URL.path;
+ if ([path isEqualToString:@"/main.html"]) {
+ respond(task, [NSString stringWithFormat:@"<script>"
+ "function checkWebSockets() {"
+ "var ws = new WebSocket('ws://127.0.0.1:%d');"
+ "ws._onerror_ = function() { fetch('/webSocketFail') };"
+ "ws._onopen_ = function() { fetch('/webSocketSuccess') };"
+ "}"
+ "fetch('http://localhost:%d/').then(()=>{"
+ "fetch('/loadSuccess').then(()=>{ checkWebSockets() })"
"}).catch(()=>{"
- "var ws = new WebSocket('ws://127.0.0.1:%d');"
- "ws._onerror_ = function() { fetch('/loadFail') };"
+ "fetch('/loadFail').then(()=>{ checkWebSockets() })"
"})"
- "</script>", server.port(), server.port()] dataUsingEncoding:NSUTF8StringEncoding];
- [task didReceiveResponse:adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:data.length textEncodingName:nil]).get()];
- [task didReceiveData:data];
- [task didFinish];
- } else if ([task.request.URL.path isEqualToString:@"/loadSuccess"]) {
+ "</script>", webSocketServer.port(), server.port()].UTF8String);
+ } else if ([path isEqualToString:@"/loadSuccess"]) {
+ respond(task, "hi");
loadSuccess = true;
+ } else if ([path isEqualToString:@"/loadFail"]) {
+ respond(task, "hi");
+ loadSuccess = false;
+ } else if ([path isEqualToString:@"/webSocketSuccess"]) {
+ webSocketSuccess = true;
done = true;
- } else if ([task.request.URL.path isEqualToString:@"/loadFail"]) {
- loadFail = true;
+ } else if ([path isEqualToString:@"/webSocketFail"]) {
+ webSocketSuccess = false;
done = true;
} else
ASSERT_NOT_REACHED();
}];
- {
+ auto runTest = [&] {
+ loadSuccess = WTF::nullopt;
+ webSocketSuccess = WTF::nullopt;
+ done = false;
auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test://host1/main.html"]]];
TestWebKitAPI::Util::run(&done);
- }
- EXPECT_TRUE(loadSuccess);
- EXPECT_FALSE(loadFail);
+ };
+
+ runTest();
+ EXPECT_TRUE(*loadSuccess);
+ EXPECT_TRUE(*webSocketSuccess);
EXPECT_EQ(server.totalRequests(), 1u);
+
+ configuration.get()._loadsFromNetwork = NO;
+ runTest();
+ EXPECT_FALSE(*loadSuccess);
+ EXPECT_FALSE(*webSocketSuccess);
+ EXPECT_EQ(server.totalRequests(), 1u);
- loadSuccess = false;
- loadFail = false;
- done = false;
+ configuration.get()._allowedNetworkHosts = [NSSet set];
+ runTest();
+ EXPECT_FALSE(*loadSuccess);
+ EXPECT_FALSE(*webSocketSuccess);
+ EXPECT_EQ(server.totalRequests(), 1u);
- configuration.get()._loadsFromNetwork = NO;
- {
+ configuration.get()._allowedNetworkHosts = nil;
+ runTest();
+ EXPECT_TRUE(*loadSuccess);
+ EXPECT_TRUE(*webSocketSuccess);
+ EXPECT_EQ(server.totalRequests(), 2u);
+
+ configuration.get()._allowedNetworkHosts = [NSSet setWithObject:@"localhost"];
+ runTest();
+ EXPECT_TRUE(*loadSuccess);
+ EXPECT_FALSE(*webSocketSuccess);
+ EXPECT_EQ(server.totalRequests(), 3u);
+}
+
+TEST(URLSchemeHandler, AllowedNetworkHostsRedirect)
+{
+ TestWebKitAPI::HTTPServer serverLocalhost({
+ { "/redirectTarget", { {{ "Access-Control-Allow-Origin", "*" }}, "test content" } }
+ });
+ TestWebKitAPI::HTTPServer server127001({
+ { "/", { 301, {
+ { "Access-Control-Allow-Origin", "*" },
+ { "Location", makeString("http://localhost:", serverLocalhost.port(), "/redirectTarget") }
+ }}},
+ });
+
+ Optional<bool> loadSuccess;
+ bool done = false;
+
+ auto handler = adoptNS([TestURLSchemeHandler new]);
+
+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ [configuration setURLSchemeHandler:handler.get() forURLScheme:@"test"];
+
+ [handler setStartURLSchemeTaskHandler:[&](WKWebView *, id<WKURLSchemeTask> task) {
+ NSString *path = task.request.URL.path;
+ if ([path isEqualToString:@"/main.html"]) {
+ respond(task, [NSString stringWithFormat:@"<script>"
+ "fetch('http://127.0.0.1:%d/').then(()=>{"
+ "fetch('/loadSuccess')"
+ "}).catch(()=>{"
+ "fetch('/loadFail')"
+ "})"
+ "</script>", server127001.port()].UTF8String);
+ } else if ([path isEqualToString:@"/loadSuccess"]) {
+ loadSuccess = true;
+ done = true;
+ } else if ([path isEqualToString:@"/loadFail"]) {
+ loadSuccess = false;
+ done = true;
+ }
+ }];
+
+ auto runTest = [&] {
+ loadSuccess = WTF::nullopt;
+ done = false;
+ configuration.get().websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test://host1/main.html"]]];
TestWebKitAPI::Util::run(&done);
- }
- EXPECT_FALSE(loadSuccess);
- EXPECT_TRUE(loadFail);
- EXPECT_EQ(server.totalRequests(), 1u);
+ };
+
+ runTest();
+ EXPECT_TRUE(*loadSuccess);
+ EXPECT_EQ(serverLocalhost.totalRequests(), 1u);
+ EXPECT_EQ(server127001.totalRequests(), 1u);
+
+ configuration.get()._allowedNetworkHosts = [NSSet set];
+ runTest();
+ EXPECT_FALSE(*loadSuccess);
+ EXPECT_EQ(serverLocalhost.totalRequests(), 1u);
+ EXPECT_EQ(server127001.totalRequests(), 1u);
+
+ configuration.get()._allowedNetworkHosts = [NSSet setWithObject:@"127.0.0.1"];
+ runTest();
+ EXPECT_FALSE(*loadSuccess);
+ EXPECT_EQ(serverLocalhost.totalRequests(), 1u);
+ EXPECT_EQ(server127001.totalRequests(), 2u);
}
TEST(URLSchemeHandler, LoadsSubresources)
Modified: trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h (277335 => 277336)
--- trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h 2021-05-11 19:47:50 UTC (rev 277336)
@@ -71,6 +71,7 @@
void send(RetainPtr<dispatch_data_t>&&, CompletionHandler<void()>&& = nullptr) const;
void receiveBytes(CompletionHandler<void(Vector<uint8_t>&&)>&&) const;
void receiveHTTPRequest(CompletionHandler<void(Vector<char>&&)>&&, Vector<char>&& buffer = { }) const;
+ void webSocketHandshake(CompletionHandler<void()>&& = { });
void terminate();
void cancel();
Modified: trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm (277335 => 277336)
--- trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm 2021-05-11 19:02:56 UTC (rev 277335)
+++ trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm 2021-05-11 19:47:50 UTC (rev 277336)
@@ -30,7 +30,9 @@
#import <wtf/BlockPtr.h>
#import <wtf/CompletionHandler.h>
#import <wtf/RetainPtr.h>
+#import <wtf/SHA1.h>
#import <wtf/ThreadSafeRefCounted.h>
+#import <wtf/text/Base64.h>
#import <wtf/text/StringBuilder.h>
#import <wtf/text/WTFString.h>
@@ -325,6 +327,34 @@
}).get());
}
+void Connection::webSocketHandshake(CompletionHandler<void()>&& connectionHandler)
+{
+ receiveHTTPRequest([connection = Connection(*this), connectionHandler = WTFMove(connectionHandler)] (Vector<char>&& request) mutable {
+
+ auto webSocketAcceptValue = [] (const Vector<char>& request) {
+ constexpr auto* keyHeaderField = "Sec-WebSocket-Key: ";
+ const char* keyBegin = strnstr(request.data(), keyHeaderField, request.size()) + strlen(keyHeaderField);
+ ASSERT(keyBegin);
+ const char* keyEnd = strnstr(keyBegin, "\r\n", request.size() + (keyBegin - request.data()));
+ ASSERT(keyEnd);
+
+ constexpr auto* webSocketKeyGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ SHA1 sha1;
+ sha1.addBytes(reinterpret_cast<const uint8_t*>(keyBegin), keyEnd - keyBegin);
+ sha1.addBytes(reinterpret_cast<const uint8_t*>(webSocketKeyGUID), strlen(webSocketKeyGUID));
+ SHA1::Digest hash;
+ sha1.computeHash(hash);
+ return base64Encode(hash.data(), SHA1::hashSize);
+ };
+
+ connection.send(HTTPResponse(101, {
+ { "Upgrade", "websocket" },
+ { "Connection", "Upgrade" },
+ { "Sec-WebSocket-Accept", webSocketAcceptValue(request) }
+ }).serialize(HTTPResponse::IncludeContentLength::No), WTFMove(connectionHandler));
+ });
+}
+
void Connection::terminate()
{
nw_connection_cancel(m_connection.get());