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
) {