Upstream version 10.39.225.0
[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       buf_len_(0),
49       index_(0),
50       data_(NULL),
51       next_state_(STATE_NONE),
52       weak_factory_(this) {
53 }
54
55 ViewCacheHelper::~ViewCacheHelper() {
56   if (entry_)
57     entry_->Close();
58 }
59
60 int ViewCacheHelper::GetEntryInfoHTML(const std::string& key,
61                                       const URLRequestContext* context,
62                                       std::string* out,
63                                       const CompletionCallback& callback) {
64   return GetInfoHTML(key, context, std::string(), out, callback);
65 }
66
67 int ViewCacheHelper::GetContentsHTML(const URLRequestContext* context,
68                                      const std::string& url_prefix,
69                                      std::string* out,
70                                      const CompletionCallback& callback) {
71   return GetInfoHTML(std::string(), context, url_prefix, out, callback);
72 }
73
74 // static
75 void ViewCacheHelper::HexDump(const char *buf, size_t buf_len,
76                               std::string* result) {
77   const size_t kMaxRows = 16;
78   int offset = 0;
79
80   const unsigned char *p;
81   while (buf_len) {
82     base::StringAppendF(result, "%08x: ", offset);
83     offset += kMaxRows;
84
85     p = (const unsigned char *) buf;
86
87     size_t i;
88     size_t row_max = std::min(kMaxRows, buf_len);
89
90     // print hex codes:
91     for (i = 0; i < row_max; ++i)
92       base::StringAppendF(result, "%02x ", *p++);
93     for (i = row_max; i < kMaxRows; ++i)
94       result->append("   ");
95     result->append(" ");
96
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);
102       } else {
103         result->push_back('.');
104       }
105     }
106
107     result->push_back('\n');
108
109     buf += row_max;
110     buf_len -= row_max;
111   }
112 }
113
114 //-----------------------------------------------------------------------------
115
116 int ViewCacheHelper::GetInfoHTML(const std::string& key,
117                                  const URLRequestContext* context,
118                                  const std::string& url_prefix,
119                                  std::string* out,
120                                  const CompletionCallback& callback) {
121   DCHECK(callback_.is_null());
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
136 void ViewCacheHelper::DoCallback(int rv) {
137   DCHECK_NE(ERR_IO_PENDING, rv);
138   DCHECK(!callback_.is_null());
139
140   callback_.Run(rv);
141   callback_.Reset();
142 }
143
144 void ViewCacheHelper::HandleResult(int rv) {
145   DCHECK_NE(ERR_IO_PENDING, rv);
146   DCHECK_NE(ERR_FAILED, rv);
147   context_ = NULL;
148   if (!callback_.is_null())
149     DoCallback(rv);
150 }
151
152 int ViewCacheHelper::DoLoop(int result) {
153   DCHECK(next_state_ != STATE_NONE);
154
155   int rv = result;
156   do {
157     State state = next_state_;
158     next_state_ = STATE_NONE;
159     switch (state) {
160       case STATE_GET_BACKEND:
161         DCHECK_EQ(OK, rv);
162         rv = DoGetBackend();
163         break;
164       case STATE_GET_BACKEND_COMPLETE:
165         rv = DoGetBackendComplete(rv);
166         break;
167       case STATE_OPEN_NEXT_ENTRY:
168         DCHECK_EQ(OK, rv);
169         rv = DoOpenNextEntry();
170         break;
171       case STATE_OPEN_NEXT_ENTRY_COMPLETE:
172         rv = DoOpenNextEntryComplete(rv);
173         break;
174       case STATE_OPEN_ENTRY:
175         DCHECK_EQ(OK, rv);
176         rv = DoOpenEntry();
177         break;
178       case STATE_OPEN_ENTRY_COMPLETE:
179         rv = DoOpenEntryComplete(rv);
180         break;
181       case STATE_READ_RESPONSE:
182         DCHECK_EQ(OK, rv);
183         rv = DoReadResponse();
184         break;
185       case STATE_READ_RESPONSE_COMPLETE:
186         rv = DoReadResponseComplete(rv);
187         break;
188       case STATE_READ_DATA:
189         DCHECK_EQ(OK, rv);
190         rv = DoReadData();
191         break;
192       case STATE_READ_DATA_COMPLETE:
193         rv = DoReadDataComplete(rv);
194         break;
195
196       default:
197         NOTREACHED() << "bad state";
198         rv = ERR_FAILED;
199         break;
200     }
201   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
202
203   if (rv != ERR_IO_PENDING)
204     HandleResult(rv);
205
206   return rv;
207 }
208
209 int ViewCacheHelper::DoGetBackend() {
210   next_state_ = STATE_GET_BACKEND_COMPLETE;
211
212   if (!context_->http_transaction_factory())
213     return ERR_FAILED;
214
215   HttpCache* http_cache = context_->http_transaction_factory()->GetCache();
216   if (!http_cache)
217     return ERR_FAILED;
218
219   return http_cache->GetBackend(
220       &disk_cache_, base::Bind(&ViewCacheHelper::OnIOComplete,
221                                base::Unretained(this)));
222 }
223
224 int ViewCacheHelper::DoGetBackendComplete(int result) {
225   if (result == ERR_FAILED) {
226     data_->append("no disk cache");
227     return OK;
228   }
229
230   DCHECK_EQ(OK, result);
231   if (key_.empty()) {
232     data_->assign(VIEW_CACHE_HEAD);
233     DCHECK(!iter_);
234     next_state_ = STATE_OPEN_NEXT_ENTRY;
235     return OK;
236   }
237
238   next_state_ = STATE_OPEN_ENTRY;
239   return OK;
240 }
241
242 int ViewCacheHelper::DoOpenNextEntry() {
243   next_state_ = STATE_OPEN_NEXT_ENTRY_COMPLETE;
244   if (!iter_)
245     iter_ = disk_cache_->CreateIterator();
246   return
247       iter_->OpenNextEntry(&entry_, base::Bind(&ViewCacheHelper::OnIOComplete,
248                                                base::Unretained(this)));
249 }
250
251 int ViewCacheHelper::DoOpenNextEntryComplete(int result) {
252   if (result == ERR_FAILED) {
253     data_->append(VIEW_CACHE_TAIL);
254     return OK;
255   }
256
257   DCHECK_EQ(OK, result);
258   data_->append(FormatEntryInfo(entry_, url_prefix_));
259   entry_->Close();
260   entry_ = NULL;
261
262   next_state_ = STATE_OPEN_NEXT_ENTRY;
263   return OK;
264 }
265
266 int ViewCacheHelper::DoOpenEntry() {
267   next_state_ = STATE_OPEN_ENTRY_COMPLETE;
268   return disk_cache_->OpenEntry(
269       key_, &entry_,
270       base::Bind(&ViewCacheHelper::OnIOComplete, base::Unretained(this)));
271 }
272
273 int ViewCacheHelper::DoOpenEntryComplete(int result) {
274   if (result == ERR_FAILED) {
275     data_->append("no matching cache entry for: " + EscapeForHTML(key_));
276     return OK;
277   }
278
279   data_->assign(VIEW_CACHE_HEAD);
280   data_->append(EscapeForHTML(entry_->GetKey()));
281   next_state_ = STATE_READ_RESPONSE;
282   return OK;
283 }
284
285 int ViewCacheHelper::DoReadResponse() {
286   next_state_ = STATE_READ_RESPONSE_COMPLETE;
287   buf_len_ = entry_->GetDataSize(0);
288   if (!buf_len_)
289     return buf_len_;
290
291   buf_ = new IOBuffer(buf_len_);
292   return entry_->ReadData(
293       0,
294       0,
295       buf_.get(),
296       buf_len_,
297       base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr()));
298 }
299
300 int ViewCacheHelper::DoReadResponseComplete(int result) {
301   if (result && result == buf_len_) {
302     HttpResponseInfo response;
303     bool truncated;
304     if (HttpCache::ParseResponseInfo(
305             buf_->data(), buf_len_, &response, &truncated) &&
306         response.headers.get()) {
307       if (truncated)
308         data_->append("<pre>RESPONSE_INFO_TRUNCATED</pre>");
309
310       data_->append("<hr><pre>");
311       data_->append(EscapeForHTML(response.headers->GetStatusLine()));
312       data_->push_back('\n');
313
314       void* iter = NULL;
315       std::string name, value;
316       while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) {
317         data_->append(EscapeForHTML(name));
318         data_->append(": ");
319         data_->append(EscapeForHTML(value));
320         data_->push_back('\n');
321       }
322       data_->append("</pre>");
323     }
324   }
325
326   index_ = 0;
327   next_state_ = STATE_READ_DATA;
328   return OK;
329 }
330
331 int ViewCacheHelper::DoReadData() {
332   data_->append("<hr><pre>");
333
334   next_state_ = STATE_READ_DATA_COMPLETE;
335   buf_len_ = entry_->GetDataSize(index_);
336   if (!buf_len_)
337     return buf_len_;
338
339   buf_ = new IOBuffer(buf_len_);
340   return entry_->ReadData(
341       index_,
342       0,
343       buf_.get(),
344       buf_len_,
345       base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr()));
346 }
347
348 int ViewCacheHelper::DoReadDataComplete(int result) {
349   if (result && result == buf_len_) {
350     HexDump(buf_->data(), buf_len_, data_);
351   }
352   data_->append("</pre>");
353   index_++;
354   if (index_ < HttpCache::kNumCacheEntryDataIndices) {
355     next_state_ = STATE_READ_DATA;
356   } else {
357     data_->append(VIEW_CACHE_TAIL);
358     entry_->Close();
359     entry_ = NULL;
360   }
361   return OK;
362 }
363
364 void ViewCacheHelper::OnIOComplete(int result) {
365   DoLoop(result);
366 }
367
368 }  // namespace net.