• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/string_util.h"
8 #include "net/base/escape.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 #include "net/disk_cache/disk_cache.h"
12 #include "net/http/http_cache.h"
13 #include "net/http/http_response_headers.h"
14 #include "net/http/http_response_info.h"
15 #include "net/url_request/url_request_context.h"
16 
17 #define VIEW_CACHE_HEAD \
18   "<html><body><table>"
19 
20 #define VIEW_CACHE_TAIL \
21   "</table></body></html>"
22 
23 namespace net {
24 
25 namespace {
26 
HexDump(const char * buf,size_t buf_len,std::string * result)27 void HexDump(const char *buf, size_t buf_len, std::string* result) {
28   const size_t kMaxRows = 16;
29   int offset = 0;
30 
31   const unsigned char *p;
32   while (buf_len) {
33     base::StringAppendF(result, "%08x:  ", offset);
34     offset += kMaxRows;
35 
36     p = (const unsigned char *) buf;
37 
38     size_t i;
39     size_t row_max = std::min(kMaxRows, buf_len);
40 
41     // print hex codes:
42     for (i = 0; i < row_max; ++i)
43       base::StringAppendF(result, "%02x  ", *p++);
44     for (i = row_max; i < kMaxRows; ++i)
45       result->append("    ");
46 
47     // print ASCII glyphs if possible:
48     p = (const unsigned char *) buf;
49     for (i = 0; i < row_max; ++i, ++p) {
50       if (*p < 0x7F && *p > 0x1F) {
51         AppendEscapedCharForHTML(*p, result);
52       } else {
53         result->push_back('.');
54       }
55     }
56 
57     result->push_back('\n');
58 
59     buf += row_max;
60     buf_len -= row_max;
61   }
62 }
63 
FormatEntryInfo(disk_cache::Entry * entry,const std::string & url_prefix)64 std::string FormatEntryInfo(disk_cache::Entry* entry,
65                             const std::string& url_prefix) {
66   std::string key = entry->GetKey();
67   GURL url = GURL(url_prefix + key);
68   std::string row =
69       "<tr><td><a href=\"" + url.spec() + "\">" + EscapeForHTML(key) +
70       "</a></td></tr>";
71   return row;
72 }
73 
74 }  // namespace.
75 
ViewCacheHelper()76 ViewCacheHelper::ViewCacheHelper()
77     : disk_cache_(NULL),
78       entry_(NULL),
79       iter_(NULL),
80       buf_len_(0),
81       index_(0),
82       data_(NULL),
83       callback_(NULL),
84       next_state_(STATE_NONE),
85       ALLOW_THIS_IN_INITIALIZER_LIST(
86           cache_callback_(this, &ViewCacheHelper::OnIOComplete)),
87       ALLOW_THIS_IN_INITIALIZER_LIST(
88           entry_callback_(new CancelableCompletionCallback<ViewCacheHelper>(
89               this, &ViewCacheHelper::OnIOComplete))) {
90 }
91 
~ViewCacheHelper()92 ViewCacheHelper::~ViewCacheHelper() {
93   if (entry_)
94     entry_->Close();
95 
96   // Cancel any pending entry callback.
97   entry_callback_->Cancel();
98 }
99 
GetEntryInfoHTML(const std::string & key,URLRequestContext * context,std::string * out,CompletionCallback * callback)100 int ViewCacheHelper::GetEntryInfoHTML(const std::string& key,
101                                       URLRequestContext* context,
102                                       std::string* out,
103                                       CompletionCallback* callback) {
104   return GetInfoHTML(key, context, std::string(), out, callback);
105 }
106 
GetContentsHTML(URLRequestContext * context,const std::string & url_prefix,std::string * out,CompletionCallback * callback)107 int ViewCacheHelper::GetContentsHTML(URLRequestContext* context,
108                                      const std::string& url_prefix,
109                                      std::string* out,
110                                      CompletionCallback* callback) {
111   return GetInfoHTML(std::string(), context, url_prefix, out, callback);
112 }
113 
114 //-----------------------------------------------------------------------------
115 
GetInfoHTML(const std::string & key,URLRequestContext * context,const std::string & url_prefix,std::string * out,CompletionCallback * callback)116 int ViewCacheHelper::GetInfoHTML(const std::string& key,
117                                  URLRequestContext* context,
118                                  const std::string& url_prefix,
119                                  std::string* out,
120                                  CompletionCallback* callback) {
121   DCHECK(!callback_);
122   DCHECK(context);
123   key_ = key;
124   context_ = context;
125   url_prefix_ = url_prefix;
126   data_ = out;
127   next_state_ = STATE_GET_BACKEND;
128   int rv = DoLoop(OK);
129 
130   if (rv == ERR_IO_PENDING)
131     callback_ = callback;
132 
133   return rv;
134 }
135 
DoCallback(int rv)136 void ViewCacheHelper::DoCallback(int rv) {
137   DCHECK_NE(ERR_IO_PENDING, rv);
138   DCHECK(callback_);
139 
140   CompletionCallback* c = callback_;
141   callback_ = NULL;
142   c->Run(rv);
143 }
144 
HandleResult(int rv)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_)
150     DoCallback(rv);
151 }
152 
DoLoop(int result)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 
DoGetBackend()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(&disk_cache_, &cache_callback_);
221 }
222 
DoGetBackendComplete(int result)223 int ViewCacheHelper::DoGetBackendComplete(int result) {
224   if (result == ERR_FAILED) {
225     data_->append("no disk cache");
226     return OK;
227   }
228 
229   DCHECK_EQ(OK, result);
230   if (key_.empty()) {
231     data_->assign(VIEW_CACHE_HEAD);
232     DCHECK(!iter_);
233     next_state_ = STATE_OPEN_NEXT_ENTRY;
234     return OK;
235   }
236 
237   next_state_ = STATE_OPEN_ENTRY;
238   return OK;
239 }
240 
DoOpenNextEntry()241 int ViewCacheHelper::DoOpenNextEntry() {
242   next_state_ = STATE_OPEN_NEXT_ENTRY_COMPLETE;
243   return disk_cache_->OpenNextEntry(&iter_, &entry_, &cache_callback_);
244 }
245 
DoOpenNextEntryComplete(int result)246 int ViewCacheHelper::DoOpenNextEntryComplete(int result) {
247   if (result == ERR_FAILED) {
248     data_->append(VIEW_CACHE_TAIL);
249     return OK;
250   }
251 
252   DCHECK_EQ(OK, result);
253   data_->append(FormatEntryInfo(entry_, url_prefix_));
254   entry_->Close();
255   entry_ = NULL;
256 
257   next_state_ = STATE_OPEN_NEXT_ENTRY;
258   return OK;
259 }
260 
DoOpenEntry()261 int ViewCacheHelper::DoOpenEntry() {
262   next_state_ = STATE_OPEN_ENTRY_COMPLETE;
263   return disk_cache_->OpenEntry(key_, &entry_, &cache_callback_);
264 }
265 
DoOpenEntryComplete(int result)266 int ViewCacheHelper::DoOpenEntryComplete(int result) {
267   if (result == ERR_FAILED) {
268     data_->append("no matching cache entry for: " + EscapeForHTML(key_));
269     return OK;
270   }
271 
272   data_->assign(VIEW_CACHE_HEAD);
273   data_->append(EscapeForHTML(entry_->GetKey()));
274   next_state_ = STATE_READ_RESPONSE;
275   return OK;
276 }
277 
DoReadResponse()278 int ViewCacheHelper::DoReadResponse() {
279   next_state_ = STATE_READ_RESPONSE_COMPLETE;
280   buf_len_ = entry_->GetDataSize(0);
281   entry_callback_->AddRef();
282   if (!buf_len_)
283     return buf_len_;
284 
285   buf_ = new IOBuffer(buf_len_);
286   return entry_->ReadData(0, 0, buf_, buf_len_, entry_callback_);
287 }
288 
DoReadResponseComplete(int result)289 int ViewCacheHelper::DoReadResponseComplete(int result) {
290   entry_callback_->Release();
291   if (result && result == buf_len_) {
292     HttpResponseInfo response;
293     bool truncated;
294     if (HttpCache::ParseResponseInfo(buf_->data(), buf_len_, &response,
295                                           &truncated) &&
296         response.headers) {
297       if (truncated)
298         data_->append("<pre>RESPONSE_INFO_TRUNCATED</pre>");
299 
300       data_->append("<hr><pre>");
301       data_->append(EscapeForHTML(response.headers->GetStatusLine()));
302       data_->push_back('\n');
303 
304       void* iter = NULL;
305       std::string name, value;
306       while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) {
307         data_->append(EscapeForHTML(name));
308         data_->append(": ");
309         data_->append(EscapeForHTML(value));
310         data_->push_back('\n');
311       }
312       data_->append("</pre>");
313     }
314   }
315 
316   index_ = 0;
317   next_state_ = STATE_READ_DATA;
318   return OK;
319 }
320 
DoReadData()321 int ViewCacheHelper::DoReadData() {
322   data_->append("<hr><pre>");
323 
324   next_state_ = STATE_READ_DATA_COMPLETE;
325   buf_len_ = entry_->GetDataSize(index_);
326   entry_callback_->AddRef();
327   if (!buf_len_)
328     return buf_len_;
329 
330   buf_ = new IOBuffer(buf_len_);
331   return entry_->ReadData(index_, 0, buf_, buf_len_, entry_callback_);
332 }
333 
DoReadDataComplete(int result)334 int ViewCacheHelper::DoReadDataComplete(int result) {
335   entry_callback_->Release();
336   if (result && result == buf_len_) {
337     HexDump(buf_->data(), buf_len_, data_);
338   }
339   data_->append("</pre>");
340   index_++;
341   if (index_ < HttpCache::kNumCacheEntryDataIndices) {
342     next_state_ = STATE_READ_DATA;
343   } else {
344     data_->append(VIEW_CACHE_TAIL);
345     entry_->Close();
346     entry_ = NULL;
347   }
348   return OK;
349 }
350 
OnIOComplete(int result)351 void ViewCacheHelper::OnIOComplete(int result) {
352   DoLoop(result);
353 }
354 
355 }  // namespace net.
356