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
14 namespace net {
15
CallbackImpl(const base::WeakPtr<DiskCacheBasedSSLHostInfo> & obj,void (DiskCacheBasedSSLHostInfo::* meth)(int))16 DiskCacheBasedSSLHostInfo::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
~CallbackImpl()25 DiskCacheBasedSSLHostInfo::CallbackImpl::~CallbackImpl() {}
26
RunWithParams(const Tuple1<int> & params)27 void 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
DiskCacheBasedSSLHostInfo(const std::string & hostname,const SSLConfig & ssl_config,CertVerifier * cert_verifier,HttpCache * http_cache)36 DiskCacheBasedSSLHostInfo::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
Start()54 void DiskCacheBasedSSLHostInfo::Start() {
55 DCHECK(CalledOnValidThread());
56 DCHECK_EQ(GET_BACKEND, state_);
57 DoLoop(OK);
58 }
59
WaitForDataReady(CompletionCallback * callback)60 int 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
Persist()73 void 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
~DiskCacheBasedSSLHostInfo()89 DiskCacheBasedSSLHostInfo::~DiskCacheBasedSSLHostInfo() {
90 DCHECK(!user_callback_);
91 if (entry_)
92 entry_->Close();
93 if (!IsCallbackPending())
94 delete callback_;
95 }
96
key() const97 std::string DiskCacheBasedSSLHostInfo::key() const {
98 return "sslhostinfo:" + hostname_;
99 }
100
DoLoop(int rv)101 void 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
DoGetBackendComplete(int rv)147 int 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
DoOpenComplete(int rv)157 int 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
DoReadComplete(int rv)168 int 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
DoWriteComplete(int rv)176 int DiskCacheBasedSSLHostInfo::DoWriteComplete(int rv) {
177 state_ = SET_DONE;
178 return OK;
179 }
180
DoCreateComplete(int rv)181 int 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
DoGetBackend()191 int DiskCacheBasedSSLHostInfo::DoGetBackend() {
192 state_ = GET_BACKEND_COMPLETE;
193 return http_cache_->GetBackend(callback_->backend_pointer(), callback_);
194 }
195
DoOpen()196 int DiskCacheBasedSSLHostInfo::DoOpen() {
197 state_ = OPEN_COMPLETE;
198 return backend_->OpenEntry(key(), callback_->entry_pointer(), callback_);
199 }
200
DoRead()201 int 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
DoWrite()214 int 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
DoCreate()223 int DiskCacheBasedSSLHostInfo::DoCreate() {
224 DCHECK(entry_ == NULL);
225 state_ = CREATE_COMPLETE;
226 return backend_->CreateEntry(key(), callback_->entry_pointer(), callback_);
227 }
228
WaitForDataReadyDone()229 int 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
SetDone()250 int DiskCacheBasedSSLHostInfo::SetDone() {
251 if (entry_)
252 entry_->Close();
253 entry_ = NULL;
254 state_ = NONE;
255 return OK;
256 }
257
IsCallbackPending() const258 bool 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