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()
51 next_state_(STATE_NONE
),
55 ViewCacheHelper::~ViewCacheHelper() {
60 int ViewCacheHelper::GetEntryInfoHTML(const std::string
& key
,
61 const URLRequestContext
* context
,
63 const CompletionCallback
& callback
) {
64 return GetInfoHTML(key
, context
, std::string(), out
, callback
);
67 int ViewCacheHelper::GetContentsHTML(const URLRequestContext
* context
,
68 const std::string
& url_prefix
,
70 const CompletionCallback
& callback
) {
71 return GetInfoHTML(std::string(), context
, url_prefix
, out
, callback
);
75 void ViewCacheHelper::HexDump(const char *buf
, size_t buf_len
,
76 std::string
* result
) {
77 const size_t kMaxRows
= 16;
80 const unsigned char *p
;
82 base::StringAppendF(result
, "%08x: ", offset
);
85 p
= (const unsigned char *) buf
;
88 size_t row_max
= std::min(kMaxRows
, buf_len
);
91 for (i
= 0; i
< row_max
; ++i
)
92 base::StringAppendF(result
, "%02x ", *p
++);
93 for (i
= row_max
; i
< kMaxRows
; ++i
)
97 // print ASCII glyphs if possible:
98 p
= (const unsigned char *) buf
;
99 for (i
= 0; i
< row_max
; ++i
, ++p
) {
100 if (*p
< 0x7F && *p
> 0x1F) {
101 AppendEscapedCharForHTML(*p
, result
);
103 result
->push_back('.');
107 result
->push_back('\n');
114 //-----------------------------------------------------------------------------
116 int ViewCacheHelper::GetInfoHTML(const std::string
& key
,
117 const URLRequestContext
* context
,
118 const std::string
& url_prefix
,
120 const CompletionCallback
& callback
) {
121 DCHECK(callback_
.is_null());
125 url_prefix_
= url_prefix
;
127 next_state_
= STATE_GET_BACKEND
;
130 if (rv
== ERR_IO_PENDING
)
131 callback_
= callback
;
136 void ViewCacheHelper::DoCallback(int rv
) {
137 DCHECK_NE(ERR_IO_PENDING
, rv
);
138 DCHECK(!callback_
.is_null());
144 void ViewCacheHelper::HandleResult(int rv
) {
145 DCHECK_NE(ERR_IO_PENDING
, rv
);
146 DCHECK_NE(ERR_FAILED
, rv
);
148 if (!callback_
.is_null())
152 int ViewCacheHelper::DoLoop(int result
) {
153 DCHECK(next_state_
!= STATE_NONE
);
157 State state
= next_state_
;
158 next_state_
= STATE_NONE
;
160 case STATE_GET_BACKEND
:
164 case STATE_GET_BACKEND_COMPLETE
:
165 rv
= DoGetBackendComplete(rv
);
167 case STATE_OPEN_NEXT_ENTRY
:
169 rv
= DoOpenNextEntry();
171 case STATE_OPEN_NEXT_ENTRY_COMPLETE
:
172 rv
= DoOpenNextEntryComplete(rv
);
174 case STATE_OPEN_ENTRY
:
178 case STATE_OPEN_ENTRY_COMPLETE
:
179 rv
= DoOpenEntryComplete(rv
);
181 case STATE_READ_RESPONSE
:
183 rv
= DoReadResponse();
185 case STATE_READ_RESPONSE_COMPLETE
:
186 rv
= DoReadResponseComplete(rv
);
188 case STATE_READ_DATA
:
192 case STATE_READ_DATA_COMPLETE
:
193 rv
= DoReadDataComplete(rv
);
197 NOTREACHED() << "bad state";
201 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
);
203 if (rv
!= ERR_IO_PENDING
)
209 int ViewCacheHelper::DoGetBackend() {
210 next_state_
= STATE_GET_BACKEND_COMPLETE
;
212 if (!context_
->http_transaction_factory())
215 HttpCache
* http_cache
= context_
->http_transaction_factory()->GetCache();
219 return http_cache
->GetBackend(
220 &disk_cache_
, base::Bind(&ViewCacheHelper::OnIOComplete
,
221 base::Unretained(this)));
224 int ViewCacheHelper::DoGetBackendComplete(int result
) {
225 if (result
== ERR_FAILED
) {
226 data_
->append("no disk cache");
230 DCHECK_EQ(OK
, result
);
232 data_
->assign(VIEW_CACHE_HEAD
);
234 next_state_
= STATE_OPEN_NEXT_ENTRY
;
238 next_state_
= STATE_OPEN_ENTRY
;
242 int ViewCacheHelper::DoOpenNextEntry() {
243 next_state_
= STATE_OPEN_NEXT_ENTRY_COMPLETE
;
245 iter_
= disk_cache_
->CreateIterator();
247 iter_
->OpenNextEntry(&entry_
, base::Bind(&ViewCacheHelper::OnIOComplete
,
248 base::Unretained(this)));
251 int ViewCacheHelper::DoOpenNextEntryComplete(int result
) {
252 if (result
== ERR_FAILED
) {
253 data_
->append(VIEW_CACHE_TAIL
);
257 DCHECK_EQ(OK
, result
);
258 data_
->append(FormatEntryInfo(entry_
, url_prefix_
));
262 next_state_
= STATE_OPEN_NEXT_ENTRY
;
266 int ViewCacheHelper::DoOpenEntry() {
267 next_state_
= STATE_OPEN_ENTRY_COMPLETE
;
268 return disk_cache_
->OpenEntry(
270 base::Bind(&ViewCacheHelper::OnIOComplete
, base::Unretained(this)));
273 int ViewCacheHelper::DoOpenEntryComplete(int result
) {
274 if (result
== ERR_FAILED
) {
275 data_
->append("no matching cache entry for: " + EscapeForHTML(key_
));
279 data_
->assign(VIEW_CACHE_HEAD
);
280 data_
->append(EscapeForHTML(entry_
->GetKey()));
281 next_state_
= STATE_READ_RESPONSE
;
285 int ViewCacheHelper::DoReadResponse() {
286 next_state_
= STATE_READ_RESPONSE_COMPLETE
;
287 buf_len_
= entry_
->GetDataSize(0);
291 buf_
= new IOBuffer(buf_len_
);
292 return entry_
->ReadData(
297 base::Bind(&ViewCacheHelper::OnIOComplete
, weak_factory_
.GetWeakPtr()));
300 int ViewCacheHelper::DoReadResponseComplete(int result
) {
301 if (result
&& result
== buf_len_
) {
302 HttpResponseInfo response
;
304 if (HttpCache::ParseResponseInfo(
305 buf_
->data(), buf_len_
, &response
, &truncated
) &&
306 response
.headers
.get()) {
308 data_
->append("<pre>RESPONSE_INFO_TRUNCATED</pre>");
310 data_
->append("<hr><pre>");
311 data_
->append(EscapeForHTML(response
.headers
->GetStatusLine()));
312 data_
->push_back('\n');
315 std::string name
, value
;
316 while (response
.headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
317 data_
->append(EscapeForHTML(name
));
319 data_
->append(EscapeForHTML(value
));
320 data_
->push_back('\n');
322 data_
->append("</pre>");
327 next_state_
= STATE_READ_DATA
;
331 int ViewCacheHelper::DoReadData() {
332 data_
->append("<hr><pre>");
334 next_state_
= STATE_READ_DATA_COMPLETE
;
335 buf_len_
= entry_
->GetDataSize(index_
);
339 buf_
= new IOBuffer(buf_len_
);
340 return entry_
->ReadData(
345 base::Bind(&ViewCacheHelper::OnIOComplete
, weak_factory_
.GetWeakPtr()));
348 int ViewCacheHelper::DoReadDataComplete(int result
) {
349 if (result
&& result
== buf_len_
) {
350 HexDump(buf_
->data(), buf_len_
, data_
);
352 data_
->append("</pre>");
354 if (index_
< HttpCache::kNumCacheEntryDataIndices
) {
355 next_state_
= STATE_READ_DATA
;
357 data_
->append(VIEW_CACHE_TAIL
);
364 void ViewCacheHelper::OnIOComplete(int result
) {