blob: 2cb1dd3d43d1423c21848873a12b7455b41455f2 [file] [log] [blame]
// Copyright 2016 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 "content/common/origin_trials/trial_token_validator.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "content/common/origin_trials/trial_token.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
#include "content/public/common/origin_trial_policy.h"
#include "content/public/common/origin_util.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "third_party/WebKit/public/platform/WebOriginTrialTokenStatus.h"
namespace content {
blink::WebOriginTrialTokenStatus TrialTokenValidator::ValidateToken(
const std::string& token,
const url::Origin& origin,
std::string* feature_name) {
ContentClient* content_client = GetContentClient();
const OriginTrialPolicy* origin_trial_policy =
content_client->GetOriginTrialPolicy();
if (!origin_trial_policy)
return blink::WebOriginTrialTokenStatus::NotSupported;
// TODO(iclelland): Allow for multiple signing keys, and iterate over all
// active keys here. https://crbug.com/543220
base::StringPiece public_key = origin_trial_policy->GetPublicKey();
if (public_key.empty())
return blink::WebOriginTrialTokenStatus::NotSupported;
blink::WebOriginTrialTokenStatus status;
std::unique_ptr<TrialToken> trial_token =
TrialToken::From(token, public_key, &status);
if (status != blink::WebOriginTrialTokenStatus::Success)
return status;
status = trial_token->IsValid(origin, base::Time::Now());
if (status != blink::WebOriginTrialTokenStatus::Success)
return status;
if (origin_trial_policy->IsFeatureDisabled(trial_token->feature_name()))
return blink::WebOriginTrialTokenStatus::FeatureDisabled;
*feature_name = trial_token->feature_name();
return blink::WebOriginTrialTokenStatus::Success;
}
bool TrialTokenValidator::RequestEnablesFeature(
const net::URLRequest* request,
base::StringPiece feature_name) {
// TODO(mek): Possibly cache the features that are availble for request in
// UserData associated with the request.
return RequestEnablesFeature(request->url(), request->response_headers(),
feature_name);
}
bool TrialTokenValidator::RequestEnablesFeature(
const GURL& request_url,
const net::HttpResponseHeaders* response_headers,
base::StringPiece feature_name) {
if (!base::FeatureList::IsEnabled(features::kOriginTrials))
return false;
if (!IsOriginSecure(request_url))
return false;
url::Origin origin(request_url);
size_t iter = 0;
std::string token;
while (response_headers->EnumerateHeader(&iter, "Origin-Trial", &token)) {
std::string token_feature;
// TODO(mek): Log the validation errors to histograms?
if (ValidateToken(token, origin, &token_feature) ==
blink::WebOriginTrialTokenStatus::Success)
if (token_feature == feature_name)
return true;
}
return false;
}
std::unique_ptr<TrialTokenValidator::FeatureToTokensMap>
TrialTokenValidator::GetValidTokensFromHeaders(
const url::Origin& origin,
const net::HttpResponseHeaders* headers) {
std::unique_ptr<FeatureToTokensMap> tokens(
base::MakeUnique<FeatureToTokensMap>());
if (!base::FeatureList::IsEnabled(features::kOriginTrials))
return tokens;
if (!IsOriginSecure(origin.GetURL()))
return tokens;
size_t iter = 0;
std::string token;
while (headers->EnumerateHeader(&iter, "Origin-Trial", &token)) {
std::string token_feature;
if (TrialTokenValidator::ValidateToken(token, origin, &token_feature) ==
blink::WebOriginTrialTokenStatus::Success) {
(*tokens)[token_feature].push_back(token);
}
}
return tokens;
}
std::unique_ptr<TrialTokenValidator::FeatureToTokensMap>
TrialTokenValidator::GetValidTokens(const url::Origin& origin,
const FeatureToTokensMap& tokens) {
std::unique_ptr<FeatureToTokensMap> out_tokens(
base::MakeUnique<FeatureToTokensMap>());
if (!base::FeatureList::IsEnabled(features::kOriginTrials))
return out_tokens;
if (!IsOriginSecure(origin.GetURL()))
return out_tokens;
for (const auto& feature : tokens) {
for (const std::string& token : feature.second) {
std::string token_feature;
if (TrialTokenValidator::ValidateToken(token, origin, &token_feature) ==
blink::WebOriginTrialTokenStatus::Success) {
DCHECK_EQ(token_feature, feature.first);
(*out_tokens)[feature.first].push_back(token);
}
}
}
return out_tokens;
}
} // namespace content