blob: 7021cfb20e1b9d38da1460be541ea2daf757c837 [file] [log] [blame]
// Copyright (c) 2010 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/callback.h"
#include "base/logging.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 {
DiskCacheBasedSSLHostInfo::CallbackImpl::CallbackImpl(
const base::WeakPtr<DiskCacheBasedSSLHostInfo>& obj,
void (DiskCacheBasedSSLHostInfo::*meth)(int))
: obj_(obj),
meth_(meth),
backend_(NULL),
entry_(NULL) {
}
DiskCacheBasedSSLHostInfo::CallbackImpl::~CallbackImpl() {}
void DiskCacheBasedSSLHostInfo::CallbackImpl::RunWithParams(
const Tuple1<int>& params) {
if (!obj_) {
delete this;
} else {
DispatchToMethod(obj_.get(), meth_, params);
}
}
DiskCacheBasedSSLHostInfo::DiskCacheBasedSSLHostInfo(
const std::string& hostname,
const SSLConfig& ssl_config,
CertVerifier* cert_verifier,
HttpCache* http_cache)
: SSLHostInfo(hostname, ssl_config, cert_verifier),
weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
callback_(new CallbackImpl(weak_ptr_factory_.GetWeakPtr(),
&DiskCacheBasedSSLHostInfo::DoLoop)),
state_(GET_BACKEND),
ready_(false),
hostname_(hostname),
http_cache_(http_cache),
backend_(NULL),
entry_(NULL),
user_callback_(NULL) {
}
void DiskCacheBasedSSLHostInfo::Start() {
DCHECK(CalledOnValidThread());
DCHECK_EQ(GET_BACKEND, state_);
DoLoop(OK);
}
int DiskCacheBasedSSLHostInfo::WaitForDataReady(CompletionCallback* callback) {
DCHECK(CalledOnValidThread());
DCHECK(state_ != GET_BACKEND);
if (ready_)
return OK;
if (callback) {
DCHECK(!user_callback_);
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_ == NULL);
new_data_ = Serialize();
if (!backend_)
return;
state_ = CREATE;
DoLoop(OK);
}
DiskCacheBasedSSLHostInfo::~DiskCacheBasedSSLHostInfo() {
DCHECK(!user_callback_);
if (entry_)
entry_->Close();
if (!IsCallbackPending())
delete callback_;
}
std::string DiskCacheBasedSSLHostInfo::key() const {
return "sslhostinfo:" + hostname_;
}
void 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 = WaitForDataReadyDone();
break;
case CREATE:
rv = DoCreate();
break;
case CREATE_COMPLETE:
rv = DoCreateComplete(rv);
break;
case WRITE:
rv = DoWrite();
break;
case WRITE_COMPLETE:
rv = DoWriteComplete(rv);
break;
case SET_DONE:
rv = SetDone();
break;
default:
rv = OK;
NOTREACHED();
}
} while (rv != ERR_IO_PENDING && state_ != NONE);
}
int DiskCacheBasedSSLHostInfo::DoGetBackendComplete(int rv) {
if (rv == OK) {
backend_ = callback_->backend();
state_ = OPEN;
} else {
state_ = WAIT_FOR_DATA_READY_DONE;
}
return OK;
}
int DiskCacheBasedSSLHostInfo::DoOpenComplete(int rv) {
if (rv == OK) {
entry_ = callback_->entry();
state_ = READ;
} else {
state_ = WAIT_FOR_DATA_READY_DONE;
}
return OK;
}
int DiskCacheBasedSSLHostInfo::DoReadComplete(int rv) {
if (rv > 0)
data_ = std::string(read_buffer_->data(), rv);
state_ = WAIT_FOR_DATA_READY_DONE;
return OK;
}
int DiskCacheBasedSSLHostInfo::DoWriteComplete(int rv) {
state_ = SET_DONE;
return OK;
}
int DiskCacheBasedSSLHostInfo::DoCreateComplete(int rv) {
if (rv != OK) {
state_ = SET_DONE;
} else {
entry_ = callback_->entry();
state_ = WRITE;
}
return OK;
}
int DiskCacheBasedSSLHostInfo::DoGetBackend() {
state_ = GET_BACKEND_COMPLETE;
return http_cache_->GetBackend(callback_->backend_pointer(), callback_);
}
int DiskCacheBasedSSLHostInfo::DoOpen() {
state_ = OPEN_COMPLETE;
return backend_->OpenEntry(key(), callback_->entry_pointer(), 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, 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(), callback_, true /* truncate */);
}
int DiskCacheBasedSSLHostInfo::DoCreate() {
DCHECK(entry_ == NULL);
state_ = CREATE_COMPLETE;
return backend_->CreateEntry(key(), callback_->entry_pointer(), callback_);
}
int DiskCacheBasedSSLHostInfo::WaitForDataReadyDone() {
CompletionCallback* callback;
DCHECK(!ready_);
state_ = NONE;
ready_ = true;
callback = user_callback_;
user_callback_ = NULL;
// 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_);
if (callback)
callback->Run(OK);
return OK;
}
int DiskCacheBasedSSLHostInfo::SetDone() {
if (entry_)
entry_->Close();
entry_ = NULL;
state_ = NONE;
return OK;
}
bool DiskCacheBasedSSLHostInfo::IsCallbackPending() const {
switch (state_) {
case GET_BACKEND_COMPLETE:
case OPEN_COMPLETE:
case READ_COMPLETE:
case CREATE_COMPLETE:
case WRITE_COMPLETE:
return true;
default:
return false;
}
}
} // namespace net