Index: third_party/WebKit/Source/core/origin_trials/OriginTrialContext.cpp |
diff --git a/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.cpp b/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.cpp |
index 446036a3ea035d255392cd59da0531b73e81e021..b029625208d926c61bdcffbe80c98248bce157af 100644 |
--- a/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.cpp |
+++ b/third_party/WebKit/Source/core/origin_trials/OriginTrialContext.cpp |
@@ -27,102 +27,12 @@ namespace blink { |
namespace { |
-// The enum entries below are written to histograms and thus cannot be deleted |
-// or reordered. |
-// New entries must be added immediately before the end. |
-enum MessageGeneratedResult { |
- MessageGeneratedResultNotRequested = 0, |
- MessageGeneratedResultYes = 1, |
- MessageGeneratedResultNo = 2, |
- MessageGeneratedResultLast = MessageGeneratedResultNo |
-}; |
- |
-static EnumerationHistogram& enabledResultHistogram() |
+static EnumerationHistogram& tokenValidationResultHistogram() |
{ |
- DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, histogram, new EnumerationHistogram("OriginTrials.FeatureEnabled", static_cast<int>(WebOriginTrialTokenStatus::Last))); |
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, histogram, new EnumerationHistogram("OriginTrials.ValidationResult", static_cast<int>(WebOriginTrialTokenStatus::Last))); |
return histogram; |
} |
-static EnumerationHistogram& messageGeneratedResultHistogram() |
-{ |
- DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, histogram, new EnumerationHistogram("OriginTrials.FeatureEnabled.MessageGenerated", MessageGeneratedResultLast)); |
- return histogram; |
-} |
- |
-String getDisabledMessage(const String& featureName) |
-{ |
- return "The '" + featureName + "' feature is currently enabled in limited trials. Please see https://bit.ly/OriginTrials for information on enabling a trial for your site."; |
-} |
- |
-String getInvalidTokenMessage(const String& featureName) |
-{ |
- return "The provided token(s) are not valid for the '" + featureName + "' feature."; |
-} |
- |
-String getNotSupportedMessage() |
-{ |
- return "This browser does not support origin trials."; |
-} |
- |
-int getTokenValidationResultPriority( |
- WebOriginTrialTokenStatus validationResult) |
-{ |
- // There could be zero, one or multiple trial tokens provided for a given |
- // context, and any number of them could be invalid. The tokens could be |
- // invalid for a variety of reasons. For multiple invalid tokens, the |
- // failures are collected into a single result for collecting metrics. At a |
- // high level, the idea is to report on the tokens that were closest to |
- // being valid for enabling a feature. This gives the priority as: |
- // 1. Expired, but otherwise valid |
- // 2. Wrong feature, but correct origin |
- // 3. Wrong origin, but correct format for token data |
- // 4. Invalid signature for token |
- // 5. Wrong version for token (not currently supported version number(s)) |
- // 6. Invalid data in token (can be before/after validating signature) |
- // 7. Embedder does not support origin trials |
- // 8. No tokens provided |
- // NOTE: Lower numbers are higher priority |
- // See this document for details: |
- // https://docs.google.com/document/d/1qVP2CK1lbfmtIJRIm6nwuEFFhGhYbtThLQPo3CSTtmg/edit#bookmark=id.k1j0q938so3b |
- switch (validationResult) { |
- case WebOriginTrialTokenStatus::Success: |
- case WebOriginTrialTokenStatus::Insecure: |
- case WebOriginTrialTokenStatus::FeatureDisabled: |
- // This function should only be used for token validation failures |
- NOTREACHED(); |
- return 99; |
- case WebOriginTrialTokenStatus::Expired: |
- return 1; |
- case WebOriginTrialTokenStatus::WrongFeature: |
- return 2; |
- case WebOriginTrialTokenStatus::WrongOrigin: |
- return 3; |
- case WebOriginTrialTokenStatus::InvalidSignature: |
- return 4; |
- case WebOriginTrialTokenStatus::WrongVersion: |
- return 5; |
- case WebOriginTrialTokenStatus::Malformed: |
- return 6; |
- case WebOriginTrialTokenStatus::NotSupported: |
- return 7; |
- case WebOriginTrialTokenStatus::NoTokens: |
- return 8; |
- } |
- |
- NOTREACHED(); |
- return 99; |
-} |
- |
-WebOriginTrialTokenStatus UpdateResultFromValidationFailure( |
- WebOriginTrialTokenStatus newResult, |
- WebOriginTrialTokenStatus currentResult) |
-{ |
- if (getTokenValidationResultPriority(newResult) < getTokenValidationResultPriority(currentResult)) { |
- return newResult; |
- } |
- return currentResult; |
-} |
- |
bool isWhitespace(UChar chr) |
{ |
return (chr == ' ') || (chr == '\t'); |
@@ -242,14 +152,21 @@ std::unique_ptr<Vector<String>> OriginTrialContext::getTokens(ExecutionContext* |
void OriginTrialContext::addToken(const String& token) |
{ |
- if (!token.isEmpty()) |
+ if (!token.isEmpty()) { |
m_tokens.append(token); |
+ validateToken(token); |
+ } |
initializePendingFeatures(); |
} |
void OriginTrialContext::addTokens(const Vector<String>& tokens) |
{ |
- m_tokens.appendVector(tokens); |
+ for (const String& token : tokens) { |
+ if (!token.isEmpty()) { |
+ m_tokens.append(token); |
+ validateToken(token); |
+ } |
+ } |
initializePendingFeatures(); |
} |
@@ -292,97 +209,36 @@ bool OriginTrialContext::featureBindingsInstalled(const String& featureName) |
return m_bindingsInstalled.contains(featureName); |
} |
-bool OriginTrialContext::isFeatureEnabled(const String& featureName, String* errorMessage) |
+bool OriginTrialContext::isFeatureEnabled(const String& featureName) |
{ |
- if (!RuntimeEnabledFeatures::originTrialsEnabled()) { |
- // Do not set an error message. When the framework is disabled, it |
- // should behave the same as when only runtime flags are used. |
+ if (!RuntimeEnabledFeatures::originTrialsEnabled()) |
return false; |
- } |
- |
- WebOriginTrialTokenStatus result = checkFeatureEnabled(featureName, errorMessage); |
- |
- // Record metrics for the enabled result, but only once per context. |
- if (!m_enabledResultCountedForFeature.contains(featureName)) { |
- enabledResultHistogram().count(static_cast<int>(result)); |
- m_enabledResultCountedForFeature.add(featureName); |
- } |
- |
- if (result == WebOriginTrialTokenStatus::Success) { |
- return true; |
- } |
- |
- // If an error message has already been generated in this context, for this |
- // feature, do not generate another one. This avoids cluttering the console |
- // with error messages on every attempt to access the feature. |
- // Metrics are also recorded, to track whether too many messages are being |
- // generated over time. |
- MessageGeneratedResult generateMessage = MessageGeneratedResultYes; |
- if (!errorMessage) { |
- generateMessage = MessageGeneratedResultNotRequested; |
- } else if (m_errorMessageGeneratedForFeature.contains(featureName)) { |
- *errorMessage = ""; |
- generateMessage = MessageGeneratedResultNo; |
- } |
- messageGeneratedResultHistogram().count(generateMessage); |
- if (generateMessage != MessageGeneratedResultYes) { |
- return false; |
- } |
- |
- // Generate an error message, only if one was not already provided by the |
- // enabled check. |
- if (!errorMessage->length()) { |
- switch (result) { |
- case WebOriginTrialTokenStatus::NotSupported: |
- *errorMessage = getNotSupportedMessage(); |
- break; |
- case WebOriginTrialTokenStatus::NoTokens: |
- *errorMessage = getDisabledMessage(featureName); |
- break; |
- default: |
- *errorMessage = getInvalidTokenMessage(featureName); |
- break; |
- } |
- } |
- m_errorMessageGeneratedForFeature.add(featureName); |
- return false; |
+ return m_enabledFeatures.contains(featureName); |
} |
-WebOriginTrialTokenStatus OriginTrialContext::checkFeatureEnabled(const String& featureName, String* errorMessage) |
+void OriginTrialContext::validateToken(const String& token) |
{ |
+ DCHECK(!token.isEmpty()); |
+ |
// Feature trials are only enabled for secure origins |
- bool isSecure = errorMessage |
- ? m_host->isSecureContext(*errorMessage) |
- : m_host->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 WebOriginTrialTokenStatus::Insecure; |
+ if (!m_host->isSecureContext()) { |
+ tokenValidationResultHistogram().count(static_cast<int>(WebOriginTrialTokenStatus::Insecure)); |
+ return; |
} |
if (!m_trialTokenValidator) { |
- return WebOriginTrialTokenStatus::NotSupported; |
+ tokenValidationResultHistogram().count(static_cast<int>(WebOriginTrialTokenStatus::NotSupported)); |
+ return; |
} |
- WebOriginTrialTokenStatus failedValidationResult = WebOriginTrialTokenStatus::NoTokens; |
WebSecurityOrigin origin(m_host->getSecurityOrigin()); |
- for (const String& token : m_tokens) { |
- // Check with the validator service to verify the signature and that |
- // the token is valid for the combination of origin and feature. |
- WebOriginTrialTokenStatus tokenResult = m_trialTokenValidator->validateToken(token, origin, featureName); |
- // If the feature is disabled by policy, or if the token is valid, we |
- // can return immediately now. |
- if (tokenResult == WebOriginTrialTokenStatus::FeatureDisabled || tokenResult == WebOriginTrialTokenStatus::Success) { |
- return tokenResult; |
- } |
- failedValidationResult = UpdateResultFromValidationFailure(tokenResult, failedValidationResult); |
- } |
+ WebString featureName; |
+ WebOriginTrialTokenStatus tokenResult = m_trialTokenValidator->validateToken(token, origin, &featureName); |
+ if (tokenResult == WebOriginTrialTokenStatus::Success) |
+ m_enabledFeatures.add(featureName); |
- return failedValidationResult; |
+ tokenValidationResultHistogram().count(static_cast<int>(tokenResult)); |
} |
DEFINE_TRACE(OriginTrialContext) |