Update broken references to image assets
[chromium-blink-merge.git] / content / browser / appcache / appcache_internals_ui.cc
blobf14909da53da56eed32a067e98012ecb9ed8c8d4
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/appcache/appcache_internals_ui.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_piece.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/values.h"
16 #include "content/browser/appcache/appcache.h"
17 #include "content/browser/appcache/appcache_response.h"
18 #include "content/browser/storage_partition_impl.h"
19 #include "content/grit/content_resources.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/web_ui.h"
23 #include "content/public/browser/web_ui_data_source.h"
24 #include "content/public/common/url_constants.h"
25 #include "net/base/escape.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/url_request/view_cache_helper.h"
29 namespace content {
31 namespace {
32 const char kRequestGetAllAppCacheInfo[] = "getAllAppCache";
33 const char kRequestDeleteAppCache[] = "deleteAppCache";
34 const char kRequestGetAppCacheDetails[] = "getAppCacheDetails";
35 const char kRequestGetFileDetails[] = "getFileDetails";
37 const char kFunctionOnAllAppCacheInfoReady[] =
38 "appcache.onAllAppCacheInfoReady";
39 const char kFunctionOnAppCacheInfoDeleted[] = "appcache.onAppCacheInfoDeleted";
40 const char kFunctionOnAppCacheDetailsReady[] =
41 "appcache.onAppCacheDetailsReady";
42 const char kFunctionOnFileDetailsReady[] = "appcache.onFileDetailsReady";
43 const char kFunctionOnFileDetailsFailed[] = "appcache.onFileDetailsFailed";
45 int64 ToInt64(const std::string& str) {
46 int64 i = 0;
47 base::StringToInt64(str.c_str(), &i);
48 return i;
51 bool SortByResourceUrl(const AppCacheResourceInfo& lhs,
52 const AppCacheResourceInfo& rhs) {
53 return lhs.url.spec() < rhs.url.spec();
56 scoped_ptr<base::DictionaryValue> GetDictionaryValueForResponseEnquiry(
57 const content::AppCacheInternalsUI::Proxy::ResponseEnquiry&
58 response_enquiry) {
59 scoped_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue());
60 dict_value->SetString("manifestURL", response_enquiry.manifest_url);
61 dict_value->SetString("groupId",
62 base::Int64ToString(response_enquiry.group_id));
63 dict_value->SetString("responseId",
64 base::Int64ToString(response_enquiry.response_id));
65 return dict_value;
68 scoped_ptr<base::DictionaryValue> GetDictionaryValueForAppCacheInfo(
69 const content::AppCacheInfo& appcache_info) {
70 scoped_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue());
71 dict_value->SetString("manifestURL", appcache_info.manifest_url.spec());
72 dict_value->SetDouble("creationTime", appcache_info.creation_time.ToJsTime());
73 dict_value->SetDouble("lastUpdateTime",
74 appcache_info.last_update_time.ToJsTime());
75 dict_value->SetDouble("lastAccessTime",
76 appcache_info.last_access_time.ToJsTime());
77 dict_value->SetString(
78 "size",
79 base::UTF16ToUTF8(base::FormatBytesUnlocalized(appcache_info.size)));
80 dict_value->SetString("groupId", base::Int64ToString(appcache_info.group_id));
82 return dict_value;
85 scoped_ptr<base::ListValue> GetListValueForAppCacheInfoVector(
86 const AppCacheInfoVector& appcache_info_vector) {
87 scoped_ptr<base::ListValue> list(new base::ListValue());
88 for (const AppCacheInfo& info : appcache_info_vector)
89 list->Append(GetDictionaryValueForAppCacheInfo(info));
90 return list;
93 scoped_ptr<base::ListValue> GetListValueFromAppCacheInfoCollection(
94 AppCacheInfoCollection* appcache_collection) {
95 scoped_ptr<base::ListValue> list(new base::ListValue());
96 for (const auto& key_value : appcache_collection->infos_by_origin) {
97 base::DictionaryValue* dict = new base::DictionaryValue;
98 dict->SetString("originURL", key_value.first.spec());
99 dict->Set("manifests", GetListValueForAppCacheInfoVector(key_value.second));
100 list->Append(scoped_ptr<base::Value>(dict));
102 return list;
105 scoped_ptr<base::DictionaryValue> GetDictionaryValueForAppCacheResourceInfo(
106 const AppCacheResourceInfo& resource_info) {
107 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
108 dict->SetString("url", resource_info.url.spec());
109 dict->SetString(
110 "size",
111 base::UTF16ToUTF8(base::FormatBytesUnlocalized(resource_info.size)));
112 dict->SetString("responseId", base::Int64ToString(resource_info.response_id));
113 dict->SetBoolean("isExplicit", resource_info.is_explicit);
114 dict->SetBoolean("isManifest", resource_info.is_manifest);
115 dict->SetBoolean("isMaster", resource_info.is_master);
116 dict->SetBoolean("isFallback", resource_info.is_fallback);
117 dict->SetBoolean("isIntercept", resource_info.is_intercept);
118 dict->SetBoolean("isForeign", resource_info.is_foreign);
120 return dict;
123 scoped_ptr<base::ListValue> GetListValueForAppCacheResourceInfoVector(
124 AppCacheResourceInfoVector* resource_info_vector) {
125 scoped_ptr<base::ListValue> list(new base::ListValue);
126 for (const AppCacheResourceInfo& res_info : *resource_info_vector)
127 list->Append(GetDictionaryValueForAppCacheResourceInfo(res_info));
128 return list;
131 } // namespace
133 AppCacheInternalsUI::Proxy::Proxy(
134 base::WeakPtr<AppCacheInternalsUI> appcache_internals_ui,
135 const base::FilePath& partition_path)
136 : appcache_internals_ui_(appcache_internals_ui),
137 partition_path_(partition_path) {}
139 void AppCacheInternalsUI::Proxy::Initialize(
140 const scoped_refptr<ChromeAppCacheService>& chrome_appcache_service) {
141 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
142 BrowserThread::PostTask(
143 BrowserThread::IO, FROM_HERE,
144 base::Bind(&Proxy::Initialize, this, chrome_appcache_service));
145 return;
147 appcache_service_ = chrome_appcache_service->AsWeakPtr();
148 shutdown_called_ = false;
149 preparing_response_ = false;
152 AppCacheInternalsUI::Proxy::~Proxy() {
153 DCHECK(shutdown_called_);
156 void AppCacheInternalsUI::Proxy::Shutdown() {
157 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
158 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
159 base::Bind(&Proxy::Shutdown, this));
160 return;
162 shutdown_called_ = true;
163 if (appcache_service_) {
164 appcache_service_->storage()->CancelDelegateCallbacks(this);
165 appcache_service_.reset();
166 response_enquiries_.clear();
170 void AppCacheInternalsUI::Proxy::RequestAllAppCacheInfo() {
171 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
172 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
173 base::Bind(&Proxy::RequestAllAppCacheInfo, this));
174 return;
176 if (appcache_service_) {
177 scoped_refptr<AppCacheInfoCollection> collection(
178 new AppCacheInfoCollection());
179 appcache_service_->GetAllAppCacheInfo(
180 collection.get(),
181 base::Bind(&Proxy::OnAllAppCacheInfoReady, this, collection));
185 void AppCacheInternalsUI::Proxy::OnAllAppCacheInfoReady(
186 scoped_refptr<AppCacheInfoCollection> collection,
187 int net_result_code) {
188 BrowserThread::PostTask(
189 BrowserThread::UI, FROM_HERE,
190 base::Bind(&AppCacheInternalsUI::OnAllAppCacheInfoReady,
191 appcache_internals_ui_, collection, partition_path_));
194 void AppCacheInternalsUI::Proxy::DeleteAppCache(
195 const std::string& manifest_url) {
196 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
197 BrowserThread::PostTask(
198 BrowserThread::IO, FROM_HERE,
199 base::Bind(&Proxy::DeleteAppCache, this, manifest_url));
200 return;
202 if (appcache_service_) {
203 appcache_service_->DeleteAppCacheGroup(
204 GURL(manifest_url),
205 base::Bind(&Proxy::OnAppCacheInfoDeleted, this, manifest_url));
209 void AppCacheInternalsUI::Proxy::OnAppCacheInfoDeleted(
210 const std::string& manifest_url,
211 int net_result_code) {
212 BrowserThread::PostTask(
213 BrowserThread::UI, FROM_HERE,
214 base::Bind(&AppCacheInternalsUI::OnAppCacheInfoDeleted,
215 appcache_internals_ui_, partition_path_, manifest_url,
216 net_result_code == net::OK));
219 void AppCacheInternalsUI::Proxy::RequestAppCacheDetails(
220 const std::string& manifest_url) {
221 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
222 BrowserThread::PostTask(
223 BrowserThread::IO, FROM_HERE,
224 base::Bind(&Proxy::RequestAppCacheDetails, this, manifest_url));
225 return;
228 if (appcache_service_)
229 appcache_service_->storage()->LoadOrCreateGroup(GURL(manifest_url), this);
232 void AppCacheInternalsUI::Proxy::OnGroupLoaded(AppCacheGroup* appcache_group,
233 const GURL& manifest_gurl) {
234 scoped_ptr<AppCacheResourceInfoVector> resource_info_vector;
235 if (appcache_group && appcache_group->newest_complete_cache()) {
236 resource_info_vector.reset(new AppCacheResourceInfoVector);
237 appcache_group->newest_complete_cache()->ToResourceInfoVector(
238 resource_info_vector.get());
239 std::sort(resource_info_vector->begin(), resource_info_vector->end(),
240 SortByResourceUrl);
242 BrowserThread::PostTask(
243 BrowserThread::UI, FROM_HERE,
244 base::Bind(&AppCacheInternalsUI::OnAppCacheDetailsReady,
245 appcache_internals_ui_, partition_path_, manifest_gurl.spec(),
246 base::Passed(&resource_info_vector)));
249 void AppCacheInternalsUI::Proxy::RequestFileDetails(
250 const ResponseEnquiry& response_enquiry) {
251 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
252 BrowserThread::PostTask(
253 BrowserThread::IO, FROM_HERE,
254 base::Bind(&Proxy::RequestFileDetails, this, response_enquiry));
255 return;
257 DCHECK(!shutdown_called_);
258 response_enquiries_.push_back(response_enquiry);
259 HandleFileDetailsRequest();
262 void AppCacheInternalsUI::Proxy::HandleFileDetailsRequest() {
263 if (preparing_response_ || !response_enquiries_.size() || !appcache_service_)
264 return;
265 preparing_response_ = true;
266 appcache_service_->storage()->LoadResponseInfo(
267 GURL(response_enquiries_.front().manifest_url),
268 response_enquiries_.front().group_id,
269 response_enquiries_.front().response_id, this);
272 void AppCacheInternalsUI::Proxy::OnResponseInfoLoaded(
273 AppCacheResponseInfo* response,
274 int64 response_id) {
275 if (shutdown_called_)
276 return;
277 if (!appcache_service_)
278 return;
279 ResponseEnquiry response_enquiry = response_enquiries_.front();
280 response_enquiries_.pop_front();
281 if (response) {
282 scoped_refptr<AppCacheResponseInfo> response_info = response;
283 const int64 kLimit = 100 * 1000;
284 int64 amount_to_read =
285 std::min(kLimit, response_info->response_data_size());
286 scoped_refptr<net::IOBuffer> response_data(new net::IOBuffer(
287 base::CheckedNumeric<size_t>(amount_to_read).ValueOrDie()));
288 scoped_ptr<AppCacheResponseReader> reader(
289 appcache_service_->storage()->CreateResponseReader(
290 GURL(response_enquiry.manifest_url), response_enquiry.group_id,
291 response_enquiry.response_id));
293 reader->ReadData(
294 response_data.get(), amount_to_read,
295 base::Bind(&Proxy::OnResponseDataReadComplete, this, response_enquiry,
296 response_info, base::Passed(&reader), response_data));
297 } else {
298 OnResponseDataReadComplete(response_enquiry, nullptr, nullptr, nullptr, -1);
302 void AppCacheInternalsUI::Proxy::OnResponseDataReadComplete(
303 const ResponseEnquiry& response_enquiry,
304 scoped_refptr<AppCacheResponseInfo> response_info,
305 scoped_ptr<AppCacheResponseReader> reader,
306 scoped_refptr<net::IOBuffer> response_data,
307 int net_result_code) {
308 if (shutdown_called_)
309 return;
310 if (!response_info || net_result_code < 0) {
311 BrowserThread::PostTask(
312 BrowserThread::UI, FROM_HERE,
313 base::Bind(&AppCacheInternalsUI::OnFileDetailsFailed,
314 appcache_internals_ui_, response_enquiry, net_result_code));
315 } else {
316 BrowserThread::PostTask(
317 BrowserThread::UI, FROM_HERE,
318 base::Bind(&AppCacheInternalsUI::OnFileDetailsReady,
319 appcache_internals_ui_, response_enquiry, response_info,
320 response_data, net_result_code));
322 preparing_response_ = false;
323 HandleFileDetailsRequest();
326 AppCacheInternalsUI::AppCacheInternalsUI(WebUI* web_ui)
327 : WebUIController(web_ui), weak_ptr_factory_(this) {
328 web_ui->RegisterMessageCallback(
329 kRequestGetAllAppCacheInfo,
330 base::Bind(&AppCacheInternalsUI::GetAllAppCache, AsWeakPtr()));
332 web_ui->RegisterMessageCallback(
333 kRequestDeleteAppCache,
334 base::Bind(&AppCacheInternalsUI::DeleteAppCache, AsWeakPtr()));
336 web_ui->RegisterMessageCallback(
337 kRequestGetAppCacheDetails,
338 base::Bind(&AppCacheInternalsUI::GetAppCacheDetails, AsWeakPtr()));
340 web_ui->RegisterMessageCallback(
341 kRequestGetFileDetails,
342 base::Bind(&AppCacheInternalsUI::GetFileDetails, AsWeakPtr()));
344 WebUIDataSource* source =
345 WebUIDataSource::Create(kChromeUIAppCacheInternalsHost);
347 source->SetJsonPath("strings.js");
348 source->AddResourcePath("appcache_internals.js", IDR_APPCACHE_INTERNALS_JS);
349 source->AddResourcePath("appcache_internals.css", IDR_APPCACHE_INTERNALS_CSS);
350 source->SetDefaultResource(IDR_APPCACHE_INTERNALS_HTML);
352 WebUIDataSource::Add(browser_context(), source);
354 BrowserContext::StoragePartitionCallback callback =
355 base::Bind(&AppCacheInternalsUI::CreateProxyForPartition, AsWeakPtr());
356 BrowserContext::ForEachStoragePartition(browser_context(), callback);
359 AppCacheInternalsUI::~AppCacheInternalsUI() {
360 for (auto& proxy : appcache_proxies_)
361 proxy->Shutdown();
364 void AppCacheInternalsUI::CreateProxyForPartition(
365 StoragePartition* storage_partition) {
366 scoped_refptr<Proxy> proxy =
367 new Proxy(weak_ptr_factory_.GetWeakPtr(), storage_partition->GetPath());
368 proxy->Initialize(static_cast<StoragePartitionImpl*>(storage_partition)
369 ->GetAppCacheService());
370 appcache_proxies_.push_back(proxy);
373 void AppCacheInternalsUI::GetAllAppCache(const base::ListValue* args) {
374 DCHECK_CURRENTLY_ON(BrowserThread::UI);
375 for (scoped_refptr<Proxy>& proxy : appcache_proxies_)
376 proxy->RequestAllAppCacheInfo();
379 void AppCacheInternalsUI::DeleteAppCache(const base::ListValue* args) {
380 DCHECK_CURRENTLY_ON(BrowserThread::UI);
381 std::string manifest_url, partition_path;
382 args->GetString(0, &partition_path);
383 args->GetString(1, &manifest_url);
384 Proxy* proxy =
385 GetProxyForPartitionPath(base::FilePath::FromUTF8Unsafe(partition_path));
386 if (proxy)
387 proxy->DeleteAppCache(manifest_url);
390 void AppCacheInternalsUI::GetAppCacheDetails(const base::ListValue* args) {
391 std::string manifest_url, partition_path;
392 args->GetString(0, &partition_path);
393 args->GetString(1, &manifest_url);
394 Proxy* proxy =
395 GetProxyForPartitionPath(base::FilePath::FromUTF8Unsafe(partition_path));
396 if (proxy)
397 proxy->RequestAppCacheDetails(manifest_url);
400 void AppCacheInternalsUI::GetFileDetails(const base::ListValue* args) {
401 std::string manifest_url, partition_path, group_id_str, response_id_str;
402 args->GetString(0, &partition_path);
403 args->GetString(1, &manifest_url);
404 args->GetString(2, &group_id_str);
405 args->GetString(3, &response_id_str);
406 Proxy* proxy =
407 GetProxyForPartitionPath(base::FilePath::FromUTF8Unsafe(partition_path));
408 if (proxy)
409 proxy->RequestFileDetails(
410 {manifest_url, ToInt64(group_id_str), ToInt64(response_id_str)});
413 void AppCacheInternalsUI::OnAllAppCacheInfoReady(
414 scoped_refptr<AppCacheInfoCollection> collection,
415 const base::FilePath& partition_path) {
416 web_ui()->CallJavascriptFunction(
417 kFunctionOnAllAppCacheInfoReady,
418 base::StringValue(partition_path.AsUTF8Unsafe()),
419 *GetListValueFromAppCacheInfoCollection(collection.get()));
422 void AppCacheInternalsUI::OnAppCacheInfoDeleted(
423 const base::FilePath& partition_path,
424 const std::string& manifest_url,
425 bool deleted) {
426 web_ui()->CallJavascriptFunction(
427 kFunctionOnAppCacheInfoDeleted,
428 base::StringValue(partition_path.AsUTF8Unsafe()),
429 base::StringValue(manifest_url), base::FundamentalValue(deleted));
432 void AppCacheInternalsUI::OnAppCacheDetailsReady(
433 const base::FilePath& partition_path,
434 const std::string& manifest_url,
435 scoped_ptr<AppCacheResourceInfoVector> resource_info_vector) {
436 if (resource_info_vector) {
437 web_ui()->CallJavascriptFunction(
438 kFunctionOnAppCacheDetailsReady, base::StringValue(manifest_url),
439 base::StringValue(partition_path.AsUTF8Unsafe()),
440 *GetListValueForAppCacheResourceInfoVector(resource_info_vector.get()));
441 } else {
442 web_ui()->CallJavascriptFunction(
443 kFunctionOnAppCacheDetailsReady, base::StringValue(manifest_url),
444 base::StringValue(partition_path.AsUTF8Unsafe()));
448 void AppCacheInternalsUI::OnFileDetailsReady(
449 const Proxy::ResponseEnquiry& response_enquiry,
450 scoped_refptr<AppCacheResponseInfo> response_info,
451 scoped_refptr<net::IOBuffer> response_data,
452 int data_length) {
453 std::string headers;
454 if (response_info->http_response_info()) {
455 headers.append("<hr><pre>");
456 headers.append(net::EscapeForHTML(
457 response_info->http_response_info()->headers->GetStatusLine()));
458 headers.push_back('\n');
460 void* iter = nullptr;
461 std::string name, value;
462 while (response_info->http_response_info()->headers->EnumerateHeaderLines(
463 &iter, &name, &value)) {
464 headers.append(net::EscapeForHTML(name));
465 headers.append(": ");
466 headers.append(net::EscapeForHTML(value));
467 headers.push_back('\n');
469 headers.append("</pre>");
470 } else {
471 headers.append("Failed to read response headers. <br>");
473 std::string hex_dump = base::StringPrintf(
474 "<hr><pre> Showing %d of %d bytes\n\n", static_cast<int>(data_length),
475 static_cast<int>(response_info->response_data_size()));
476 net::ViewCacheHelper::HexDump(response_data->data(), data_length, &hex_dump);
477 if (data_length < response_info->response_data_size())
478 hex_dump.append("\nNote: data is truncated...");
479 hex_dump.append("</pre>");
480 web_ui()->CallJavascriptFunction(
481 kFunctionOnFileDetailsReady,
482 *GetDictionaryValueForResponseEnquiry(response_enquiry),
483 base::StringValue(headers), base::StringValue(hex_dump));
486 void AppCacheInternalsUI::OnFileDetailsFailed(
487 const Proxy::ResponseEnquiry& response_enquiry,
488 int net_result_code) {
489 web_ui()->CallJavascriptFunction(
490 kFunctionOnFileDetailsFailed,
491 *GetDictionaryValueForResponseEnquiry(response_enquiry),
492 base::FundamentalValue(net_result_code));
495 AppCacheInternalsUI::Proxy* AppCacheInternalsUI::GetProxyForPartitionPath(
496 const base::FilePath& partition_path) {
497 for (const scoped_refptr<Proxy>& proxy : appcache_proxies_) {
498 if (proxy->partition_path_ == partition_path)
499 return proxy.get();
501 NOTREACHED();
502 return nullptr;
505 } // namespace content