diff options
15 files changed, 403 insertions, 113 deletions
diff --git a/third_party/WebKit/Source/build/scripts/templates/OriginTrials.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/OriginTrials.cpp.tmpl index 37c26020..c95d7fb 100644 --- a/third_party/WebKit/Source/build/scripts/templates/OriginTrials.cpp.tmpl +++ b/third_party/WebKit/Source/build/scripts/templates/OriginTrials.cpp.tmpl @@ -3,35 +3,63 @@ #include "core/origin_trials/OriginTrials.h" +#include "core/dom/ExecutionContext.h" #include "core/origin_trials/OriginTrialContext.h" #include "platform/RuntimeEnabledFeatures.h" namespace blink { + +OriginTrials::OriginTrials(PassOwnPtrWillBeRawPtr<OriginTrialContext> originTrialContext) + : m_originTrialContext(originTrialContext) {} + +// static +const char* OriginTrials::supplementName() +{ + return "OriginTrials"; +} + +// static +OriginTrials* OriginTrials::from(ExecutionContext* host) +{ + OriginTrials* originTrials = reinterpret_cast<OriginTrials*>(WillBeHeapSupplement<ExecutionContext>::from(host, supplementName())); + if (!originTrials) { + originTrials = new OriginTrials(host->createOriginTrialContext()); + WillBeHeapSupplement<ExecutionContext>::provideTo(*host, supplementName(), adoptPtrWillBeNoop(originTrials)); + } + return originTrials; +} + {% for feature in features %} {% if feature.origin_trial_feature_name %} // static bool OriginTrials::{{feature.first_lowered_name}}Enabled(ExecutionContext* executionContext, String& errorMessage) { - return {{feature.first_lowered_name}}EnabledImpl(executionContext, &errorMessage); + return OriginTrials::from(executionContext)->{{feature.first_lowered_name}}EnabledImpl(&errorMessage); } // static bool OriginTrials::{{feature.first_lowered_name}}Enabled(ExecutionContext* executionContext) { - return {{feature.first_lowered_name}}EnabledImpl(executionContext, nullptr); + return OriginTrials::from(executionContext)->{{feature.first_lowered_name}}EnabledImpl(nullptr); } + {% endif %} {% endfor %} {% for feature in features %} {% if feature.origin_trial_feature_name %} -// static -bool OriginTrials::{{feature.first_lowered_name}}EnabledImpl(ExecutionContext* executionContext, String* errorMessage) { +bool OriginTrials::{{feature.first_lowered_name}}EnabledImpl(String* errorMessage) { if (RuntimeEnabledFeatures::{{feature.first_lowered_name}}Enabled()) return true; - return OriginTrialContext::isFeatureEnabled(executionContext, "{{feature.origin_trial_feature_name}}", errorMessage); + if (!m_originTrialContext) return false; + return m_originTrialContext->isFeatureEnabled("{{feature.origin_trial_feature_name}}", errorMessage); } {% endif %} {% endfor %} +DEFINE_TRACE(OriginTrials) +{ + visitor->trace(m_originTrialContext); + WillBeHeapSupplement<ExecutionContext>::trace(visitor); +} } // namespace blink diff --git a/third_party/WebKit/Source/build/scripts/templates/OriginTrials.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/OriginTrials.h.tmpl index f49790e..d7f4d54 100644 --- a/third_party/WebKit/Source/build/scripts/templates/OriginTrials.h.tmpl +++ b/third_party/WebKit/Source/build/scripts/templates/OriginTrials.h.tmpl @@ -5,32 +5,43 @@ #define OriginTrials_h #include "core/CoreExport.h" +#include "platform/Supplementable.h" #include "wtf/text/WTFString.h" namespace blink { class ExecutionContext; +class OriginTrialContext; // A class that stores dynamic tests for experimental features which can be // enabled through the experimental framework via API keys. -class CORE_EXPORT OriginTrials { +class CORE_EXPORT OriginTrials final : public NoBaseWillBeGarbageCollected<OriginTrials>, public WillBeHeapSupplement<ExecutionContext> { +WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(OriginTrials) public: + OriginTrials(PassOwnPtrWillBeRawPtr<OriginTrialContext>); + + static const char* supplementName(); + static OriginTrials* from(ExecutionContext*); + {% for feature in features %} {% if feature.origin_trial_feature_name %} + static bool {{feature.first_lowered_name}}Enabled(ExecutionContext* executionContext, String& errorMessage); static bool {{feature.first_lowered_name}}Enabled(ExecutionContext* executionContext); {% endif %} {% endfor %} -private: - OriginTrials() { } + DECLARE_TRACE(); +private: {% for feature in features %} {% if feature.origin_trial_feature_name %} - static bool {{feature.first_lowered_name}}EnabledImpl(ExecutionContext* executionContext, String* errorMessage); + bool {{feature.first_lowered_name}}EnabledImpl(String* errorMessage); {% endif %} {% endfor %} + + OwnPtrWillBeMember<OriginTrialContext> m_originTrialContext; }; } // namespace blink diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi index 64ac28d..244fcab 100644 --- a/third_party/WebKit/Source/core/core.gypi +++ b/third_party/WebKit/Source/core/core.gypi @@ -1917,6 +1917,8 @@ 'loader/appcache/ApplicationCache.h', 'loader/appcache/ApplicationCacheHost.cpp', 'loader/appcache/ApplicationCacheHost.h', + 'origin_trials/DocumentOriginTrialContext.cpp', + 'origin_trials/DocumentOriginTrialContext.h', 'origin_trials/OriginTrialContext.cpp', 'origin_trials/OriginTrialContext.h', 'page/AutoscrollController.cpp', @@ -4031,6 +4033,7 @@ 'loader/LinkHeaderTest.cpp', 'loader/LinkLoaderTest.cpp', 'loader/MixedContentCheckerTest.cpp', + 'origin_trials/DocumentOriginTrialContextTest.cpp', 'origin_trials/OriginTrialContextTest.cpp', 'page/ChromeClientTest.cpp', 'page/ContextMenuControllerTest.cpp', diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 93a13ab..a24e8423 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp @@ -184,6 +184,7 @@ #include "core/loader/ImageLoader.h" #include "core/loader/NavigationScheduler.h" #include "core/loader/appcache/ApplicationCacheHost.h" +#include "core/origin_trials/DocumentOriginTrialContext.h" #include "core/page/ChromeClient.h" #include "core/page/EventWithHitTestResults.h" #include "core/page/FocusController.h" @@ -5916,6 +5917,11 @@ void Document::enforceStrictMixedContentChecking() frame()->loader().client()->didEnforceStrictMixedContentChecking(); } +PassOwnPtrWillBeRawPtr<OriginTrialContext> Document::createOriginTrialContext() +{ + return adoptPtrWillBeNoop(new DocumentOriginTrialContext(this)); +} + DEFINE_TRACE(Document) { #if ENABLE(OILPAN) diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index 3088fc8..c13baa7 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h @@ -140,6 +140,7 @@ class NodeIntersectionObserverData; class NodeIterator; class NthIndexCache; class OriginAccessEntry; +class OriginTrialContext; class Page; class PlatformMouseEvent; class ProcessingInstruction; @@ -1079,6 +1080,7 @@ protected: ParserSynchronizationPolicy getParserSynchronizationPolicy() const { return m_parserSyncPolicy; } private: + friend class DocumentOriginTrialContextTest; friend class IgnoreDestructiveWriteCountIncrementer; friend class NthIndexCache; @@ -1162,6 +1164,8 @@ private: const OriginAccessEntry& accessEntryFromURL(); + PassOwnPtrWillBeRawPtr<OriginTrialContext> createOriginTrialContext() override; + DocumentLifecycle m_lifecycle; bool m_hasNodesWithPlaceholderStyle; diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp index bb89d5a..bda769b 100644 --- a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp +++ b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp @@ -36,6 +36,7 @@ #include "core/frame/UseCounter.h" #include "core/html/PublicURLManager.h" #include "core/inspector/InspectorInstrumentation.h" +#include "core/origin_trials/OriginTrialContext.h" #include "core/workers/WorkerGlobalScope.h" #include "core/workers/WorkerThread.h" #include "wtf/MainThread.h" @@ -265,6 +266,11 @@ void ExecutionContext::setReferrerPolicy(ReferrerPolicy referrerPolicy) m_referrerPolicy = referrerPolicy; } +PassOwnPtrWillBeRawPtr<OriginTrialContext> ExecutionContext::createOriginTrialContext() +{ + return nullptr; +} + void ExecutionContext::removeURLFromMemoryCache(const KURL& url) { memoryCache()->removeURLFromCache(url); diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.h b/third_party/WebKit/Source/core/dom/ExecutionContext.h index 8bb226b..e5e67bc 100644 --- a/third_party/WebKit/Source/core/dom/ExecutionContext.h +++ b/third_party/WebKit/Source/core/dom/ExecutionContext.h @@ -53,6 +53,7 @@ class EventQueue; class EventTarget; class ExecutionContextTask; class LocalDOMWindow; +class OriginTrialContext; class PublicURLManager; class SecurityOrigin; class ScriptCallStack; @@ -155,6 +156,9 @@ public: virtual void setReferrerPolicy(ReferrerPolicy); ReferrerPolicy getReferrerPolicy() const { return m_referrerPolicy; } + // Override to enable experimental features through origin trials + virtual PassOwnPtrWillBeRawPtr<OriginTrialContext> createOriginTrialContext(); + protected: ExecutionContext(); virtual ~ExecutionContext(); diff --git a/third_party/WebKit/Source/core/origin_trials/DocumentOriginTrialContext.cpp b/third_party/WebKit/Source/core/origin_trials/DocumentOriginTrialContext.cpp new file mode 100644 index 0000000..f43bceb --- /dev/null +++ b/third_party/WebKit/Source/core/origin_trials/DocumentOriginTrialContext.cpp @@ -0,0 +1,41 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/origin_trials/DocumentOriginTrialContext.h" + +#include "core/dom/ElementTraversal.h" +#include "core/html/HTMLHeadElement.h" +#include "core/html/HTMLMetaElement.h" + +namespace blink { + +class Document; + +DocumentOriginTrialContext::DocumentOriginTrialContext(Document* document) + : m_parent(document) +{ +} + +Vector<String> DocumentOriginTrialContext::getTokens() +{ + // When in a document, the tokens are provided in a meta tag + Vector<String> tokens; + HTMLHeadElement* head = m_parent->head(); + if (head) { + for (HTMLMetaElement& metaElement : Traversal<HTMLMetaElement>::childrenOf(*head)) { + if (equalIgnoringCase(metaElement.httpEquiv(), kTrialHeaderName)) { + tokens.append(metaElement.content()); + } + } + } + return tokens; +} + +DEFINE_TRACE(DocumentOriginTrialContext) +{ + visitor->trace(m_parent); + OriginTrialContext::trace(visitor); +} + +} // namespace blink diff --git a/third_party/WebKit/Source/core/origin_trials/DocumentOriginTrialContext.h b/third_party/WebKit/Source/core/origin_trials/DocumentOriginTrialContext.h new file mode 100644 index 0000000..01231c9 --- /dev/null +++ b/third_party/WebKit/Source/core/origin_trials/DocumentOriginTrialContext.h @@ -0,0 +1,41 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DocumentOriginTrialContext_h +#define DocumentOriginTrialContext_h + +#include "core/CoreExport.h" +#include "core/dom/Document.h" +#include "core/origin_trials/OriginTrialContext.h" +#include "platform/heap/Handle.h" +#include "wtf/Forward.h" +#include <utility> + +namespace blink { + +class WebApiKeyValidator; + +// DocumentOriginTrialContext is a specialization of OriginTrialContext for +// the Document execution context. It enables and disables feature trials based +// on the tokens found in <meta> tags in the document header. +class CORE_EXPORT DocumentOriginTrialContext : public OriginTrialContext { +public: + explicit DocumentOriginTrialContext(Document*); + ~DocumentOriginTrialContext() override = default; + + ExecutionContext* executionContext() override { return m_parent; } + Vector<String> getTokens() override; + + DECLARE_VIRTUAL_TRACE(); + +protected: + friend class DocumentOriginTrialContextTest; + +private: + RawPtrWillBeMember<Document> m_parent; +}; + +} // namespace blink + +#endif // DocumentOriginTrialContext_h diff --git a/third_party/WebKit/Source/core/origin_trials/DocumentOriginTrialContextTest.cpp b/third_party/WebKit/Source/core/origin_trials/DocumentOriginTrialContextTest.cpp new file mode 100644 index 0000000..1c6b231 --- /dev/null +++ b/third_party/WebKit/Source/core/origin_trials/DocumentOriginTrialContextTest.cpp @@ -0,0 +1,117 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/origin_trials/DocumentOriginTrialContext.h" + +#include "core/HTMLNames.h" +#include "core/dom/DOMException.h" +#include "core/dom/ExceptionCode.h" +#include "core/frame/FrameView.h" +#include "core/html/HTMLDocument.h" +#include "core/html/HTMLHeadElement.h" +#include "core/html/HTMLMetaElement.h" +#include "core/testing/DummyPageHolder.h" +#include "platform/weborigin/KURL.h" +#include "platform/weborigin/SecurityOrigin.h" +#include "public/platform/WebTrialTokenValidator.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +using ::testing::UnorderedElementsAre; + +namespace { + +// API Key which will appear valid +const char* kGoodTrialToken = "1|AnySignatureWillDo|https://www.example.com|Frobulate|2000000000"; +const char* kAnotherTrialToken = "1|AnySignatureWillDo|https://www.example.com|FrobulateV2|2000000000"; + +} // namespace + +class DocumentOriginTrialContextTest : public ::testing::Test { +protected: + DocumentOriginTrialContextTest() + : m_pageHolder(DummyPageHolder::create()) + , m_frameworkWasEnabled(RuntimeEnabledFeatures::experimentalFrameworkEnabled()) + { + RuntimeEnabledFeatures::setExperimentalFrameworkEnabled(true); + } + + ~DocumentOriginTrialContextTest() + { + RuntimeEnabledFeatures::setExperimentalFrameworkEnabled(m_frameworkWasEnabled); + m_pageHolder.clear(); + } + + void SetUp() override + { + setInnerHTML( + "<html>" + "<head>" + "</head>" + "<body>" + "</body>" + "</html>"); + } + + Document& document() { return m_pageHolder->document(); } + + void setPageOrigin(const String& origin) + { + KURL pageURL(ParsedURLString, origin); + RefPtr<SecurityOrigin> pageOrigin = SecurityOrigin::create(pageURL); + document().updateSecurityOrigin(pageOrigin); + } + + void setInnerHTML(const char* htmlContent) + { + document().documentElement()->setInnerHTML(String::fromUTF8(htmlContent), ASSERT_NO_EXCEPTION); + document().view()->updateAllLifecyclePhases(); + } + + void addTrialToken(const AtomicString& token) + { + HTMLElement* head = document().head(); + ASSERT_TRUE(head); + + RefPtrWillBeRawPtr<HTMLMetaElement> meta = HTMLMetaElement::create(document()); + meta->setAttribute(HTMLNames::http_equivAttr, OriginTrialContext::kTrialHeaderName); + meta->setAttribute(HTMLNames::contentAttr, token); + head->appendChild(meta.release()); + } + + Vector<String> getTokens() + { + return document().createOriginTrialContext()->getTokens(); + } + +private: + OwnPtr<DummyPageHolder> m_pageHolder; + const bool m_frameworkWasEnabled; +}; + +TEST_F(DocumentOriginTrialContextTest, DetectsZeroTokens) +{ + String errorMessage; + Vector<String> tokens = getTokens(); + EXPECT_EQ(0UL, tokens.size()); +} + +TEST_F(DocumentOriginTrialContextTest, ExtractsSingleToken) +{ + addTrialToken(kGoodTrialToken); + Vector<String> tokens = getTokens(); + EXPECT_EQ(1UL, tokens.size()); + EXPECT_EQ(kGoodTrialToken, tokens[0]); +} + +TEST_F(DocumentOriginTrialContextTest, ExtractsAllTokens) +{ + addTrialToken(kGoodTrialToken); + addTrialToken(kAnotherTrialToken); + EXPECT_THAT(getTokens(), UnorderedElementsAre(kGoodTrialToken, kAnotherTrialToken)); +} + +} // namespace blink diff --git a/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.cpp b/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.cpp index 636d43a..788e2d8 100644 --- a/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.cpp +++ b/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.cpp @@ -17,8 +17,6 @@ namespace blink { namespace { -const char kTrialHeaderName[] = "origin-trial"; - String getCurrentOrigin(ExecutionContext* executionContext) { return executionContext->securityOrigin()->toString(); @@ -30,40 +28,13 @@ String getDisabledMessage(const String& featureName) return "The '" + featureName + "' feature is currently enabled in limited trials. Please see [Phosphor console URL] for information on enabling a trial for your site."; } -bool hasValidToken(ExecutionContext* executionContext, const String& featureName, String* errorMessage, WebTrialTokenValidator* validator) -{ - bool foundAnyToken = false; - String origin = getCurrentOrigin(executionContext); - - // When in a document, the token is provided in a meta tag - if (executionContext->isDocument()) { - HTMLHeadElement* head = toDocument(executionContext)->head(); - for (HTMLMetaElement* metaElement = head ? Traversal<HTMLMetaElement>::firstChild(*head) : 0; metaElement; metaElement = Traversal<HTMLMetaElement>::nextSibling(*metaElement)) { - if (equalIgnoringCase(metaElement->httpEquiv(), kTrialHeaderName)) { - foundAnyToken = true; - String tokenString = metaElement->content(); - // Check with the validator service to verify the signature. - if (validator->validateToken(tokenString, origin, featureName)) { - return true; - } - } - } - } +} // namespace - if (errorMessage) { - if (foundAnyToken) { - *errorMessage = "The provided token(s) are not valid for the '" + featureName + "' feature."; - } else { - *errorMessage = getDisabledMessage(featureName); - } - } - return false; -} +const char OriginTrialContext::kTrialHeaderName[] = "origin-trial"; -} // namespace +OriginTrialContext::OriginTrialContext() {} -// static -bool OriginTrialContext::isFeatureEnabled(ExecutionContext* executionContext, const String& featureName, String* errorMessage, WebTrialTokenValidator* validator) +bool OriginTrialContext::isFeatureEnabled(const String& featureName, String* errorMessage, WebTrialTokenValidator* validator) { if (!RuntimeEnabledFeatures::experimentalFrameworkEnabled()) { // TODO(iclelland): Set an error message here, the first time the @@ -71,16 +42,16 @@ bool OriginTrialContext::isFeatureEnabled(ExecutionContext* executionContext, co return false; } - if (!executionContext) { - ASSERT_NOT_REACHED(); - return false; - } - // Feature trials are only enabled for secure origins bool isSecure = errorMessage - ? executionContext->isSecureContext(*errorMessage) - : executionContext->isSecureContext(); + ? executionContext()->isSecureContext(*errorMessage) + : executionContext()->isSecureContext(); if (!isSecure) { + // The execution context should always set a message here, if a valid + // pointer was passed in. If it does not, then we should find out why + // not, and decide whether the OriginTrialContext should be using its + // own error messages for this case. + DCHECK(!errorMessage || !errorMessage->isEmpty()); return false; } @@ -93,7 +64,32 @@ bool OriginTrialContext::isFeatureEnabled(ExecutionContext* executionContext, co } } - return hasValidToken(executionContext, featureName, errorMessage, validator); + return hasValidToken(getTokens(), featureName, errorMessage, validator); +} + +bool OriginTrialContext::hasValidToken(Vector<String> tokens, const String& featureName, String* errorMessage, WebTrialTokenValidator* validator) +{ + String origin = getCurrentOrigin(executionContext()); + + for (const String& token : tokens) { + // Check with the validator service to verify the signature. + if (validator->validateToken(token, origin, featureName)) { + return true; + } + } + + if (errorMessage) { + if (tokens.size()) { + *errorMessage = "The provided token(s) are not valid for the '" + featureName + "' feature."; + } else { + *errorMessage = getDisabledMessage(featureName); + } + } + return false; +} + +DEFINE_TRACE(OriginTrialContext) +{ } } // namespace blink diff --git a/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.h b/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.h index 579307d..afe5771 100644 --- a/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.h +++ b/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.h @@ -6,12 +6,13 @@ #define OriginTrialContext_h #include "core/CoreExport.h" -#include "core/dom/DOMException.h" -#include "core/dom/ExecutionContext.h" -#include "wtf/text/WTFString.h" +#include "platform/heap/Handle.h" +#include "wtf/Forward.h" +#include "wtf/Vector.h" namespace blink { +class ExecutionContext; class WebTrialTokenValidator; // The Experimental Framework (EF) provides limited access to experimental @@ -27,24 +28,34 @@ class WebTrialTokenValidator; // feature names. Instead, the EF validates the name provided by the feature // implementation against any provided tokens. // -// This class is not intended to be instantiated. Any required state is kept -// with a WebApiKeyValidator object held in the Platform object. -// The static methods in this class may be called either from the main thread -// or from a worker thread. +// This class is abstract, and should be subclassed for each execution context +// which supports origin trials. // // TODO(chasej): Link to documentation, or provide more detail on keys, .etc -class CORE_EXPORT OriginTrialContext { +class CORE_EXPORT OriginTrialContext : public NoBaseWillBeGarbageCollectedFinalized<OriginTrialContext> { +public: + static const char kTrialHeaderName[]; + virtual ~OriginTrialContext() = default; + + virtual ExecutionContext* executionContext() = 0; + virtual Vector<String> getTokens() = 0; + + DECLARE_VIRTUAL_TRACE(); + +protected: + OriginTrialContext(); + private: friend class OriginTrialContextTest; friend class OriginTrials; - OriginTrialContext(); - // Returns true if the feature should be considered enabled for the current // execution context. This method usually makes use of the token validator // object in the platform, but this may be overridden if a custom validator // is required (for testing, for instance). - static bool isFeatureEnabled(ExecutionContext*, const String& featureName, String* errorMessage, WebTrialTokenValidator* = nullptr); + bool isFeatureEnabled(const String& featureName, String* errorMessage, WebTrialTokenValidator* = nullptr); + + bool hasValidToken(Vector<String> tokens, const String& featureName, String* errorMessage, WebTrialTokenValidator*); }; } // namespace blink diff --git a/third_party/WebKit/Source/core/origin_trials/OriginTrialContextTest.cpp b/third_party/WebKit/Source/core/origin_trials/OriginTrialContextTest.cpp index 6464351..49f7952 100644 --- a/third_party/WebKit/Source/core/origin_trials/OriginTrialContextTest.cpp +++ b/third_party/WebKit/Source/core/origin_trials/OriginTrialContextTest.cpp @@ -12,10 +12,12 @@ #include "core/html/HTMLHeadElement.h" #include "core/html/HTMLMetaElement.h" #include "core/testing/DummyPageHolder.h" +#include "core/testing/NullExecutionContext.h" #include "platform/weborigin/KURL.h" #include "platform/weborigin/SecurityOrigin.h" #include "public/platform/WebTrialTokenValidator.h" #include "testing/gtest/include/gtest/gtest.h" +#include "wtf/Vector.h" namespace blink { namespace { @@ -66,75 +68,76 @@ private: DISALLOW_COPY_AND_ASSIGN(MockTokenValidator); }; -} // namespace - -class OriginTrialContextTest : public ::testing::Test { -protected: - OriginTrialContextTest() - : m_page(DummyPageHolder::create()) - , m_frameworkWasEnabled(RuntimeEnabledFeatures::experimentalFrameworkEnabled()) - , m_tokenValidator(adoptPtr(new MockTokenValidator())) +// Concrete subclass of OriginTrialContext which simply maintains a vector of +// token strings to use for tests. +class TestOriginTrialContext : public OriginTrialContext { +public: + explicit TestOriginTrialContext() + : m_parent(adoptRefWillBeNoop(new NullExecutionContext())) { - if (!RuntimeEnabledFeatures::experimentalFrameworkEnabled()) { - RuntimeEnabledFeatures::setExperimentalFrameworkEnabled(true); - } } - ~OriginTrialContextTest() - { - if (!m_frameworkWasEnabled) { - RuntimeEnabledFeatures::setExperimentalFrameworkEnabled(false); - } + ~TestOriginTrialContext() override = default; - m_page.clear(); - } + ExecutionContext* executionContext() override { return m_parent.get(); } - void SetUp() override + void addToken(const String& token) { - m_document = toHTMLDocument(&m_page->document()); - setInnerHTML( - "<html>" - "<head>" - "</head>" - "<body>" - "</body>" - "</html>"); + m_tokens.append(token); } - ExecutionContext* executionContext() { return &(m_page->document()); } - MockTokenValidator* tokenValidator() { return m_tokenValidator.get(); } - HTMLDocument& document() const { return *m_document; } - - void setPageOrigin(const String& origin) + void updateSecurityOrigin(const String& origin) { KURL pageURL(ParsedURLString, origin); RefPtr<SecurityOrigin> pageOrigin = SecurityOrigin::create(pageURL); - m_page->document().updateSecurityOrigin(pageOrigin); + m_parent->setSecurityOrigin(pageOrigin); + m_parent->setIsSecureContext(SecurityOrigin::isSecure(pageURL)); } - void setInnerHTML(const char* htmlContent) + Vector<String> getTokens() override { - document().documentElement()->setInnerHTML(String::fromUTF8(htmlContent), ASSERT_NO_EXCEPTION); - document().view()->updateAllLifecyclePhases(); + Vector<String> tokens; + for (String token : m_tokens) { + tokens.append(token); + } + return tokens; } - void addTrialToken(const String& token) + DEFINE_INLINE_VIRTUAL_TRACE() { - HTMLElement* head = document().head(); - ASSERT_TRUE(head); - - RefPtrWillBeRawPtr<HTMLMetaElement> meta = HTMLMetaElement::create(document()); - meta->setAttribute(HTMLNames::http_equivAttr, "origin-trial"); - AtomicString value(token); - meta->setAttribute(HTMLNames::contentAttr, value); - head->appendChild(meta.release()); + visitor->trace(m_parent); + OriginTrialContext::trace(visitor); } +private: + RefPtrWillBeMember<NullExecutionContext> m_parent; + Vector<String> m_tokens; +}; + +} // namespace + +class OriginTrialContextTest : public ::testing::Test { +protected: + OriginTrialContextTest() + : m_frameworkWasEnabled(RuntimeEnabledFeatures::experimentalFrameworkEnabled()) + , m_tokenValidator(adoptPtr(new MockTokenValidator())) + , m_originTrialContext(adoptPtrWillBeNoop(new TestOriginTrialContext)) + { + RuntimeEnabledFeatures::setExperimentalFrameworkEnabled(true); + } + + ~OriginTrialContextTest() + { + RuntimeEnabledFeatures::setExperimentalFrameworkEnabled(m_frameworkWasEnabled); + } + + MockTokenValidator* tokenValidator() { return m_tokenValidator.get(); } + bool isFeatureEnabled(const String& origin, const String& featureName, const String& token, String* errorMessage) { - setPageOrigin(origin); - addTrialToken(token); - return OriginTrialContext::isFeatureEnabled(executionContext(), featureName, errorMessage, tokenValidator()); + m_originTrialContext->updateSecurityOrigin(origin); + m_originTrialContext->addToken(token); + return m_originTrialContext->isFeatureEnabled(featureName, errorMessage, tokenValidator()); } bool isFeatureEnabledWithoutErrorMessage(const String& origin, const String& featureName, const char* token) @@ -143,10 +146,9 @@ protected: } private: - OwnPtr<DummyPageHolder> m_page; - RefPtrWillBePersistent<HTMLDocument> m_document; const bool m_frameworkWasEnabled; OwnPtr<MockTokenValidator> m_tokenValidator; + OwnPtrWillBePersistent<TestOriginTrialContext> m_originTrialContext; }; TEST_F(OriginTrialContextTest, EnabledNonExistingFeature) @@ -219,7 +221,17 @@ TEST_F(OriginTrialContextTest, EnabledNonSecureRegisteredOrigin) kGoodToken, &errorMessage); EXPECT_FALSE(isOriginEnabled); - EXPECT_TRUE(errorMessage.contains("secure origin")) << "Message should indicate only secure origins are allowed, was: " << errorMessage; + EXPECT_EQ(0, tokenValidator()->callCount()); + EXPECT_FALSE(errorMessage.isEmpty()); +} + +TEST_F(OriginTrialContextTest, EnabledNonSecureRegisteredOriginWithoutErrorMessage) +{ + bool isOriginEnabled = isFeatureEnabledWithoutErrorMessage( + kFrobulateEnabledOriginUnsecure, + kFrobulateFeatureName, + kGoodToken); + EXPECT_FALSE(isOriginEnabled); EXPECT_EQ(0, tokenValidator()->callCount()); } diff --git a/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp b/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp index f2a649d..a52527e 100644 --- a/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp +++ b/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp @@ -25,6 +25,7 @@ public: NullExecutionContext::NullExecutionContext() : m_tasksNeedSuspension(false) + , m_isSecureContext(true) , m_queue(adoptPtrWillBeNoop(new NullEventQueue())) { } @@ -33,9 +34,16 @@ void NullExecutionContext::postTask(const WebTraceLocation&, PassOwnPtr<Executio { } +void NullExecutionContext::setIsSecureContext(bool isSecureContext) +{ + m_isSecureContext = isSecureContext; +} + bool NullExecutionContext::isSecureContext(String& errorMessage, const SecureContextCheck privilegeContextCheck) const { - return true; + if (!m_isSecureContext) + errorMessage = "A secure context is required"; + return m_isSecureContext; } } // namespace blink diff --git a/third_party/WebKit/Source/core/testing/NullExecutionContext.h b/third_party/WebKit/Source/core/testing/NullExecutionContext.h index 9883edf..9f88e8c 100644 --- a/third_party/WebKit/Source/core/testing/NullExecutionContext.h +++ b/third_party/WebKit/Source/core/testing/NullExecutionContext.h @@ -40,6 +40,7 @@ public: void addConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage>) override { } void logExceptionToConsole(const String& errorMessage, int scriptId, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>) override { } + void setIsSecureContext(bool); bool isSecureContext(String& errorMessage, const SecureContextCheck = StandardSecureContextCheck) const override; DEFINE_INLINE_TRACE() @@ -63,6 +64,7 @@ protected: private: bool m_tasksNeedSuspension; + bool m_isSecureContext; OwnPtrWillBeMember<EventQueue> m_queue; KURL m_dummyURL; |
