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