diff options
| author | iclelland <iclelland@chromium.org> | 2016-03-07 09:36:22 -0800 |
|---|---|---|
| committer | Commit bot <commit-bot@chromium.org> | 2016-03-07 17:37:46 +0000 |
| commit | c970675cb18a6ba91220d95128dced7b3ffd24b2 (patch) | |
| tree | 2ef205cbd73671756e6829cddb7f96745251f9ff | |
| parent | 83013584d091473d3a5fee6a823bc63b223a472c (diff) | |
| download | chromium_src-c970675cb18a6ba91220d95128dced7b3ffd24b2.zip chromium_src-c970675cb18a6ba91220d95128dced7b3ffd24b2.tar.gz chromium_src-c970675cb18a6ba91220d95128dced7b3ffd24b2.tar.bz2 | |
[Experimental Framework] Make the OriginTrialContext a supplement to ExecutionContext
This patch makes OriginTrialContext a supplement to the ExecutionContext object,
rather than being a collection of static methods. This allows us to maintain
state on the object, and allows it to be specialized for the different types of
execution contexts, so that document contexts can be handled differently than
workers, for instance.
BUG=582063
Review URL: https://codereview.chromium.org/1743623002
Cr-Commit-Position: refs/heads/master@{#379575}
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; |
