OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/url_request/view_cache_helper.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/profiler/scoped_tracker.h" | |
10 #include "base/strings/stringprintf.h" | |
11 #include "net/base/escape.h" | |
12 #include "net/base/io_buffer.h" | |
13 #include "net/base/net_errors.h" | |
14 #include "net/disk_cache/disk_cache.h" | |
15 #include "net/http/http_cache.h" | |
16 #include "net/http/http_response_headers.h" | |
17 #include "net/http/http_response_info.h" | |
18 #include "net/url_request/url_request_context.h" | |
19 | |
20 #define VIEW_CACHE_HEAD \ | |
21 "<html><meta charset=\"utf-8\">" \ | |
22 "<meta http-equiv=\"Content-Security-Policy\" " \ | |
23 " content=\"object-src 'none'; script-src 'none' 'unsafe-eval'\">" \ | |
24 "<body><table>" | |
25 | |
26 #define VIEW_CACHE_TAIL \ | |
27 "</table></body></html>" | |
28 | |
29 namespace net { | |
30 | |
31 namespace { | |
32 | |
33 std::string FormatEntryInfo(disk_cache::Entry* entry, | |
34 const std::string& url_prefix) { | |
35 std::string key = entry->GetKey(); | |
36 GURL url = GURL(url_prefix + key); | |
37 std::string row = | |
38 "<tr><td><a href=\"" + url.spec() + "\">" + EscapeForHTML(key) + | |
39 "</a></td></tr>"; | |
40 return row; | |
41 } | |
42 | |
43 } // namespace. | |
44 | |
45 ViewCacheHelper::ViewCacheHelper() | |
46 : context_(NULL), | |
47 disk_cache_(NULL), | |
48 entry_(NULL), | |
49 buf_len_(0), | |
50 index_(0), | |
51 data_(NULL), | |
52 next_state_(STATE_NONE), | |
53 weak_factory_(this) { | |
54 } | |
55 | |
56 ViewCacheHelper::~ViewCacheHelper() { | |
57 if (entry_) | |
58 entry_->Close(); | |
59 } | |
60 | |
61 int ViewCacheHelper::GetEntryInfoHTML(const std::string& key, | |
62 const URLRequestContext* context, | |
63 std::string* out, | |
64 const CompletionCallback& callback) { | |
65 return GetInfoHTML(key, context, std::string(), out, callback); | |
66 } | |
67 | |
68 int ViewCacheHelper::GetContentsHTML(const URLRequestContext* context, | |
69 const std::string& url_prefix, | |
70 std::string* out, | |
71 const CompletionCallback& callback) { | |
72 return GetInfoHTML(std::string(), context, url_prefix, out, callback); | |
73 } | |
74 | |
75 // static | |
76 void ViewCacheHelper::HexDump(const char *buf, size_t buf_len, | |
77 std::string* result) { | |
78 const size_t kMaxRows = 16; | |
79 int offset = 0; | |
80 | |
81 const unsigned char *p; | |
82 while (buf_len) { | |
83 base::StringAppendF(result, "%08x: ", offset); | |
84 offset += kMaxRows; | |
85 | |
86 p = (const unsigned char *) buf; | |
87 | |
88 size_t i; | |
89 size_t row_max = std::min(kMaxRows, buf_len); | |
90 | |
91 // print hex codes: | |
92 for (i = 0; i < row_max; ++i) | |
93 base::StringAppendF(result, "%02x ", *p++); | |
94 for (i = row_max; i < kMaxRows; ++i) | |
95 result->append(" "); | |
96 result->append(" "); | |
97 | |
98 // print ASCII glyphs if possible: | |
99 p = (const unsigned char *) buf; | |
100 for (i = 0; i < row_max; ++i, ++p) { | |
101 if (*p < 0x7F && *p > 0x1F) { | |
102 AppendEscapedCharForHTML(*p, result); | |
103 } else { | |
104 result->push_back('.'); | |
105 } | |
106 } | |
107 | |
108 result->push_back('\n'); | |
109 | |
110 buf += row_max; | |
111 buf_len -= row_max; | |
112 } | |
113 } | |
114 | |
115 //----------------------------------------------------------------------------- | |
116 | |
117 int ViewCacheHelper::GetInfoHTML(const std::string& key, | |
118 const URLRequestContext* context, | |
119 const std::string& url_prefix, | |
120 std::string* out, | |
121 const CompletionCallback& callback) { | |
122 DCHECK(callback_.is_null()); | |
123 DCHECK(context); | |
124 key_ = key; | |
125 context_ = context; | |
126 url_prefix_ = url_prefix; | |
127 data_ = out; | |
128 next_state_ = STATE_GET_BACKEND; | |
129 int rv = DoLoop(OK); | |
130 | |
131 if (rv == ERR_IO_PENDING) | |
132 callback_ = callback; | |
133 | |
134 return rv; | |
135 } | |
136 | |
137 void ViewCacheHelper::DoCallback(int rv) { | |
138 DCHECK_NE(ERR_IO_PENDING, rv); | |
139 DCHECK(!callback_.is_null()); | |
140 | |
141 callback_.Run(rv); | |
142 callback_.Reset(); | |
143 } | |
144 | |
145 void ViewCacheHelper::HandleResult(int rv) { | |
146 DCHECK_NE(ERR_IO_PENDING, rv); | |
147 DCHECK_NE(ERR_FAILED, rv); | |
148 context_ = NULL; | |
149 if (!callback_.is_null()) | |
150 DoCallback(rv); | |
151 } | |
152 | |
153 int ViewCacheHelper::DoLoop(int result) { | |
154 DCHECK(next_state_ != STATE_NONE); | |
155 | |
156 int rv = result; | |
157 do { | |
158 State state = next_state_; | |
159 next_state_ = STATE_NONE; | |
160 switch (state) { | |
161 case STATE_GET_BACKEND: | |
162 DCHECK_EQ(OK, rv); | |
163 rv = DoGetBackend(); | |
164 break; | |
165 case STATE_GET_BACKEND_COMPLETE: | |
166 rv = DoGetBackendComplete(rv); | |
167 break; | |
168 case STATE_OPEN_NEXT_ENTRY: | |
169 DCHECK_EQ(OK, rv); | |
170 rv = DoOpenNextEntry(); | |
171 break; | |
172 case STATE_OPEN_NEXT_ENTRY_COMPLETE: | |
173 rv = DoOpenNextEntryComplete(rv); | |
174 break; | |
175 case STATE_OPEN_ENTRY: | |
176 DCHECK_EQ(OK, rv); | |
177 rv = DoOpenEntry(); | |
178 break; | |
179 case STATE_OPEN_ENTRY_COMPLETE: | |
180 rv = DoOpenEntryComplete(rv); | |
181 break; | |
182 case STATE_READ_RESPONSE: | |
183 DCHECK_EQ(OK, rv); | |
184 rv = DoReadResponse(); | |
185 break; | |
186 case STATE_READ_RESPONSE_COMPLETE: | |
187 rv = DoReadResponseComplete(rv); | |
188 break; | |
189 case STATE_READ_DATA: | |
190 DCHECK_EQ(OK, rv); | |
191 rv = DoReadData(); | |
192 break; | |
193 case STATE_READ_DATA_COMPLETE: | |
194 rv = DoReadDataComplete(rv); | |
195 break; | |
196 | |
197 default: | |
198 NOTREACHED() << "bad state"; | |
199 rv = ERR_FAILED; | |
200 break; | |
201 } | |
202 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | |
203 | |
204 if (rv != ERR_IO_PENDING) | |
205 HandleResult(rv); | |
206 | |
207 return rv; | |
208 } | |
209 | |
210 int ViewCacheHelper::DoGetBackend() { | |
211 next_state_ = STATE_GET_BACKEND_COMPLETE; | |
212 | |
213 if (!context_->http_transaction_factory()) | |
214 return ERR_FAILED; | |
215 | |
216 HttpCache* http_cache = context_->http_transaction_factory()->GetCache(); | |
217 if (!http_cache) | |
218 return ERR_FAILED; | |
219 | |
220 return http_cache->GetBackend( | |
221 &disk_cache_, base::Bind(&ViewCacheHelper::OnIOComplete, | |
222 base::Unretained(this))); | |
223 } | |
224 | |
225 int ViewCacheHelper::DoGetBackendComplete(int result) { | |
226 if (result == ERR_FAILED) { | |
227 data_->append("no disk cache"); | |
228 return OK; | |
229 } | |
230 | |
231 DCHECK_EQ(OK, result); | |
232 if (key_.empty()) { | |
233 data_->assign(VIEW_CACHE_HEAD); | |
234 DCHECK(!iter_); | |
235 next_state_ = STATE_OPEN_NEXT_ENTRY; | |
236 return OK; | |
237 } | |
238 | |
239 next_state_ = STATE_OPEN_ENTRY; | |
240 return OK; | |
241 } | |
242 | |
243 int ViewCacheHelper::DoOpenNextEntry() { | |
244 next_state_ = STATE_OPEN_NEXT_ENTRY_COMPLETE; | |
245 if (!iter_) | |
246 iter_ = disk_cache_->CreateIterator(); | |
247 return | |
248 iter_->OpenNextEntry(&entry_, base::Bind(&ViewCacheHelper::OnIOComplete, | |
249 base::Unretained(this))); | |
250 } | |
251 | |
252 int ViewCacheHelper::DoOpenNextEntryComplete(int result) { | |
253 if (result == ERR_FAILED) { | |
254 data_->append(VIEW_CACHE_TAIL); | |
255 return OK; | |
256 } | |
257 | |
258 DCHECK_EQ(OK, result); | |
259 data_->append(FormatEntryInfo(entry_, url_prefix_)); | |
260 entry_->Close(); | |
261 entry_ = NULL; | |
262 | |
263 next_state_ = STATE_OPEN_NEXT_ENTRY; | |
264 return OK; | |
265 } | |
266 | |
267 int ViewCacheHelper::DoOpenEntry() { | |
268 next_state_ = STATE_OPEN_ENTRY_COMPLETE; | |
269 return disk_cache_->OpenEntry( | |
270 key_, &entry_, | |
271 base::Bind(&ViewCacheHelper::OnIOComplete, base::Unretained(this))); | |
272 } | |
273 | |
274 int ViewCacheHelper::DoOpenEntryComplete(int result) { | |
275 if (result == ERR_FAILED) { | |
276 data_->append("no matching cache entry for: " + EscapeForHTML(key_)); | |
277 return OK; | |
278 } | |
279 | |
280 data_->assign(VIEW_CACHE_HEAD); | |
281 data_->append(EscapeForHTML(entry_->GetKey())); | |
282 next_state_ = STATE_READ_RESPONSE; | |
283 return OK; | |
284 } | |
285 | |
286 int ViewCacheHelper::DoReadResponse() { | |
287 next_state_ = STATE_READ_RESPONSE_COMPLETE; | |
288 buf_len_ = entry_->GetDataSize(0); | |
289 if (!buf_len_) | |
290 return buf_len_; | |
291 | |
292 buf_ = new IOBuffer(buf_len_); | |
293 return entry_->ReadData( | |
294 0, | |
295 0, | |
296 buf_.get(), | |
297 buf_len_, | |
298 base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr())); | |
299 } | |
300 | |
301 int ViewCacheHelper::DoReadResponseComplete(int result) { | |
302 if (result && result == buf_len_) { | |
303 HttpResponseInfo response; | |
304 bool truncated; | |
305 if (HttpCache::ParseResponseInfo( | |
306 buf_->data(), buf_len_, &response, &truncated) && | |
307 response.headers.get()) { | |
308 if (truncated) | |
309 data_->append("<pre>RESPONSE_INFO_TRUNCATED</pre>"); | |
310 | |
311 data_->append("<hr><pre>"); | |
312 data_->append(EscapeForHTML(response.headers->GetStatusLine())); | |
313 data_->push_back('\n'); | |
314 | |
315 void* iter = NULL; | |
316 std::string name, value; | |
317 while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) { | |
318 data_->append(EscapeForHTML(name)); | |
319 data_->append(": "); | |
320 data_->append(EscapeForHTML(value)); | |
321 data_->push_back('\n'); | |
322 } | |
323 data_->append("</pre>"); | |
324 } | |
325 } | |
326 | |
327 index_ = 0; | |
328 next_state_ = STATE_READ_DATA; | |
329 return OK; | |
330 } | |
331 | |
332 int ViewCacheHelper::DoReadData() { | |
333 data_->append("<hr><pre>"); | |
334 | |
335 next_state_ = STATE_READ_DATA_COMPLETE; | |
336 buf_len_ = entry_->GetDataSize(index_); | |
337 if (!buf_len_) | |
338 return buf_len_; | |
339 | |
340 buf_ = new IOBuffer(buf_len_); | |
341 return entry_->ReadData( | |
342 index_, | |
343 0, | |
344 buf_.get(), | |
345 buf_len_, | |
346 base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr())); | |
347 } | |
348 | |
349 int ViewCacheHelper::DoReadDataComplete(int result) { | |
350 if (result && result == buf_len_) { | |
351 HexDump(buf_->data(), buf_len_, data_); | |
352 } | |
353 data_->append("</pre>"); | |
354 index_++; | |
355 if (index_ < HttpCache::kNumCacheEntryDataIndices) { | |
356 next_state_ = STATE_READ_DATA; | |
357 } else { | |
358 data_->append(VIEW_CACHE_TAIL); | |
359 entry_->Close(); | |
360 entry_ = NULL; | |
361 } | |
362 return OK; | |
363 } | |
364 | |
365 void ViewCacheHelper::OnIOComplete(int result) { | |
366 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed. | |
367 tracked_objects::ScopedTracker tracking_profile( | |
368 FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 ViewCacheHelper::OnIOComplete")); | |
369 | |
370 DoLoop(result); | |
371 } | |
372 | |
373 } // namespace net. | |
OLD | NEW |