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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
// Copyright 2014 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 NET_SSL_CHANNEL_ID_SERVICE_H_
#define NET_SSL_CHANNEL_ID_SERVICE_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/task_runner.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/ssl/channel_id_store.h"
namespace crypto {
class ECPrivateKey;
} // namespace crypto
namespace net {
class ChannelIDServiceJob;
// A class for creating and fetching Channel IDs.
// Inherits from NonThreadSafe in order to use the function
// |CalledOnValidThread|.
class NET_EXPORT ChannelIDService
: NON_EXPORTED_BASE(public base::NonThreadSafe) {
public:
class NET_EXPORT Request {
public:
Request();
~Request();
// Cancel the request. Does nothing if the request finished or was already
// cancelled.
void Cancel();
bool is_active() const { return !callback_.is_null(); }
private:
friend class ChannelIDService;
friend class ChannelIDServiceJob;
void RequestStarted(ChannelIDService* service,
base::TimeTicks request_start,
const CompletionCallback& callback,
std::unique_ptr<crypto::ECPrivateKey>* key,
ChannelIDServiceJob* job);
void Post(int error, std::unique_ptr<crypto::ECPrivateKey> key);
ChannelIDService* service_;
base::TimeTicks request_start_;
CompletionCallback callback_;
std::unique_ptr<crypto::ECPrivateKey>* key_;
ChannelIDServiceJob* job_;
};
// This object owns |channel_id_store|.
explicit ChannelIDService(ChannelIDStore* channel_id_store);
~ChannelIDService();
// Sets the TaskRunner to use for asynchronous operations.
void set_task_runner_for_testing(
scoped_refptr<base::TaskRunner> task_runner) {
task_runner_ = std::move(task_runner);
}
// Returns the domain to be used for |host|. The domain is the
// "registry controlled domain", or the "ETLD + 1" where one exists, or
// the origin otherwise.
static std::string GetDomainForHost(const std::string& host);
// Fetches the channel ID for the specified host if one exists and
// creates one otherwise. Returns OK if successful or an error code upon
// failure.
//
// On successful completion, |key| holds the ECDSA keypair used for this
// channel ID.
//
// |callback| must not be null. ERR_IO_PENDING is returned if the operation
// could not be completed immediately, in which case the result code will
// be passed to the callback when available.
//
// |*out_req| will be initialized with a handle to the async request.
int GetOrCreateChannelID(const std::string& host,
std::unique_ptr<crypto::ECPrivateKey>* key,
const CompletionCallback& callback,
Request* out_req);
// Fetches the channel ID for the specified host if one exists.
// Returns OK if successful, ERR_FILE_NOT_FOUND if none exists, or an error
// code upon failure.
//
// On successful completion, |key| holds the ECDSA keypair used for this
// channel ID.
//
// |callback| must not be null. ERR_IO_PENDING is returned if the operation
// could not be completed immediately, in which case the result code will
// be passed to the callback when available. If an in-flight
// GetChannelID is pending, and a new GetOrCreateChannelID
// request arrives for the same domain, the GetChannelID request will
// not complete until a new channel ID is created.
//
// |*out_req| will be initialized with a handle to the async request.
int GetChannelID(const std::string& host,
std::unique_ptr<crypto::ECPrivateKey>* key,
const CompletionCallback& callback,
Request* out_req);
// Returns the backing ChannelIDStore.
ChannelIDStore* GetChannelIDStore();
// Returns an ID that is unique across all instances of ChannelIDService in
// this process. TODO(nharper): remove this once crbug.com/548423 is resolved.
int GetUniqueID() const { return id_; }
// Public only for unit testing.
int channel_id_count();
uint64_t requests() const { return requests_; }
uint64_t key_store_hits() const { return key_store_hits_; }
uint64_t inflight_joins() const { return inflight_joins_; }
uint64_t workers_created() const { return workers_created_; }
private:
void GotChannelID(int err,
const std::string& server_identifier,
std::unique_ptr<crypto::ECPrivateKey> key);
void GeneratedChannelID(
const std::string& server_identifier,
int error,
std::unique_ptr<ChannelIDStore::ChannelID> channel_id);
void HandleResult(int error,
const std::string& server_identifier,
std::unique_ptr<crypto::ECPrivateKey> key);
// Searches for an in-flight request for the same domain. If found,
// attaches to the request and returns true. Returns false if no in-flight
// request is found.
bool JoinToInFlightRequest(const base::TimeTicks& request_start,
const std::string& domain,
std::unique_ptr<crypto::ECPrivateKey>* key,
bool create_if_missing,
const CompletionCallback& callback,
Request* out_req);
// Looks for the channel ID for |domain| in this service's store.
// Returns OK if it can be found synchronously, ERR_IO_PENDING if the
// result cannot be obtained synchronously, or a network error code on
// failure (including failure to find a channel ID of |domain|).
int LookupChannelID(const base::TimeTicks& request_start,
const std::string& domain,
std::unique_ptr<crypto::ECPrivateKey>* key,
bool create_if_missing,
const CompletionCallback& callback,
Request* out_req);
std::unique_ptr<ChannelIDStore> channel_id_store_;
scoped_refptr<base::TaskRunner> task_runner_;
const int id_;
// inflight_ maps from a server to an active generation which is taking
// place.
std::map<std::string, std::unique_ptr<ChannelIDServiceJob>> inflight_;
uint64_t requests_;
uint64_t key_store_hits_;
uint64_t inflight_joins_;
uint64_t workers_created_;
base::WeakPtrFactory<ChannelIDService> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ChannelIDService);
};
} // namespace net
#endif // NET_SSL_CHANNEL_ID_SERVICE_H_
|