Home | History | Annotate | Download | only in http
      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.
      4 
      5 #include "net/http/disk_cache_based_quic_server_info.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback.h"
      9 #include "base/logging.h"
     10 #include "net/base/completion_callback.h"
     11 #include "net/base/io_buffer.h"
     12 #include "net/base/net_errors.h"
     13 #include "net/http/http_cache.h"
     14 #include "net/http/http_network_session.h"
     15 #include "net/quic/quic_server_id.h"
     16 
     17 namespace net {
     18 
     19 // Some APIs inside disk_cache take a handle that the caller must keep alive
     20 // until the API has finished its asynchronous execution.
     21 //
     22 // Unfortunately, DiskCacheBasedQuicServerInfo may be deleted before the
     23 // operation completes causing a use-after-free.
     24 //
     25 // This data shim struct is meant to provide a location for the disk_cache
     26 // APIs to write into even if the originating DiskCacheBasedQuicServerInfo
     27 // object has been deleted.  The lifetime for instances of this struct
     28 // should be bound to the CompletionCallback that is passed to the disk_cache
     29 // API.  We do this by binding an instance of this struct to an unused
     30 // parameter for OnIOComplete() using base::Owned().
     31 //
     32 // This is a hack. A better fix is to make it so that the disk_cache APIs
     33 // take a Callback to a mutator for setting the output value rather than
     34 // writing into a raw handle. Then the caller can just pass in a Callback
     35 // bound to WeakPtr for itself. This callback would correctly "no-op" itself
     36 // when the DiskCacheBasedQuicServerInfo object is deleted.
     37 //
     38 // TODO(ajwong): Change disk_cache's API to return results via Callback.
     39 struct DiskCacheBasedQuicServerInfo::CacheOperationDataShim {
     40   CacheOperationDataShim() : backend(NULL), entry(NULL) {}
     41 
     42   disk_cache::Backend* backend;
     43   disk_cache::Entry* entry;
     44 };
     45 
     46 DiskCacheBasedQuicServerInfo::DiskCacheBasedQuicServerInfo(
     47     const QuicServerId& server_id,
     48     HttpCache* http_cache)
     49     : QuicServerInfo(server_id),
     50       weak_factory_(this),
     51       data_shim_(new CacheOperationDataShim()),
     52       io_callback_(
     53           base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete,
     54                      weak_factory_.GetWeakPtr(),
     55                      base::Owned(data_shim_))),  // Ownership assigned.
     56       state_(GET_BACKEND),
     57       ready_(false),
     58       found_entry_(false),
     59       server_id_(server_id),
     60       http_cache_(http_cache),
     61       backend_(NULL),
     62       entry_(NULL) {
     63 }
     64 
     65 void DiskCacheBasedQuicServerInfo::Start() {
     66   DCHECK(CalledOnValidThread());
     67   DCHECK_EQ(GET_BACKEND, state_);
     68   DoLoop(OK);
     69 }
     70 
     71 int DiskCacheBasedQuicServerInfo::WaitForDataReady(
     72     const CompletionCallback& callback) {
     73   DCHECK(CalledOnValidThread());
     74   DCHECK_NE(GET_BACKEND, state_);
     75 
     76   if (ready_)
     77     return OK;
     78 
     79   if (!callback.is_null()) {
     80     // Prevent a new callback for WaitForDataReady overwriting an existing
     81     // pending callback (|user_callback_|).
     82     if (!user_callback_.is_null())
     83       return ERR_INVALID_ARGUMENT;
     84     user_callback_ = callback;
     85   }
     86 
     87   return ERR_IO_PENDING;
     88 }
     89 
     90 bool DiskCacheBasedQuicServerInfo::IsDataReady() {
     91   return ready_;
     92 }
     93 
     94 bool DiskCacheBasedQuicServerInfo::IsReadyToPersist() {
     95   // The data can be persisted if it has been loaded from the disk cache
     96   // and there are no pending writes.
     97   return ready_ && new_data_.empty();
     98 }
     99 
    100 void DiskCacheBasedQuicServerInfo::Persist() {
    101   DCHECK(CalledOnValidThread());
    102   DCHECK_NE(GET_BACKEND, state_);
    103 
    104   DCHECK(new_data_.empty());
    105   CHECK(ready_);
    106   DCHECK(user_callback_.is_null());
    107   new_data_ = Serialize();
    108 
    109   if (!backend_)
    110     return;
    111 
    112   state_ = CREATE_OR_OPEN;
    113   DoLoop(OK);
    114 }
    115 
    116 DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() {
    117   DCHECK(user_callback_.is_null());
    118   if (entry_)
    119     entry_->Close();
    120 }
    121 
    122 std::string DiskCacheBasedQuicServerInfo::key() const {
    123   return "quicserverinfo:" + server_id_.ToString();
    124 }
    125 
    126 void DiskCacheBasedQuicServerInfo::OnIOComplete(CacheOperationDataShim* unused,
    127                                                 int rv) {
    128   DCHECK_NE(NONE, state_);
    129   rv = DoLoop(rv);
    130   if (rv != ERR_IO_PENDING && !user_callback_.is_null()) {
    131     CompletionCallback callback = user_callback_;
    132     user_callback_.Reset();
    133     callback.Run(rv);
    134   }
    135 }
    136 
    137 int DiskCacheBasedQuicServerInfo::DoLoop(int rv) {
    138   do {
    139     switch (state_) {
    140       case GET_BACKEND:
    141         rv = DoGetBackend();
    142         break;
    143       case GET_BACKEND_COMPLETE:
    144         rv = DoGetBackendComplete(rv);
    145         break;
    146       case OPEN:
    147         rv = DoOpen();
    148         break;
    149       case OPEN_COMPLETE:
    150         rv = DoOpenComplete(rv);
    151         break;
    152       case READ:
    153         rv = DoRead();
    154         break;
    155       case READ_COMPLETE:
    156         rv = DoReadComplete(rv);
    157         break;
    158       case WAIT_FOR_DATA_READY_DONE:
    159         rv = DoWaitForDataReadyDone();
    160         break;
    161       case CREATE_OR_OPEN:
    162         rv = DoCreateOrOpen();
    163         break;
    164       case CREATE_OR_OPEN_COMPLETE:
    165         rv = DoCreateOrOpenComplete(rv);
    166         break;
    167       case WRITE:
    168         rv = DoWrite();
    169         break;
    170       case WRITE_COMPLETE:
    171         rv = DoWriteComplete(rv);
    172         break;
    173       case SET_DONE:
    174         rv = DoSetDone();
    175         break;
    176       default:
    177         rv = OK;
    178         NOTREACHED();
    179     }
    180   } while (rv != ERR_IO_PENDING && state_ != NONE);
    181 
    182   return rv;
    183 }
    184 
    185 int DiskCacheBasedQuicServerInfo::DoGetBackendComplete(int rv) {
    186   if (rv == OK) {
    187     backend_ = data_shim_->backend;
    188     state_ = OPEN;
    189   } else {
    190     state_ = WAIT_FOR_DATA_READY_DONE;
    191   }
    192   return OK;
    193 }
    194 
    195 int DiskCacheBasedQuicServerInfo::DoOpenComplete(int rv) {
    196   if (rv == OK) {
    197     entry_ = data_shim_->entry;
    198     state_ = READ;
    199     found_entry_ = true;
    200   } else {
    201     state_ = WAIT_FOR_DATA_READY_DONE;
    202   }
    203 
    204   return OK;
    205 }
    206 
    207 int DiskCacheBasedQuicServerInfo::DoReadComplete(int rv) {
    208   if (rv > 0)
    209     data_.assign(read_buffer_->data(), rv);
    210 
    211   state_ = WAIT_FOR_DATA_READY_DONE;
    212   return OK;
    213 }
    214 
    215 int DiskCacheBasedQuicServerInfo::DoWriteComplete(int rv) {
    216   state_ = SET_DONE;
    217   return OK;
    218 }
    219 
    220 int DiskCacheBasedQuicServerInfo::DoCreateOrOpenComplete(int rv) {
    221   if (rv != OK) {
    222     state_ = SET_DONE;
    223   } else {
    224     entry_ = data_shim_->entry;
    225     state_ = WRITE;
    226   }
    227   return OK;
    228 }
    229 
    230 int DiskCacheBasedQuicServerInfo::DoGetBackend() {
    231   state_ = GET_BACKEND_COMPLETE;
    232   return http_cache_->GetBackend(&data_shim_->backend, io_callback_);
    233 }
    234 
    235 int DiskCacheBasedQuicServerInfo::DoOpen() {
    236   state_ = OPEN_COMPLETE;
    237   return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
    238 }
    239 
    240 int DiskCacheBasedQuicServerInfo::DoRead() {
    241   const int32 size = entry_->GetDataSize(0 /* index */);
    242   if (!size) {
    243     state_ = WAIT_FOR_DATA_READY_DONE;
    244     return OK;
    245   }
    246 
    247   read_buffer_ = new IOBuffer(size);
    248   state_ = READ_COMPLETE;
    249   return entry_->ReadData(
    250       0 /* index */, 0 /* offset */, read_buffer_, size, io_callback_);
    251 }
    252 
    253 int DiskCacheBasedQuicServerInfo::DoWrite() {
    254   write_buffer_ = new IOBuffer(new_data_.size());
    255   memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
    256   state_ = WRITE_COMPLETE;
    257 
    258   return entry_->WriteData(
    259       0 /* index */, 0 /* offset */, write_buffer_, new_data_.size(),
    260       io_callback_, true /* truncate */);
    261 }
    262 
    263 int DiskCacheBasedQuicServerInfo::DoCreateOrOpen() {
    264   DCHECK(entry_ == NULL);
    265   state_ = CREATE_OR_OPEN_COMPLETE;
    266   if (found_entry_) {
    267     return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
    268   }
    269 
    270   return backend_->CreateEntry(key(), &data_shim_->entry, io_callback_);
    271 }
    272 
    273 int DiskCacheBasedQuicServerInfo::DoWaitForDataReadyDone() {
    274   DCHECK(!ready_);
    275   state_ = NONE;
    276   ready_ = true;
    277   // We close the entry because, if we shutdown before ::Persist is called,
    278   // then we might leak a cache reference, which causes a DCHECK on shutdown.
    279   if (entry_)
    280     entry_->Close();
    281   entry_ = NULL;
    282   Parse(data_);
    283   return OK;
    284 }
    285 
    286 int DiskCacheBasedQuicServerInfo::DoSetDone() {
    287   if (entry_)
    288     entry_->Close();
    289   entry_ = NULL;
    290   new_data_.clear();
    291   state_ = NONE;
    292   return OK;
    293 }
    294 
    295 }  // namespace net
    296