summaryrefslogtreecommitdiffstats
path: root/webkit/appcache
diff options
context:
space:
mode:
authormichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-12 23:34:12 +0000
committermichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-12 23:34:12 +0000
commit5e5bbf409e10a1d21037eaf93a4e45af4c211575 (patch)
tree63d0186980869cb0f0be6d04202a5b0e9845d08c /webkit/appcache
parent7c128e7c8af54578ee98c661350853835dae8350 (diff)
downloadchromium_src-5e5bbf409e10a1d21037eaf93a4e45af4c211575.zip
chromium_src-5e5bbf409e10a1d21037eaf93a4e45af4c211575.tar.gz
chromium_src-5e5bbf409e10a1d21037eaf93a4e45af4c211575.tar.bz2
Enhancements to the about://appcache-internals pages.
* added a new page to list the entries in a cache * added a new page to show an entry's headers and data BUG=none TEST=manual Review URL: http://codereview.chromium.org/7326023 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92263 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache')
-rw-r--r--webkit/appcache/appcache.cc19
-rw-r--r--webkit/appcache/appcache.h3
-rw-r--r--webkit/appcache/appcache_host.cc19
-rw-r--r--webkit/appcache/appcache_interfaces.cc5
-rw-r--r--webkit/appcache/appcache_interfaces.h3
-rw-r--r--webkit/appcache/view_appcache_internals_job.cc697
-rw-r--r--webkit/appcache/view_appcache_internals_job.h49
7 files changed, 560 insertions, 235 deletions
diff --git a/webkit/appcache/appcache.cc b/webkit/appcache/appcache.cc
index a772cdc..1860422 100644
--- a/webkit/appcache/appcache.cc
+++ b/webkit/appcache/appcache.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -231,6 +231,23 @@ FallbackNamespace* AppCache::FindFallbackNamespace(const GURL& url) {
return NULL;
}
+void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector* infos) const {
+ DCHECK(infos && infos->empty());
+ for (EntryMap::const_iterator iter = entries_.begin();
+ iter != entries_.end(); ++iter) {
+ infos->push_back(AppCacheResourceInfo());
+ AppCacheResourceInfo& info = infos->back();
+ info.url = iter->first;
+ info.is_master = iter->second.IsMaster();
+ info.is_manifest = iter->second.IsManifest();
+ info.is_fallback = iter->second.IsFallback();
+ info.is_foreign = iter->second.IsForeign();
+ info.is_explicit = iter->second.IsExplicit();
+ info.size = iter->second.response_size();
+ info.response_id = iter->second.response_id();
+ }
+}
+
// static
bool AppCache::IsInNetworkNamespace(
const GURL& url,
diff --git a/webkit/appcache/appcache.h b/webkit/appcache/appcache.h
index c55aa3e..d54dde8 100644
--- a/webkit/appcache/appcache.h
+++ b/webkit/appcache/appcache.h
@@ -106,6 +106,9 @@ class AppCache : public base::RefCounted<AppCache> {
AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry,
GURL* found_fallback_namespace, bool* found_network_namespace);
+ // Populates the 'infos' vector with an element per entry in the appcache.
+ void ToResourceInfoVector(AppCacheResourceInfoVector* infos) const;
+
static bool IsInNetworkNamespace(
const GURL& url,
const std::vector<GURL> &namespaces);
diff --git a/webkit/appcache/appcache_host.cc b/webkit/appcache/appcache_host.cc
index 6965c1d..cb040ef 100644
--- a/webkit/appcache/appcache_host.cc
+++ b/webkit/appcache/appcache_host.cc
@@ -278,22 +278,9 @@ AppCacheRequestHandler* AppCacheHost::CreateRequestHandler(
}
void AppCacheHost::GetResourceList(
- std::vector<AppCacheResourceInfo>* resource_infos) {
- if (associated_cache_.get() && associated_cache_->is_complete()) {
- for (AppCache::EntryMap::const_iterator it =
- associated_cache_->entries().begin();
- it != associated_cache_->entries().end(); ++it) {
- AppCacheResourceInfo info;
- info.url = it->first;
- info.is_master = it->second.IsMaster();
- info.is_manifest = it->second.IsManifest();
- info.is_fallback = it->second.IsFallback();
- info.is_foreign = it->second.IsForeign();
- info.is_explicit = it->second.IsExplicit();
- info.size = it->second.response_size();
- resource_infos->push_back(info);
- }
- }
+ AppCacheResourceInfoVector* resource_infos) {
+ if (associated_cache_.get() && associated_cache_->is_complete())
+ associated_cache_->ToResourceInfoVector(resource_infos);
}
Status AppCacheHost::GetStatus() {
diff --git a/webkit/appcache/appcache_interfaces.cc b/webkit/appcache/appcache_interfaces.cc
index 66a416e..3f9fa19 100644
--- a/webkit/appcache/appcache_interfaces.cc
+++ b/webkit/appcache/appcache_interfaces.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -40,7 +40,8 @@ AppCacheResourceInfo::AppCacheResourceInfo()
is_manifest(0),
is_fallback(0),
is_foreign(0),
- is_explicit(0) {
+ is_explicit(0),
+ response_id(kNoResponseId) {
}
AppCacheResourceInfo::~AppCacheResourceInfo() {
diff --git a/webkit/appcache/appcache_interfaces.h b/webkit/appcache/appcache_interfaces.h
index a251e21..d04a7da 100644
--- a/webkit/appcache/appcache_interfaces.h
+++ b/webkit/appcache/appcache_interfaces.h
@@ -82,8 +82,11 @@ struct AppCacheResourceInfo {
bool is_fallback;
bool is_foreign;
bool is_explicit;
+ int64 response_id;
};
+typedef std::vector<AppCacheResourceInfo> AppCacheResourceInfoVector;
+
// Interface used by backend (browser-process) to talk to frontend (renderer).
class AppCacheFrontend {
public:
diff --git a/webkit/appcache/view_appcache_internals_job.cc b/webkit/appcache/view_appcache_internals_job.cc
index 7666a46..606a1e4 100644
--- a/webkit/appcache/view_appcache_internals_job.cc
+++ b/webkit/appcache/view_appcache_internals_job.cc
@@ -3,26 +3,36 @@
// found in the LICENSE file.
#include <algorithm>
+#include <string>
#include "webkit/appcache/view_appcache_internals_job.h"
#include "base/base64.h"
-#include "base/logging.h"
#include "base/format_macros.h"
-#include "base/stringprintf.h"
-#include "base/utf_string_conversions.h"
#include "base/i18n/time_formatting.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "net/base/escape.h"
+#include "net/base/io_buffer.h"
+#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_simple_job.h"
+#include "net/url_request/view_cache_helper.h"
+#include "webkit/appcache/appcache.h"
+#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_policy.h"
+#include "webkit/appcache/appcache_response.h"
#include "webkit/appcache/appcache_service.h"
+namespace appcache {
namespace {
const char kErrorMessage[] = "Error in retrieving Application Caches.";
const char kEmptyAppCachesMessage[] = "No available Application Caches.";
-const char kRemoveAppCache[] = "Remove this AppCache";
+const char kManifestNotFoundMessage[] = "Manifest not found.";
const char kManifest[] = "Manifest: ";
const char kSize[] = "Size: ";
const char kCreationTime[] = "Creation Time: ";
@@ -31,237 +41,570 @@ const char kLastUpdateTime[] = "Last Update Time: ";
const char kFormattedDisabledAppCacheMsg[] =
"<b><i><font color=\"FF0000\">"
"This Application Cache is disabled by policy.</font></i></b><br/>";
+const char kRemoveCacheLabel[] = "Remove";
+const char kViewCacheLabel[] = "View Entries";
+const char kRemoveCacheCommand[] = "remove-cache";
+const char kViewCacheCommand[] = "view-cache";
+const char kViewEntryCommand[] = "view-entry";
-void StartHTML(std::string* out) {
+void EmitPageStart(std::string* out) {
DCHECK(out);
out->append(
- "<!DOCTYPE HTML>"
- "<html><title>AppCache Internals</title>"
- "<style>"
+ "<!DOCTYPE HTML>\n"
+ "<html><title>AppCache Internals</title>\n"
+ "<style>\n"
"body { font-family: sans-serif; font-size: 0.8em; }\n"
"tt, code, pre { font-family: WebKitHack, monospace; }\n"
".subsection_body { margin: 10px 0 10px 2em; }\n"
".subsection_title { font-weight: bold; }\n"
- "</style>"
+ "</style>\n"
"<script>\n"
- // Unfortunately we can't do XHR from chrome://appcache-internals
- // because the chrome:// protocol restricts access.
- //
- // So instead, we will send commands by doing a form
- // submission (which as a side effect will reload the page).
- "function RemoveCommand(command) {\n"
- " document.getElementById('cmd').value = command;\n"
- " document.getElementById('cmdsender').submit();\n"
+ "function PerformCommand(command, param) {\n"
+ " location = location.pathname + '?' + command + '=' + param;\n"
"}\n"
"</script>\n"
- "</head><body>"
- "<form action='' method=GET id=cmdsender>"
- "<input type='hidden' id=cmd name='remove'>"
- "</form>");
+ "</head><body>\n");
}
-void EndHTML(std::string* out) {
+void EmitPageEnd(std::string* out) {
DCHECK(out);
- out->append("</body></html>");
+ out->append("</body></html>\n");
}
-// Appends an input button to |data| with text |title| that sends the command
-// string |command| back to the browser, and then refreshes the page.
-void DrawCommandButton(const std::string& title,
+// Appends an input button to |out| with text |label| that sends
+// |command| and |param| back to the browser and navigates the frame
+// to the resulting page.
+void EmitCommandButton(const std::string& label,
const std::string& command,
- std::string* data) {
- base::StringAppendF(data, "<input type=\"button\" value=\"%s\" "
- "onclick=\"RemoveCommand('%s')\" />",
- title.c_str(),
- command.c_str());
+ const std::string& param,
+ std::string* out) {
+ base::StringAppendF(out, "<input type=\"button\" value=\"%s\" "
+ "onclick=\"PerformCommand('%s', '%s')\" />\n",
+ label.c_str(), command.c_str(), param.c_str());
}
-void AddLiTag(const std::string& element_title,
- const std::string& element_data, std::string* out) {
+void EmitListItem(const std::string& label, const std::string& data,
+ std::string* out) {
DCHECK(out);
out->append("<li>");
- out->append(element_title);
- out->append(element_data);
- out->append("</li>");
+ out->append(label);
+ out->append(data);
+ out->append("</li>\n");
}
-void WrapInHREF(const std::string& in, std::string* out) {
+void EmitAnchor(const std::string& url, const std::string& text,
+ std::string* out) {
out->append("<a href=");
- out->append(in);
+ out->append(url);
out->append(">");
- out->append(in);
+ out->append(text);
out->append("</a><br/>");
}
-void AddHTMLFromAppCacheToOutput(
- const appcache::AppCacheService& appcache_service,
- const appcache::AppCacheInfoVector& appcaches, std::string* out) {
- for (std::vector<appcache::AppCacheInfo>::const_iterator info =
+void EmitAppCacheInfo(AppCacheService* service,
+ const AppCacheInfo* info,
+ std::string* out) {
+ std::string manifest_url_base64;
+ base::Base64Encode(info->manifest_url.spec(), &manifest_url_base64);
+
+ out->append("\n<p>");
+ out->append(kManifest);
+ EmitAnchor(info->manifest_url.spec(), info->manifest_url.spec(), out);
+ if (!service->appcache_policy()->CanLoadAppCache(
+ info->manifest_url)) {
+ out->append(kFormattedDisabledAppCacheMsg);
+ }
+ out->append("\n<br/>\n");
+ EmitCommandButton(kRemoveCacheLabel, kRemoveCacheCommand,
+ manifest_url_base64, out);
+ EmitCommandButton(kViewCacheLabel, kViewCacheCommand,
+ manifest_url_base64, out);
+ out->append("<ul>");
+ EmitListItem(
+ kSize,
+ UTF16ToUTF8(FormatBytesUnlocalized(info->size)),
+ out);
+ EmitListItem(
+ kCreationTime,
+ UTF16ToUTF8(TimeFormatFriendlyDateAndTime(info->creation_time)),
+ out);
+ EmitListItem(
+ kLastUpdateTime,
+ UTF16ToUTF8(TimeFormatFriendlyDateAndTime(info->last_update_time)),
+ out);
+ EmitListItem(
+ kLastAccessTime,
+ UTF16ToUTF8(TimeFormatFriendlyDateAndTime(info->last_access_time)),
+ out);
+ out->append("</ul></p></br>\n");
+}
+
+void EmitAppCacheInfoVector(
+ AppCacheService* service,
+ const AppCacheInfoVector& appcaches,
+ std::string* out) {
+ for (std::vector<AppCacheInfo>::const_iterator info =
appcaches.begin();
info != appcaches.end(); ++info) {
- std::string manifest_url_base64;
- base::Base64Encode(info->manifest_url.spec(), &manifest_url_base64);
-
- out->append("<p>");
- std::string anchored_manifest;
- WrapInHREF(info->manifest_url.spec(), &anchored_manifest);
- out->append(kManifest);
- out->append(anchored_manifest);
- if (!appcache_service.appcache_policy()->CanLoadAppCache(
- info->manifest_url)) {
- out->append(kFormattedDisabledAppCacheMsg);
- }
- out->append("<br/>");
- DrawCommandButton(kRemoveAppCache, manifest_url_base64, out);
- out->append("<ul>");
-
- AddLiTag(kSize,
- UTF16ToUTF8(FormatBytesUnlocalized(info->size)),
- out);
- AddLiTag(kCreationTime,
- UTF16ToUTF8(TimeFormatFriendlyDateAndTime(info->creation_time)),
- out);
- AddLiTag(kLastAccessTime,
- UTF16ToUTF8(TimeFormatFriendlyDateAndTime(info->last_access_time)),
- out);
- AddLiTag(kLastUpdateTime,
- UTF16ToUTF8(TimeFormatFriendlyDateAndTime(info->last_update_time)),
- out);
-
- out->append("</ul></p></br>");
+ EmitAppCacheInfo(service, &(*info), out);
}
}
-std::string GetAppCacheManifestToRemove(const std::string& query) {
- if (!StartsWithASCII(query, "remove=", true)) {
- // Not a recognized format.
- return std::string();
- }
- std::string manifest_url_base64 = UnescapeURLComponent(
- query.substr(strlen("remove=")),
- UnescapeRule::NORMAL | UnescapeRule::URL_SPECIAL_CHARS);
- std::string manifest_url;
- base::Base64Decode(manifest_url_base64, &manifest_url);
- return manifest_url;
+void EmitTableData(const std::string& data, bool align_right, bool bold,
+ std::string* out) {
+ if (align_right)
+ out->append("<td align='right'>");
+ else
+ out->append("<td>");
+ if (bold)
+ out->append("<b>");
+ out->append(data);
+ if (bold)
+ out->append("</b>");
+ out->append("</td>");
}
-struct ManifestURLComparator {
- public:
- bool operator() (
- const appcache::AppCacheInfo& lhs,
- const appcache::AppCacheInfo& rhs) const {
- return (lhs.manifest_url.spec() < rhs.manifest_url.spec());
+std::string FormFlagsString(const AppCacheResourceInfo& info) {
+ std::string str;
+ if (info.is_manifest)
+ str.append("Manifest, ");
+ if (info.is_master)
+ str.append("Master, ");
+ if (info.is_fallback)
+ str.append("Fallback, ");
+ if (info.is_explicit)
+ str.append("Explicit, ");
+ if (info.is_foreign)
+ str.append("Foreign, ");
+ return str;
+}
+
+std::string FormViewEntryAnchor(const GURL& base_url,
+ const GURL& manifest_url, const GURL& entry_url,
+ int64 response_id) {
+ std::string manifest_url_base64;
+ std::string entry_url_base64;
+ std::string response_id_string;
+ base::Base64Encode(manifest_url.spec(), &manifest_url_base64);
+ base::Base64Encode(entry_url.spec(), &entry_url_base64);
+ response_id_string = base::Int64ToString(response_id);
+
+ std::string query(kViewEntryCommand);
+ query.push_back('=');
+ query.append(manifest_url_base64);
+ query.push_back('|');
+ query.append(entry_url_base64);
+ query.push_back('|');
+ query.append(response_id_string);
+
+ GURL::Replacements replacements;
+ replacements.SetQuery(query.data(),
+ url_parse::Component(0, query.length()));
+ GURL view_entry_url = base_url.ReplaceComponents(replacements);
+
+ std::string anchor;
+ EmitAnchor(view_entry_url.spec(), entry_url.spec(), &anchor);
+ return anchor;
+}
+
+void EmitAppCacheResourceInfoVector(
+ const GURL& base_url,
+ const GURL& manifest_url,
+ const AppCacheResourceInfoVector& resource_infos,
+ std::string* out) {
+ out->append("<table border='0'>\n");
+ out->append("<tr>");
+ EmitTableData("Flags", false, true, out);
+ EmitTableData("URL", false, true, out);
+ EmitTableData("Size (headers and data)", true, true, out);
+ out->append("</tr>\n");
+ for (AppCacheResourceInfoVector::const_iterator
+ iter = resource_infos.begin();
+ iter != resource_infos.end(); ++iter) {
+ out->append("<tr>");
+ EmitTableData(FormFlagsString(*iter), false, false, out);
+ EmitTableData(FormViewEntryAnchor(base_url, manifest_url,
+ iter->url, iter->response_id),
+ false, false, out);
+ EmitTableData(UTF16ToUTF8(FormatBytesUnlocalized(iter->size)),
+ true, false, out);
+ out->append("</tr>\n");
}
-} manifest_url_comparator;
+ out->append("</table>\n");
+}
-} // namespace
+void EmitResponseHeaders(net::HttpResponseHeaders* headers, std::string* out) {
+ out->append("<hr><pre>");
+ out->append(EscapeForHTML(headers->GetStatusLine()));
+ out->push_back('\n');
+
+ void* iter = NULL;
+ std::string name, value;
+ while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ out->append(EscapeForHTML(name));
+ out->append(": ");
+ out->append(EscapeForHTML(value));
+ out->push_back('\n');
+ }
+ out->append("</pre>");
+}
-namespace appcache {
+void EmitHexDump(const char *buf, size_t buf_len, size_t total_len,
+ std::string* out) {
+ out->append("<hr><pre>");
+ base::StringAppendF(out, "Showing %d of %d bytes\n\n",
+ static_cast<int>(buf_len), static_cast<int>(total_len));
+ net::ViewCacheHelper::HexDump(buf, buf_len, out);
+ if (buf_len < total_len)
+ out->append("\nNote: data is truncated...");
+ out->append("</pre>");
+}
-ViewAppCacheInternalsJob::ViewAppCacheInternalsJob(
- net::URLRequest* request,
- AppCacheService* service)
- : net::URLRequestSimpleJob(request),
- appcache_service_(service) {
+GURL DecodeBase64URL(const std::string base64) {
+ std::string url;
+ base::Base64Decode(base64, &url);
+ return GURL(url);
}
-ViewAppCacheInternalsJob::~ViewAppCacheInternalsJob() {
- // Cancel callback if job is destroyed before callback is called.
- if (appcache_done_callback_)
- appcache_done_callback_.release()->Cancel();
+bool ParseQuery(const std::string& query,
+ std::string* command, std::string* value) {
+ size_t position = query.find("=");
+ if (position == std::string::npos)
+ return false;
+ *command = query.substr(0, position);
+ *value = query.substr(position + 1);
+ return !command->empty() && !value->empty();
}
-void ViewAppCacheInternalsJob::GetAppCacheInfoAsync() {
- info_collection_ = new AppCacheInfoCollection;
- appcache_done_callback_ =
- new net::CancelableCompletionCallback<ViewAppCacheInternalsJob>(
- this, &ViewAppCacheInternalsJob::AppCacheDone);
- appcache_service_->GetAllAppCacheInfo(
- info_collection_, appcache_done_callback_);
+bool SortByManifestUrl(const AppCacheInfo& lhs,
+ const AppCacheInfo& rhs) {
+ return lhs.manifest_url.spec() < rhs.manifest_url.spec();
}
-void ViewAppCacheInternalsJob::RemoveAppCacheInfoAsync(
- const std::string& manifest_url_spec) {
- appcache_done_callback_ =
- new net::CancelableCompletionCallback<ViewAppCacheInternalsJob>(
- this, &ViewAppCacheInternalsJob::AppCacheDone);
+bool SortByResourceUrl(const AppCacheResourceInfo& lhs,
+ const AppCacheResourceInfo& rhs) {
+ return lhs.url.spec() < rhs.url.spec();
+}
- GURL manifest(manifest_url_spec);
- appcache_service_->DeleteAppCacheGroup(
- manifest, appcache_done_callback_);
+GURL ClearQuery(const GURL& url) {
+ GURL::Replacements replacements;
+ replacements.ClearQuery();
+ return url.ReplaceComponents(replacements);
}
-void ViewAppCacheInternalsJob::Start() {
- if (!request_)
- return;
-
- // Handle any remove appcache request, then redirect back to
- // the same URL stripped of query parameters. The redirect happens as part
- // of IsRedirectResponse().
- if (request_->url().has_query()) {
- std::string remove_appcache_manifest(
- GetAppCacheManifestToRemove(request_->url().query()));
-
- // Empty manifests are dealt with by the deleter.
- RemoveAppCacheInfoAsync(remove_appcache_manifest);
- } else {
- GetAppCacheInfoAsync();
+// Simple base class for the job subclasses defined here.
+class BaseInternalsJob : public net::URLRequestSimpleJob {
+ protected:
+ BaseInternalsJob(net::URLRequest* request, AppCacheService* service)
+ : URLRequestSimpleJob(request), appcache_service_(service) {}
+
+ AppCacheService* appcache_service_;
+};
+
+// Job that lists all appcaches in the system.
+class MainPageJob : public BaseInternalsJob {
+ public:
+ MainPageJob(net::URLRequest* request, AppCacheService* service)
+ : BaseInternalsJob(request, service) {}
+
+ virtual void Start() {
+ DCHECK(request_);
+ info_collection_ = new AppCacheInfoCollection;
+ gotinfo_complete_callback_ =
+ new net::CancelableCompletionCallback<MainPageJob>(
+ this, &MainPageJob::OnGotInfoComplete);
+ appcache_service_->GetAllAppCacheInfo(
+ info_collection_, gotinfo_complete_callback_);
+ }
+
+ // Produces a page containing the listing
+ virtual bool GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* out) const {
+ mime_type->assign("text/html");
+ charset->assign("UTF-8");
+
+ out->clear();
+ EmitPageStart(out);
+ if (!info_collection_.get()) {
+ out->append(kErrorMessage);
+ } else if (info_collection_->infos_by_origin.empty()) {
+ out->append(kEmptyAppCachesMessage);
+ } else {
+ typedef std::map<GURL, AppCacheInfoVector> InfoByOrigin;
+ AppCacheInfoVector appcaches;
+ for (InfoByOrigin::const_iterator origin =
+ info_collection_->infos_by_origin.begin();
+ origin != info_collection_->infos_by_origin.end(); ++origin) {
+ appcaches.insert(appcaches.end(),
+ origin->second.begin(), origin->second.end());
+ }
+ std::sort(appcaches.begin(), appcaches.end(), SortByManifestUrl);
+ EmitAppCacheInfoVector(appcache_service_, appcaches, out);
+ }
+ EmitPageEnd(out);
+ return true;
+ }
+
+ private:
+ virtual ~MainPageJob() {
+ if (gotinfo_complete_callback_)
+ gotinfo_complete_callback_.release()->Cancel();
+ }
+
+ void OnGotInfoComplete(int rv) {
+ gotinfo_complete_callback_ = NULL;
+ if (rv != net::OK)
+ info_collection_ = NULL;
+ StartAsync();
+ }
+
+ scoped_refptr<net::CancelableCompletionCallback<MainPageJob> >
+ gotinfo_complete_callback_;
+ scoped_refptr<AppCacheInfoCollection> info_collection_;
+ DISALLOW_COPY_AND_ASSIGN(MainPageJob);
+};
+
+// Job that redirects back to the main appcache internals page.
+class RedirectToMainPageJob : public BaseInternalsJob {
+ public:
+ RedirectToMainPageJob(net::URLRequest* request, AppCacheService* service)
+ : BaseInternalsJob(request, service) {}
+
+ virtual bool GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* data) const {
+ return true; // IsRedirectResponse induces a redirect.
}
-}
-bool ViewAppCacheInternalsJob::IsRedirectResponse(
- GURL* location, int* http_status_code) {
- if (request_->url().has_query()) {
- // Strip the query parameters.
- GURL::Replacements replacements;
- replacements.ClearQuery();
- *location = request_->url().ReplaceComponents(replacements);
+ virtual bool IsRedirectResponse(GURL* location, int* http_status_code) {
+ *location = ClearQuery(request_->url());
*http_status_code = 307;
return true;
}
- return false;
-}
+};
-void ViewAppCacheInternalsJob::GenerateHTMLAppCacheInfo(
- std::string* out) const {
- typedef std::map<GURL, AppCacheInfoVector> InfoByOrigin;
- AppCacheInfoVector appcaches;
- for (InfoByOrigin::const_iterator origin =
- info_collection_->infos_by_origin.begin();
- origin != info_collection_->infos_by_origin.end(); ++origin) {
- for (AppCacheInfoVector::const_iterator info =
- origin->second.begin(); info != origin->second.end(); ++info)
- appcaches.push_back(*info);
+// Job that removes an appcache and then redirects back to the main page.
+class RemoveAppCacheJob : public RedirectToMainPageJob {
+ public:
+ RemoveAppCacheJob(
+ net::URLRequest* request, AppCacheService* service,
+ const GURL& manifest_url)
+ : RedirectToMainPageJob(request, service),
+ manifest_url_(manifest_url) {}
+
+ virtual void Start() {
+ DCHECK(request_);
+ delete_appcache_callback_ =
+ new net::CancelableCompletionCallback<RemoveAppCacheJob>(
+ this, &RemoveAppCacheJob::OnDeleteAppCacheComplete);
+ appcache_service_->DeleteAppCacheGroup(
+ manifest_url_, delete_appcache_callback_);
}
- std::sort(appcaches.begin(), appcaches.end(), manifest_url_comparator);
+ private:
+ virtual ~RemoveAppCacheJob() {
+ if (delete_appcache_callback_)
+ delete_appcache_callback_.release()->Cancel();
+ }
- AddHTMLFromAppCacheToOutput(*appcache_service_, appcaches, out);
-}
+ void OnDeleteAppCacheComplete(int rv) {
+ delete_appcache_callback_ = NULL;
+ StartAsync(); // Causes the base class to redirect.
+ }
-void ViewAppCacheInternalsJob::AppCacheDone(int rv) {
- appcache_done_callback_ = NULL;
- if (rv != net::OK)
- info_collection_ = NULL;
- StartAsync();
-}
+ GURL manifest_url_;
+ scoped_refptr<net::CancelableCompletionCallback<RemoveAppCacheJob> >
+ delete_appcache_callback_;
+};
-bool ViewAppCacheInternalsJob::GetData(std::string* mime_type,
- std::string* charset,
- std::string* data) const {
- mime_type->assign("text/html");
- charset->assign("UTF-8");
-
- data->clear();
- StartHTML(data);
- if (!info_collection_.get())
- data->append(kErrorMessage);
- else if (info_collection_->infos_by_origin.empty())
- data->append(kEmptyAppCachesMessage);
- else
- GenerateHTMLAppCacheInfo(data);
- EndHTML(data);
- return true;
+
+// Job shows the details of a particular manifest url.
+class ViewAppCacheJob : public BaseInternalsJob,
+ public AppCacheStorage::Delegate {
+ public:
+ ViewAppCacheJob(
+ net::URLRequest* request, AppCacheService* service,
+ const GURL manifest_url)
+ : BaseInternalsJob(request, service),
+ manifest_url_(manifest_url) {}
+
+ virtual void Start() {
+ DCHECK(request_);
+ appcache_service_->storage()->LoadOrCreateGroup(manifest_url_, this);
+ }
+
+ // Produces a page containing the entries listing.
+ virtual bool GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* out) const {
+ mime_type->assign("text/html");
+ charset->assign("UTF-8");
+ out->clear();
+ EmitPageStart(out);
+ if (appcache_info_.manifest_url.is_empty()) {
+ out->append(kManifestNotFoundMessage);
+ } else {
+ EmitAppCacheInfo(appcache_service_, &appcache_info_, out);
+ EmitAppCacheResourceInfoVector(ClearQuery(request_->url()),
+ manifest_url_,
+ resource_infos_, out);
+ }
+ EmitPageEnd(out);
+ return true;
+ }
+
+ private:
+ virtual ~ViewAppCacheJob() {
+ appcache_service_->storage()->CancelDelegateCallbacks(this);
+ }
+
+ // AppCacheStorage::Delegate override
+ virtual void OnGroupLoaded(
+ AppCacheGroup* group, const GURL& manifest_url) OVERRIDE {
+ DCHECK_EQ(manifest_url_, manifest_url);
+ if (group && group->newest_complete_cache()) {
+ appcache_info_.manifest_url = manifest_url;
+ appcache_info_.size = group->newest_complete_cache()->cache_size();
+ appcache_info_.creation_time = group->creation_time();
+ appcache_info_.last_update_time =
+ group->newest_complete_cache()->update_time();
+ appcache_info_.last_access_time = base::Time::Now();
+ group->newest_complete_cache()->ToResourceInfoVector(&resource_infos_);
+ std::sort(resource_infos_.begin(), resource_infos_.end(),
+ SortByResourceUrl);
+ }
+ StartAsync();
+ }
+
+ GURL manifest_url_;
+ AppCacheInfo appcache_info_;
+ AppCacheResourceInfoVector resource_infos_;
+ DISALLOW_COPY_AND_ASSIGN(ViewAppCacheJob);
+};
+
+// Job that shows the details of a particular cached resource.
+class ViewEntryJob : public BaseInternalsJob,
+ public AppCacheStorage::Delegate {
+ public:
+ ViewEntryJob(
+ net::URLRequest* request, AppCacheService* service,
+ const GURL& manifest_url, const GURL& entry_url,
+ int64 response_id)
+ : BaseInternalsJob(request, service),
+ manifest_url_(manifest_url), entry_url_(entry_url),
+ response_id_(response_id), amount_read_(0),
+ ALLOW_THIS_IN_INITIALIZER_LIST(read_callback_(
+ this, &ViewEntryJob::OnReadComplete)) {}
+
+ virtual void Start() {
+ DCHECK(request_);
+ appcache_service_->storage()->LoadResponseInfo(
+ manifest_url_, response_id_, this);
+ }
+
+ // Produces a page containing the response headers and data.
+ virtual bool GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* out) const {
+ mime_type->assign("text/html");
+ charset->assign("UTF-8");
+ out->clear();
+ EmitPageStart(out);
+ EmitAnchor(entry_url_.spec(), entry_url_.spec(), out);
+ if (response_info_) {
+ if (response_info_->http_response_info())
+ EmitResponseHeaders(response_info_->http_response_info()->headers, out);
+ else
+ out->append("Failed to read response headers.<br>");
+
+ if (response_data_) {
+ EmitHexDump(response_data_->data(), amount_read_,
+ response_info_->response_data_size(), out);
+ } else {
+ out->append("Failed to read response data.<br>");
+ }
+ } else {
+ out->append("Failed to read response headers and data.<br>");
+ }
+ EmitPageEnd(out);
+ return true;
+ }
+
+ private:
+ virtual ~ViewEntryJob() {
+ appcache_service_->storage()->CancelDelegateCallbacks(this);
+ }
+
+ virtual void OnResponseInfoLoaded(
+ AppCacheResponseInfo* response_info, int64 response_id) OVERRIDE {
+ if (!response_info) {
+ StartAsync();
+ return;
+ }
+ response_info_ = response_info;
+
+ // Read the response data, truncating if its too large.
+ const int64 kLimit = 100 * 1000;
+ int64 amount_to_read =
+ std::min(kLimit, response_info->response_data_size());
+ response_data_ = new net::IOBuffer(amount_to_read);
+
+ reader_.reset(appcache_service_->storage()->CreateResponseReader(
+ manifest_url_, response_id_));
+ reader_->ReadData(
+ response_data_, amount_to_read, &read_callback_);
+ }
+
+ void OnReadComplete(int result) {
+ reader_.reset();
+ amount_read_ = result;
+ if (result < 0)
+ response_data_ = NULL;
+ StartAsync();
+ }
+
+ GURL manifest_url_;
+ GURL entry_url_;
+ int64 response_id_;
+ scoped_refptr<AppCacheResponseInfo> response_info_;
+ scoped_refptr<net::IOBuffer> response_data_;
+ int amount_read_;
+ scoped_ptr<AppCacheResponseReader> reader_;
+ net::CompletionCallbackImpl<ViewEntryJob> read_callback_;
+};
+
+} // namespace
+
+net::URLRequestJob* ViewAppCacheInternalsJobFactory::CreateJobForRequest(
+ net::URLRequest* request, AppCacheService* service) {
+ if (!request->url().has_query())
+ return new MainPageJob(request, service);
+
+ std::string command;
+ std::string param;
+ ParseQuery(request->url().query(), &command, &param);
+
+ if (command == kRemoveCacheCommand)
+ return new RemoveAppCacheJob(request, service,
+ DecodeBase64URL(param));
+
+ if (command == kViewCacheCommand)
+ return new ViewAppCacheJob(request, service,
+ DecodeBase64URL(param));
+
+ std::vector<std::string> tokens;
+ int64 response_id;
+ if (command == kViewEntryCommand &&
+ Tokenize(param, "|", &tokens) == 3u &&
+ base::StringToInt64(tokens[2], &response_id)) {
+ return new ViewEntryJob(request, service,
+ DecodeBase64URL(tokens[0]), // manifest url
+ DecodeBase64URL(tokens[1]), // entry url
+ response_id);
+ }
+
+ return new RedirectToMainPageJob(request, service);
}
} // namespace appcache
diff --git a/webkit/appcache/view_appcache_internals_job.h b/webkit/appcache/view_appcache_internals_job.h
index 8995713..2d45c51 100644
--- a/webkit/appcache/view_appcache_internals_job.h
+++ b/webkit/appcache/view_appcache_internals_job.h
@@ -1,57 +1,28 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
#ifndef WEBKIT_APPCACHE_VIEW_APPCACHE_INTERNALS_JOB_H_
#define WEBKIT_APPCACHE_VIEW_APPCACHE_INTERNALS_JOB_H_
-#include <string>
-
-#include "net/url_request/url_request_simple_job.h"
-#include "webkit/appcache/appcache_service.h"
+#include "base/basictypes.h"
namespace net {
class URLRequest;
-} // namespace net
+class URLRequestJob;
+}
namespace appcache {
-// A job subclass that implements a protocol to inspect the internal
-// state of appcache service.
-class ViewAppCacheInternalsJob : public net::URLRequestSimpleJob {
- public:
- // Stores handle to appcache service for getting information.
- ViewAppCacheInternalsJob(net::URLRequest* request, AppCacheService* service);
-
- // Fetches the AppCache Info and calls StartAsync after it is done.
- virtual void Start();
+class AppCacheService;
- virtual bool GetData(std::string* mime_type,
- std::string* charset,
- std::string* data) const;
-
- // Overridden method from net::URLRequestJob.
- virtual bool IsRedirectResponse(GURL* location, int* http_status_code);
+class ViewAppCacheInternalsJobFactory {
+ public:
+ static net::URLRequestJob* CreateJobForRequest(
+ net::URLRequest* request, AppCacheService* service);
private:
- virtual ~ViewAppCacheInternalsJob();
-
- void AppCacheDone(int rv);
-
- // Adds HTML from appcache information to out.
- void GenerateHTMLAppCacheInfo(std::string* out) const;
- void GetAppCacheInfoAsync();
- void RemoveAppCacheInfoAsync(const std::string& manifest_url_spec);
-
- // This is a common callback for both remove and getinfo for appcache.
- scoped_refptr<net::CancelableCompletionCallback<ViewAppCacheInternalsJob> >
- appcache_done_callback_;
-
- scoped_refptr<AppCacheInfoCollection> info_collection_;
- // Not owned.
- AppCacheService* appcache_service_;
-
- DISALLOW_COPY_AND_ASSIGN(ViewAppCacheInternalsJob);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ViewAppCacheInternalsJobFactory);
};
} // namespace appcache