Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(800)

Side by Side Diff: net/http/disk_based_cert_cache.cc

Issue 329733002: Disk Based Certificate Cache Implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed style issues with patch 7. v2 Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/disk_based_cert_cache.h"
6
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "net/disk_cache/disk_cache.h"
17
18 namespace net {
19
20 namespace {
21
22 // Used to obtain a unique cache key for a certificate in the form of
23 // "cert:<hash>".
24 std::string GetCacheKeyToCert(const X509Certificate::OSCertHandle cert_handle) {
25 SHA1HashValue fingerprint =
26 X509Certificate::CalculateFingerprint(cert_handle);
27
28 return "cert:" +
29 base::HexEncode(fingerprint.data, arraysize(fingerprint.data));
30 }
31
32 } // namespace
33
34 // WriteWorkers represent pending Set jobs in the DiskBasedCertCache. Each
35 // certificate requested to be cached is assigned a Writeworker on a one-to-one
36 // basis. The same certificate should not have multiple WriteWorkers at the same
37 // time; instead, add a user_callback_ to the existing WriteWorker.
wtc 2014/06/21 00:43:12 Typo: user_callback_ => user callback
38 class DiskBasedCertCache::WriteWorker {
39 public:
40 // |backend| is the backend to store |certificate| in, using
41 // |key| as the key for the disk_cache::Entry.
42 // |cleanup_callback| is called to clean up this ReadWorker,
43 // regardless of success or failure.
44 WriteWorker(disk_cache::Backend* backend,
45 const std::string& key,
46 const X509Certificate::OSCertHandle cert_handle,
wtc 2014/06/21 00:43:13 Nit: this 'const' isn't necessary.
47 const base::Closure& cleanup_callback);
48
49 ~WriteWorker();
50
51 // Writes the given certificate to the cache. On completion, will invoke all
52 // user callbacks.
53 void Start();
54
55 // Adds a callback to the set of callbacks to be notified when this
wtc 2014/06/21 00:43:12 Nit: to be notified => to run
56 // WriteWorker finishes processing.
57 void AddCallback(const SetCallback& user_callback);
58
59 // Signals the WriteWorker to finish early. The WriteWorker will be destroyed
wtc 2014/06/21 00:43:13 Nit: finish early => abort early ?
60 // upon the completion of any pending callbacks. User callbacks will be
61 // invoked with an empty string.
62 void Cancel();
63
64 private:
65 enum WriteState {
66 STATE_CREATE_OR_OPEN,
67 STATE_FINISH_CREATE_OR_OPEN,
68 STATE_START_WRITE,
wtc 2014/06/21 00:43:12 Nit: this state would be named STATE_WRITE in our
69 STATE_FINISH_WRITE,
wtc 2014/06/21 00:43:12 Our naming convention for the STATE_FINISH_XXX sta
70 STATE_WRITE_NONE
wtc 2014/06/21 00:43:13 Nit: This state can be named simply STATE_NONE.
71 };
72
73 void OnIOComplete(int rv);
74 int DoLoop(int rv);
75 int DoCreateOrOpen();
76 int DoFinishCreateOrOpen(int rv);
77 int DoStartWrite();
78 int DoFinishWrite(int rv);
79 void Finish(int rv);
80
81 // invokes all of the |user_callbacks_|
wtc 2014/06/21 00:43:12 Nit: capitalize "Invokes".
82 void CallCallbacks(int rv);
83
84 disk_cache::Backend* backend_;
85 const X509Certificate::OSCertHandle cert_handle_;
86 std::string key_;
87 bool canceled_;
88
89 disk_cache::Entry* entry_;
90 WriteState state_;
91 bool create_failed_;
92 scoped_refptr<IOBuffer> buffer;
wtc 2014/06/21 00:43:12 This member should be named buffer_, with a traili
93
94 base::Closure cleanup_callback_;
95 std::vector<SetCallback> user_callbacks_;
96 CompletionCallback io_callback_;
97
98 base::WeakPtrFactory<WriteWorker> weak_factory_;
99 };
100
101 DiskBasedCertCache::WriteWorker::WriteWorker(
102 disk_cache::Backend* backend,
103 const std::string& key,
104 X509Certificate::OSCertHandle cert_handle,
105 const base::Closure& cleanup_callback)
106 : backend_(backend),
107 cert_handle_(cert_handle),
108 key_(key),
109 canceled_(false),
110 entry_(NULL),
111 state_(STATE_CREATE_OR_OPEN),
wtc 2014/06/21 00:43:12 Nit: see if you can initialize state_ to STATE_WRI
112 create_failed_(false),
113 cleanup_callback_(cleanup_callback),
114 weak_factory_(this) {
115 io_callback_ =
116 base::Bind(&WriteWorker::OnIOComplete, weak_factory_.GetWeakPtr());
117 }
118
119 void DiskBasedCertCache::WriteWorker::Start() {
120 int rv = DoLoop(OK);
121
122 if (state_ != STATE_WRITE_NONE)
wtc 2014/06/21 00:43:12 In our convention, I think we would check the |rv|
123 return;
124
125 Finish(rv);
126 }
127
128 void DiskBasedCertCache::WriteWorker::AddCallback(
129 const SetCallback& user_callback) {
130 user_callbacks_.push_back(user_callback);
131 }
132
133 void DiskBasedCertCache::WriteWorker::OnIOComplete(int rv) {
134 if (canceled_) {
135 Finish(ERR_FAILED);
136 return;
137 }
138
139 rv = DoLoop(rv);
140
141 if (state_ != STATE_WRITE_NONE)
142 return;
143
144 Finish(rv);
145 }
146
147 int DiskBasedCertCache::WriteWorker::DoLoop(int rv) {
148 do {
149 switch (state_) {
150 case STATE_CREATE_OR_OPEN:
151 rv = DoCreateOrOpen();
152 break;
153 case STATE_FINISH_CREATE_OR_OPEN:
154 rv = DoFinishCreateOrOpen(rv);
155 break;
156 case STATE_START_WRITE:
157 rv = DoStartWrite();
158 break;
159 case STATE_FINISH_WRITE:
160 rv = DoFinishWrite(rv);
161 break;
162 case STATE_WRITE_NONE:
163 break;
164 }
165 } while (rv != ERR_IO_PENDING && state_ != STATE_WRITE_NONE);
166
167 return rv;
168 }
169
170 int DiskBasedCertCache::WriteWorker::DoCreateOrOpen() {
171 state_ = STATE_FINISH_CREATE_OR_OPEN;
172
173 if (create_failed_)
174 return backend_->OpenEntry(key_, &entry_, io_callback_);
175
176 return backend_->CreateEntry(key_, &entry_, io_callback_);
177 }
178
179 int DiskBasedCertCache::WriteWorker::DoFinishCreateOrOpen(int rv) {
180 // ERR_FAILED implies create entry failed. In order to avoid trying
181 // to open the entry multiple times, the flag create_failed_ is set and
182 // checked.
183 if (rv < 0 && !create_failed_) {
184 create_failed_ = true;
wtc 2014/06/21 00:43:12 Instead of using the create_failed_ boolean, you c
185 state_ = STATE_CREATE_OR_OPEN;
186 return OK;
187 }
188 if (rv < 0) {
189 state_ = STATE_WRITE_NONE;
190 return rv;
191 }
192
193 state_ = STATE_START_WRITE;
194 return OK;
195 }
196
197 int DiskBasedCertCache::WriteWorker::DoStartWrite() {
198 std::string write_data;
199 bool encoded = X509Certificate::GetDEREncoded(cert_handle_, &write_data);
200
201 if (!encoded) {
202 state_ = STATE_WRITE_NONE;
203 return ERR_FAILED;
204 }
205
206 buffer = new IOBuffer(write_data.size());
207 memcpy(buffer->data(), write_data.data(), write_data.size());
208
209 state_ = STATE_FINISH_WRITE;
210
211 return entry_->WriteData(0 /* index */,
212 0 /* offset */,
213 buffer,
214 write_data.size(),
215 io_callback_,
216 true /* truncate */);
217 }
218
219 int DiskBasedCertCache::WriteWorker::DoFinishWrite(int rv) {
220 if (rv < 0) {
221 state_ = STATE_WRITE_NONE;
222 return rv;
223 }
224 state_ = STATE_WRITE_NONE;
225 return OK;
wtc 2014/06/21 00:43:12 The function can be simply state_ = STATE_WRITE
226 }
227
228 void DiskBasedCertCache::WriteWorker::CallCallbacks(int rv) {
229 for (std::vector<SetCallback>::iterator it = user_callbacks_.begin();
230 it != user_callbacks_.end();
231 ++it) {
232 it->Run((rv >= 0) ? key_ : std::string());
wtc 2014/06/21 00:43:12 Move (rv >= 0) ? key_ : std::string() outside the
233 it->Reset();
234 }
235 }
236
237 void DiskBasedCertCache::WriteWorker::Finish(int rv) {
238 cleanup_callback_.Run();
239 cleanup_callback_.Reset();
240 CallCallbacks(rv);
241 delete this;
242 }
243
244 void DiskBasedCertCache::WriteWorker::Cancel() {
245 canceled_ = true;
246 }
247
248 DiskBasedCertCache::WriteWorker::~WriteWorker() {
249 if (entry_)
250 entry_->Close();
251 }
252
253 // ReadWorkers represent pending Get jobs in the DiskBasedCertCache. Each
254 // certificate requested to be retrieved from the cache is assigned a ReadWorker
255 // on a one-to-one basis. The same |key| should not have multiple ReadWorkers
256 // at the same time; instead, call AddCallback to add a user_callback_ to
257 // the the existing ReadWorker.
258 class DiskBasedCertCache::ReadWorker {
259 public:
260 // |backend| is the backend to read |certificate| from, using
261 // |key| as the key for the disk_cache::Entry.
262 // |cleanup_callback| is called to clean up this ReadWorker,
263 // regardless of success or failure.
264 ReadWorker(disk_cache::Backend* backend,
265 const std::string& key,
266 const base::Closure& cleanup_callback);
267
268 ~ReadWorker();
269
270 // Reads the given certificate from the cache. On completion, will invoke all
271 // user callbacks.
272 void Start();
273
274 // Adds a callback to the set of callbacks to be notified when this
275 // ReadWorker finishes processing.
276 void AddCallback(const GetCallback& user_callback);
277
278 // Signals the ReadWorker to finish early. The ReadWorker will be destroyed
279 // upon the completion of any pending callbacks. User callbacks will be
280 // invoked with a NULL cert handle.
281 void Cancel();
282
283 private:
284 enum ReadState {
285 STATE_READ_OPEN,
286 STATE_START_READ,
287 STATE_FINISH_READ,
288 STATE_READ_NONE
289 };
290
291 void OnIOComplete(int rv);
292 int DoLoop(int rv);
293 int DoOpen();
294 int DoStartRead(int rv);
295 int DoFinishRead(int rv);
296 void Finish(int rv);
297
298 // invokes all of |user_callbacks_|
299 void CallCallbacks(int rv);
300
301 disk_cache::Backend* backend_;
302 X509Certificate::OSCertHandle cert_handle_;
303 std::string key_;
304 bool canceled_;
305
306 disk_cache::Entry* entry_;
307
308 ReadState state_;
309 int entry_size_;
310 scoped_refptr<IOBuffer> buffer;
311
312 base::Closure cleanup_callback_;
313 std::vector<GetCallback> user_callbacks_;
314 CompletionCallback io_callback_;
315 base::WeakPtrFactory<ReadWorker> weak_factory_;
316 };
317
318 DiskBasedCertCache::ReadWorker::ReadWorker(
319 disk_cache::Backend* backend,
320 const std::string& key,
321 const base::Closure& cleanup_callback)
322 : backend_(backend),
323 cert_handle_(NULL),
324 key_(key),
325 canceled_(false),
326 entry_(NULL),
327 state_(STATE_READ_OPEN),
328 entry_size_(0),
329 cleanup_callback_(cleanup_callback),
330 weak_factory_(this) {
331 io_callback_ =
332 base::Bind(&ReadWorker::OnIOComplete, weak_factory_.GetWeakPtr());
333 }
334
335 void DiskBasedCertCache::ReadWorker::Start() {
336 int rv = DoLoop(OK);
337
338 if (state_ != STATE_READ_NONE)
339 return;
340
341 Finish(rv);
342 }
343
344 void DiskBasedCertCache::ReadWorker::AddCallback(
345 const GetCallback& user_callback) {
346 user_callbacks_.push_back(user_callback);
347 }
348
349 void DiskBasedCertCache::ReadWorker::OnIOComplete(int rv) {
350 if (canceled_) {
351 Finish(ERR_FAILED);
352 return;
353 }
354
355 rv = DoLoop(rv);
356
357 if (state_ != STATE_READ_NONE)
358 return;
359
360 Finish(rv);
361 }
362
363 int DiskBasedCertCache::ReadWorker::DoLoop(int rv) {
364 do {
365 switch (state_) {
366 case STATE_READ_OPEN:
367 rv = DoOpen();
368 break;
369 case STATE_START_READ:
370 rv = DoStartRead(rv);
371 break;
372 case STATE_FINISH_READ:
373 rv = DoFinishRead(rv);
374 break;
375 case STATE_READ_NONE:
376 break;
377 }
378 } while (rv != ERR_IO_PENDING && state_ != STATE_READ_NONE);
379
380 return rv;
381 }
382
383 int DiskBasedCertCache::ReadWorker::DoOpen() {
384 state_ = STATE_START_READ;
385 return backend_->OpenEntry(key_, &entry_, io_callback_);
386 }
387
388 int DiskBasedCertCache::ReadWorker::DoStartRead(int rv) {
389 if (rv < 0) {
390 state_ = STATE_READ_NONE;
391 return rv;
392 }
wtc 2014/06/21 00:43:12 Nit: we usually use a STATE_FINISH_OPEN state to h
393
394 entry_size_ = entry_->GetDataSize(0 /* index */);
395 state_ = STATE_FINISH_READ;
396 buffer = new IOBuffer(entry_size_);
397 return entry_->ReadData(
398 0 /* index */, 0 /* offset */, buffer, entry_size_, io_callback_);
399 }
400
401 int DiskBasedCertCache::ReadWorker::DoFinishRead(int rv) {
402 if (rv < 0) {
403 state_ = STATE_READ_NONE;
404 return rv;
405 }
406
407 state_ = STATE_READ_NONE;
408
409 cert_handle_ =
410 X509Certificate::CreateOSCertHandleFromBytes(buffer->data(), entry_size_);
411
412 DCHECK(cert_handle_);
413 return OK;
414 }
415
416 void DiskBasedCertCache::ReadWorker::CallCallbacks(int rv) {
417 for (std::vector<GetCallback>::iterator it = user_callbacks_.begin();
418 it != user_callbacks_.end();
419 ++it) {
420 it->Run((rv >= 0) ? cert_handle_ : NULL);
421 it->Reset();
422 }
423 }
424
425 void DiskBasedCertCache::ReadWorker::Finish(int rv) {
426 cleanup_callback_.Run();
427 cleanup_callback_.Reset();
428 CallCallbacks(rv);
429
430 delete this;
431 }
432
433 void DiskBasedCertCache::ReadWorker::Cancel() {
434 canceled_ = true;
435 }
436
437 DiskBasedCertCache::ReadWorker::~ReadWorker() {
438 if (entry_)
439 entry_->Close();
440 if (cert_handle_)
441 X509Certificate::FreeOSCertHandle(cert_handle_);
442 }
443
444 DiskBasedCertCache::DiskBasedCertCache(disk_cache::Backend* backend)
445 : backend_(backend), weak_factory_(this) {
446 DCHECK(backend_);
447 }
448
449 DiskBasedCertCache::~DiskBasedCertCache() {
450 for (WriteWorkerMap::iterator it = write_worker_map_.begin();
451 it != write_worker_map_.end();
452 ++it)
453 it->second->Cancel();
wtc 2014/06/21 00:43:12 1. Add curly braces around the bodies of these two
brandonsalmon 2014/06/21 02:21:32 I believe so, I did check for this earlier. From c
454 for (ReadWorkerMap::iterator it = read_worker_map_.begin();
455 it != read_worker_map_.end();
456 ++it)
457 it->second->Cancel();
458 }
459
460 void DiskBasedCertCache::Get(const std::string& key, const GetCallback& cb) {
461 DCHECK(!key.empty());
462
463 ReadWorkerMap::iterator it = read_worker_map_.find(key);
464
465 if (it == read_worker_map_.end()) {
466 ReadWorker* worker =
467 new ReadWorker(backend_,
468 key,
469 base::Bind(&DiskBasedCertCache::FinishedReadOperation,
470 weak_factory_.GetWeakPtr(),
471 key));
472 read_worker_map_[key] = worker;
473 worker->AddCallback(cb);
474 worker->Start();
475 } else {
476 it->second->AddCallback(cb);
477 }
478 }
479
480 void DiskBasedCertCache::Set(const X509Certificate::OSCertHandle cert_handle,
481 const SetCallback& cb) {
482 DCHECK(!cb.is_null());
483 DCHECK(cert_handle);
484 std::string key = GetCacheKeyToCert(cert_handle);
485
486 WriteWorkerMap::iterator it = write_worker_map_.find(key);
487
488 if (it == write_worker_map_.end()) {
489 WriteWorker* worker =
490 new WriteWorker(backend_,
491 key,
492 cert_handle,
493 base::Bind(&DiskBasedCertCache::FinishedWriteOperation,
494 weak_factory_.GetWeakPtr(),
495 key));
496 write_worker_map_[key] = worker;
497 worker->AddCallback(cb);
498 worker->Start();
499 } else {
500 it->second->AddCallback(cb);
501 }
502 }
503
504 void DiskBasedCertCache::FinishedWriteOperation(const std::string& key) {
505 write_worker_map_.erase(key);
506 }
507
508 void DiskBasedCertCache::FinishedReadOperation(const std::string& key) {
509 read_worker_map_.erase(key);
510 }
511
512 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698