1// Copyright (c) 2010 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_ssl_host_info.h"
6
7#include "base/callback.h"
8#include "base/logging.h"
9#include "net/base/io_buffer.h"
10#include "net/base/net_errors.h"
11#include "net/http/http_cache.h"
12#include "net/http/http_network_session.h"
13
14namespace net {
15
16DiskCacheBasedSSLHostInfo::CallbackImpl::CallbackImpl(
17    const base::WeakPtr<DiskCacheBasedSSLHostInfo>& obj,
18    void (DiskCacheBasedSSLHostInfo::*meth)(int))
19    : obj_(obj),
20      meth_(meth),
21      backend_(NULL),
22      entry_(NULL) {
23}
24
25DiskCacheBasedSSLHostInfo::CallbackImpl::~CallbackImpl() {}
26
27void DiskCacheBasedSSLHostInfo::CallbackImpl::RunWithParams(
28    const Tuple1<int>& params) {
29  if (!obj_) {
30    delete this;
31  } else {
32    DispatchToMethod(obj_.get(), meth_, params);
33  }
34}
35
36DiskCacheBasedSSLHostInfo::DiskCacheBasedSSLHostInfo(
37    const std::string& hostname,
38    const SSLConfig& ssl_config,
39    CertVerifier* cert_verifier,
40    HttpCache* http_cache)
41    : SSLHostInfo(hostname, ssl_config, cert_verifier),
42      weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
43      callback_(new CallbackImpl(weak_ptr_factory_.GetWeakPtr(),
44                                 &DiskCacheBasedSSLHostInfo::DoLoop)),
45      state_(GET_BACKEND),
46      ready_(false),
47      hostname_(hostname),
48      http_cache_(http_cache),
49      backend_(NULL),
50      entry_(NULL),
51      user_callback_(NULL) {
52}
53
54void DiskCacheBasedSSLHostInfo::Start() {
55  DCHECK(CalledOnValidThread());
56  DCHECK_EQ(GET_BACKEND, state_);
57  DoLoop(OK);
58}
59
60int DiskCacheBasedSSLHostInfo::WaitForDataReady(CompletionCallback* callback) {
61  DCHECK(CalledOnValidThread());
62  DCHECK(state_ != GET_BACKEND);
63
64  if (ready_)
65    return OK;
66  if (callback) {
67    DCHECK(!user_callback_);
68    user_callback_ = callback;
69  }
70  return ERR_IO_PENDING;
71}
72
73void DiskCacheBasedSSLHostInfo::Persist() {
74  DCHECK(CalledOnValidThread());
75  DCHECK(state_ != GET_BACKEND);
76
77  DCHECK(new_data_.empty());
78  CHECK(ready_);
79  DCHECK(user_callback_ == NULL);
80  new_data_ = Serialize();
81
82  if (!backend_)
83    return;
84
85  state_ = CREATE;
86  DoLoop(OK);
87}
88
89DiskCacheBasedSSLHostInfo::~DiskCacheBasedSSLHostInfo() {
90  DCHECK(!user_callback_);
91  if (entry_)
92    entry_->Close();
93  if (!IsCallbackPending())
94    delete callback_;
95}
96
97std::string DiskCacheBasedSSLHostInfo::key() const {
98  return "sslhostinfo:" + hostname_;
99}
100
101void DiskCacheBasedSSLHostInfo::DoLoop(int rv) {
102  do {
103    switch (state_) {
104      case GET_BACKEND:
105        rv = DoGetBackend();
106        break;
107      case GET_BACKEND_COMPLETE:
108        rv = DoGetBackendComplete(rv);
109        break;
110      case OPEN:
111        rv = DoOpen();
112        break;
113      case OPEN_COMPLETE:
114        rv = DoOpenComplete(rv);
115        break;
116      case READ:
117        rv = DoRead();
118        break;
119      case READ_COMPLETE:
120        rv = DoReadComplete(rv);
121        break;
122      case WAIT_FOR_DATA_READY_DONE:
123        rv = WaitForDataReadyDone();
124        break;
125      case CREATE:
126        rv = DoCreate();
127        break;
128      case CREATE_COMPLETE:
129        rv = DoCreateComplete(rv);
130        break;
131      case WRITE:
132        rv = DoWrite();
133        break;
134      case WRITE_COMPLETE:
135        rv = DoWriteComplete(rv);
136        break;
137      case SET_DONE:
138        rv = SetDone();
139        break;
140      default:
141        rv = OK;
142        NOTREACHED();
143    }
144  } while (rv != ERR_IO_PENDING && state_ != NONE);
145}
146
147int DiskCacheBasedSSLHostInfo::DoGetBackendComplete(int rv) {
148  if (rv == OK) {
149    backend_ = callback_->backend();
150    state_ = OPEN;
151  } else {
152    state_ = WAIT_FOR_DATA_READY_DONE;
153  }
154  return OK;
155}
156
157int DiskCacheBasedSSLHostInfo::DoOpenComplete(int rv) {
158  if (rv == OK) {
159    entry_ = callback_->entry();
160    state_ = READ;
161  } else {
162    state_ = WAIT_FOR_DATA_READY_DONE;
163  }
164
165  return OK;
166}
167
168int DiskCacheBasedSSLHostInfo::DoReadComplete(int rv) {
169  if (rv > 0)
170    data_ = std::string(read_buffer_->data(), rv);
171
172  state_ = WAIT_FOR_DATA_READY_DONE;
173  return OK;
174}
175
176int DiskCacheBasedSSLHostInfo::DoWriteComplete(int rv) {
177  state_ = SET_DONE;
178  return OK;
179}
180
181int DiskCacheBasedSSLHostInfo::DoCreateComplete(int rv) {
182  if (rv != OK) {
183    state_ = SET_DONE;
184  } else {
185    entry_ = callback_->entry();
186    state_ = WRITE;
187  }
188  return OK;
189}
190
191int DiskCacheBasedSSLHostInfo::DoGetBackend() {
192  state_ = GET_BACKEND_COMPLETE;
193  return http_cache_->GetBackend(callback_->backend_pointer(), callback_);
194}
195
196int DiskCacheBasedSSLHostInfo::DoOpen() {
197  state_ = OPEN_COMPLETE;
198  return backend_->OpenEntry(key(), callback_->entry_pointer(), callback_);
199}
200
201int DiskCacheBasedSSLHostInfo::DoRead() {
202  const int32 size = entry_->GetDataSize(0 /* index */);
203  if (!size) {
204    state_ = WAIT_FOR_DATA_READY_DONE;
205    return OK;
206  }
207
208  read_buffer_ = new IOBuffer(size);
209  state_ = READ_COMPLETE;
210  return entry_->ReadData(0 /* index */, 0 /* offset */, read_buffer_,
211                          size, callback_);
212}
213
214int DiskCacheBasedSSLHostInfo::DoWrite() {
215  write_buffer_ = new IOBuffer(new_data_.size());
216  memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
217  state_ = WRITE_COMPLETE;
218
219  return entry_->WriteData(0 /* index */, 0 /* offset */, write_buffer_,
220                           new_data_.size(), callback_, true /* truncate */);
221}
222
223int DiskCacheBasedSSLHostInfo::DoCreate() {
224  DCHECK(entry_ == NULL);
225  state_ = CREATE_COMPLETE;
226  return backend_->CreateEntry(key(), callback_->entry_pointer(), callback_);
227}
228
229int DiskCacheBasedSSLHostInfo::WaitForDataReadyDone() {
230  CompletionCallback* callback;
231
232  DCHECK(!ready_);
233  state_ = NONE;
234  ready_ = true;
235  callback = user_callback_;
236  user_callback_ = NULL;
237  // We close the entry because, if we shutdown before ::Persist is called,
238  // then we might leak a cache reference, which causes a DCHECK on shutdown.
239  if (entry_)
240    entry_->Close();
241  entry_ = NULL;
242  Parse(data_);
243
244  if (callback)
245    callback->Run(OK);
246
247  return OK;
248}
249
250int DiskCacheBasedSSLHostInfo::SetDone() {
251  if (entry_)
252    entry_->Close();
253  entry_ = NULL;
254  state_ = NONE;
255  return OK;
256}
257
258bool DiskCacheBasedSSLHostInfo::IsCallbackPending() const {
259  switch (state_) {
260    case GET_BACKEND_COMPLETE:
261    case OPEN_COMPLETE:
262    case READ_COMPLETE:
263    case CREATE_COMPLETE:
264    case WRITE_COMPLETE:
265      return true;
266    default:
267      return false;
268  }
269}
270
271}  // namespace net
272