Roll src/third_party/WebKit 8b42d1d:744641d (svn 186770:186771)
[chromium-blink-merge.git] / net / http / disk_cache_based_quic_server_info.cc
blob6a5ee175d5187f8773a75d2c88f8dc26415e26f5
1 // Copyright 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.
5 #include "net/http/disk_cache_based_quic_server_info.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/profiler/scoped_tracker.h"
13 #include "net/base/completion_callback.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "net/http/http_cache.h"
17 #include "net/http/http_network_session.h"
18 #include "net/quic/quic_server_id.h"
20 namespace net {
22 // Some APIs inside disk_cache take a handle that the caller must keep alive
23 // until the API has finished its asynchronous execution.
25 // Unfortunately, DiskCacheBasedQuicServerInfo may be deleted before the
26 // operation completes causing a use-after-free.
28 // This data shim struct is meant to provide a location for the disk_cache
29 // APIs to write into even if the originating DiskCacheBasedQuicServerInfo
30 // object has been deleted. The lifetime for instances of this struct
31 // should be bound to the CompletionCallback that is passed to the disk_cache
32 // API. We do this by binding an instance of this struct to an unused
33 // parameter for OnIOComplete() using base::Owned().
35 // This is a hack. A better fix is to make it so that the disk_cache APIs
36 // take a Callback to a mutator for setting the output value rather than
37 // writing into a raw handle. Then the caller can just pass in a Callback
38 // bound to WeakPtr for itself. This callback would correctly "no-op" itself
39 // when the DiskCacheBasedQuicServerInfo object is deleted.
41 // TODO(ajwong): Change disk_cache's API to return results via Callback.
42 struct DiskCacheBasedQuicServerInfo::CacheOperationDataShim {
43 CacheOperationDataShim() : backend(NULL), entry(NULL) {}
45 disk_cache::Backend* backend;
46 disk_cache::Entry* entry;
49 DiskCacheBasedQuicServerInfo::DiskCacheBasedQuicServerInfo(
50 const QuicServerId& server_id,
51 HttpCache* http_cache)
52 : QuicServerInfo(server_id),
53 data_shim_(new CacheOperationDataShim()),
54 state_(GET_BACKEND),
55 ready_(false),
56 found_entry_(false),
57 server_id_(server_id),
58 http_cache_(http_cache),
59 backend_(NULL),
60 entry_(NULL),
61 last_failure_(NO_FAILURE),
62 weak_factory_(this) {
63 io_callback_ =
64 base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete,
65 weak_factory_.GetWeakPtr(),
66 base::Owned(data_shim_)); // Ownership assigned.
69 void DiskCacheBasedQuicServerInfo::Start() {
70 DCHECK(CalledOnValidThread());
71 DCHECK_EQ(GET_BACKEND, state_);
72 DCHECK_EQ(last_failure_, NO_FAILURE);
73 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START);
74 load_start_time_ = base::TimeTicks::Now();
75 DoLoop(OK);
78 int DiskCacheBasedQuicServerInfo::WaitForDataReady(
79 const CompletionCallback& callback) {
80 DCHECK(CalledOnValidThread());
81 DCHECK_NE(GET_BACKEND, state_);
82 wait_for_data_start_time_ = base::TimeTicks::Now();
84 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY);
85 if (ready_) {
86 wait_for_data_end_time_ = base::TimeTicks::Now();
87 RecordLastFailure();
88 return OK;
91 if (!callback.is_null()) {
92 // Prevent a new callback for WaitForDataReady overwriting an existing
93 // pending callback (|wait_for_ready_callback_|).
94 if (!wait_for_ready_callback_.is_null()) {
95 RecordQuicServerInfoFailure(WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE);
96 return ERR_INVALID_ARGUMENT;
98 wait_for_ready_callback_ = callback;
101 return ERR_IO_PENDING;
104 void DiskCacheBasedQuicServerInfo::CancelWaitForDataReadyCallback() {
105 DCHECK(CalledOnValidThread());
107 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL);
108 if (!wait_for_ready_callback_.is_null()) {
109 RecordLastFailure();
110 wait_for_ready_callback_.Reset();
114 bool DiskCacheBasedQuicServerInfo::IsDataReady() {
115 return ready_;
118 bool DiskCacheBasedQuicServerInfo::IsReadyToPersist() {
119 // The data can be persisted if it has been loaded from the disk cache
120 // and there are no pending writes.
121 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST);
122 if (ready_ && new_data_.empty())
123 return true;
124 RecordQuicServerInfoFailure(READY_TO_PERSIST_FAILURE);
125 return false;
128 void DiskCacheBasedQuicServerInfo::Persist() {
129 DCHECK(CalledOnValidThread());
130 if (!IsReadyToPersist()) {
131 // Handle updates while a write is pending or if we haven't loaded from disk
132 // cache. Save the data to be written into a temporary buffer and then
133 // persist that data when we are ready to persist.
134 pending_write_data_ = Serialize();
135 return;
137 PersistInternal();
140 void DiskCacheBasedQuicServerInfo::PersistInternal() {
141 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
142 tracked_objects::ScopedTracker tracking_profile(
143 FROM_HERE_WITH_EXPLICIT_FUNCTION(
144 "422516 DiskCacheBasedQuicServerInfo::PersistInternal"));
146 DCHECK(CalledOnValidThread());
147 DCHECK_NE(GET_BACKEND, state_);
148 DCHECK(new_data_.empty());
149 CHECK(ready_);
150 DCHECK(wait_for_ready_callback_.is_null());
152 if (pending_write_data_.empty()) {
153 new_data_ = Serialize();
154 } else {
155 new_data_ = pending_write_data_;
156 pending_write_data_.clear();
159 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST);
160 if (!backend_) {
161 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
162 return;
165 state_ = CREATE_OR_OPEN;
166 DoLoop(OK);
169 void DiskCacheBasedQuicServerInfo::OnExternalCacheHit() {
170 DCHECK(CalledOnValidThread());
171 DCHECK_NE(GET_BACKEND, state_);
173 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT);
174 if (!backend_) {
175 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
176 return;
179 backend_->OnExternalCacheHit(key());
182 DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() {
183 DCHECK(wait_for_ready_callback_.is_null());
184 if (entry_)
185 entry_->Close();
188 std::string DiskCacheBasedQuicServerInfo::key() const {
189 return "quicserverinfo:" + server_id_.ToString();
192 void DiskCacheBasedQuicServerInfo::OnIOComplete(CacheOperationDataShim* unused,
193 int rv) {
194 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
195 tracked_objects::ScopedTracker tracking_profile(
196 FROM_HERE_WITH_EXPLICIT_FUNCTION(
197 "422516 DiskCacheBasedQuicServerInfo::OnIOComplete"));
199 DCHECK_NE(NONE, state_);
200 rv = DoLoop(rv);
201 if (rv == ERR_IO_PENDING)
202 return;
204 base::WeakPtr<DiskCacheBasedQuicServerInfo> weak_this =
205 weak_factory_.GetWeakPtr();
207 if (!wait_for_ready_callback_.is_null()) {
208 wait_for_data_end_time_ = base::TimeTicks::Now();
209 RecordLastFailure();
210 base::ResetAndReturn(&wait_for_ready_callback_).Run(rv);
212 // |wait_for_ready_callback_| could delete the object if there is an error.
213 // Check if |weak_this| still exists before accessing it.
214 if (weak_this.get() && ready_ && !pending_write_data_.empty()) {
215 DCHECK_EQ(NONE, state_);
216 PersistInternal();
220 int DiskCacheBasedQuicServerInfo::DoLoop(int rv) {
221 do {
222 switch (state_) {
223 case GET_BACKEND:
224 rv = DoGetBackend();
225 break;
226 case GET_BACKEND_COMPLETE:
227 rv = DoGetBackendComplete(rv);
228 break;
229 case OPEN:
230 rv = DoOpen();
231 break;
232 case OPEN_COMPLETE:
233 rv = DoOpenComplete(rv);
234 break;
235 case READ:
236 rv = DoRead();
237 break;
238 case READ_COMPLETE:
239 rv = DoReadComplete(rv);
240 break;
241 case WAIT_FOR_DATA_READY_DONE:
242 rv = DoWaitForDataReadyDone();
243 break;
244 case CREATE_OR_OPEN:
245 rv = DoCreateOrOpen();
246 break;
247 case CREATE_OR_OPEN_COMPLETE:
248 rv = DoCreateOrOpenComplete(rv);
249 break;
250 case WRITE:
251 rv = DoWrite();
252 break;
253 case WRITE_COMPLETE:
254 rv = DoWriteComplete(rv);
255 break;
256 case SET_DONE:
257 rv = DoSetDone();
258 break;
259 default:
260 rv = OK;
261 NOTREACHED();
263 } while (rv != ERR_IO_PENDING && state_ != NONE);
265 return rv;
268 int DiskCacheBasedQuicServerInfo::DoGetBackendComplete(int rv) {
269 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
270 tracked_objects::ScopedTracker tracking_profile(
271 FROM_HERE_WITH_EXPLICIT_FUNCTION(
272 "422516 DiskCacheBasedQuicServerInfo::DoGetBackendComplete"));
274 if (rv == OK) {
275 backend_ = data_shim_->backend;
276 state_ = OPEN;
277 } else {
278 RecordQuicServerInfoFailure(GET_BACKEND_FAILURE);
279 state_ = WAIT_FOR_DATA_READY_DONE;
281 return OK;
284 int DiskCacheBasedQuicServerInfo::DoOpenComplete(int rv) {
285 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
286 tracked_objects::ScopedTracker tracking_profile(
287 FROM_HERE_WITH_EXPLICIT_FUNCTION(
288 "422516 DiskCacheBasedQuicServerInfo::DoOpenComplete"));
290 if (rv == OK) {
291 entry_ = data_shim_->entry;
292 state_ = READ;
293 found_entry_ = true;
294 } else {
295 RecordQuicServerInfoFailure(OPEN_FAILURE);
296 state_ = WAIT_FOR_DATA_READY_DONE;
299 return OK;
302 int DiskCacheBasedQuicServerInfo::DoReadComplete(int rv) {
303 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
304 tracked_objects::ScopedTracker tracking_profile(
305 FROM_HERE_WITH_EXPLICIT_FUNCTION(
306 "422516 DiskCacheBasedQuicServerInfo::DoReadComplete"));
308 if (rv > 0)
309 data_.assign(read_buffer_->data(), rv);
310 else if (rv < 0)
311 RecordQuicServerInfoFailure(READ_FAILURE);
313 state_ = WAIT_FOR_DATA_READY_DONE;
314 return OK;
317 int DiskCacheBasedQuicServerInfo::DoWriteComplete(int rv) {
318 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
319 tracked_objects::ScopedTracker tracking_profile(
320 FROM_HERE_WITH_EXPLICIT_FUNCTION(
321 "422516 DiskCacheBasedQuicServerInfo::DoWriteComplete"));
323 if (rv < 0)
324 RecordQuicServerInfoFailure(WRITE_FAILURE);
325 state_ = SET_DONE;
326 return OK;
329 int DiskCacheBasedQuicServerInfo::DoCreateOrOpenComplete(int rv) {
330 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
331 tracked_objects::ScopedTracker tracking_profile(
332 FROM_HERE_WITH_EXPLICIT_FUNCTION(
333 "422516 DiskCacheBasedQuicServerInfo::DoCreateOrOpenComplete"));
335 if (rv != OK) {
336 RecordQuicServerInfoFailure(CREATE_OR_OPEN_FAILURE);
337 state_ = SET_DONE;
338 } else {
339 if (!entry_) {
340 entry_ = data_shim_->entry;
341 found_entry_ = true;
343 DCHECK(entry_);
344 state_ = WRITE;
346 return OK;
349 int DiskCacheBasedQuicServerInfo::DoGetBackend() {
350 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
351 tracked_objects::ScopedTracker tracking_profile(
352 FROM_HERE_WITH_EXPLICIT_FUNCTION(
353 "422516 DiskCacheBasedQuicServerInfo::DoGetBackend"));
355 state_ = GET_BACKEND_COMPLETE;
356 return http_cache_->GetBackend(&data_shim_->backend, io_callback_);
359 int DiskCacheBasedQuicServerInfo::DoOpen() {
360 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
361 tracked_objects::ScopedTracker tracking_profile(
362 FROM_HERE_WITH_EXPLICIT_FUNCTION(
363 "422516 DiskCacheBasedQuicServerInfo::DoOpen"));
365 state_ = OPEN_COMPLETE;
366 return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
369 int DiskCacheBasedQuicServerInfo::DoRead() {
370 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
371 tracked_objects::ScopedTracker tracking_profile(
372 FROM_HERE_WITH_EXPLICIT_FUNCTION(
373 "422516 DiskCacheBasedQuicServerInfo::DoRead"));
375 const int32 size = entry_->GetDataSize(0 /* index */);
376 if (!size) {
377 state_ = WAIT_FOR_DATA_READY_DONE;
378 return OK;
381 read_buffer_ = new IOBuffer(size);
382 state_ = READ_COMPLETE;
383 return entry_->ReadData(
384 0 /* index */, 0 /* offset */, read_buffer_.get(), size, io_callback_);
387 int DiskCacheBasedQuicServerInfo::DoWrite() {
388 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
389 tracked_objects::ScopedTracker tracking_profile(
390 FROM_HERE_WITH_EXPLICIT_FUNCTION(
391 "422516 DiskCacheBasedQuicServerInfo::DoWrite"));
393 write_buffer_ = new IOBuffer(new_data_.size());
394 memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
395 state_ = WRITE_COMPLETE;
397 return entry_->WriteData(0 /* index */,
398 0 /* offset */,
399 write_buffer_.get(),
400 new_data_.size(),
401 io_callback_,
402 true /* truncate */);
405 int DiskCacheBasedQuicServerInfo::DoCreateOrOpen() {
406 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
407 tracked_objects::ScopedTracker tracking_profile(
408 FROM_HERE_WITH_EXPLICIT_FUNCTION(
409 "422516 DiskCacheBasedQuicServerInfo::DoCreateOrOpen"));
411 state_ = CREATE_OR_OPEN_COMPLETE;
412 if (entry_)
413 return OK;
415 if (found_entry_) {
416 return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
419 return backend_->CreateEntry(key(), &data_shim_->entry, io_callback_);
422 int DiskCacheBasedQuicServerInfo::DoWaitForDataReadyDone() {
423 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
424 tracked_objects::ScopedTracker tracking_profile(
425 FROM_HERE_WITH_EXPLICIT_FUNCTION(
426 "422516 DiskCacheBasedQuicServerInfo::DoWaitForDataReadyDone"));
428 DCHECK(!ready_);
429 state_ = NONE;
430 ready_ = true;
431 // We close the entry because, if we shutdown before ::Persist is called,
432 // then we might leak a cache reference, which causes a DCHECK on shutdown.
433 if (entry_)
434 entry_->Close();
435 entry_ = NULL;
437 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PARSE);
438 if (!Parse(data_)) {
439 if (data_.empty())
440 RecordQuicServerInfoFailure(PARSE_NO_DATA_FAILURE);
441 else
442 RecordQuicServerInfoFailure(PARSE_FAILURE);
445 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheLoadTime",
446 base::TimeTicks::Now() - load_start_time_);
447 return OK;
450 int DiskCacheBasedQuicServerInfo::DoSetDone() {
451 if (entry_)
452 entry_->Close();
453 entry_ = NULL;
454 new_data_.clear();
455 state_ = NONE;
456 return OK;
459 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoStatus(
460 QuicServerInfoAPICall call) {
461 if (!backend_) {
462 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.NoBackend", call,
463 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
464 } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
465 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.MemoryCache", call,
466 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
467 } else {
468 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.DiskCache", call,
469 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
473 void DiskCacheBasedQuicServerInfo::RecordLastFailure() {
474 if (last_failure_ != NO_FAILURE) {
475 UMA_HISTOGRAM_ENUMERATION(
476 "Net.QuicDiskCache.FailureReason.WaitForDataReady",
477 last_failure_, NUM_OF_FAILURES);
479 last_failure_ = NO_FAILURE;
482 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoFailure(
483 FailureReason failure) {
484 last_failure_ = failure;
486 if (!backend_) {
487 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.NoBackend",
488 failure, NUM_OF_FAILURES);
489 } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
490 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.MemoryCache",
491 failure, NUM_OF_FAILURES);
492 } else {
493 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.DiskCache",
494 failure, NUM_OF_FAILURES);
498 } // namespace net