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/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"
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'\">" \
26 #define VIEW_CACHE_TAIL \
27 "</table></body></html>"
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
);
38 "<tr><td><a href=\"" + url
.spec() + "\">" + EscapeForHTML(key
) +
45 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
;
246 iter_
= disk_cache_
->CreateIterator();
248 iter_
->OpenNextEntry(&entry_
, base::Bind(&ViewCacheHelper::OnIOComplete
,
249 base::Unretained(this)));
252 int ViewCacheHelper::DoOpenNextEntryComplete(int result
) {
253 if (result
== ERR_FAILED
) {
254 data_
->append(VIEW_CACHE_TAIL
);
258 DCHECK_EQ(OK
, result
);
259 data_
->append(FormatEntryInfo(entry_
, url_prefix_
));
263 next_state_
= STATE_OPEN_NEXT_ENTRY
;
267 int ViewCacheHelper::DoOpenEntry() {
268 next_state_
= STATE_OPEN_ENTRY_COMPLETE
;
269 return disk_cache_
->OpenEntry(
271 base::Bind(&ViewCacheHelper::OnIOComplete
, base::Unretained(this)));
274 int ViewCacheHelper::DoOpenEntryComplete(int result
) {
275 if (result
== ERR_FAILED
) {
276 data_
->append("no matching cache entry for: " + EscapeForHTML(key_
));
280 data_
->assign(VIEW_CACHE_HEAD
);
281 data_
->append(EscapeForHTML(entry_
->GetKey()));
282 next_state_
= STATE_READ_RESPONSE
;
286 int ViewCacheHelper::DoReadResponse() {
287 next_state_
= STATE_READ_RESPONSE_COMPLETE
;
288 buf_len_
= entry_
->GetDataSize(0);
292 buf_
= new IOBuffer(buf_len_
);
293 return entry_
->ReadData(
298 base::Bind(&ViewCacheHelper::OnIOComplete
, weak_factory_
.GetWeakPtr()));
301 int ViewCacheHelper::DoReadResponseComplete(int result
) {
302 if (result
&& result
== buf_len_
) {
303 HttpResponseInfo response
;
305 if (HttpCache::ParseResponseInfo(
306 buf_
->data(), buf_len_
, &response
, &truncated
) &&
307 response
.headers
.get()) {
309 data_
->append("<pre>RESPONSE_INFO_TRUNCATED</pre>");
311 data_
->append("<hr><pre>");
312 data_
->append(EscapeForHTML(response
.headers
->GetStatusLine()));
313 data_
->push_back('\n');
316 std::string name
, value
;
317 while (response
.headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
318 data_
->append(EscapeForHTML(name
));
320 data_
->append(EscapeForHTML(value
));
321 data_
->push_back('\n');
323 data_
->append("</pre>");
328 next_state_
= STATE_READ_DATA
;
332 int ViewCacheHelper::DoReadData() {
333 data_
->append("<hr><pre>");
335 next_state_
= STATE_READ_DATA_COMPLETE
;
336 buf_len_
= entry_
->GetDataSize(index_
);
340 buf_
= new IOBuffer(buf_len_
);
341 return entry_
->ReadData(
346 base::Bind(&ViewCacheHelper::OnIOComplete
, weak_factory_
.GetWeakPtr()));
349 int ViewCacheHelper::DoReadDataComplete(int result
) {
350 if (result
&& result
== buf_len_
) {
351 HexDump(buf_
->data(), buf_len_
, data_
);
353 data_
->append("</pre>");
355 if (index_
< HttpCache::kNumCacheEntryDataIndices
) {
356 next_state_
= STATE_READ_DATA
;
358 data_
->append(VIEW_CACHE_TAIL
);
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"));