Chromium Code Reviews| Index: webkit/appcache/view_appcache_internals_job.cc |
| =================================================================== |
| --- webkit/appcache/view_appcache_internals_job.cc (revision 91517) |
| +++ webkit/appcache/view_appcache_internals_job.cc (working copy) |
| @@ -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/format_macros.h" |
| +#include "base/i18n/time_formatting.h" |
| #include "base/logging.h" |
| -#include "base/format_macros.h" |
| +#include "base/string_number_conversions.h" |
| +#include "base/string_util.h" |
| #include "base/stringprintf.h" |
| #include "base/utf_string_conversions.h" |
| -#include "base/i18n/time_formatting.h" |
| -#include "base/string_util.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,569 @@ |
| 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); |
| + EmitAppCacheInfo(service, &(*info), out); |
| + } |
| +} |
| - 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>"); |
| +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>"); |
| +} |
| - 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); |
| +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. "); |
|
rvargas (doing something else)
2011/07/11 22:34:07
Is it intentional that this one ends with a period
michaeln
2011/07/12 23:35:26
Done, changed to a comma like the others. The URL
|
| + if (info.is_explicit) |
| + str.append("Explicit, "); |
| + if (info.is_foreign) |
| + str.append("Foreign, "); |
| + return str; |
| +} |
| - out->append("</ul></p></br>"); |
| - } |
| +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; |
| } |
| -std::string GetAppCacheManifestToRemove(const std::string& query) { |
| - if (!StartsWithASCII(query, "remove=", true)) { |
| - // Not a recognized format. |
| - return std::string(); |
| +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"); |
| } |
| - 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; |
| + out->append("</table>\n"); |
| } |
| -struct ManifestURLComparator { |
| - public: |
| - bool operator() ( |
| - const appcache::AppCacheInfo& lhs, |
| - const appcache::AppCacheInfo& rhs) const { |
| - return (lhs.manifest_url.spec() < rhs.manifest_url.spec()); |
| +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'); |
| } |
| -} manifest_url_comparator; |
| + out->append("</pre>"); |
| +} |
| -} // namespace |
| +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>"); |
| +} |
| -namespace appcache { |
| +GURL DecodeBase64URL(const std::string base64) { |
| + std::string url; |
| + base::Base64Decode(base64, &url); |
| + return GURL(url); |
| +} |
| -ViewAppCacheInternalsJob::ViewAppCacheInternalsJob( |
| - net::URLRequest* request, |
| - AppCacheService* service) |
| - : net::URLRequestSimpleJob(request), |
| - appcache_service_(service) { |
| +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(); |
| } |
| -ViewAppCacheInternalsJob::~ViewAppCacheInternalsJob() { |
| - // Cancel callback if job is destroyed before callback is called. |
| - if (appcache_done_callback_) |
| - appcache_done_callback_.release()->Cancel(); |
| +bool SortByManifestUrl(const AppCacheInfo& lhs, |
| + const AppCacheInfo& rhs) { |
| + return lhs.manifest_url.spec() < rhs.manifest_url.spec(); |
| } |
| -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 SortByResourceUrl(const AppCacheResourceInfo& lhs, |
| + const AppCacheResourceInfo& rhs) { |
| + return lhs.url.spec() < rhs.url.spec(); |
| } |
| -void ViewAppCacheInternalsJob::RemoveAppCacheInfoAsync( |
| - const std::string& manifest_url_spec) { |
| - appcache_done_callback_ = |
| - new net::CancelableCompletionCallback<ViewAppCacheInternalsJob>( |
| - this, &ViewAppCacheInternalsJob::AppCacheDone); |
| - |
| - 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; |
| +// 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) {} |
| - // 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())); |
| + AppCacheService* appcache_service_; |
| +}; |
| - // Empty manifests are dealt with by the deleter. |
| - RemoveAppCacheInfoAsync(remove_appcache_manifest); |
| - } else { |
| - GetAppCacheInfoAsync(); |
| +// 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_); |
| } |
| -} |
| -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); |
| + // 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. |
| + } |
| + |
| + 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, |
|
rvargas (doing something else)
2011/07/11 22:34:07
nit: put the arguments on the previous line.
|
| + 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, |
|
rvargas (doing something else)
2011/07/11 22:34:07
ditto
|
| + 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) { |
|
rvargas (doing something else)
2011/07/11 22:34:07
nit: Add OVERRIDE
michaeln
2011/07/12 23:35:26
Done.
|
| + 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, |
|
rvargas (doing something else)
2011/07/11 22:34:07
ditto
|
| + 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) { |
| + 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_; |
| +}; |
| + |
| +} // anon namespace |
|
rvargas (doing something else)
2011/07/11 22:34:07
s/anon namespace/namespace
michaeln
2011/07/12 23:35:26
Done.
|
| + |
| +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 |