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.
5 #include "net/url_request/view_cache_helper.h"
8 #include "base/bind_helpers.h"
9 #include "base/strings/stringprintf.h"
10 #include "net/base/escape.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13 #include "net/disk_cache/disk_cache.h"
14 #include "net/http/http_cache.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/http/http_response_info.h"
17 #include "net/url_request/url_request_context.h"
19 #define VIEW_CACHE_HEAD \
20 "<html><meta charset=\"utf-8\">" \
21 "<meta http-equiv=\"Content-Security-Policy\" " \
22 " content=\"object-src 'none'; script-src 'none' 'unsafe-eval'\">" \
25 #define VIEW_CACHE_TAIL \
26 "</table></body></html>"
32 std::string FormatEntryInfo(disk_cache::Entry* entry,
33 const std::string& url_prefix) {
34 std::string key = entry->GetKey();
35 GURL url = GURL(url_prefix + key);
37 "<tr><td><a href=\"" + url.spec() + "\">" + EscapeForHTML(key) +
44 ViewCacheHelper::ViewCacheHelper()
52 next_state_(STATE_NONE),
56 ViewCacheHelper::~ViewCacheHelper() {
61 int ViewCacheHelper::GetEntryInfoHTML(const std::string& key,
62 const URLRequestContext* context,
64 const CompletionCallback& callback) {
65 return GetInfoHTML(key, context, std::string(), out, callback);
68 int ViewCacheHelper::GetContentsHTML(const URLRequestContext* context,
69 const std::string& url_prefix,
71 const CompletionCallback& callback) {
72 return GetInfoHTML(std::string(), context, url_prefix, out, callback);
76 void ViewCacheHelper::HexDump(const char *buf, size_t buf_len,
77 std::string* result) {
78 const size_t kMaxRows = 16;
81 const unsigned char *p;
83 base::StringAppendF(result, "%08x: ", offset);
86 p = (const unsigned char *) buf;
89 size_t row_max = std::min(kMaxRows, buf_len);
92 for (i = 0; i < row_max; ++i)
93 base::StringAppendF(result, "%02x ", *p++);
94 for (i = row_max; i < kMaxRows; ++i)
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);
104 result->push_back('.');
108 result->push_back('\n');
115 //-----------------------------------------------------------------------------
117 int ViewCacheHelper::GetInfoHTML(const std::string& key,
118 const URLRequestContext* context,
119 const std::string& url_prefix,
121 const CompletionCallback& callback) {
122 DCHECK(callback_.is_null());
126 url_prefix_ = url_prefix;
128 next_state_ = STATE_GET_BACKEND;
131 if (rv == ERR_IO_PENDING)
132 callback_ = callback;
137 void ViewCacheHelper::DoCallback(int rv) {
138 DCHECK_NE(ERR_IO_PENDING, rv);
139 DCHECK(!callback_.is_null());
145 void ViewCacheHelper::HandleResult(int rv) {
146 DCHECK_NE(ERR_IO_PENDING, rv);
147 DCHECK_NE(ERR_FAILED, rv);
149 if (!callback_.is_null())
153 int ViewCacheHelper::DoLoop(int result) {
154 DCHECK(next_state_ != STATE_NONE);
158 State state = next_state_;
159 next_state_ = STATE_NONE;
161 case STATE_GET_BACKEND:
165 case STATE_GET_BACKEND_COMPLETE:
166 rv = DoGetBackendComplete(rv);
168 case STATE_OPEN_NEXT_ENTRY:
170 rv = DoOpenNextEntry();
172 case STATE_OPEN_NEXT_ENTRY_COMPLETE:
173 rv = DoOpenNextEntryComplete(rv);
175 case STATE_OPEN_ENTRY:
179 case STATE_OPEN_ENTRY_COMPLETE:
180 rv = DoOpenEntryComplete(rv);
182 case STATE_READ_RESPONSE:
184 rv = DoReadResponse();
186 case STATE_READ_RESPONSE_COMPLETE:
187 rv = DoReadResponseComplete(rv);
189 case STATE_READ_DATA:
193 case STATE_READ_DATA_COMPLETE:
194 rv = DoReadDataComplete(rv);
198 NOTREACHED() << "bad state";
202 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
204 if (rv != ERR_IO_PENDING)
210 int ViewCacheHelper::DoGetBackend() {
211 next_state_ = STATE_GET_BACKEND_COMPLETE;
213 if (!context_->http_transaction_factory())
216 HttpCache* http_cache = context_->http_transaction_factory()->GetCache();
220 return http_cache->GetBackend(
221 &disk_cache_, base::Bind(&ViewCacheHelper::OnIOComplete,
222 base::Unretained(this)));
225 int ViewCacheHelper::DoGetBackendComplete(int result) {
226 if (result == ERR_FAILED) {
227 data_->append("no disk cache");
231 DCHECK_EQ(OK, result);
233 data_->assign(VIEW_CACHE_HEAD);
235 next_state_ = STATE_OPEN_NEXT_ENTRY;
239 next_state_ = STATE_OPEN_ENTRY;
243 int ViewCacheHelper::DoOpenNextEntry() {
244 next_state_ = STATE_OPEN_NEXT_ENTRY_COMPLETE;
245 return disk_cache_->OpenNextEntry(
247 base::Bind(&ViewCacheHelper::OnIOComplete, base::Unretained(this)));
250 int ViewCacheHelper::DoOpenNextEntryComplete(int result) {
251 if (result == ERR_FAILED) {
252 data_->append(VIEW_CACHE_TAIL);
256 DCHECK_EQ(OK, result);
257 data_->append(FormatEntryInfo(entry_, url_prefix_));
261 next_state_ = STATE_OPEN_NEXT_ENTRY;
265 int ViewCacheHelper::DoOpenEntry() {
266 next_state_ = STATE_OPEN_ENTRY_COMPLETE;
267 return disk_cache_->OpenEntry(
269 base::Bind(&ViewCacheHelper::OnIOComplete, base::Unretained(this)));
272 int ViewCacheHelper::DoOpenEntryComplete(int result) {
273 if (result == ERR_FAILED) {
274 data_->append("no matching cache entry for: " + EscapeForHTML(key_));
278 data_->assign(VIEW_CACHE_HEAD);
279 data_->append(EscapeForHTML(entry_->GetKey()));
280 next_state_ = STATE_READ_RESPONSE;
284 int ViewCacheHelper::DoReadResponse() {
285 next_state_ = STATE_READ_RESPONSE_COMPLETE;
286 buf_len_ = entry_->GetDataSize(0);
290 buf_ = new IOBuffer(buf_len_);
291 return entry_->ReadData(
296 base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr()));
299 int ViewCacheHelper::DoReadResponseComplete(int result) {
300 if (result && result == buf_len_) {
301 HttpResponseInfo response;
303 if (HttpCache::ParseResponseInfo(
304 buf_->data(), buf_len_, &response, &truncated) &&
305 response.headers.get()) {
307 data_->append("<pre>RESPONSE_INFO_TRUNCATED</pre>");
309 data_->append("<hr><pre>");
310 data_->append(EscapeForHTML(response.headers->GetStatusLine()));
311 data_->push_back('\n');
314 std::string name, value;
315 while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) {
316 data_->append(EscapeForHTML(name));
318 data_->append(EscapeForHTML(value));
319 data_->push_back('\n');
321 data_->append("</pre>");
326 next_state_ = STATE_READ_DATA;
330 int ViewCacheHelper::DoReadData() {
331 data_->append("<hr><pre>");
333 next_state_ = STATE_READ_DATA_COMPLETE;
334 buf_len_ = entry_->GetDataSize(index_);
338 buf_ = new IOBuffer(buf_len_);
339 return entry_->ReadData(
344 base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr()));
347 int ViewCacheHelper::DoReadDataComplete(int result) {
348 if (result && result == buf_len_) {
349 HexDump(buf_->data(), buf_len_, data_);
351 data_->append("</pre>");
353 if (index_ < HttpCache::kNumCacheEntryDataIndices) {
354 next_state_ = STATE_READ_DATA;
356 data_->append(VIEW_CACHE_TAIL);
363 void ViewCacheHelper::OnIOComplete(int result) {