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

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: Minor fixes and implemented size checking on cache read/write. 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.
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 X509Certificate::OSCertHandle cert_handle,
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 run when this
56 // WriteWorker finishes processing.
57 void AddCallback(const SetCallback& user_callback);
58
59 // Signals the WriteWorker to abort early. The WriteWorker will be destroyed
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 State {
66 STATE_CREATE,
67 STATE_CREATE_COMPLETE,
68 STATE_OPEN,
69 STATE_OPEN_COMPLETE,
70 STATE_WRITE,
71 STATE_WRITE_COMPLETE,
72 STATE_NONE
73 };
74
75 void OnIOComplete(int rv);
76 int DoLoop(int rv);
77
78 int DoCreate();
79 int DoCreateComplete(int rv);
80 int DoOpen();
81 int DoOpenComplete(int rv);
82 int DoWrite();
83 int DoWriteComplete(int rv);
84
85 void Finish(int rv);
86
87 // Invokes all of the |user_callbacks_|
88 void RunCallbacks(int rv);
89
90 disk_cache::Backend* backend_;
91 const X509Certificate::OSCertHandle cert_handle_;
92 std::string key_;
93 bool canceled_;
94
95 disk_cache::Entry* entry_;
96 State state_;
97 scoped_refptr<IOBuffer> buffer_;
98 int io_buf_len_;
99
100 base::Closure cleanup_callback_;
101 std::vector<SetCallback> user_callbacks_;
102 CompletionCallback io_callback_;
103 };
104
105 DiskBasedCertCache::WriteWorker::WriteWorker(
106 disk_cache::Backend* backend,
107 const std::string& key,
108 X509Certificate::OSCertHandle cert_handle,
109 const base::Closure& cleanup_callback)
110 : backend_(backend),
111 cert_handle_(cert_handle),
112 key_(key),
113 canceled_(false),
114 entry_(NULL),
115 state_(STATE_NONE),
116 io_buf_len_(0),
117 cleanup_callback_(cleanup_callback),
118 io_callback_(
119 base::Bind(&WriteWorker::OnIOComplete, base::Unretained(this))) {
120 }
121
122 void DiskBasedCertCache::WriteWorker::Start() {
123 DCHECK_EQ(STATE_NONE, state_);
124 state_ = STATE_CREATE;
125 int rv = DoLoop(OK);
126
127 if (rv == ERR_IO_PENDING)
128 return;
129
130 Finish(rv);
131 }
132
133 void DiskBasedCertCache::WriteWorker::AddCallback(
134 const SetCallback& user_callback) {
135 user_callbacks_.push_back(user_callback);
136 }
137
138 void DiskBasedCertCache::WriteWorker::OnIOComplete(int rv) {
139 if (canceled_) {
140 Finish(ERR_FAILED);
141 return;
142 }
143
144 rv = DoLoop(rv);
145
146 if (rv == ERR_IO_PENDING)
147 return;
148
149 Finish(rv);
150 }
151
152 int DiskBasedCertCache::WriteWorker::DoLoop(int rv) {
153 do {
154 State next_state = state_;
155 state_ = STATE_NONE;
156 switch (next_state) {
157 case STATE_CREATE:
158 rv = DoCreate();
159 break;
160 case STATE_CREATE_COMPLETE:
161 rv = DoCreateComplete(rv);
162 break;
163 case STATE_OPEN:
164 rv = DoOpen();
165 break;
166 case STATE_OPEN_COMPLETE:
167 rv = DoOpenComplete(rv);
168 break;
169 case STATE_WRITE:
170 rv = DoWrite();
171 break;
172 case STATE_WRITE_COMPLETE:
173 rv = DoWriteComplete(rv);
174 break;
175 case STATE_NONE:
176 NOTREACHED();
177 break;
178 }
179 } while (rv != ERR_IO_PENDING && state_ != STATE_NONE);
180
Ryan Sleevi 2014/06/25 19:31:57 Did git cl format do these? Normally we'd include
181 return rv;
182 }
183
184 int DiskBasedCertCache::WriteWorker::DoCreate() {
185 state_ = STATE_CREATE_COMPLETE;
186
187 return backend_->CreateEntry(key_, &entry_, io_callback_);
188 }
189
190 int DiskBasedCertCache::WriteWorker::DoCreateComplete(int rv) {
191 // An error here usually signifies that the entry already exists.
192 // If this occurs, it is necessary to instead open the previously
193 // existing entry.
194 if (rv < 0) {
195 state_ = STATE_OPEN;
196 return OK;
197 }
198
199 state_ = STATE_WRITE;
200 return OK;
201 }
202
203 int DiskBasedCertCache::WriteWorker::DoOpen() {
204 return backend_->OpenEntry(key_, &entry_, io_callback_);
205 }
206
207 int DiskBasedCertCache::WriteWorker::DoOpenComplete(int rv) {
208 if (rv < 0) {
209 state_ = STATE_NONE;
210 return rv;
211 }
212 state_ = STATE_WRITE;
213 return OK;
214 }
215
216 int DiskBasedCertCache::WriteWorker::DoWrite() {
217 std::string write_data;
218 bool encoded = X509Certificate::GetDEREncoded(cert_handle_, &write_data);
219
220 if (!encoded) {
221 state_ = STATE_NONE;
222 return ERR_FAILED;
223 }
224
225 buffer_ = new IOBuffer(write_data.size());
226 io_buf_len_ = write_data.size();
227 memcpy(buffer_->data(), write_data.data(), io_buf_len_);
228
229 state_ = STATE_WRITE_COMPLETE;
230
231 return entry_->WriteData(0 /* index */,
232 0 /* offset */,
233 buffer_,
234 write_data.size(),
235 io_callback_,
236 true /* truncate */);
237 }
238
239 int DiskBasedCertCache::WriteWorker::DoWriteComplete(int rv) {
240 state_ = STATE_NONE;
241 if (rv < io_buf_len_)
242 return ERR_FAILED;
243
244 return OK;
245 }
246
247 void DiskBasedCertCache::WriteWorker::RunCallbacks(int rv) {
248 std::string key;
249 if (rv >= 0)
250 key = key_;
251
252 for (std::vector<SetCallback>::const_iterator it = user_callbacks_.begin();
253 it != user_callbacks_.end();
254 ++it) {
255 it->Run(key);
256 }
257 user_callbacks_.clear();
258 }
259
260 void DiskBasedCertCache::WriteWorker::Finish(int rv) {
261 cleanup_callback_.Run();
262 cleanup_callback_.Reset();
263 RunCallbacks(rv);
264 delete this;
265 }
266
267 void DiskBasedCertCache::WriteWorker::Cancel() {
268 canceled_ = true;
269 }
270
271 DiskBasedCertCache::WriteWorker::~WriteWorker() {
272 if (entry_)
273 entry_->Close();
274 }
275
276 // ReadWorkers represent pending Get jobs in the DiskBasedCertCache. Each
277 // certificate requested to be retrieved from the cache is assigned a ReadWorker
278 // on a one-to-one basis. The same |key| should not have multiple ReadWorkers
279 // at the same time; instead, call AddCallback to add a user_callback_ to
280 // the the existing ReadWorker.
281 class DiskBasedCertCache::ReadWorker {
282 public:
283 // |backend| is the backend to read |certificate| from, using
284 // |key| as the key for the disk_cache::Entry.
285 // |cleanup_callback| is called to clean up this ReadWorker,
286 // regardless of success or failure.
287 ReadWorker(disk_cache::Backend* backend,
288 const std::string& key,
289 const base::Closure& cleanup_callback);
290
291 ~ReadWorker();
292
293 // Reads the given certificate from the cache. On completion, will invoke all
294 // user callbacks.
295 void Start();
296
297 // Adds a callback to the set of callbacks to be run when this
298 // ReadWorker finishes processing.
299 void AddCallback(const GetCallback& user_callback);
300
301 // Signals the ReadWorker to abort early. The ReadWorker will be destroyed
302 // upon the completion of any pending callbacks. User callbacks will be
303 // invoked with a NULL cert handle.
304 void Cancel();
305
306 private:
307 enum State {
308 STATE_OPEN,
309 STATE_OPEN_COMPLETE,
310 STATE_READ,
311 STATE_READ_COMPLETE,
312 STATE_NONE
313 };
314
315 void OnIOComplete(int rv);
316 int DoLoop(int rv);
317 int DoOpen();
318 int DoOpenComplete(int rv);
319 int DoRead();
320 int DoReadComplete(int rv);
321 void Finish(int rv);
322
323 // Invokes all of |user_callbacks_|
324 void RunCallbacks();
325
326 disk_cache::Backend* backend_;
327 X509Certificate::OSCertHandle cert_handle_;
328 std::string key_;
329 bool canceled_;
330
331 disk_cache::Entry* entry_;
332
333 State state_;
334 scoped_refptr<IOBuffer> buffer_;
335 int io_buf_len_;
336
337 base::Closure cleanup_callback_;
338 std::vector<GetCallback> user_callbacks_;
339 CompletionCallback io_callback_;
340 };
341
342 DiskBasedCertCache::ReadWorker::ReadWorker(
343 disk_cache::Backend* backend,
344 const std::string& key,
345 const base::Closure& cleanup_callback)
346 : backend_(backend),
347 cert_handle_(NULL),
348 key_(key),
349 canceled_(false),
350 entry_(NULL),
351 state_(STATE_NONE),
352 io_buf_len_(0),
353 cleanup_callback_(cleanup_callback),
354 io_callback_(
355 base::Bind(&ReadWorker::OnIOComplete, base::Unretained(this))) {
356 }
357
358 void DiskBasedCertCache::ReadWorker::Start() {
359 DCHECK_EQ(STATE_NONE, state_);
360 state_ = STATE_OPEN;
361 int rv = DoLoop(OK);
362
363 if (rv == ERR_IO_PENDING)
364 return;
365
366 Finish(rv);
367 }
368
369 void DiskBasedCertCache::ReadWorker::AddCallback(
370 const GetCallback& user_callback) {
371 user_callbacks_.push_back(user_callback);
372 }
373
374 void DiskBasedCertCache::ReadWorker::OnIOComplete(int rv) {
375 if (canceled_) {
376 Finish(ERR_FAILED);
377 return;
378 }
379
380 rv = DoLoop(rv);
381
382 if (rv == ERR_IO_PENDING)
383 return;
384
385 Finish(rv);
386 }
387
388 int DiskBasedCertCache::ReadWorker::DoLoop(int rv) {
389 do {
390 State next_state = state_;
391 state_ = STATE_NONE;
392 switch (next_state) {
393 case STATE_OPEN:
394 rv = DoOpen();
395 break;
396 case STATE_OPEN_COMPLETE:
397 rv = DoOpenComplete(rv);
398 break;
399 case STATE_READ:
400 rv = DoRead();
401 break;
402 case STATE_READ_COMPLETE:
403 rv = DoReadComplete(rv);
404 break;
405 case STATE_NONE:
406 NOTREACHED();
407 break;
408 }
409 } while (rv != ERR_IO_PENDING && state_ != STATE_NONE);
410
411 return rv;
412 }
413
414 int DiskBasedCertCache::ReadWorker::DoOpen() {
415 state_ = STATE_OPEN_COMPLETE;
416 return backend_->OpenEntry(key_, &entry_, io_callback_);
417 }
418
419 int DiskBasedCertCache::ReadWorker::DoOpenComplete(int rv) {
420 if (rv < 0) {
421 state_ = STATE_NONE;
422 return rv;
423 }
424 state_ = STATE_READ;
425 return OK;
426 }
427
428 int DiskBasedCertCache::ReadWorker::DoRead() {
429 state_ = STATE_READ_COMPLETE;
430 io_buf_len_ = entry_->GetDataSize(0 /* index */);
431 buffer_ = new IOBuffer(io_buf_len_);
432 return entry_->ReadData(
433 0 /* index */, 0 /* offset */, buffer_, io_buf_len_, io_callback_);
434 }
435
436 int DiskBasedCertCache::ReadWorker::DoReadComplete(int rv) {
437 state_ = STATE_NONE;
438 if (rv < io_buf_len_)
439 return ERR_FAILED;
440
441 cert_handle_ = X509Certificate::CreateOSCertHandleFromBytes(buffer_->data(),
442 io_buf_len_);
443 if (!cert_handle_)
444 return ERR_FAILED;
445
446 return OK;
447 }
448
449 void DiskBasedCertCache::ReadWorker::RunCallbacks() {
450 for (std::vector<GetCallback>::const_iterator it = user_callbacks_.begin();
451 it != user_callbacks_.end();
452 ++it) {
453 it->Run(cert_handle_);
454 }
455 user_callbacks_.clear();
456 }
457
458 void DiskBasedCertCache::ReadWorker::Finish(int rv) {
459 cleanup_callback_.Run();
460 cleanup_callback_.Reset();
461 RunCallbacks();
462 delete this;
463 }
464
465 void DiskBasedCertCache::ReadWorker::Cancel() {
466 canceled_ = true;
467 }
468
469 DiskBasedCertCache::ReadWorker::~ReadWorker() {
470 if (entry_)
471 entry_->Close();
472 if (cert_handle_)
473 X509Certificate::FreeOSCertHandle(cert_handle_);
474 }
475
476 DiskBasedCertCache::DiskBasedCertCache(disk_cache::Backend* backend)
477 : backend_(backend), weak_factory_(this) {
478 DCHECK(backend_);
479 }
480
481 DiskBasedCertCache::~DiskBasedCertCache() {
482 for (WriteWorkerMap::iterator it = write_worker_map_.begin();
483 it != write_worker_map_.end();
484 ++it) {
485 it->second->Cancel();
486 }
487 for (ReadWorkerMap::iterator it = read_worker_map_.begin();
488 it != read_worker_map_.end();
489 ++it) {
490 it->second->Cancel();
491 }
492 }
493
494 void DiskBasedCertCache::Get(const std::string& key, const GetCallback& cb) {
495 DCHECK(!key.empty());
496
497 ReadWorkerMap::iterator it = read_worker_map_.find(key);
498
499 if (it == read_worker_map_.end()) {
500 ReadWorker* worker =
501 new ReadWorker(backend_,
502 key,
503 base::Bind(&DiskBasedCertCache::FinishedReadOperation,
504 weak_factory_.GetWeakPtr(),
505 key));
506 read_worker_map_[key] = worker;
507 worker->AddCallback(cb);
508 worker->Start();
509 } else {
510 it->second->AddCallback(cb);
511 }
512 }
513
514 void DiskBasedCertCache::Set(const X509Certificate::OSCertHandle cert_handle,
515 const SetCallback& cb) {
516 DCHECK(!cb.is_null());
517 DCHECK(cert_handle);
518 std::string key = GetCacheKeyToCert(cert_handle);
519
520 WriteWorkerMap::iterator it = write_worker_map_.find(key);
521
522 if (it == write_worker_map_.end()) {
523 WriteWorker* worker =
524 new WriteWorker(backend_,
525 key,
526 cert_handle,
527 base::Bind(&DiskBasedCertCache::FinishedWriteOperation,
528 weak_factory_.GetWeakPtr(),
529 key));
530 write_worker_map_[key] = worker;
531 worker->AddCallback(cb);
532 worker->Start();
533 } else {
534 it->second->AddCallback(cb);
535 }
536 }
537
538 void DiskBasedCertCache::FinishedWriteOperation(const std::string& key) {
539 write_worker_map_.erase(key);
540 }
541
542 void DiskBasedCertCache::FinishedReadOperation(const std::string& key) {
543 read_worker_map_.erase(key);
544 }
545
546 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698