diff options
author | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-12 23:34:12 +0000 |
---|---|---|
committer | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-12 23:34:12 +0000 |
commit | 5e5bbf409e10a1d21037eaf93a4e45af4c211575 (patch) | |
tree | 63d0186980869cb0f0be6d04202a5b0e9845d08c /webkit/appcache | |
parent | 7c128e7c8af54578ee98c661350853835dae8350 (diff) | |
download | chromium_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.cc | 19 | ||||
-rw-r--r-- | webkit/appcache/appcache.h | 3 | ||||
-rw-r--r-- | webkit/appcache/appcache_host.cc | 19 | ||||
-rw-r--r-- | webkit/appcache/appcache_interfaces.cc | 5 | ||||
-rw-r--r-- | webkit/appcache/appcache_interfaces.h | 3 | ||||
-rw-r--r-- | webkit/appcache/view_appcache_internals_job.cc | 697 | ||||
-rw-r--r-- | webkit/appcache/view_appcache_internals_job.h | 49 |
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, ¶m); + + 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 |