summaryrefslogtreecommitdiff
path: root/chromium/third_party/WebKit/common/origin_trials/trial_token_validator.cc
blob: a68b239b8be0f5d5307a235fa0d66376b4faeeae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// 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 "third_party/WebKit/common/origin_trials/trial_token_validator.h"

#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "third_party/WebKit/common/origin_trials/trial_policy.h"
#include "third_party/WebKit/common/origin_trials/trial_token.h"

namespace blink {

TrialTokenValidator::TrialTokenValidator(std::unique_ptr<TrialPolicy> policy)
    : policy_(std::move(policy)) {}
TrialTokenValidator::~TrialTokenValidator() {}

OriginTrialTokenStatus TrialTokenValidator::ValidateToken(
    const std::string& token,
    const url::Origin& origin,
    std::string* feature_name,
    base::Time current_time) const {
  if (!policy_ || !policy_->IsOriginTrialsSupported())
    return OriginTrialTokenStatus::kNotSupported;

  // TODO(iclelland): Allow for multiple signing keys, and iterate over all
  // active keys here. https://crbug.com/543220
  base::StringPiece public_key = policy_->GetPublicKey();

  OriginTrialTokenStatus status;
  std::unique_ptr<TrialToken> trial_token =
      TrialToken::From(token, public_key, &status);
  if (status != OriginTrialTokenStatus::kSuccess)
    return status;

  status = trial_token->IsValid(origin, current_time);
  if (status != OriginTrialTokenStatus::kSuccess)
    return status;

  if (policy_->IsFeatureDisabled(trial_token->feature_name()))
    return OriginTrialTokenStatus::kFeatureDisabled;

  if (policy_->IsTokenDisabled(trial_token->signature()))
    return OriginTrialTokenStatus::kTokenDisabled;

  *feature_name = trial_token->feature_name();
  return OriginTrialTokenStatus::kSuccess;
}

bool TrialTokenValidator::RequestEnablesFeature(const net::URLRequest* request,
                                                base::StringPiece feature_name,
                                                base::Time current_time) const {
  // 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, current_time);
}

bool TrialTokenValidator::RequestEnablesFeature(
    const GURL& request_url,
    const net::HttpResponseHeaders* response_headers,
    base::StringPiece feature_name,
    base::Time current_time) const {
  if (!IsTrialPossibleOnOrigin(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, current_time) ==
        OriginTrialTokenStatus::kSuccess)
      if (token_feature == feature_name)
        return true;
  }
  return false;
}

std::unique_ptr<TrialTokenValidator::FeatureToTokensMap>
TrialTokenValidator::GetValidTokensFromHeaders(
    const url::Origin& origin,
    const net::HttpResponseHeaders* headers,
    base::Time current_time) const {
  std::unique_ptr<FeatureToTokensMap> tokens(
      base::MakeUnique<FeatureToTokensMap>());
  if (!IsTrialPossibleOnOrigin(origin))
    return tokens;

  size_t iter = 0;
  std::string token;
  if (headers) {
    while (headers->EnumerateHeader(&iter, "Origin-Trial", &token)) {
      std::string token_feature;
      if (TrialTokenValidator::ValidateToken(token, origin, &token_feature,
                                             current_time) ==
          OriginTrialTokenStatus::kSuccess) {
        (*tokens)[token_feature].push_back(token);
      }
    }
  }
  return tokens;
}

std::unique_ptr<TrialTokenValidator::FeatureToTokensMap>
TrialTokenValidator::GetValidTokens(const url::Origin& origin,
                                    const FeatureToTokensMap& tokens,
                                    base::Time current_time) const {
  std::unique_ptr<FeatureToTokensMap> out_tokens(
      base::MakeUnique<FeatureToTokensMap>());
  if (!IsTrialPossibleOnOrigin(origin))
    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,
                                             current_time) ==
          OriginTrialTokenStatus::kSuccess) {
        DCHECK_EQ(token_feature, feature.first);
        (*out_tokens)[feature.first].push_back(token);
      }
    }
  }
  return out_tokens;
}

bool TrialTokenValidator::IsTrialPossibleOnOrigin(const GURL& url) const {
  return policy_->IsOriginTrialsSupported() && policy_->IsOriginSecure(url);
}

bool TrialTokenValidator::IsTrialPossibleOnOrigin(
    const url::Origin& origin) const {
  return IsTrialPossibleOnOrigin(origin.GetURL());
}

}  // namespace blink