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

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: Improved unittests, error checking, and improved functionality in workers (although this isn't prop… 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/callback_helpers.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "net/base/io_buffer.h"
13 #include "net/base/net_errors.h"
14
15 namespace net {
16
17 //-----------------------------------------------------------------------------
Ryan Sleevi 2014/06/17 00:00:20 vertical whitespace comments apply
18
19 class DiskBasedCertCache::WriteWorker {
Ryan Sleevi 2014/06/17 00:00:20 Document
20 public:
21 WriteWorker(disk_cache::Backend* backend,
22 std::string key,
23 const X509Certificate::OSCertHandle cert_handle,
24 base::Callback<void(const std::string&)> cleanup_callback,
25 SetCallback user_callback);
Ryan Sleevi 2014/06/17 00:00:20 const-refs
26
27 ~WriteWorker();
28
29 void Start();
Ryan Sleevi 2014/06/17 00:00:20 Document
30
31 void AddCallback(SetCallback user_callback);
Ryan Sleevi 2014/06/17 00:00:19 const-ref document
32
33 private:
34 // Types --------------------------------------------------------------------
35 enum WriteState {
36 CREATE_OR_OPEN,
37 FINISH_CREATE_OR_OPEN,
38 START_WRITE,
39 FINISH_WRITE,
40 WRITE_NONE
41 };
42
43 // Methods ------------------------------------------------------------------
44
45 void OnIOComplete(int rv);
46 void DoLoop(int rv);
47 int DoCreateOrOpen();
48 int DoFinishCreateOrOpen(int rv);
49 int DoStartWrite();
50 int DoFinishWrite(int rv);
51 void CallCallbacks(const std::string& key);
52
53 // Variables ----------------------------------------------------------------
54 disk_cache::Backend* backend_;
55 const X509Certificate::OSCertHandle cert_handle_;
56 std::string key_;
57
58 disk_cache::Entry* entry_;
59 WriteState state_;
60 bool create_failed_;
61 scoped_refptr<IOBuffer> buffer;
62
63 base::Callback<void(const std::string&)> cleanup_callback_;
64 std::vector<SetCallback> user_callbacks_;
65 CompletionCallback io_callback_;
66
67 base::WeakPtrFactory<WriteWorker> weak_factory_;
68 };
69
70 DiskBasedCertCache::WriteWorker::WriteWorker(
71 disk_cache::Backend* backend,
72 std::string key,
73 X509Certificate::OSCertHandle cert_handle,
74 base::Callback<void(const std::string&)> cleanup_callback,
75 SetCallback user_callback)
76 : backend_(backend),
77 cert_handle_(cert_handle),
78 key_(key),
79 entry_(NULL),
80 state_(CREATE_OR_OPEN),
81 create_failed_(false),
82 cleanup_callback_(cleanup_callback),
83 weak_factory_(this) {
84 io_callback_ =
85 base::Bind(&WriteWorker::OnIOComplete, weak_factory_.GetWeakPtr());
86 AddCallback(user_callback);
87 }
88
89 void DiskBasedCertCache::WriteWorker::Start() {
90 DoLoop(OK);
91 }
92
93 void DiskBasedCertCache::WriteWorker::AddCallback(SetCallback user_callback) {
94 user_callbacks_.push_back(user_callback);
95 }
96
97 void DiskBasedCertCache::WriteWorker::OnIOComplete(int rv) {
98 DoLoop(rv);
99 }
100
101 void DiskBasedCertCache::WriteWorker::DoLoop(int rv) {
102 do {
103 switch (state_) {
104 case CREATE_OR_OPEN:
105 rv = DoCreateOrOpen();
106 break;
107 case FINISH_CREATE_OR_OPEN:
108 rv = DoFinishCreateOrOpen(rv);
109 break;
110 case START_WRITE:
111 rv = DoStartWrite();
112 break;
113 case FINISH_WRITE:
114 rv = DoFinishWrite(rv);
115 break;
116 case WRITE_NONE:
117 break;
118 }
119 } while (rv != ERR_IO_PENDING && state_ != WRITE_NONE);
120
121 if (state_ == WRITE_NONE) {
Ryan Sleevi 2014/06/17 00:00:19 STYLE: We prefer error-handling/short circuiting a
122 if (entry_)
123 entry_->Close();
124 base::ResetAndReturn(&cleanup_callback_).Run(key_);
Ryan Sleevi 2014/06/17 00:00:20 DANGER: We almost always try to avoid calling call
125 }
126 }
127
128 int DiskBasedCertCache::WriteWorker::DoCreateOrOpen() {
129 DCHECK(entry_ == NULL);
Ryan Sleevi 2014/06/17 00:00:20 For == NULL dchecks, just do DCHECK(entry_)
130
131 state_ = FINISH_CREATE_OR_OPEN;
132
133 if (create_failed_) {
134 return backend_->OpenEntry(key_, &entry_, io_callback_);
135 }
Ryan Sleevi 2014/06/17 00:00:19 No braces on simple { }
136
137 return backend_->CreateEntry(key_, &entry_, io_callback_);
138 }
139
140 int DiskBasedCertCache::WriteWorker::DoFinishCreateOrOpen(int rv) {
141 // ERR_FAILED implies create entry failed, and we should try opening instead.
142 //!create_failed is checked to make sure we only try to open once.
Ryan Sleevi 2014/06/17 00:00:19 When possible, it's better to avoid pronouns (like
143 if (rv == ERR_FAILED && !create_failed_) {
144 create_failed_ = true;
145 state_ = CREATE_OR_OPEN;
146 return OK;
147 } else if (rv < 0) {
148 CallCallbacks("");
149 state_ = WRITE_NONE;
150 return ERR_FAILED;
151 }
152
153 state_ = START_WRITE;
154 return OK;
155 }
156
157 int DiskBasedCertCache::WriteWorker::DoStartWrite() {
158 std::string write_data;
159 bool encoded = X509Certificate::GetDEREncoded(cert_handle_, &write_data);
160
161 if (!encoded) {
162 CallCallbacks(NULL);
163 state_ = WRITE_NONE;
164 return ERR_FAILED;
165 }
166
167 buffer = new IOBuffer(write_data.size());
168 memcpy(buffer->data(), write_data.data(), write_data.size());
169
170 state_ = FINISH_WRITE;
171
172 return entry_->WriteData(0 /* index */,
173 0 /* offset */,
174 buffer,
175 write_data.size(),
176 io_callback_,
177 true /* truncate */);
178 }
179
180 int DiskBasedCertCache::WriteWorker::DoFinishWrite(int rv) {
181 if (rv < 0) {
182 CallCallbacks("");
Ryan Sleevi 2014/06/17 00:00:20 use std::string() for empty strings, rather than "
183 state_ = WRITE_NONE;
184 return ERR_FAILED;
185 }
186
187 state_ = WRITE_NONE;
188
189 CallCallbacks(key_);
190 return OK;
191 }
192
193 void DiskBasedCertCache::WriteWorker::CallCallbacks(const std::string& key) {
194 for (std::vector<SetCallback>::iterator it = user_callbacks_.begin();
195 it != user_callbacks_.end();
196 it++) {
197 if (!it->is_null())
198 base::ResetAndReturn(&(*it)).Run(key_);
Ryan Sleevi 2014/06/17 00:00:20 1) When would it->is_null be true? Seems like they
199 }
200 }
201
202 DiskBasedCertCache::WriteWorker::~WriteWorker() {
203 weak_factory_.InvalidateWeakPtrs();
Ryan Sleevi 2014/06/17 00:00:19 You don't need to do this explicitly. WeakPtrFacto
204 }
205
206 //---------------------------------------------------------------------------
207
208 class DiskBasedCertCache::ReadWorker {
209 public:
210 ReadWorker(disk_cache::Backend* backend,
211 std::string key,
212 base::Callback<void(const std::string&)> cleanup_callback,
213 GetCallback user_callback);
214
215 ~ReadWorker();
216
217 void Start();
218
219 void AddCallback(GetCallback user_callback);
Ryan Sleevi 2014/06/17 00:00:19 Same comments regarding const-refs, comments, etc
220
221 private:
222 // Types --------------------------------------------------------------------
Ryan Sleevi 2014/06/17 00:00:20 Same comments regarding vertical whitespace (eg: d
223 enum ReadState { OPEN, START_READ, FINISH_READ, READ_NONE };
224
225 // Methods ------------------------------------------------------------------
226 void OnIOComplete(int rv);
227 void DoLoop(int rv);
228 int DoOpen();
229 int DoStartRead(int rv);
230 int DoFinishRead(int rv);
231
232 void CallCallbacks(X509Certificate::OSCertHandle cert_handle);
233
234 // Variables ----------------------------------------------------------------
235 disk_cache::Backend* backend_;
236
237 std::string key_;
238 disk_cache::Entry* entry_;
239 ReadState state_;
240 int entry_size_;
241 scoped_refptr<IOBuffer> buffer;
242
243 base::Callback<void(const std::string&)> cleanup_callback_;
244 std::vector<GetCallback> user_callbacks_;
245 CompletionCallback io_callback_;
246 base::WeakPtrFactory<ReadWorker> weak_factory_;
247 };
248
249 DiskBasedCertCache::ReadWorker::ReadWorker(
250 disk_cache::Backend* backend,
251 std::string key,
252 base::Callback<void(const std::string&)> cleanup_callback,
253 GetCallback user_callback)
254 : backend_(backend),
255 key_(key),
256 entry_(NULL),
257 state_(OPEN),
258 entry_size_(0),
259 cleanup_callback_(cleanup_callback),
260 weak_factory_(this) {
261 io_callback_ =
262 base::Bind(&ReadWorker::OnIOComplete, weak_factory_.GetWeakPtr());
263 AddCallback(user_callback);
264 }
265
266 void DiskBasedCertCache::ReadWorker::Start() {
267 DoLoop(OK);
268 }
269
270 void DiskBasedCertCache::ReadWorker::AddCallback(GetCallback user_callback) {
271 user_callbacks_.push_back(user_callback);
272 }
273
274 void DiskBasedCertCache::ReadWorker::OnIOComplete(int rv) {
275 DoLoop(rv);
276 }
277
278 void DiskBasedCertCache::ReadWorker::DoLoop(int rv) {
279 do {
280 switch (state_) {
281 case OPEN:
282 rv = DoOpen();
283 break;
284 case START_READ:
285 rv = DoStartRead(rv);
286 break;
287 case FINISH_READ:
288 rv = DoFinishRead(rv);
289 break;
290 case READ_NONE:
291 break;
292 }
293 } while (rv != ERR_IO_PENDING && state_ != READ_NONE);
294
295 if (state_ == READ_NONE) {
296 if (entry_)
297 entry_->Close();
298 base::ResetAndReturn(&cleanup_callback_).Run(key_);
Ryan Sleevi 2014/06/17 00:00:19 Same comments re: entry functions calling callback
299 }
300 }
301
302 int DiskBasedCertCache::ReadWorker::DoOpen() {
303 state_ = START_READ;
304
305 return backend_->OpenEntry(key_, &entry_, io_callback_);
306 }
307
308 int DiskBasedCertCache::ReadWorker::DoStartRead(int rv) {
309 if (rv < 0) {
310 CallCallbacks(NULL);
311 state_ = READ_NONE;
312 return ERR_FAILED;
313 }
314
315 entry_size_ = entry_->GetDataSize(0 /* index */);
316
317 state_ = FINISH_READ;
318
319 buffer = new IOBuffer(entry_size_);
Ryan Sleevi 2014/06/17 00:00:20 Lots of unnecessary vertical whitespace here (and
320
321 return entry_->ReadData(
322 0 /* index */, 0 /* offset */, buffer, entry_size_, io_callback_);
323 }
324
325 int DiskBasedCertCache::ReadWorker::DoFinishRead(int rv) {
326 if (rv < 0) {
327 CallCallbacks(NULL);
328 state_ = READ_NONE;
329 return ERR_FAILED;
330 }
331
332 state_ = READ_NONE;
333
334 X509Certificate::OSCertHandle retrieved_cert_handle =
335 X509Certificate::CreateOSCertHandleFromBytes(buffer->data(), entry_size_);
336
337 CHECK(retrieved_cert_handle);
338 CallCallbacks(retrieved_cert_handle);
339 X509Certificate::FreeOSCertHandle(retrieved_cert_handle);
340 return OK;
341 }
342
343 void DiskBasedCertCache::ReadWorker::CallCallbacks(
344 X509Certificate::OSCertHandle cert_handle) {
345 for (std::vector<GetCallback>::iterator it = user_callbacks_.begin();
346 it != user_callbacks_.end();
347 it++) {
348 if (!it->is_null())
349 base::ResetAndReturn(&(*it)).Run(cert_handle);
350 }
351 }
352
353 DiskBasedCertCache::ReadWorker::~ReadWorker() {
354 weak_factory_.InvalidateWeakPtrs();
355 }
356
357 //-----------------------------------------------------------------------------
358
359 DiskBasedCertCache::DiskBasedCertCache(disk_cache::Backend* backend)
360 : backend_(backend), weak_factory_(this) {
Ryan Sleevi 2014/06/17 00:00:19 Run git-cl format, and I believe it will restructu
361 DCHECK(backend_);
362 write_io_callback_ = base::Bind(&DiskBasedCertCache::FinishedWriteOperation,
363 weak_factory_.GetWeakPtr());
364 read_io_callback_ = base::Bind(&DiskBasedCertCache::FinishedReadOperation,
365 weak_factory_.GetWeakPtr());
Ryan Sleevi 2014/06/17 00:00:20 You can create these two callbacks in the ctor ini
366 }
367
368 DiskBasedCertCache::~DiskBasedCertCache() {
369 weak_factory_.InvalidateWeakPtrs();
370 for (WriteWorkerMap::iterator it = write_worker_map_.begin();
371 it != write_worker_map_.end();
372 it++) {
373 delete it->second;
374 }
Ryan Sleevi 2014/06/17 00:00:19 You can use base/stl_util.h STLDeleteContainerPai
375 for (ReadWorkerMap::iterator it = read_worker_map_.begin();
376 it != read_worker_map_.end();
377 it++) {
378 delete it->second;
379 }
380 }
381
382 void DiskBasedCertCache::Get(
383 std::string& key,
384 base::Callback<void(X509Certificate::OSCertHandle cert_handle)> cb) {
385 CHECK(!key.empty());
Ryan Sleevi 2014/06/17 00:00:19 Use DCHECK() when defining preconditions/post-cond
386
387 ReadWorkerMap::iterator it = read_worker_map_.find(key);
388
389 if (it == read_worker_map_.end()) {
390 read_worker_map_[key] =
391 new ReadWorker(backend_, key, read_io_callback_, cb);
392 read_worker_map_[key]->Start();
Ryan Sleevi 2014/06/17 00:00:19 Avoid duplicate accesses to [key], when possible.
393 } else {
394 read_worker_map_[key]->AddCallback(cb);
Ryan Sleevi 2014/06/17 00:00:20 Here, you'd it->second->AddCallback(cb);
395 }
396 }
397
398 void DiskBasedCertCache::Set(const X509Certificate::OSCertHandle cert_handle,
399 base::Callback<void(const std::string&)> cb) {
400 CHECK(!cb.is_null());
401 CHECK(cert_handle);
Ryan Sleevi 2014/06/17 00:00:20 ditto comments re: DCHECK
402 std::string key = Key(cert_handle);
403
404 WriteWorkerMap::iterator it = write_worker_map_.find(key);
405
406 if (it == write_worker_map_.end()) {
407 write_worker_map_[key] =
408 new WriteWorker(backend_, key, cert_handle, write_io_callback_, cb);
409 write_worker_map_[key]->Start();
410 } else {
411 write_worker_map_[key]->AddCallback(cb);
412 }
413 }
414
415 std::string DiskBasedCertCache::Key(
416 const X509Certificate::OSCertHandle cert_handle) const {
417 SHA1HashValue fingerprint =
418 X509Certificate::CalculateFingerprint(cert_handle);
419
420 return "cert:" +
421 base::HexEncode(fingerprint.data, arraysize(fingerprint.data));
422 }
423
424 void DiskBasedCertCache::FinishedWriteOperation(const std::string& key) {
425 WriteWorkerMap::iterator it = write_worker_map_.find(key);
426 WriteWorker* temp = it->second;
427 write_worker_map_.erase(it);
428 delete temp;
429 }
430
431 void DiskBasedCertCache::FinishedReadOperation(const std::string& key) {
432 ReadWorkerMap::iterator it = read_worker_map_.find(key);
433 ReadWorker* temp = it->second;
434 read_worker_map_.erase(it);
435 delete temp;
436 }
437
438 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698