Make SecurityOrigin safe to create and use from any thread
https://bugs.webkit.org/show_bug.cgi?id=184216

Reviewed by Youenn Fablet.

We found that we have a decent amount of code constructing and using SecurityOrigin
objects from non-main threads. Unfortunately, this was not safe, mostly due to
SecurityOrigin's reliance on the SchemeRegistry.

This patch makes it safe to construct a SecurityOrigin on any thread A and use
it later on the same thread A. However, developers still need to call isolatedCopy()
if they want to pass such object to another thread B.

* page/SecurityOrigin.cpp:
(WebCore::SecurityOrigin::canDisplay const):
* page/SecurityOrigin.h:
* page/SecurityPolicy.cpp:
(WebCore::originAccessMapLock):
(WebCore::originAccessMap):
(WebCore::SecurityPolicy::isAccessWhiteListed):
(WebCore::SecurityPolicy::addOriginAccessWhitelistEntry):
(WebCore::SecurityPolicy::removeOriginAccessWhitelistEntry):
(WebCore::SecurityPolicy::resetOriginAccessWhitelists):
* platform/SchemeRegistry.cpp:
(WebCore::schemeRegistryLock):
(WebCore::allBuiltinSchemes):
(WebCore::builtinLocalURLSchemes):
(WebCore::localURLSchemes):
(WebCore::displayIsolatedURLSchemes):
(WebCore::builtinSecureSchemes):
(WebCore::secureSchemes):
(WebCore::builtinSchemesWithUniqueOrigins):
(WebCore::schemesWithUniqueOrigins):
(WebCore::builtinEmptyDocumentSchemes):
(WebCore::emptyDocumentSchemes):
(WebCore::schemesForbiddenFromDomainRelaxation):
(WebCore::builtinCanDisplayOnlyIfCanRequestSchemes):
(WebCore::canDisplayOnlyIfCanRequestSchemes):
(WebCore::notAllowingJavascriptURLsSchemes):
(WebCore::SchemeRegistry::registerURLSchemeAsLocal):
(WebCore::SchemeRegistry::removeURLSchemeRegisteredAsLocal):
(WebCore::schemesAllowingLocalStorageAccessInPrivateBrowsing):
(WebCore::schemesAllowingDatabaseAccessInPrivateBrowsing):
(WebCore::builtinCORSEnabledSchemes):
(WebCore::CORSEnabledSchemes):
(WebCore::ContentSecurityPolicyBypassingSchemes):
(WebCore::cachePartitioningSchemes):
(WebCore::serviceWorkerSchemes):
(WebCore::alwaysRevalidatedSchemes):
(WebCore::SchemeRegistry::shouldTreatURLSchemeAsLocal):
(WebCore::SchemeRegistry::registerURLSchemeAsNoAccess):
(WebCore::SchemeRegistry::shouldTreatURLSchemeAsNoAccess):
(WebCore::SchemeRegistry::registerURLSchemeAsDisplayIsolated):
(WebCore::SchemeRegistry::shouldTreatURLSchemeAsDisplayIsolated):
(WebCore::SchemeRegistry::registerURLSchemeAsSecure):
(WebCore::SchemeRegistry::shouldTreatURLSchemeAsSecure):
(WebCore::SchemeRegistry::canDisplayOnlyIfCanRequest):
(WebCore::SchemeRegistry::registerAsCanDisplayOnlyIfCanRequest):
(WebCore::SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy):
(WebCore::SchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy):
(WebCore::SchemeRegistry::schemeShouldBypassContentSecurityPolicy):
(WebCore::SchemeRegistry::registerURLSchemeAsCachePartitioned):
(WebCore::SchemeRegistry::shouldPartitionCacheForURLScheme):
(WebCore::SchemeRegistry::registerURLSchemeServiceWorkersCanHandle):
(WebCore::SchemeRegistry::canServiceWorkersHandleURLScheme):
(WebCore::SchemeRegistry::isServiceWorkerContainerCustomScheme):
* platform/SchemeRegistry.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@230205 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/platform/SchemeRegistry.cpp b/Source/WebCore/platform/SchemeRegistry.cpp
index 7e4d613..53dc195 100644
--- a/Source/WebCore/platform/SchemeRegistry.cpp
+++ b/Source/WebCore/platform/SchemeRegistry.cpp
@@ -65,6 +65,12 @@
     return set;
 }
 
