OLD | NEW |
---|---|
(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 | |
OLD | NEW |