| Index: third_party/WebKit/Source/platform/weborigin/SchemeRegistry.cpp
|
| diff --git a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.cpp b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.cpp
|
| index 89aa5e93407a2b1792a1064f119f9381e582bce2..ab648fe5e365012856642d61abce8350a35eecf8 100644
|
| --- a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.cpp
|
| +++ b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.cpp
|
| @@ -27,14 +27,27 @@
|
| #include "platform/weborigin/SchemeRegistry.h"
|
|
|
| #include "wtf/ThreadSpecific.h"
|
| -#include "wtf/Threading.h"
|
| #include "wtf/ThreadingPrimitives.h"
|
| #include "wtf/text/StringBuilder.h"
|
|
|
| namespace blink {
|
|
|
| +static Mutex& mutex() {
|
| + // The first call to this should be made before or during blink
|
| + // initialization to avoid racy static local initialization.
|
| + DEFINE_STATIC_LOCAL(Mutex, m, ());
|
| + return m;
|
| +}
|
| +
|
| +// Defines static local variable after making sure that a lock is held.
|
| +// (We can't use DEFINE_STATIC_LOCAL for this because it asserts thread
|
| +// safety, which is externally guaranteed by the local mutex() lock)
|
| +#define DEFINE_STATIC_LOCAL_WITH_LOCK(type, name, arguments) \
|
| + ASSERT(mutex().locked()); \
|
| + static type& name = *new type arguments
|
| +
|
| static URLSchemesSet& localURLSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, localSchemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, localSchemes, ());
|
|
|
| if (localSchemes.isEmpty())
|
| localSchemes.add("file");
|
| @@ -43,55 +56,58 @@
|
| }
|
|
|
| static URLSchemesSet& displayIsolatedURLSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, displayIsolatedSchemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, displayIsolatedSchemes, ());
|
| return displayIsolatedSchemes;
|
| }
|
|
|
| static URLSchemesSet& secureSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, secureSchemes,
|
| - ({
|
| - "https", "about", "data", "wss",
|
| - }));
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, secureSchemes,
|
| + ({
|
| + "https", "about", "data", "wss",
|
| + }));
|
| return secureSchemes;
|
| }
|
|
|
| static URLSchemesSet& schemesWithUniqueOrigins() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, schemesWithUniqueOrigins,
|
| - ({
|
| - "about", "javascript", "data",
|
| - }));
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, schemesWithUniqueOrigins,
|
| + ({
|
| + "about", "javascript", "data",
|
| + }));
|
| return schemesWithUniqueOrigins;
|
| }
|
|
|
| static URLSchemesSet& emptyDocumentSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, emptyDocumentSchemes, ({
|
| - "about",
|
| - }));
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, emptyDocumentSchemes,
|
| + ({
|
| + "about",
|
| + }));
|
| return emptyDocumentSchemes;
|
| }
|
|
|
| static HashSet<String>& schemesForbiddenFromDomainRelaxation() {
|
| - DEFINE_STATIC_LOCAL(HashSet<String>, schemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(HashSet<String>, schemes, ());
|
| return schemes;
|
| }
|
|
|
| static URLSchemesSet& notAllowingJavascriptURLsSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, notAllowingJavascriptURLsSchemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, notAllowingJavascriptURLsSchemes,
|
| + ());
|
| return notAllowingJavascriptURLsSchemes;
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsLocal(const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| localURLSchemes().add(scheme);
|
| }
|
|
|
| const URLSchemesSet& SchemeRegistry::localSchemes() {
|
| + MutexLocker locker(mutex());
|
| return localURLSchemes();
|
| }
|
|
|
| static URLSchemesSet& CORSEnabledSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, CORSEnabledSchemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, CORSEnabledSchemes, ());
|
|
|
| if (CORSEnabledSchemes.isEmpty()) {
|
| CORSEnabledSchemes.add("http");
|
| @@ -103,7 +119,7 @@
|
| }
|
|
|
| static URLSchemesSet& serviceWorkerSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, serviceWorkerSchemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, serviceWorkerSchemes, ());
|
|
|
| if (serviceWorkerSchemes.isEmpty()) {
|
| // HTTP is required because http://localhost is considered secure.
|
| @@ -117,7 +133,7 @@
|
| }
|
|
|
| static URLSchemesSet& fetchAPISchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, fetchAPISchemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, fetchAPISchemes, ());
|
|
|
| if (fetchAPISchemes.isEmpty()) {
|
| fetchAPISchemes.add("http");
|
| @@ -128,23 +144,26 @@
|
| }
|
|
|
| static URLSchemesSet& firstPartyWhenTopLevelSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, firstPartyWhenTopLevelSchemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, firstPartyWhenTopLevelSchemes,
|
| + ());
|
| return firstPartyWhenTopLevelSchemes;
|
| }
|
|
|
| static URLSchemesMap<SchemeRegistry::PolicyAreas>&
|
| ContentSecurityPolicyBypassingSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesMap<SchemeRegistry::PolicyAreas>, schemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesMap<SchemeRegistry::PolicyAreas>,
|
| + schemes, ());
|
| return schemes;
|
| }
|
|
|
| static URLSchemesSet& secureContextBypassingSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, secureContextBypassingSchemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, secureContextBypassingSchemes,
|
| + ());
|
| return secureContextBypassingSchemes;
|
| }
|
|
|
| static URLSchemesSet& allowedInReferrerSchemes() {
|
| - DEFINE_STATIC_LOCAL(URLSchemesSet, allowedInReferrerSchemes, ());
|
| + DEFINE_STATIC_LOCAL_WITH_LOCK(URLSchemesSet, allowedInReferrerSchemes, ());
|
|
|
| if (allowedInReferrerSchemes.isEmpty()) {
|
| allowedInReferrerSchemes.add("http");
|
| @@ -154,35 +173,22 @@
|
| return allowedInReferrerSchemes;
|
| }
|
|
|
| -// All new maps should be added here. Must be called before we create other
|
| -// threads to avoid racy static local initialization.
|
| void SchemeRegistry::initialize() {
|
| - localURLSchemes();
|
| - displayIsolatedURLSchemes();
|
| - secureSchemes();
|
| - schemesWithUniqueOrigins();
|
| - emptyDocumentSchemes();
|
| - schemesForbiddenFromDomainRelaxation();
|
| - notAllowingJavascriptURLsSchemes();
|
| - CORSEnabledSchemes();
|
| - serviceWorkerSchemes();
|
| - fetchAPISchemes();
|
| - firstPartyWhenTopLevelSchemes();
|
| - ContentSecurityPolicyBypassingSchemes();
|
| - secureContextBypassingSchemes();
|
| - allowedInReferrerSchemes();
|
| + // Instantiate the mutex object.
|
| + mutex();
|
| }
|
|
|
| bool SchemeRegistry::shouldTreatURLSchemeAsLocal(const String& scheme) {
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return localURLSchemes().contains(scheme);
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsNoAccess(const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| schemesWithUniqueOrigins().add(scheme);
|
| }
|
|
|
| @@ -190,12 +196,13 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return schemesWithUniqueOrigins().contains(scheme);
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsDisplayIsolated(const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| displayIsolatedURLSchemes().add(scheme);
|
| }
|
|
|
| @@ -204,6 +211,7 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return displayIsolatedURLSchemes().contains(scheme);
|
| }
|
|
|
| @@ -214,8 +222,8 @@
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsSecure(const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| secureSchemes().add(scheme);
|
| }
|
|
|
| @@ -223,12 +231,13 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return secureSchemes().contains(scheme);
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsEmptyDocument(const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| emptyDocumentSchemes().add(scheme);
|
| }
|
|
|
| @@ -236,17 +245,18 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return emptyDocumentSchemes().contains(scheme);
|
| }
|
|
|
| void SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(
|
| bool forbidden,
|
| const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return;
|
|
|
| + MutexLocker locker(mutex());
|
| if (forbidden)
|
| schemesForbiddenFromDomainRelaxation().add(scheme);
|
| else
|
| @@ -258,6 +268,7 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return schemesForbiddenFromDomainRelaxation().contains(scheme);
|
| }
|
|
|
| @@ -268,8 +279,8 @@
|
|
|
| void SchemeRegistry::registerURLSchemeAsNotAllowingJavascriptURLs(
|
| const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| notAllowingJavascriptURLsSchemes().add(scheme);
|
| }
|
|
|
| @@ -278,12 +289,13 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return notAllowingJavascriptURLsSchemes().contains(scheme);
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsCORSEnabled(const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| CORSEnabledSchemes().add(scheme);
|
| }
|
|
|
| @@ -291,13 +303,19 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return CORSEnabledSchemes().contains(scheme);
|
| }
|
|
|
| String SchemeRegistry::listOfCORSEnabledURLSchemes() {
|
| StringBuilder builder;
|
| bool addSeparator = false;
|
| - for (const auto& scheme : CORSEnabledSchemes()) {
|
| + URLSchemesSet schemes;
|
| + {
|
| + MutexLocker locker(mutex());
|
| + schemes = CORSEnabledSchemes();
|
| + }
|
| + for (const auto& scheme : schemes) {
|
| if (addSeparator)
|
| builder.append(", ");
|
| else
|
| @@ -314,8 +332,8 @@
|
|
|
| void SchemeRegistry::registerURLSchemeAsAllowingServiceWorkers(
|
| const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| serviceWorkerSchemes().add(scheme);
|
| }
|
|
|
| @@ -324,13 +342,14 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return serviceWorkerSchemes().contains(scheme);
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsSupportingFetchAPI(
|
| const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| fetchAPISchemes().add(scheme);
|
| }
|
|
|
| @@ -339,20 +358,21 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return fetchAPISchemes().contains(scheme);
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsFirstPartyWhenTopLevel(
|
| const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| firstPartyWhenTopLevelSchemes().add(scheme);
|
| }
|
|
|
| void SchemeRegistry::removeURLSchemeAsFirstPartyWhenTopLevel(
|
| const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| firstPartyWhenTopLevelSchemes().remove(scheme);
|
| }
|
|
|
| @@ -361,18 +381,19 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return firstPartyWhenTopLevelSchemes().contains(scheme);
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsAllowedForReferrer(
|
| const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| allowedInReferrerSchemes().add(scheme);
|
| }
|
|
|
| void SchemeRegistry::removeURLSchemeAsAllowedForReferrer(const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| + MutexLocker locker(mutex());
|
| allowedInReferrerSchemes().remove(scheme);
|
| }
|
|
|
| @@ -381,21 +402,22 @@
|
| DCHECK_EQ(scheme, scheme.lower());
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return allowedInReferrerSchemes().contains(scheme);
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(
|
| const String& scheme,
|
| PolicyAreas policyAreas) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| ContentSecurityPolicyBypassingSchemes().add(scheme, policyAreas);
|
| }
|
|
|
| void SchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(
|
| const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| ContentSecurityPolicyBypassingSchemes().remove(scheme);
|
| }
|
|
|
| @@ -408,14 +430,15 @@
|
|
|
| // get() returns 0 (PolicyAreaNone) if there is no entry in the map.
|
| // Thus by default, schemes do not bypass CSP.
|
| + MutexLocker locker(mutex());
|
| return (ContentSecurityPolicyBypassingSchemes().get(scheme) & policyAreas) ==
|
| policyAreas;
|
| }
|
|
|
| void SchemeRegistry::registerURLSchemeBypassingSecureContextCheck(
|
| const String& scheme) {
|
| - DCHECK(WTF::isBeforeThreadCreated());
|
| - DCHECK_EQ(scheme, scheme.lower());
|
| + DCHECK_EQ(scheme, scheme.lower());
|
| + MutexLocker locker(mutex());
|
| secureContextBypassingSchemes().add(scheme.lower());
|
| }
|
|
|
| @@ -423,6 +446,7 @@
|
| const String& scheme) {
|
| if (scheme.isEmpty())
|
| return false;
|
| + MutexLocker locker(mutex());
|
| return secureContextBypassingSchemes().contains(scheme.lower());
|
| }
|
|
|
|
|