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

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 issues with last upload, and changed cleanup_callback_ to be previously bound with the correc… 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 <list>
Ryan Sleevi 2014/06/18 22:16:03 Curious: Was there a particular reason for choosin
brandonsalmon 2014/06/19 21:32:31 In this circumstance, I could not see any particul
8
9 #include "base/callback_helpers.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
15 #include "net/disk_cache/disk_cache.h"
16
17 namespace net {
18
19 // WriteWorkers represent pending set jobs in the DiskBasedCertCache. Each
20 // certificate requested to be cached is assigned a Writeworker on a one-to-one
21 // basis. The same certificate should not have multiple WriteWorkers at the same
22 // time, instead, add a user_callback_ to the existing WriteWorker.
Ryan Sleevi 2014/06/18 22:16:04 comment nit: // time, instead, add a user_callback
23 class DiskBasedCertCache::WriteWorker {
24 public:
25 // |backend| is a pointer to the initialized disk_cache::backend stored in
26 // DiskBasedCertCache. |key| is the key corresponding to this certificate
27 // to be used in caching. |cert_handle| is the certificate to be stored.
28 // |cleanup_callback| is a callback to the function that will
29 // delete this worker. |user_callback| is a callback to the user
30 // to signify that the certificate has been correctly stored, or that the
31 // operation failed.
Ryan Sleevi 2014/06/18 22:16:04 comment style: we generally don't note types in pr
32 WriteWorker(disk_cache::Backend* backend,
33 const std::string& key,
34 const X509Certificate::OSCertHandle cert_handle,
35 const base::Callback<void(void)>& cleanup_callback,
36 const SetCallback& user_callback);
Ryan Sleevi 2014/06/18 22:16:03 It seems like, for consistency, that the caller sh
37
38 ~WriteWorker();
39
40 // Begin the do-loop for this WriteWorker (will call all user_callbacks_ on
41 // completion).
Ryan Sleevi 2014/06/18 22:16:03 Comment rewording: // Writes the given certificat
42 void Start();
43
44 // Add a callback to this worker. Should be used when |cert_handle_| is
45 // requested to be stored in the cache multiple times within the lifetime
46 // of this worker.
Ryan Sleevi 2014/06/18 22:16:03 Comment rewording: We try to avoid descriptions of
47 void AddCallback(const SetCallback& user_callback);
48
49 private:
50 enum WriteState {
51 CREATE_OR_OPEN,
52 FINISH_CREATE_OR_OPEN,
53 START_WRITE,
54 FINISH_WRITE,
55 WRITE_NONE
56 };
57
58 void OnIOComplete(int rv);
59 void DoLoop(int rv);
60 int DoCreateOrOpen();
61 int DoFinishCreateOrOpen(int rv);
62 int DoStartWrite();
63 int DoFinishWrite(int rv);
64
65 // CallCallbacks is used to call all user callbacks (i.e. callbacks that were
66 // given by the user to the DiskBasedCertCache when calling Set).
Ryan Sleevi 2014/06/18 22:16:03 // Invokes all of the |user_callbacks_|
67 void CallCallbacks(const std::string& key);
Ryan Sleevi 2014/06/18 22:16:03 Why do you pass |key|, when you have |key_| as a m
brandonsalmon 2014/06/19 21:32:31 I did this so I could use CallCallbacks(std::strin
68
69 disk_cache::Backend* backend_;
70 const X509Certificate::OSCertHandle cert_handle_;
71 std::string key_;
72
73 disk_cache::Entry* entry_;
74 WriteState state_;
75 bool create_failed_;
76 scoped_refptr<IOBuffer> buffer;
77
78 base::Callback<void(void)> cleanup_callback_;
Ryan Sleevi 2014/06/18 22:16:03 the name for this is "base::Closure" - avoids the
79 std::list<SetCallback> user_callbacks_;
80 CompletionCallback io_callback_; /* used to access the backend */
Ryan Sleevi 2014/06/18 22:16:03 Delete this comment; Among other things, io_callba
81
82 base::WeakPtrFactory<WriteWorker> weak_factory_;
83 };
84
85 // ReadWorkers represent pending get jobs in the DiskBasedCertCache. Each
Ryan Sleevi 2014/06/18 22:16:03 s/get/Get/
86 // certificate requested to be retrieved from the cache is assigned a ReadWorker
87 // on a one-to-one basis. The same |key| should not have multiple ReadWorkers
88 // at the same time, instead, call AddCallback to add a user_callback_ to
89 // the the existing ReadWorker.
Ryan Sleevi 2014/06/18 22:16:04 Similar comment cleanup as above.
90 class DiskBasedCertCache::ReadWorker {
91 public:
92 // |backend| is a pointer to the initialized disk_cache::backend stored in
93 // DiskBasedCertCache. |key| is the key corresponding to this certificate
94 // to be used in caching. |cleanup_callback| is a callback to the function
95 // that will delete this worker. |user_callback| is a callback to the user
96 // to signify that the certificate has been correctly stored, or that the
97 // operation failed.
98 ReadWorker(disk_cache::Backend* backend,
Ryan Sleevi 2014/06/18 22:16:03 Same comment comments as above
99 const std::string& key,
100 const base::Callback<void(void)>& cleanup_callback,
101 const GetCallback& user_callback);
Ryan Sleevi 2014/06/18 22:16:03 ditto AddCallback
102
103 ~ReadWorker();
104
105 // Begin the do-loop for this ReadWorker (will call all user_callbacks_ on
106 // completion).
107 void Start();
108
109 // Add a callback to this worker. Should be used when |key_| is
110 // requested to be retrieved from the cache multiple times within lifetime
111 // of this worker.
112 void AddCallback(const GetCallback& user_callback);
113
114 private:
115 enum ReadState { OPEN, START_READ, FINISH_READ, READ_NONE };
116
117 void OnIOComplete(int rv);
118 void DoLoop(int rv);
119 int DoOpen();
120 int DoStartRead(int rv);
121 int DoFinishRead(int rv);
122
123 // CallCallbacks is used to call all user callbacks (i.e. callbacks that were
124 // given by the user to the DiskBasedCertCache when calling Get).
125 void CallCallbacks(X509Certificate::OSCertHandle cert_handle);
126
127 disk_cache::Backend* backend_;
128
129 std::string key_;
130 disk_cache::Entry* entry_;
131 ReadState state_;
132 int entry_size_;
133 scoped_refptr<IOBuffer> buffer;
134
135 base::Callback<void(void)> cleanup_callback_;
136 std::list<GetCallback> user_callbacks_;
137 CompletionCallback io_callback_;
138 base::WeakPtrFactory<ReadWorker> weak_factory_;
139 };
140
141 std::string GetCacheKeyToCert(const X509Certificate::OSCertHandle cert_handle) {
142 SHA1HashValue fingerprint =
143 X509Certificate::CalculateFingerprint(cert_handle);
144
145 return "cert:" +
146 base::HexEncode(fingerprint.data, arraysize(fingerprint.data));
147 }
Ryan Sleevi 2014/06/18 22:16:03 This function should be between lines 18/19 in an
148
149 DiskBasedCertCache::WriteWorker::WriteWorker(
150 disk_cache::Backend* backend,
151 const std::string& key,
152 X509Certificate::OSCertHandle cert_handle,
153 const base::Callback<void(void)>& cleanup_callback,
154 const SetCallback& user_callback)
155 : backend_(backend),
156 cert_handle_(cert_handle),
157 key_(key),
158 entry_(NULL),
159 state_(CREATE_OR_OPEN),
160 create_failed_(false),
161 cleanup_callback_(cleanup_callback),
162 weak_factory_(this) {
163 io_callback_ =
164 base::Bind(&WriteWorker::OnIOComplete, weak_factory_.GetWeakPtr());
165 AddCallback(user_callback);
166 }
167
168 void DiskBasedCertCache::WriteWorker::Start() {
169 DoLoop(OK);
170
171 if (state_ == WRITE_NONE) {
Ryan Sleevi 2014/06/18 22:16:03 if (state_ != WRITE_NONE) return; if (entry_)
172 if (entry_)
173 entry_->Close();
174 base::ResetAndReturn(&cleanup_callback_).Run();
175 }
176 }
177
178 void DiskBasedCertCache::WriteWorker::AddCallback(
179 const SetCallback& user_callback) {
180 user_callbacks_.push_back(user_callback);
181 }
182
183 void DiskBasedCertCache::WriteWorker::OnIOComplete(int rv) {
184 DoLoop(rv);
185
186 if (state_ == WRITE_NONE) {
187 if (entry_)
188 entry_->Close();
189 base::ResetAndReturn(&cleanup_callback_).Run();
190 }
Ryan Sleevi 2014/06/18 22:16:03 Ditto cleanup as above.
191 }
192
193 void DiskBasedCertCache::WriteWorker::DoLoop(int rv) {
194 do {
195 switch (state_) {
196 case CREATE_OR_OPEN:
197 rv = DoCreateOrOpen();
198 break;
199 case FINISH_CREATE_OR_OPEN:
200 rv = DoFinishCreateOrOpen(rv);
201 break;
202 case START_WRITE:
203 rv = DoStartWrite();
204 break;
205 case FINISH_WRITE:
206 rv = DoFinishWrite(rv);
207 break;
208 case WRITE_NONE:
209 break;
210 }
211 } while (rv != ERR_IO_PENDING && state_ != WRITE_NONE);
212 }
213
214 int DiskBasedCertCache::WriteWorker::DoCreateOrOpen() {
215 state_ = FINISH_CREATE_OR_OPEN;
216
217 if (create_failed_)
218 return backend_->OpenEntry(key_, &entry_, io_callback_);
219
220 return backend_->CreateEntry(key_, &entry_, io_callback_);
221 }
222
223 int DiskBasedCertCache::WriteWorker::DoFinishCreateOrOpen(int rv) {
224 // ERR_FAILED implies create entry failed. In order to avoid trying
225 // to open the entry multiple times, the flag create_failed_ is set and
226 // checked.
227 if (rv == ERR_FAILED && !create_failed_) {
Ryan Sleevi 2014/06/18 22:16:03 Why combine CREATE_OR_OPEN into one state? It see
228 create_failed_ = true;
229 state_ = CREATE_OR_OPEN;
230 return OK;
231 } else if (rv < 0) {
232 CallCallbacks(std::string());
Ryan Sleevi 2014/06/18 22:16:03 DANGER! So the same comments I made on the previo
233 state_ = WRITE_NONE;
234 return ERR_FAILED;
235 }
236
237 state_ = START_WRITE;
238 return OK;
239 }
240
241 int DiskBasedCertCache::WriteWorker::DoStartWrite() {
242 std::string write_data;
243 bool encoded = X509Certificate::GetDEREncoded(cert_handle_, &write_data);
244
245 if (!encoded) {
246 CallCallbacks(std::string());
247 state_ = WRITE_NONE;
248 return ERR_FAILED;
249 }
Ryan Sleevi 2014/06/18 22:16:04 Let's chat in person how to structure these 'failu
250
251 buffer = new IOBuffer(write_data.size());
252 memcpy(buffer->data(), write_data.data(), write_data.size());
253
254 state_ = FINISH_WRITE;
255
256 return entry_->WriteData(0 /* index */,
257 0 /* offset */,
258 buffer,
259 write_data.size(),
260 io_callback_,
261 true /* truncate */);
262 }
263
264 int DiskBasedCertCache::WriteWorker::DoFinishWrite(int rv) {
265 if (rv < 0) {
266 CallCallbacks(std::string());
267 state_ = WRITE_NONE;
268 return ERR_FAILED;
269 }
270
271 state_ = WRITE_NONE;
272
273 CallCallbacks(key_);
274 return OK;
275 }
276
277 void DiskBasedCertCache::WriteWorker::CallCallbacks(const std::string& key) {
278 for (std::list<SetCallback>::iterator it = user_callbacks_.begin();
279 it != user_callbacks_.end();
280 it++) {
281 base::ResetAndReturn(&(*it)).Run(key_);
Ryan Sleevi 2014/06/18 22:16:03 Same danger regarding the risk of the following:
282 }
283 }
284
285 DiskBasedCertCache::WriteWorker::~WriteWorker() {
286 }
287
288 DiskBasedCertCache::ReadWorker::ReadWorker(
289 disk_cache::Backend* backend,
290 const std::string& key,
291 const base::Callback<void(void)>& cleanup_callback,
292 const GetCallback& user_callback)
293 : backend_(backend),
294 key_(key),
295 entry_(NULL),
296 state_(OPEN),
297 entry_size_(0),
298 cleanup_callback_(cleanup_callback),
299 weak_factory_(this) {
300 io_callback_ =
301 base::Bind(&ReadWorker::OnIOComplete, weak_factory_.GetWeakPtr());
302 AddCallback(user_callback);
303 }
304
305 void DiskBasedCertCache::ReadWorker::Start() {
306 DoLoop(OK);
307
308 if (state_ == READ_NONE) {
309 if (entry_)
310 entry_->Close();
311 base::ResetAndReturn(&cleanup_callback_).Run();
312 }
313 }
314
315 void DiskBasedCertCache::ReadWorker::AddCallback(
316 const GetCallback& user_callback) {
317 user_callbacks_.push_back(user_callback);
318 }
319
320 void DiskBasedCertCache::ReadWorker::OnIOComplete(int rv) {
321 DoLoop(rv);
322
323 if (state_ == READ_NONE) {
324 if (entry_)
325 entry_->Close();
326 base::ResetAndReturn(&cleanup_callback_).Run();
327 }
328 }
329
330 void DiskBasedCertCache::ReadWorker::DoLoop(int rv) {
331 do {
332 switch (state_) {
333 case OPEN:
334 rv = DoOpen();
335 break;
336 case START_READ:
337 rv = DoStartRead(rv);
338 break;
339 case FINISH_READ:
340 rv = DoFinishRead(rv);
341 break;
342 case READ_NONE:
343 break;
344 }
345 } while (rv != ERR_IO_PENDING && state_ != READ_NONE);
346 }
347
348 int DiskBasedCertCache::ReadWorker::DoOpen() {
349 state_ = START_READ;
350 return backend_->OpenEntry(key_, &entry_, io_callback_);
351 }
352
353 int DiskBasedCertCache::ReadWorker::DoStartRead(int rv) {
354 if (rv < 0) {
355 CallCallbacks(NULL);
356 state_ = READ_NONE;
357 return ERR_FAILED;
358 }
359
360 entry_size_ = entry_->GetDataSize(0 /* index */);
361 state_ = FINISH_READ;
362 buffer = new IOBuffer(entry_size_);
363 return entry_->ReadData(
364 0 /* index */, 0 /* offset */, buffer, entry_size_, io_callback_);
365 }
366
367 int DiskBasedCertCache::ReadWorker::DoFinishRead(int rv) {
368 if (rv < 0) {
369 CallCallbacks(NULL);
370 state_ = READ_NONE;
371 return ERR_FAILED;
372 }
373
374 state_ = READ_NONE;
375
376 X509Certificate::OSCertHandle retrieved_cert_handle =
377 X509Certificate::CreateOSCertHandleFromBytes(buffer->data(), entry_size_);
378
379 DCHECK(retrieved_cert_handle);
380
381 CallCallbacks(retrieved_cert_handle);
382 X509Certificate::FreeOSCertHandle(retrieved_cert_handle);
383 return OK;
384 }
385
386 void DiskBasedCertCache::ReadWorker::CallCallbacks(
387 X509Certificate::OSCertHandle cert_handle) {
388 for (std::list<GetCallback>::iterator it = user_callbacks_.begin();
389 it != user_callbacks_.end();
390 it++) {
391 base::ResetAndReturn(&(*it)).Run(cert_handle);
392 }
393 }
394
395 DiskBasedCertCache::ReadWorker::~ReadWorker() {
396 }
397
398 DiskBasedCertCache::DiskBasedCertCache(disk_cache::Backend* backend)
399 : backend_(backend), weak_factory_(this) {
400 DCHECK(backend_);
401 }
402
403 DiskBasedCertCache::~DiskBasedCertCache() {
404 STLDeleteContainerPairSecondPointers(read_worker_map_.begin(),
405 read_worker_map_.end());
406 STLDeleteContainerPairSecondPointers(write_worker_map_.begin(),
407 write_worker_map_.end());
408 }
409
410 void DiskBasedCertCache::Get(const std::string& key, const GetCallback& cb) {
411 DCHECK(!key.empty());
412
413 ReadWorkerMap::iterator it = read_worker_map_.find(key);
414
415 if (it == read_worker_map_.end()) {
416 std::pair<ReadWorkerMap::iterator, bool> entry = read_worker_map_.insert(
417 make_pair(key,
418 new ReadWorker(
419 backend_,
420 key,
421 base::Bind(&DiskBasedCertCache::FinishedReadOperation,
422 weak_factory_.GetWeakPtr(),
423 key),
424 cb)));
425 DCHECK(entry.second);
426 entry.first->second->Start();
427 } else {
428 it->second->AddCallback(cb);
429 }
430 }
431
432 void DiskBasedCertCache::Set(const X509Certificate::OSCertHandle cert_handle,
433 const SetCallback& cb) {
434 DCHECK(!cb.is_null());
435 DCHECK(cert_handle);
436 std::string key = GetCacheKeyToCert(cert_handle);
437
438 WriteWorkerMap::iterator it = write_worker_map_.find(key);
439
440 if (it == write_worker_map_.end()) {
441 std::pair<WriteWorkerMap::iterator, bool> entry = write_worker_map_.insert(
442 make_pair(key,
443 new WriteWorker(
444 backend_,
445 key,
446 cert_handle,
447 base::Bind(&DiskBasedCertCache::FinishedWriteOperation,
448 weak_factory_.GetWeakPtr(),
449 key),
450 cb)));
451 DCHECK(entry.second);
452 entry.first->second->Start();
453 } else {
454 it->second->AddCallback(cb);
455 }
456 }
457
458 void DiskBasedCertCache::FinishedWriteOperation(const std::string& key) {
459 WriteWorkerMap::iterator it = write_worker_map_.find(key);
460 delete it->second;
461 write_worker_map_.erase(it);
462 }
463
464 void DiskBasedCertCache::FinishedReadOperation(const std::string& key) {
465 ReadWorkerMap::iterator it = read_worker_map_.find(key);
466 delete it->second;
467 read_worker_map_.erase(it);
468 }
469
470 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698