+static Lock& schemeRegistryLock()
+{
+    static NeverDestroyed<Lock> lock;
+    return lock;
+}
+
 static const URLSchemesMap& allBuiltinSchemes()
 {
     static const auto schemes = makeNeverDestroyed([] {
@@ -91,10 +97,14 @@
         };
 
         URLSchemesMap set;
-        for (auto& scheme : builtinLocalURLSchemes())
-            set.add(scheme);
-        for (auto& function : functions)
-            add(set, function);
+        {
+            Locker<Lock> locker(schemeRegistryLock());
+            for (auto& scheme : builtinLocalURLSchemes())
+                set.add(scheme);
+
+            for (auto& function : functions)
+                add(set, function);
+        }
         for (auto& scheme : otherSchemes)
             set.add(scheme);
         return set;
@@ -104,6 +114,7 @@
 
 static const URLSchemesMap& builtinLocalURLSchemes()
 {
+    ASSERT(schemeRegistryLock().isHeld());
     static const auto schemes = makeNeverDestroyed(URLSchemesMap {
         "file",
 #if PLATFORM(COCOA)
@@ -113,27 +124,23 @@
     return schemes;
 }
 
-static Lock& localURLSchemesLock()
-{
-    static NeverDestroyed<Lock> lock;
-    return lock;
-}
-
 static URLSchemesMap& localURLSchemes()
 {
-    ASSERT(localURLSchemesLock().isHeld());
+    ASSERT(schemeRegistryLock().isHeld());
     static NeverDestroyed<URLSchemesMap> localSchemes = builtinLocalURLSchemes();
     return localSchemes;
 }
 
 static URLSchemesMap& displayIsolatedURLSchemes()
 {
+    ASSERT(schemeRegistryLock().isHeld());
     static NeverDestroyed<URLSchemesMap> displayIsolatedSchemes;
     return displayIsolatedSchemes;
 }
 
 const Vector<String>& builtinSecureSchemes()
 {
+    ASSERT(schemeRegistryLock().isHeld());
     static const auto schemes = makeNeverDestroyed(Vector<String> {
         "https",
         "about",
@@ -146,21 +153,16 @@
     return schemes;
 }
 
-static Lock& secureSchemesLock()
-{
-    static NeverDestroyed<Lock> lock;
-    return lock;
-}
-
 static URLSchemesMap& secureSchemes()
 {
-    ASSERT(secureSchemesLock().isHeld());
+    ASSERT(schemeRegistryLock().isHeld());
     static auto secureSchemes = makeNeverDestroyedSchemeSet(builtinSecureSchemes);
     return secureSchemes;
 }
 
 const Vector<String>& builtinSchemesWithUniqueOrigins()
 {
+    ASSERT(schemeRegistryLock().isHeld());
     static const auto schemes = makeNeverDestroyed(Vector<String> {
         "about",
         "javascript",
@@ -173,42 +175,49 @@
 
 static URLSchemesMap& schemesWithUniqueOrigins()
 {
+    ASSERT(schemeRegistryLock().isHeld());
     static auto schemesWithUniqueOrigins = makeNeverDestroyedSchemeSet(builtinSchemesWithUniqueOrigins);
     return schemesWithUniqueOrigins;
 }
 
 const Vector<String>& builtinEmptyDocumentSchemes()
 {
+    ASSERT(isMainThread());
     static const auto schemes = makeNeverDestroyed(Vector<String> { "about" });
     return schemes;
 }
 
 static URLSchemesMap& emptyDocumentSchemes()
 {
+    ASSERT(isMainThread());
     static auto emptyDocumentSchemes = makeNeverDestroyedSchemeSet(builtinEmptyDocumentSchemes);
     return emptyDocumentSchemes;
 }
 
 static URLSchemesMap& schemesForbiddenFromDomainRelaxation()
 {
+    ASSERT(isMainThread());
     static NeverDestroyed<URLSchemesMap> schemes;
     return schemes;
 }
 
 const Vector<String>& builtinCanDisplayOnlyIfCanRequestSchemes()
 {
+    ASSERT(schemeRegistryLock().isHeld());
     static const auto schemes = makeNeverDestroyed(Vector<String> { "blob" });
     return schemes;
 }
 
 static URLSchemesMap& canDisplayOnlyIfCanRequestSchemes()
 {
+    ASSERT(schemeRegistryLock().isHeld());
     static auto canDisplayOnlyIfCanRequestSchemes = makeNeverDestroyedSchemeSet(builtinCanDisplayOnlyIfCanRequestSchemes);
     return canDisplayOnlyIfCanRequestSchemes;
 }
 
 static URLSchemesMap& notAllowingJavascriptURLsSchemes()
 {
+    ASSERT(isMainThread());
     static NeverDestroyed<URLSchemesMap> notAllowingJavascriptURLsSchemes;
     return notAllowingJavascriptURLsSchemes;
 }
@@ -218,13 +227,13 @@
     if (scheme.isNull())
         return;
 
-    Locker<Lock> locker(localURLSchemesLock());
+    Locker<Lock> locker(schemeRegistryLock());
     localURLSchemes().add(scheme);
 }
 
 void SchemeRegistry::removeURLSchemeRegisteredAsLocal(const String& scheme)
 {
-    Locker<Lock> locker(localURLSchemesLock());
+    Locker<Lock> locker(schemeRegistryLock());
     if (builtinLocalURLSchemes().contains(scheme))
         return;
 
@@ -233,24 +242,28 @@
 
 static URLSchemesMap& schemesAllowingLocalStorageAccessInPrivateBrowsing()
 {
+    ASSERT(isMainThread());
     static NeverDestroyed<URLSchemesMap> schemesAllowingLocalStorageAccessInPrivateBrowsing;
     return schemesAllowingLocalStorageAccessInPrivateBrowsing;
 }
 
 static URLSchemesMap& schemesAllowingDatabaseAccessInPrivateBrowsing()
 {
+    ASSERT(isMainThread());
     static NeverDestroyed<URLSchemesMap> schemesAllowingDatabaseAccessInPrivateBrowsing;
     return schemesAllowingDatabaseAccessInPrivateBrowsing;
 }
 
 const Vector<String>& builtinCORSEnabledSchemes()
 {
+    ASSERT(isMainThread());
     static const auto schemes = makeNeverDestroyed(Vector<String> { "http", "https" });
     return schemes;
 }
 
 static URLSchemesMap& CORSEnabledSchemes()
 {
+    ASSERT(isMainThread());
     // FIXME: http://bugs.webkit.org/show_bug.cgi?id=77160
     static auto schemes = makeNeverDestroyedSchemeSet(builtinCORSEnabledSchemes);
     return schemes;
@@ -258,31 +271,28 @@
 
 static URLSchemesMap& ContentSecurityPolicyBypassingSchemes()
 {
+    ASSERT(schemeRegistryLock().isHeld());
     static NeverDestroyed<URLSchemesMap> schemes;
     return schemes;
 }
 
 static URLSchemesMap& cachePartitioningSchemes()
 {
+    ASSERT(schemeRegistryLock().isHeld());
     static NeverDestroyed<URLSchemesMap> schemes;
     return schemes;
 }
 
-static Lock& serviceWorkerSchemesLock()
-{
-    static NeverDestroyed<Lock> lock;
-    return lock;
-}
-
 static URLSchemesMap& serviceWorkerSchemes()
 {
-    ASSERT(serviceWorkerSchemesLock().isHeld());
+    ASSERT(schemeRegistryLock().isHeld());
     static NeverDestroyed<URLSchemesMap> schemes;
     return schemes;
 }
 
 static URLSchemesMap& alwaysRevalidatedSchemes()
 {
+    ASSERT(isMainThread());
     static NeverDestroyed<URLSchemesMap> schemes;
     return schemes;
 }
@@ -292,7 +302,7 @@
     if (scheme.isNull())
         return false;
 
-    Locker<Lock> locker(localURLSchemesLock());
+    Locker<Lock> locker(schemeRegistryLock());
     return localURLSchemes().contains(scheme);
 }
 
@@ -300,24 +310,36 @@
 {
     if (scheme.isNull())
         return;
+
+    Locker<Lock> locker(schemeRegistryLock());
     schemesWithUniqueOrigins().add(scheme);
 }
 
 bool SchemeRegistry::shouldTreatURLSchemeAsNoAccess(const String& scheme)
 {
-    return !scheme.isNull() && schemesWithUniqueOrigins().contains(scheme);
+    if (scheme.isNull())
+        return false;
+
+    Locker<Lock> locker(schemeRegistryLock());
+    return schemesWithUniqueOrigins().contains(scheme);
 }
 
 void SchemeRegistry::registerURLSchemeAsDisplayIsolated(const String& scheme)
 {
     if (scheme.isNull())
         return;
+
+    Locker<Lock> locker(schemeRegistryLock());
     displayIsolatedURLSchemes().add(scheme);
 }
 
 bool SchemeRegistry::shouldTreatURLSchemeAsDisplayIsolated(const String& scheme)
 {
-    return !scheme.isNull() && displayIsolatedURLSchemes().contains(scheme);
+    if (scheme.isNull())
+        return false;
+
+    Locker<Lock> locker(schemeRegistryLock());
+    return displayIsolatedURLSchemes().contains(scheme);
 }
 
 void SchemeRegistry::registerURLSchemeAsSecure(const String& scheme)
@@ -325,7 +347,7 @@
     if (scheme.isNull())
         return;
 
-    Locker<Lock> locker(secureSchemesLock());
+    Locker<Lock> locker(schemeRegistryLock());
     secureSchemes().add(scheme);
 }
 
@@ -334,7 +356,7 @@
     if (scheme.isNull())
         return false;
 
-    Locker<Lock> locker(secureSchemesLock());
+    Locker<Lock> locker(schemeRegistryLock());
     return secureSchemes().contains(scheme);
 }
 
@@ -368,13 +390,19 @@
 
 bool SchemeRegistry::canDisplayOnlyIfCanRequest(const String& scheme)
 {
-    return !scheme.isNull() && canDisplayOnlyIfCanRequestSchemes().contains(scheme);
+    if (scheme.isNull())
+        return false;
+
+    Locker<Lock> locker(schemeRegistryLock());
+    return canDisplayOnlyIfCanRequestSchemes().contains(scheme);
 }
 
 void SchemeRegistry::registerAsCanDisplayOnlyIfCanRequest(const String& scheme)
 {
     if (scheme.isNull())
         return;
+
+    Locker<Lock> locker(schemeRegistryLock());
     canDisplayOnlyIfCanRequestSchemes().add(scheme);
 }
 
@@ -430,6 +458,8 @@
 {
     if (scheme.isNull())
         return;
+
+    Locker<Lock> locker(schemeRegistryLock());
     ContentSecurityPolicyBypassingSchemes().add(scheme);
 }
 
@@ -437,12 +467,18 @@
 {
     if (scheme.isNull())
         return;
+
+    Locker<Lock> locker(schemeRegistryLock());
     ContentSecurityPolicyBypassingSchemes().remove(scheme);
 }
 
 bool SchemeRegistry::schemeShouldBypassContentSecurityPolicy(const String& scheme)
 {
-    return !scheme.isNull() && ContentSecurityPolicyBypassingSchemes().contains(scheme);
+    if (scheme.isNull())
+        return false;
+
+    Locker<Lock> locker(schemeRegistryLock());
+    return ContentSecurityPolicyBypassingSchemes().contains(scheme);
 }
 
 void SchemeRegistry::registerURLSchemeAsAlwaysRevalidated(const String& scheme)
@@ -461,12 +497,18 @@
 {
     if (scheme.isNull())
         return;
+
+    Locker<Lock> locker(schemeRegistryLock());
     cachePartitioningSchemes().add(scheme);
 }
 
 bool SchemeRegistry::shouldPartitionCacheForURLScheme(const String& scheme)
 {
-    return !scheme.isNull() && cachePartitioningSchemes().contains(scheme);
+    if (scheme.isNull())
+        return false;
+
+    Locker<Lock> locker(schemeRegistryLock());
+    return cachePartitioningSchemes().contains(scheme);
 }
 
 void SchemeRegistry::registerURLSchemeServiceWorkersCanHandle(const String& scheme)
@@ -474,7 +516,7 @@
     if (scheme.isNull())
         return;
 
-    Locker<Lock> locker(serviceWorkerSchemesLock());
+    Locker<Lock> locker(schemeRegistryLock());
     serviceWorkerSchemes().add(scheme);
 }
 
@@ -490,13 +532,13 @@
             return true;
     }
 
-    Locker<Lock> locker(serviceWorkerSchemesLock());
+    Locker<Lock> locker(schemeRegistryLock());
     return serviceWorkerSchemes().contains(scheme);
 }
 
 bool SchemeRegistry::isServiceWorkerContainerCustomScheme(const String& scheme)
 {
-    Locker<Lock> locker(serviceWorkerSchemesLock());
+    Locker<Lock> locker(schemeRegistryLock());
     return !scheme.isNull() && serviceWorkerSchemes().contains(scheme);
 }