summaryrefslogtreecommitdiff
path: root/chromium/net/url_request/view_cache_helper.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/url_request/view_cache_helper.cc')
-rw-r--r--chromium/net/url_request/view_cache_helper.cc367
1 files changed, 367 insertions, 0 deletions
diff --git a/chromium/net/url_request/view_cache_helper.cc b/chromium/net/url_request/view_cache_helper.cc
new file mode 100644
index 00000000000..346c7cdb50c
--- /dev/null
+++ b/chromium/net/url_request/view_cache_helper.cc
@@ -0,0 +1,367 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/url_request/view_cache_helper.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/strings/stringprintf.h"
+#include "net/base/escape.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
+#include "net/url_request/url_request_context.h"
+
+#define VIEW_CACHE_HEAD \
+ "<html><meta charset=\"utf-8\">" \
+ "<meta http-equiv=\"Content-Security-Policy\" " \
+ " content=\"object-src 'none'; script-src 'none' 'unsafe-eval'\">" \
+ "<body><table>"
+
+#define VIEW_CACHE_TAIL \
+ "</table></body></html>"
+
+namespace net {
+
+namespace {
+
+std::string FormatEntryInfo(disk_cache::Entry* entry,
+ const std::string& url_prefix) {
+ std::string key = entry->GetKey();
+ GURL url = GURL(url_prefix + key);
+ std::string row =
+ "<tr><td><a href=\"" + url.spec() + "\">" + EscapeForHTML(key) +
+ "</a></td></tr>";
+ return row;
+}
+
+} // namespace.
+
+ViewCacheHelper::ViewCacheHelper()
+ : context_(NULL),
+ disk_cache_(NULL),
+ entry_(NULL),
+ iter_(NULL),
+ buf_len_(0),
+ index_(0),
+ data_(NULL),
+ next_state_(STATE_NONE),
+ weak_factory_(this) {
+}
+
+ViewCacheHelper::~ViewCacheHelper() {
+ if (entry_)
+ entry_->Close();
+}
+
+int ViewCacheHelper::GetEntryInfoHTML(const std::string& key,
+ const URLRequestContext* context,
+ std::string* out,
+ const CompletionCallback& callback) {
+ return GetInfoHTML(key, context, std::string(), out, callback);
+}
+
+int ViewCacheHelper::GetContentsHTML(const URLRequestContext* context,
+ const std::string& url_prefix,
+ std::string* out,
+ const CompletionCallback& callback) {
+ return GetInfoHTML(std::string(), context, url_prefix, out, callback);
+}
+
+// static
+void ViewCacheHelper::HexDump(const char *buf, size_t buf_len,
+ std::string* result) {
+ const size_t kMaxRows = 16;
+ int offset = 0;
+
+ const unsigned char *p;
+ while (buf_len) {
+ base::StringAppendF(result, "%08x: ", offset);
+ offset += kMaxRows;
+
+ p = (const unsigned char *) buf;
+
+ size_t i;
+ size_t row_max = std::min(kMaxRows, buf_len);
+
+ // print hex codes:
+ for (i = 0; i < row_max; ++i)
+ base::StringAppendF(result, "%02x ", *p++);
+ for (i = row_max; i < kMaxRows; ++i)
+ result->append(" ");
+ result->append(" ");
+
+ // print ASCII glyphs if possible:
+ p = (const unsigned char *) buf;
+ for (i = 0; i < row_max; ++i, ++p) {
+ if (*p < 0x7F && *p > 0x1F) {
+ AppendEscapedCharForHTML(*p, result);
+ } else {
+ result->push_back('.');
+ }
+ }
+
+ result->push_back('\n');
+
+ buf += row_max;
+ buf_len -= row_max;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+int ViewCacheHelper::GetInfoHTML(const std::string& key,
+ const URLRequestContext* context,
+ const std::string& url_prefix,
+ std::string* out,
+ const CompletionCallback& callback) {
+ DCHECK(callback_.is_null());
+ DCHECK(context);
+ key_ = key;
+ context_ = context;
+ url_prefix_ = url_prefix;
+ data_ = out;
+ next_state_ = STATE_GET_BACKEND;
+ int rv = DoLoop(OK);
+
+ if (rv == ERR_IO_PENDING)
+ callback_ = callback;
+
+ return rv;
+}
+
+void ViewCacheHelper::DoCallback(int rv) {
+ DCHECK_NE(ERR_IO_PENDING, rv);
+ DCHECK(!callback_.is_null());
+
+ callback_.Run(rv);
+ callback_.Reset();
+}
+
+void ViewCacheHelper::HandleResult(int rv) {
+ DCHECK_NE(ERR_IO_PENDING, rv);
+ DCHECK_NE(ERR_FAILED, rv);
+ context_ = NULL;
+ if (!callback_.is_null())
+ DoCallback(rv);
+}
+
+int ViewCacheHelper::DoLoop(int result) {
+ DCHECK(next_state_ != STATE_NONE);
+
+ int rv = result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_GET_BACKEND:
+ DCHECK_EQ(OK, rv);
+ rv = DoGetBackend();
+ break;
+ case STATE_GET_BACKEND_COMPLETE:
+ rv = DoGetBackendComplete(rv);
+ break;
+ case STATE_OPEN_NEXT_ENTRY:
+ DCHECK_EQ(OK, rv);
+ rv = DoOpenNextEntry();
+ break;
+ case STATE_OPEN_NEXT_ENTRY_COMPLETE:
+ rv = DoOpenNextEntryComplete(rv);
+ break;
+ case STATE_OPEN_ENTRY:
+ DCHECK_EQ(OK, rv);
+ rv = DoOpenEntry();
+ break;
+ case STATE_OPEN_ENTRY_COMPLETE:
+ rv = DoOpenEntryComplete(rv);
+ break;
+ case STATE_READ_RESPONSE:
+ DCHECK_EQ(OK, rv);
+ rv = DoReadResponse();
+ break;
+ case STATE_READ_RESPONSE_COMPLETE:
+ rv = DoReadResponseComplete(rv);
+ break;
+ case STATE_READ_DATA:
+ DCHECK_EQ(OK, rv);
+ rv = DoReadData();
+ break;
+ case STATE_READ_DATA_COMPLETE:
+ rv = DoReadDataComplete(rv);
+ break;
+
+ default:
+ NOTREACHED() << "bad state";
+ rv = ERR_FAILED;
+ break;
+ }
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
+
+ if (rv != ERR_IO_PENDING)
+ HandleResult(rv);
+
+ return rv;
+}
+
+int ViewCacheHelper::DoGetBackend() {
+ next_state_ = STATE_GET_BACKEND_COMPLETE;
+
+ if (!context_->http_transaction_factory())
+ return ERR_FAILED;
+
+ HttpCache* http_cache = context_->http_transaction_factory()->GetCache();
+ if (!http_cache)
+ return ERR_FAILED;
+
+ return http_cache->GetBackend(
+ &disk_cache_, base::Bind(&ViewCacheHelper::OnIOComplete,
+ base::Unretained(this)));
+}
+
+int ViewCacheHelper::DoGetBackendComplete(int result) {
+ if (result == ERR_FAILED) {
+ data_->append("no disk cache");
+ return OK;
+ }
+
+ DCHECK_EQ(OK, result);
+ if (key_.empty()) {
+ data_->assign(VIEW_CACHE_HEAD);
+ DCHECK(!iter_);
+ next_state_ = STATE_OPEN_NEXT_ENTRY;
+ return OK;
+ }
+
+ next_state_ = STATE_OPEN_ENTRY;
+ return OK;
+}
+
+int ViewCacheHelper::DoOpenNextEntry() {
+ next_state_ = STATE_OPEN_NEXT_ENTRY_COMPLETE;
+ return disk_cache_->OpenNextEntry(
+ &iter_, &entry_,
+ base::Bind(&ViewCacheHelper::OnIOComplete, base::Unretained(this)));
+}
+
+int ViewCacheHelper::DoOpenNextEntryComplete(int result) {
+ if (result == ERR_FAILED) {
+ data_->append(VIEW_CACHE_TAIL);
+ return OK;
+ }
+
+ DCHECK_EQ(OK, result);
+ data_->append(FormatEntryInfo(entry_, url_prefix_));
+ entry_->Close();
+ entry_ = NULL;
+
+ next_state_ = STATE_OPEN_NEXT_ENTRY;
+ return OK;
+}
+
+int ViewCacheHelper::DoOpenEntry() {
+ next_state_ = STATE_OPEN_ENTRY_COMPLETE;
+ return disk_cache_->OpenEntry(
+ key_, &entry_,
+ base::Bind(&ViewCacheHelper::OnIOComplete, base::Unretained(this)));
+}
+
+int ViewCacheHelper::DoOpenEntryComplete(int result) {
+ if (result == ERR_FAILED) {
+ data_->append("no matching cache entry for: " + EscapeForHTML(key_));
+ return OK;
+ }
+
+ data_->assign(VIEW_CACHE_HEAD);
+ data_->append(EscapeForHTML(entry_->GetKey()));
+ next_state_ = STATE_READ_RESPONSE;
+ return OK;
+}
+
+int ViewCacheHelper::DoReadResponse() {
+ next_state_ = STATE_READ_RESPONSE_COMPLETE;
+ buf_len_ = entry_->GetDataSize(0);
+ if (!buf_len_)
+ return buf_len_;
+
+ buf_ = new IOBuffer(buf_len_);
+ return entry_->ReadData(
+ 0,
+ 0,
+ buf_.get(),
+ buf_len_,
+ base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr()));
+}
+
+int ViewCacheHelper::DoReadResponseComplete(int result) {
+ if (result && result == buf_len_) {
+ HttpResponseInfo response;
+ bool truncated;
+ if (HttpCache::ParseResponseInfo(
+ buf_->data(), buf_len_, &response, &truncated) &&
+ response.headers.get()) {
+ if (truncated)
+ data_->append("<pre>RESPONSE_INFO_TRUNCATED</pre>");
+
+ data_->append("<hr><pre>");
+ data_->append(EscapeForHTML(response.headers->GetStatusLine()));
+ data_->push_back('\n');
+
+ void* iter = NULL;
+ std::string name, value;
+ while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ data_->append(EscapeForHTML(name));
+ data_->append(": ");
+ data_->append(EscapeForHTML(value));
+ data_->push_back('\n');
+ }
+ data_->append("</pre>");
+ }
+ }
+
+ index_ = 0;
+ next_state_ = STATE_READ_DATA;
+ return OK;
+}
+
+int ViewCacheHelper::DoReadData() {
+ data_->append("<hr><pre>");
+
+ next_state_ = STATE_READ_DATA_COMPLETE;
+ buf_len_ = entry_->GetDataSize(index_);
+ if (!buf_len_)
+ return buf_len_;
+
+ buf_ = new IOBuffer(buf_len_);
+ return entry_->ReadData(
+ index_,
+ 0,
+ buf_.get(),
+ buf_len_,
+ base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr()));
+}
+
+int ViewCacheHelper::DoReadDataComplete(int result) {
+ if (result && result == buf_len_) {
+ HexDump(buf_->data(), buf_len_, data_);
+ }
+ data_->append("</pre>");
+ index_++;
+ if (index_ < HttpCache::kNumCacheEntryDataIndices) {
+ next_state_ = STATE_READ_DATA;
+ } else {
+ data_->append(VIEW_CACHE_TAIL);
+ entry_->Close();
+ entry_ = NULL;
+ }
+ return OK;
+}
+
+void ViewCacheHelper::OnIOComplete(int result) {
+ DoLoop(result);
+}
+
+} // namespace net.