| // 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 |