| Index: net/http/disk_cache_based_ssl_host_info.cc
|
| diff --git a/net/http/disk_cache_based_ssl_host_info.cc b/net/http/disk_cache_based_ssl_host_info.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a1a75b78ce2441489448afa94448a496287eb93b
|
| --- /dev/null
|
| +++ b/net/http/disk_cache_based_ssl_host_info.cc
|
| @@ -0,0 +1,281 @@
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "net/http/disk_cache_based_ssl_host_info.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/callback.h"
|
| +#include "base/logging.h"
|
| +#include "net/base/completion_callback.h"
|
| +#include "net/base/io_buffer.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/http/http_cache.h"
|
| +#include "net/http/http_network_session.h"
|
| +
|
| +namespace net {
|
| +
|
| +// Some APIs inside disk_cache take a handle that the caller must keep alive
|
| +// until the API has finished its asynchronous execution.
|
| +//
|
| +// Unfortunately, DiskCacheBasedSSLHostInfo may be deleted before the
|
| +// operation completes causing a use-after-free.
|
| +//
|
| +// This data shim struct is meant to provide a location for the disk_cache
|
| +// APIs to write into even if the originating DiskCacheBasedSSLHostInfo
|
| +// object has been deleted. The lifetime for instances of this struct
|
| +// should be bound to the CompletionCallback that is passed to the disk_cache
|
| +// API. We do this by binding an instance of this struct to an unused
|
| +// parameter for OnIOComplete() using base::Owned().
|
| +//
|
| +// This is a hack. A better fix is to make it so that the disk_cache APIs
|
| +// take a Callback to a mutator for setting the output value rather than
|
| +// writing into a raw handle. Then the caller can just pass in a Callback
|
| +// bound to WeakPtr for itself. This callback would correctly "no-op" itself
|
| +// when the DiskCacheBasedSSLHostInfo object is deleted.
|
| +//
|
| +// TODO(ajwong): Change disk_cache's API to return results via Callback.
|
| +struct DiskCacheBasedSSLHostInfo::CacheOperationDataShim {
|
| + CacheOperationDataShim() : backend(NULL), entry(NULL) {}
|
| +
|
| + disk_cache::Backend* backend;
|
| + disk_cache::Entry* entry;
|
| +};
|
| +
|
| +DiskCacheBasedSSLHostInfo::DiskCacheBasedSSLHostInfo(
|
| + const std::string& hostname,
|
| + const SSLConfig& ssl_config,
|
| + CertVerifier* cert_verifier,
|
| + HttpCache* http_cache)
|
| + : SSLHostInfo(hostname, ssl_config, cert_verifier),
|
| + weak_factory_(this),
|
| + data_shim_(new CacheOperationDataShim()),
|
| + io_callback_(
|
| + base::Bind(&DiskCacheBasedSSLHostInfo::OnIOComplete,
|
| + weak_factory_.GetWeakPtr(),
|
| + base::Owned(data_shim_))), // Ownership assigned.
|
| + state_(GET_BACKEND),
|
| + ready_(false),
|
| + found_entry_(false),
|
| + hostname_(hostname),
|
| + http_cache_(http_cache),
|
| + backend_(NULL),
|
| + entry_(NULL) {
|
| +}
|
| +
|
| +void DiskCacheBasedSSLHostInfo::Start() {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK_EQ(GET_BACKEND, state_);
|
| + DoLoop(OK);
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::WaitForDataReady(
|
| + const CompletionCallback& callback) {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK(state_ != GET_BACKEND);
|
| +
|
| + if (ready_)
|
| + return OK;
|
| +
|
| + if (!callback.is_null()) {
|
| + DCHECK(user_callback_.is_null());
|
| + user_callback_ = callback;
|
| + }
|
| +
|
| + return ERR_IO_PENDING;
|
| +}
|
| +
|
| +void DiskCacheBasedSSLHostInfo::Persist() {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK(state_ != GET_BACKEND);
|
| +
|
| + DCHECK(new_data_.empty());
|
| + CHECK(ready_);
|
| + DCHECK(user_callback_.is_null());
|
| + new_data_ = Serialize();
|
| +
|
| + if (!backend_)
|
| + return;
|
| +
|
| + state_ = CREATE_OR_OPEN;
|
| + DoLoop(OK);
|
| +}
|
| +
|
| +DiskCacheBasedSSLHostInfo::~DiskCacheBasedSSLHostInfo() {
|
| + DCHECK(user_callback_.is_null());
|
| + if (entry_)
|
| + entry_->Close();
|
| +}
|
| +
|
| +std::string DiskCacheBasedSSLHostInfo::key() const {
|
| + return "sslhostinfo:" + hostname_;
|
| +}
|
| +
|
| +void DiskCacheBasedSSLHostInfo::OnIOComplete(CacheOperationDataShim* unused,
|
| + int rv) {
|
| + rv = DoLoop(rv);
|
| + if (rv != ERR_IO_PENDING && !user_callback_.is_null()) {
|
| + CompletionCallback callback = user_callback_;
|
| + user_callback_.Reset();
|
| + callback.Run(rv);
|
| + }
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoLoop(int rv) {
|
| + do {
|
| + switch (state_) {
|
| + case GET_BACKEND:
|
| + rv = DoGetBackend();
|
| + break;
|
| + case GET_BACKEND_COMPLETE:
|
| + rv = DoGetBackendComplete(rv);
|
| + break;
|
| + case OPEN:
|
| + rv = DoOpen();
|
| + break;
|
| + case OPEN_COMPLETE:
|
| + rv = DoOpenComplete(rv);
|
| + break;
|
| + case READ:
|
| + rv = DoRead();
|
| + break;
|
| + case READ_COMPLETE:
|
| + rv = DoReadComplete(rv);
|
| + break;
|
| + case WAIT_FOR_DATA_READY_DONE:
|
| + rv = DoWaitForDataReadyDone();
|
| + break;
|
| + case CREATE_OR_OPEN:
|
| + rv = DoCreateOrOpen();
|
| + break;
|
| + case CREATE_OR_OPEN_COMPLETE:
|
| + rv = DoCreateOrOpenComplete(rv);
|
| + break;
|
| + case WRITE:
|
| + rv = DoWrite();
|
| + break;
|
| + case WRITE_COMPLETE:
|
| + rv = DoWriteComplete(rv);
|
| + break;
|
| + case SET_DONE:
|
| + rv = DoSetDone();
|
| + break;
|
| + default:
|
| + rv = OK;
|
| + NOTREACHED();
|
| + }
|
| + } while (rv != ERR_IO_PENDING && state_ != NONE);
|
| +
|
| + return rv;
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoGetBackendComplete(int rv) {
|
| + if (rv == OK) {
|
| + backend_ = data_shim_->backend;
|
| + state_ = OPEN;
|
| + } else {
|
| + state_ = WAIT_FOR_DATA_READY_DONE;
|
| + }
|
| + return OK;
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoOpenComplete(int rv) {
|
| + if (rv == OK) {
|
| + entry_ = data_shim_->entry;
|
| + state_ = READ;
|
| + found_entry_ = true;
|
| + } else {
|
| + state_ = WAIT_FOR_DATA_READY_DONE;
|
| + }
|
| +
|
| + return OK;
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoReadComplete(int rv) {
|
| + if (rv > 0)
|
| + data_.assign(read_buffer_->data(), rv);
|
| +
|
| + state_ = WAIT_FOR_DATA_READY_DONE;
|
| + return OK;
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoWriteComplete(int rv) {
|
| + state_ = SET_DONE;
|
| + return OK;
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoCreateOrOpenComplete(int rv) {
|
| + if (rv != OK) {
|
| + state_ = SET_DONE;
|
| + } else {
|
| + entry_ = data_shim_->entry;
|
| + state_ = WRITE;
|
| + }
|
| + return OK;
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoGetBackend() {
|
| + state_ = GET_BACKEND_COMPLETE;
|
| + return http_cache_->GetBackend(&data_shim_->backend, io_callback_);
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoOpen() {
|
| + state_ = OPEN_COMPLETE;
|
| + return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoRead() {
|
| + const int32 size = entry_->GetDataSize(0 /* index */);
|
| + if (!size) {
|
| + state_ = WAIT_FOR_DATA_READY_DONE;
|
| + return OK;
|
| + }
|
| +
|
| + read_buffer_ = new IOBuffer(size);
|
| + state_ = READ_COMPLETE;
|
| + return entry_->ReadData(
|
| + 0 /* index */, 0 /* offset */, read_buffer_, size, io_callback_);
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoWrite() {
|
| + write_buffer_ = new IOBuffer(new_data_.size());
|
| + memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
|
| + state_ = WRITE_COMPLETE;
|
| +
|
| + return entry_->WriteData(
|
| + 0 /* index */, 0 /* offset */, write_buffer_, new_data_.size(),
|
| + io_callback_, true /* truncate */);
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoCreateOrOpen() {
|
| + DCHECK(entry_ == NULL);
|
| + state_ = CREATE_OR_OPEN_COMPLETE;
|
| + if (found_entry_) {
|
| + return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
|
| + }
|
| +
|
| + return backend_->CreateEntry(key(), &data_shim_->entry, io_callback_);
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoWaitForDataReadyDone() {
|
| + DCHECK(!ready_);
|
| + state_ = NONE;
|
| + ready_ = true;
|
| + // We close the entry because, if we shutdown before ::Persist is called,
|
| + // then we might leak a cache reference, which causes a DCHECK on shutdown.
|
| + if (entry_)
|
| + entry_->Close();
|
| + entry_ = NULL;
|
| + Parse(data_);
|
| + return OK;
|
| +}
|
| +
|
| +int DiskCacheBasedSSLHostInfo::DoSetDone() {
|
| + if (entry_)
|
| + entry_->Close();
|
| + entry_ = NULL;
|
| + state_ = NONE;
|
| + return OK;
|
| +}
|
| +
|
| +} // namespace net
|
|
|