- Revision
- 280319
- Author
- [email protected]
- Date
- 2021-07-26 15:09:27 -0700 (Mon, 26 Jul 2021)
Log Message
ServiceWorkerRegistration.unregister method fails in WKWebView
https://bugs.webkit.org/show_bug.cgi?id=227524
<rdar://problem/80264108>
Reviewed by Youenn Fablet.
Source/WebCore:
We should only check the app-bound domain list when registering a new
worker. Unregistering or updating an existing registration is fine because
we know that every registration has already gone through this check.
* workers/service/server/SWServer.cpp:
(WebCore::SWServer::addRegistrationFromStore):
(WebCore::SWServer::validateRegistrationDomain):
(WebCore::SWServer::scheduleJob):
* workers/service/server/SWServer.h:
Tools:
API test coverage. Drive-by fix to remove unnecessary WKWebView
configuration flags from tests that don't need them.
Note this will also fix https://bugs.webkit.org/show_bug.cgi?id=227531
where updating an existing worker fails after registering 3 domains,
but writing a test for that would require registering service workers
on 3 domains that are not localhost or a loopback IP address, which
we currently do not have infrastructure for.
Testing unregister was only possible because the script URL passed in
during the unregister job is null, so it does not get caught in the
localhost/loopback IP address check, unlike the update case.
* TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm:
(TEST):
(-[SWInAppBrowserPrivacyMessageHandler userContentController:didReceiveScriptMessage:]):
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (280318 => 280319)
--- trunk/Source/WebCore/ChangeLog 2021-07-26 22:07:20 UTC (rev 280318)
+++ trunk/Source/WebCore/ChangeLog 2021-07-26 22:09:27 UTC (rev 280319)
@@ -1,3 +1,21 @@
+2021-07-26 Kate Cheney <[email protected]>
+
+ ServiceWorkerRegistration.unregister method fails in WKWebView
+ https://bugs.webkit.org/show_bug.cgi?id=227524
+ <rdar://problem/80264108>
+
+ Reviewed by Youenn Fablet.
+
+ We should only check the app-bound domain list when registering a new
+ worker. Unregistering or updating an existing registration is fine because
+ we know that every registration has already gone through this check.
+
+ * workers/service/server/SWServer.cpp:
+ (WebCore::SWServer::addRegistrationFromStore):
+ (WebCore::SWServer::validateRegistrationDomain):
+ (WebCore::SWServer::scheduleJob):
+ * workers/service/server/SWServer.h:
+
2021-07-26 Cameron McCormack <[email protected]>
Don't allow descriptors to be set to CSS-wide keywords
Modified: trunk/Source/WebCore/workers/service/server/SWServer.cpp (280318 => 280319)
--- trunk/Source/WebCore/workers/service/server/SWServer.cpp 2021-07-26 22:07:20 UTC (rev 280318)
+++ trunk/Source/WebCore/workers/service/server/SWServer.cpp 2021-07-26 22:09:27 UTC (rev 280319)
@@ -158,9 +158,9 @@
{
// Pages should not have been able to make a new registration to this key while the import was still taking place.
ASSERT(!m_scopeToRegistrationMap.contains(data.registration.key));
-
+
auto registrableDomain = WebCore::RegistrableDomain(data.scriptURL);
- validateRegistrationDomain(registrableDomain, [this, weakThis = makeWeakPtr(this), data = "" (bool isValid) mutable {
+ validateRegistrationDomain(registrableDomain, ServiceWorkerJobType::Register, [this, weakThis = makeWeakPtr(this), data = "" (bool isValid) mutable {
if (!weakThis)
return;
if (m_hasServiceWorkerEntitlement || isValid) {
@@ -346,19 +346,19 @@
allServers().add(this);
}
-void SWServer::validateRegistrationDomain(WebCore::RegistrableDomain domain, CompletionHandler<void(bool)>&& completionHandler)
+void SWServer::validateRegistrationDomain(WebCore::RegistrableDomain domain, ServiceWorkerJobType type, CompletionHandler<void(bool)>&& completionHandler)
{
if (m_hasServiceWorkerEntitlement || m_hasReceivedAppBoundDomains) {
- completionHandler(SecurityOrigin::isLocalHostOrLoopbackIPAddress(domain.string()) || (m_appBoundDomains.contains(domain) && m_uniqueRegistrationCount < maxRegistrationCount));
+ completionHandler(SecurityOrigin::isLocalHostOrLoopbackIPAddress(domain.string()) || type != ServiceWorkerJobType::Register || (m_appBoundDomains.contains(domain) && m_uniqueRegistrationCount < maxRegistrationCount));
return;
}
- m_appBoundDomainsCallback([this, weakThis = makeWeakPtr(this), domain = WTFMove(domain), completionHandler = WTFMove(completionHandler)](auto&& appBoundDomains) mutable {
+ m_appBoundDomainsCallback([this, weakThis = makeWeakPtr(this), domain = WTFMove(domain), type, completionHandler = WTFMove(completionHandler)](auto&& appBoundDomains) mutable {
if (!weakThis)
return;
m_hasReceivedAppBoundDomains = true;
m_appBoundDomains = WTFMove(appBoundDomains);
- completionHandler(SecurityOrigin::isLocalHostOrLoopbackIPAddress(domain.string()) || (m_appBoundDomains.contains(domain) && m_uniqueRegistrationCount < maxRegistrationCount));
+ completionHandler(SecurityOrigin::isLocalHostOrLoopbackIPAddress(domain.string()) || type != ServiceWorkerJobType::Register || (m_appBoundDomains.contains(domain) && m_uniqueRegistrationCount < maxRegistrationCount));
});
}
@@ -367,7 +367,7 @@
{
ASSERT(m_connections.contains(jobData.connectionIdentifier()) || jobData.connectionIdentifier() == Process::identifier());
- validateRegistrationDomain(WebCore::RegistrableDomain(jobData.scriptURL), [this, weakThis = makeWeakPtr(this), jobData = WTFMove(jobData)] (bool isValid) mutable {
+ validateRegistrationDomain(WebCore::RegistrableDomain(jobData.scriptURL), jobData.type, [this, weakThis = makeWeakPtr(this), jobData = WTFMove(jobData)] (bool isValid) mutable {
if (!weakThis)
return;
if (m_hasServiceWorkerEntitlement || isValid) {
Modified: trunk/Source/WebCore/workers/service/server/SWServer.h (280318 => 280319)
--- trunk/Source/WebCore/workers/service/server/SWServer.h 2021-07-26 22:07:20 UTC (rev 280318)
+++ trunk/Source/WebCore/workers/service/server/SWServer.h 2021-07-26 22:09:27 UTC (rev 280319)
@@ -220,7 +220,7 @@
LastNavigationWasAppInitiated clientIsAppInitiatedForRegistrableDomain(const RegistrableDomain&);
private:
- void validateRegistrationDomain(WebCore::RegistrableDomain, CompletionHandler<void(bool)>&&);
+ void validateRegistrationDomain(WebCore::RegistrableDomain, ServiceWorkerJobType, CompletionHandler<void(bool)>&&);
void scriptFetchFinished(const ServiceWorkerFetchResult&);
Modified: trunk/Tools/ChangeLog (280318 => 280319)
--- trunk/Tools/ChangeLog 2021-07-26 22:07:20 UTC (rev 280318)
+++ trunk/Tools/ChangeLog 2021-07-26 22:09:27 UTC (rev 280319)
@@ -1,3 +1,28 @@
+2021-07-26 Kate Cheney <[email protected]>
+
+ ServiceWorkerRegistration.unregister method fails in WKWebView
+ https://bugs.webkit.org/show_bug.cgi?id=227524
+ <rdar://problem/80264108>
+
+ Reviewed by Youenn Fablet.
+
+ API test coverage. Drive-by fix to remove unnecessary WKWebView
+ configuration flags from tests that don't need them.
+
+ Note this will also fix https://bugs.webkit.org/show_bug.cgi?id=227531
+ where updating an existing worker fails after registering 3 domains,
+ but writing a test for that would require registering service workers
+ on 3 domains that are not localhost or a loopback IP address, which
+ we currently do not have infrastructure for.
+
+ Testing unregister was only possible because the script URL passed in
+ during the unregister job is null, so it does not get caught in the
+ localhost/loopback IP address check, unlike the update case.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm:
+ (TEST):
+ (-[SWInAppBrowserPrivacyMessageHandler userContentController:didReceiveScriptMessage:]):
+
2021-07-25 Wenson Hsieh <[email protected]>
[iOS] Unified field is unselected after focusing URL bar if text was selected in a fixed position container
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm (280318 => 280319)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm 2021-07-26 22:07:20 UTC (rev 280318)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm 2021-07-26 22:09:27 UTC (rev 280319)
@@ -369,7 +369,6 @@
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
- [configuration setLimitsNavigationsToAppBoundDomains:YES];
auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
auto delegate = adoptNS([AppBoundDomainDelegate new]);
@@ -396,7 +395,6 @@
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
- [configuration setLimitsNavigationsToAppBoundDomains:YES];
auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
auto delegate = adoptNS([AppBoundDomainDelegate new]);
@@ -814,6 +812,8 @@
TestWebKitAPI::Util::run(&done);
}
+static String expectedMessage;
+
@interface SWInAppBrowserPrivacyMessageHandler : NSObject <WKScriptMessageHandler>
@end
@@ -820,7 +820,7 @@
@implementation SWInAppBrowserPrivacyMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
- EXPECT_WK_STREQ(@"Message from worker: ServiceWorker received: Hello from an app-bound domain", [message body]);
+ EXPECT_WK_STREQ(message.body, expectedMessage);
isDone = true;
}
@end
@@ -852,6 +852,31 @@
</script>
)SWRESOURCE";
+static const char* mainUnregisterBytes = R"SWRESOURCE(
+<script>
+
+function log(msg)
+{
+ window.webkit.messageHandlers.sw.postMessage(msg);
+}
+
+try {
+
+navigator.serviceWorker.register('/sw.js').then(function(reg) {
+ reg.unregister()
+ .then(() => log("Unregistration success"))
+ .catch(error => log("Unregistration failed " + error));
+
+}).catch(function(error) {
+ log("Registration failed with: " + error);
+});
+} catch(e) {
+ log("Exception: " + e);
+}
+
+</script>
+)SWRESOURCE";
+
static const char* scriptBytes = R"SWRESOURCE(
self.addEventListener("message", (event) => {
@@ -888,6 +913,7 @@
isDone = false;
// Expect the service worker load to complete successfully.
+ expectedMessage = "Message from worker: ServiceWorker received: Hello from an app-bound domain";
[webView loadRequest:server1.requestWithLocalhost()];
TestWebKitAPI::Util::run(&isDone);
isDone = false;
@@ -908,8 +934,68 @@
}];
TestWebKitAPI::Util::run(&isDone);
isDone = false;
+
+ [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
+ isDone = true;
+ }];
+ TestWebKitAPI::Util::run(&isDone);
+ isDone = false;
}
+TEST(InAppBrowserPrivacy, UnregisterServiceWorker)
+{
+ initializeInAppBrowserPrivacyTestSettings();
+ isDone = false;
+
+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ auto messageHandler = adoptNS([[SWInAppBrowserPrivacyMessageHandler alloc] init]);
+ [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+ [configuration preferences]._serviceWorkerEntitlementDisabledForTesting = YES;
+ [configuration setLimitsNavigationsToAppBoundDomains:YES];
+
+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+ ServiceWorkerTCPServer server({
+ { "text/html", mainUnregisterBytes },
+ { "application/_javascript_", scriptBytes},
+ });
+
+ [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+ [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
+ isDone = true;
+ }];
+ TestWebKitAPI::Util::run(&isDone);
+ isDone = false;
+
+ expectedMessage = "Unregistration success";
+ [webView loadRequest:server.requestWithLocalhost()];
+ TestWebKitAPI::Util::run(&isDone);
+
+ isDone = false;
+
+ [[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:[NSSet setWithObject:WKWebsiteDataTypeServiceWorkerRegistrations] completionHandler:^(NSArray<WKWebsiteDataRecord *> *websiteDataRecords) {
+ EXPECT_EQ(0u, [websiteDataRecords count]);
+ isDone = true;
+ }];
+
+ TestWebKitAPI::Util::run(&isDone);
+ isDone = false;
+
+ // Reset service worker entitlement.
+ [webView _clearServiceWorkerEntitlementOverride:^(void) {
+ cleanUpInAppBrowserPrivacyTestSettings();
+ isDone = true;
+ }];
+ TestWebKitAPI::Util::run(&isDone);
+ isDone = false;
+
+ [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
+ isDone = true;
+ }];
+ TestWebKitAPI::Util::run(&isDone);
+ isDone = false;
+}
+
TEST(InAppBrowserPrivacy, NonAppBoundDomainDoesNotAllowServiceWorkers)
{
initializeInAppBrowserPrivacyTestSettings();