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.
4
5 #include "content/browser/appcache/appcache_internals_ui.h"
6
7 #include <stddef.h>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/task/post_task.h"
18 #include "base/threading/platform_thread.h"
19 #include "base/values.h"
20 #include "content/browser/appcache/appcache.h"
21 #include "content/browser/appcache/appcache_disk_cache_ops.h"
22 #include "content/browser/appcache/appcache_response_info.h"
23 #include "content/browser/storage_partition_impl.h"
24 #include "content/grit/dev_ui_content_resources.h"
25 #include "content/public/browser/browser_context.h"
26 #include "content/public/browser/browser_task_traits.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/web_ui.h"
29 #include "content/public/browser/web_ui_data_source.h"
30 #include "content/public/common/url_constants.h"
31 #include "net/base/escape.h"
32 #include "net/http/http_response_headers.h"
33 #include "net/url_request/view_cache_helper.h"
34 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
35 #include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
36
37 namespace content {
38
39 namespace {
40 const char kRequestGetAllAppCacheInfo[] = "getAllAppCache";
41 const char kRequestDeleteAppCache[] = "deleteAppCache";
42 const char kRequestGetAppCacheDetails[] = "getAppCacheDetails";
43 const char kRequestGetFileDetails[] = "getFileDetails";
44
45 const char kFunctionOnAllAppCacheInfoReady[] =
46 "appcache.onAllAppCacheInfoReady";
47 const char kFunctionOnAppCacheInfoDeleted[] = "appcache.onAppCacheInfoDeleted";
48 const char kFunctionOnAppCacheDetailsReady[] =
49 "appcache.onAppCacheDetailsReady";
50 const char kFunctionOnFileDetailsReady[] = "appcache.onFileDetailsReady";
51 const char kFunctionOnFileDetailsFailed[] = "appcache.onFileDetailsFailed";
52
ToInt64(const std::string & str)53 int64_t ToInt64(const std::string& str) {
54 int64_t i = 0;
55 base::StringToInt64(str.c_str(), &i);
56 return i;
57 }
58
SortByResourceUrl(const blink::mojom::AppCacheResourceInfo & lhs,const blink::mojom::AppCacheResourceInfo & rhs)59 bool SortByResourceUrl(const blink::mojom::AppCacheResourceInfo& lhs,
60 const blink::mojom::AppCacheResourceInfo& rhs) {
61 return lhs.url.spec() < rhs.url.spec();
62 }
63
GetDictionaryValueForResponseEnquiry(const content::AppCacheInternalsUI::ProxyResponseEnquiry & response_enquiry)64 std::unique_ptr<base::DictionaryValue> GetDictionaryValueForResponseEnquiry(
65 const content::AppCacheInternalsUI::ProxyResponseEnquiry&
66 response_enquiry) {
67 auto dict_value = std::make_unique<base::DictionaryValue>();
68 dict_value->SetString("manifestURL", response_enquiry.manifest_url);
69 dict_value->SetString("groupId",
70 base::NumberToString(response_enquiry.group_id));
71 dict_value->SetString("responseId",
72 base::NumberToString(response_enquiry.response_id));
73 return dict_value;
74 }
75
GetDictionaryValueForAppCacheInfo(const blink::mojom::AppCacheInfo & appcache_info)76 std::unique_ptr<base::DictionaryValue> GetDictionaryValueForAppCacheInfo(
77 const blink::mojom::AppCacheInfo& appcache_info) {
78 auto dict_value = std::make_unique<base::DictionaryValue>();
79 dict_value->SetString("manifestURL", appcache_info.manifest_url.spec());
80 dict_value->SetDouble("creationTime", appcache_info.creation_time.ToJsTime());
81 dict_value->SetDouble("lastUpdateTime",
82 appcache_info.last_update_time.ToJsTime());
83 dict_value->SetDouble("lastAccessTime",
84 appcache_info.last_access_time.ToJsTime());
85 dict_value->SetDouble("tokenExpires", appcache_info.token_expires.ToJsTime());
86 dict_value->SetString("responseSizes",
87 base::UTF16ToUTF8(base::FormatBytesUnlocalized(
88 appcache_info.response_sizes)));
89 dict_value->SetString("paddingSizes",
90 base::UTF16ToUTF8(base::FormatBytesUnlocalized(
91 appcache_info.padding_sizes)));
92 dict_value->SetString(
93 "totalSize",
94 base::UTF16ToUTF8(base::FormatBytesUnlocalized(
95 appcache_info.response_sizes + appcache_info.padding_sizes)));
96 dict_value->SetString("groupId",
97 base::NumberToString(appcache_info.group_id));
98
99 dict_value->SetString(
100 "manifestParserVersion",
101 base::NumberToString(appcache_info.manifest_parser_version));
102 dict_value->SetString("manifestScope", appcache_info.manifest_scope);
103
104 return dict_value;
105 }
106
GetListValueForAppCacheInfoVector(const std::vector<blink::mojom::AppCacheInfo> appcache_info_vector)107 std::unique_ptr<base::ListValue> GetListValueForAppCacheInfoVector(
108 const std::vector<blink::mojom::AppCacheInfo> appcache_info_vector) {
109 auto list = std::make_unique<base::ListValue>();
110 for (const blink::mojom::AppCacheInfo& info : appcache_info_vector)
111 list->Append(GetDictionaryValueForAppCacheInfo(info));
112 return list;
113 }
114
GetListValueFromAppCacheInfoCollection(AppCacheInfoCollection * appcache_collection)115 std::unique_ptr<base::ListValue> GetListValueFromAppCacheInfoCollection(
116 AppCacheInfoCollection* appcache_collection) {
117 auto list = std::make_unique<base::ListValue>();
118 for (const auto& key_value : appcache_collection->infos_by_origin) {
119 auto dict = std::make_unique<base::DictionaryValue>();
120 // Use GURL::spec() to keep consistency with previous version
121 dict->SetString("originURL", key_value.first.GetURL().spec());
122 dict->Set("manifests", GetListValueForAppCacheInfoVector(key_value.second));
123 list->Append(std::move(dict));
124 }
125 return list;
126 }
127
128 std::unique_ptr<base::DictionaryValue>
GetDictionaryValueForAppCacheResourceInfo(const blink::mojom::AppCacheResourceInfo & resource_info)129 GetDictionaryValueForAppCacheResourceInfo(
130 const blink::mojom::AppCacheResourceInfo& resource_info) {
131 auto dict = std::make_unique<base::DictionaryValue>();
132 dict->SetString("url", resource_info.url.spec());
133 dict->SetString("responseSize",
134 base::UTF16ToUTF8(base::FormatBytesUnlocalized(
135 resource_info.response_size)));
136 dict->SetString("paddingSize", base::UTF16ToUTF8(base::FormatBytesUnlocalized(
137 resource_info.padding_size)));
138 dict->SetString("totalSize", base::UTF16ToUTF8(base::FormatBytesUnlocalized(
139 resource_info.response_size +
140 resource_info.padding_size)));
141 dict->SetString("responseId",
142 base::NumberToString(resource_info.response_id));
143 dict->SetBoolean("isExplicit", resource_info.is_explicit);
144 dict->SetBoolean("isManifest", resource_info.is_manifest);
145 dict->SetBoolean("isMaster", resource_info.is_master);
146 dict->SetBoolean("isFallback", resource_info.is_fallback);
147 dict->SetBoolean("isIntercept", resource_info.is_intercept);
148 dict->SetBoolean("isForeign", resource_info.is_foreign);
149 dict->SetDouble("tokenExpires", resource_info.token_expires.ToJsTime());
150
151 return dict;
152 }
153
GetListValueForAppCacheResourceInfoVector(std::vector<blink::mojom::AppCacheResourceInfo> * resource_info_vector)154 std::unique_ptr<base::ListValue> GetListValueForAppCacheResourceInfoVector(
155 std::vector<blink::mojom::AppCacheResourceInfo>* resource_info_vector) {
156 auto list = std::make_unique<base::ListValue>();
157 for (const blink::mojom::AppCacheResourceInfo& res_info :
158 *resource_info_vector)
159 list->Append(GetDictionaryValueForAppCacheResourceInfo(res_info));
160 return list;
161 }
162
163 } // namespace
164
Proxy(base::WeakPtr<AppCacheInternalsUI> appcache_internals_ui,const base::FilePath & partition_path)165 AppCacheInternalsUI::Proxy::Proxy(
166 base::WeakPtr<AppCacheInternalsUI> appcache_internals_ui,
167 const base::FilePath& partition_path)
168 : appcache_internals_ui_(appcache_internals_ui),
169 partition_path_(partition_path) {}
170
Initialize(const scoped_refptr<ChromeAppCacheService> & chrome_appcache_service)171 void AppCacheInternalsUI::Proxy::Initialize(
172 const scoped_refptr<ChromeAppCacheService>& chrome_appcache_service) {
173 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
174 base::PostTask(
175 FROM_HERE, {BrowserThread::UI},
176 base::BindOnce(&Proxy::Initialize, this, chrome_appcache_service));
177 return;
178 }
179 appcache_service_ = chrome_appcache_service->AsWeakPtr();
180 shutdown_called_ = false;
181 preparing_response_ = false;
182 }
183
~Proxy()184 AppCacheInternalsUI::Proxy::~Proxy() {
185 DCHECK(shutdown_called_);
186 }
187
Shutdown()188 void AppCacheInternalsUI::Proxy::Shutdown() {
189 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
190 base::PostTask(FROM_HERE, {BrowserThread::UI},
191 base::BindOnce(&Proxy::Shutdown, this));
192 return;
193 }
194 shutdown_called_ = true;
195 if (appcache_service_) {
196 appcache_service_->storage()->CancelDelegateCallbacks(this);
197 appcache_service_.reset();
198 response_enquiries_.clear();
199 }
200 }
201
RequestAllAppCacheInfo()202 void AppCacheInternalsUI::Proxy::RequestAllAppCacheInfo() {
203 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
204 base::PostTask(FROM_HERE, {BrowserThread::UI},
205 base::BindOnce(&Proxy::RequestAllAppCacheInfo, this));
206 return;
207 }
208 if (appcache_service_) {
209 auto collection = base::MakeRefCounted<AppCacheInfoCollection>();
210 AppCacheInfoCollection* collection_ptr = collection.get();
211 appcache_service_->GetAllAppCacheInfo(
212 collection_ptr, base::BindOnce(&Proxy::OnAllAppCacheInfoReady, this,
213 std::move(collection)));
214 }
215 }
216
OnAllAppCacheInfoReady(scoped_refptr<AppCacheInfoCollection> collection,int net_result_code)217 void AppCacheInternalsUI::Proxy::OnAllAppCacheInfoReady(
218 scoped_refptr<AppCacheInfoCollection> collection,
219 int net_result_code) {
220 appcache_internals_ui_->OnAllAppCacheInfoReady(collection, partition_path_);
221 }
222
DeleteAppCache(const std::string & manifest_url)223 void AppCacheInternalsUI::Proxy::DeleteAppCache(
224 const std::string& manifest_url) {
225 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
226 base::PostTask(FROM_HERE, {BrowserThread::UI},
227 base::BindOnce(&Proxy::DeleteAppCache, this, manifest_url));
228 return;
229 }
230 if (appcache_service_) {
231 appcache_service_->DeleteAppCacheGroup(
232 GURL(manifest_url),
233 base::BindOnce(&Proxy::OnAppCacheInfoDeleted, this, manifest_url));
234 }
235 }
236
OnAppCacheInfoDeleted(const std::string & manifest_url,int net_result_code)237 void AppCacheInternalsUI::Proxy::OnAppCacheInfoDeleted(
238 const std::string& manifest_url,
239 int net_result_code) {
240 appcache_internals_ui_->OnAppCacheInfoDeleted(partition_path_, manifest_url,
241 net_result_code == net::OK);
242 }
243
RequestAppCacheDetails(const std::string & manifest_url)244 void AppCacheInternalsUI::Proxy::RequestAppCacheDetails(
245 const std::string& manifest_url) {
246 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
247 base::PostTask(
248 FROM_HERE, {BrowserThread::UI},
249 base::BindOnce(&Proxy::RequestAppCacheDetails, this, manifest_url));
250 return;
251 }
252
253 if (appcache_service_)
254 appcache_service_->storage()->LoadOrCreateGroup(GURL(manifest_url), this);
255 }
256
OnGroupLoaded(AppCacheGroup * appcache_group,const GURL & manifest_gurl)257 void AppCacheInternalsUI::Proxy::OnGroupLoaded(AppCacheGroup* appcache_group,
258 const GURL& manifest_gurl) {
259 std::unique_ptr<std::vector<blink::mojom::AppCacheResourceInfo>>
260 resource_info_vector;
261 if (appcache_group && appcache_group->newest_complete_cache()) {
262 resource_info_vector =
263 std::make_unique<std::vector<blink::mojom::AppCacheResourceInfo>>();
264 appcache_group->newest_complete_cache()->ToResourceInfoVector(
265 resource_info_vector.get());
266 std::sort(resource_info_vector->begin(), resource_info_vector->end(),
267 SortByResourceUrl);
268 }
269 appcache_internals_ui_->OnAppCacheDetailsReady(
270 partition_path_, manifest_gurl.spec(), std::move(resource_info_vector));
271 }
272
RequestFileDetails(const ProxyResponseEnquiry & response_enquiry)273 void AppCacheInternalsUI::Proxy::RequestFileDetails(
274 const ProxyResponseEnquiry& response_enquiry) {
275 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
276 base::PostTask(
277 FROM_HERE, {BrowserThread::UI},
278 base::BindOnce(&Proxy::RequestFileDetails, this, response_enquiry));
279 return;
280 }
281 DCHECK(!shutdown_called_);
282 response_enquiries_.push_back(response_enquiry);
283 HandleFileDetailsRequest();
284 }
285
HandleFileDetailsRequest()286 void AppCacheInternalsUI::Proxy::HandleFileDetailsRequest() {
287 if (preparing_response_ || response_enquiries_.empty() || !appcache_service_)
288 return;
289 preparing_response_ = true;
290 appcache_service_->storage()->LoadResponseInfo(
291 GURL(response_enquiries_.front().manifest_url),
292 response_enquiries_.front().response_id, this);
293 }
294
OnResponseInfoLoaded(AppCacheResponseInfo * response,int64_t response_id)295 void AppCacheInternalsUI::Proxy::OnResponseInfoLoaded(
296 AppCacheResponseInfo* response,
297 int64_t response_id) {
298 if (shutdown_called_)
299 return;
300 if (!appcache_service_)
301 return;
302 ProxyResponseEnquiry response_enquiry = response_enquiries_.front();
303 response_enquiries_.pop_front();
304 if (response) {
305 scoped_refptr<AppCacheResponseInfo> response_info = response;
306 const int64_t kLimit = 100 * 1000;
307 int64_t amount_to_read =
308 std::min(kLimit, response_info->response_data_size());
309 scoped_refptr<net::IOBuffer> response_data =
310 base::MakeRefCounted<net::IOBuffer>(
311 base::checked_cast<size_t>(amount_to_read));
312 std::unique_ptr<AppCacheResponseReader> reader =
313 appcache_service_->storage()->CreateResponseReader(
314 GURL(response_enquiry.manifest_url), response_enquiry.response_id);
315
316 reader->ReadData(response_data.get(), amount_to_read,
317 base::BindOnce(&Proxy::OnResponseDataReadComplete, this,
318 response_enquiry, response_info,
319 std::move(reader), response_data));
320 } else {
321 OnResponseDataReadComplete(response_enquiry, nullptr, nullptr, nullptr, -1);
322 }
323 }
324
OnResponseDataReadComplete(const ProxyResponseEnquiry & response_enquiry,scoped_refptr<AppCacheResponseInfo> response_info,std::unique_ptr<AppCacheResponseReader> reader,scoped_refptr<net::IOBuffer> response_data,int net_result_code)325 void AppCacheInternalsUI::Proxy::OnResponseDataReadComplete(
326 const ProxyResponseEnquiry& response_enquiry,
327 scoped_refptr<AppCacheResponseInfo> response_info,
328 std::unique_ptr<AppCacheResponseReader> reader,
329 scoped_refptr<net::IOBuffer> response_data,
330 int net_result_code) {
331 if (shutdown_called_)
332 return;
333 if (!response_info || net_result_code < 0) {
334 appcache_internals_ui_->OnFileDetailsFailed(response_enquiry,
335 net_result_code);
336 } else {
337 appcache_internals_ui_->OnFileDetailsReady(response_enquiry, response_info,
338 response_data, net_result_code);
339 }
340 preparing_response_ = false;
341 HandleFileDetailsRequest();
342 }
343
AppCacheInternalsUI(WebUI * web_ui)344 AppCacheInternalsUI::AppCacheInternalsUI(WebUI* web_ui)
345 : WebUIController(web_ui) {
346 web_ui->RegisterMessageCallback(
347 kRequestGetAllAppCacheInfo,
348 base::BindRepeating(&AppCacheInternalsUI::GetAllAppCache, AsWeakPtr()));
349
350 web_ui->RegisterMessageCallback(
351 kRequestDeleteAppCache,
352 base::BindRepeating(&AppCacheInternalsUI::DeleteAppCache, AsWeakPtr()));
353
354 web_ui->RegisterMessageCallback(
355 kRequestGetAppCacheDetails,
356 base::BindRepeating(&AppCacheInternalsUI::GetAppCacheDetails,
357 AsWeakPtr()));
358
359 web_ui->RegisterMessageCallback(
360 kRequestGetFileDetails,
361 base::BindRepeating(&AppCacheInternalsUI::GetFileDetails, AsWeakPtr()));
362
363 WebUIDataSource* source =
364 WebUIDataSource::Create(kChromeUIAppCacheInternalsHost);
365 source->OverrideContentSecurityPolicyScriptSrc(
366 "script-src chrome://resources 'self' 'unsafe-eval';");
367
368 source->UseStringsJs();
369 source->AddResourcePath("appcache_internals.js", IDR_APPCACHE_INTERNALS_JS);
370 source->AddResourcePath("appcache_internals.css", IDR_APPCACHE_INTERNALS_CSS);
371 source->SetDefaultResource(IDR_APPCACHE_INTERNALS_HTML);
372
373 WebUIDataSource::Add(GetBrowserContext(), source);
374
375 BrowserContext::ForEachStoragePartition(
376 GetBrowserContext(),
377 base::BindRepeating(&AppCacheInternalsUI::CreateProxyForPartition,
378 AsWeakPtr()));
379 }
380
~AppCacheInternalsUI()381 AppCacheInternalsUI::~AppCacheInternalsUI() {
382 for (auto& proxy : appcache_proxies_)
383 proxy->Shutdown();
384 }
385
CreateProxyForPartition(StoragePartition * storage_partition)386 void AppCacheInternalsUI::CreateProxyForPartition(
387 StoragePartition* storage_partition) {
388 auto proxy = base::MakeRefCounted<Proxy>(weak_ptr_factory_.GetWeakPtr(),
389 storage_partition->GetPath());
390 proxy->Initialize(static_cast<StoragePartitionImpl*>(storage_partition)
391 ->GetAppCacheService());
392 appcache_proxies_.emplace_back(std::move(proxy));
393 }
394
GetAllAppCache(const base::ListValue * args)395 void AppCacheInternalsUI::GetAllAppCache(const base::ListValue* args) {
396 DCHECK_CURRENTLY_ON(BrowserThread::UI);
397 for (scoped_refptr<Proxy>& proxy : appcache_proxies_)
398 proxy->RequestAllAppCacheInfo();
399 }
400
DeleteAppCache(const base::ListValue * args)401 void AppCacheInternalsUI::DeleteAppCache(const base::ListValue* args) {
402 DCHECK_CURRENTLY_ON(BrowserThread::UI);
403 std::string manifest_url, partition_path;
404 args->GetString(0, &partition_path);
405 args->GetString(1, &manifest_url);
406 Proxy* proxy =
407 GetProxyForPartitionPath(base::FilePath::FromUTF8Unsafe(partition_path));
408 if (proxy)
409 proxy->DeleteAppCache(manifest_url);
410 }
411
GetAppCacheDetails(const base::ListValue * args)412 void AppCacheInternalsUI::GetAppCacheDetails(const base::ListValue* args) {
413 std::string manifest_url, partition_path;
414 args->GetString(0, &partition_path);
415 args->GetString(1, &manifest_url);
416 Proxy* proxy =
417 GetProxyForPartitionPath(base::FilePath::FromUTF8Unsafe(partition_path));
418 if (proxy)
419 proxy->RequestAppCacheDetails(manifest_url);
420 }
421
GetFileDetails(const base::ListValue * args)422 void AppCacheInternalsUI::GetFileDetails(const base::ListValue* args) {
423 std::string manifest_url, partition_path, group_id_str, response_id_str;
424 args->GetString(0, &partition_path);
425 args->GetString(1, &manifest_url);
426 args->GetString(2, &group_id_str);
427 args->GetString(3, &response_id_str);
428 Proxy* proxy =
429 GetProxyForPartitionPath(base::FilePath::FromUTF8Unsafe(partition_path));
430 if (proxy)
431 proxy->RequestFileDetails(
432 {manifest_url, ToInt64(group_id_str), ToInt64(response_id_str)});
433 }
434
OnAllAppCacheInfoReady(scoped_refptr<AppCacheInfoCollection> collection,const base::FilePath & partition_path)435 void AppCacheInternalsUI::OnAllAppCacheInfoReady(
436 scoped_refptr<AppCacheInfoCollection> collection,
437 const base::FilePath& partition_path) {
438 std::string incognito_path_prefix;
439 if (GetBrowserContext()->IsOffTheRecord())
440 incognito_path_prefix = "Incognito ";
441 web_ui()->CallJavascriptFunctionUnsafe(
442 kFunctionOnAllAppCacheInfoReady,
443 base::Value(partition_path.AsUTF8Unsafe()),
444 base::Value(incognito_path_prefix + partition_path.AsUTF8Unsafe()),
445 *GetListValueFromAppCacheInfoCollection(collection.get()));
446 }
447
OnAppCacheInfoDeleted(const base::FilePath & partition_path,const std::string & manifest_url,bool deleted)448 void AppCacheInternalsUI::OnAppCacheInfoDeleted(
449 const base::FilePath& partition_path,
450 const std::string& manifest_url,
451 bool deleted) {
452 web_ui()->CallJavascriptFunctionUnsafe(
453 kFunctionOnAppCacheInfoDeleted,
454 base::Value(partition_path.AsUTF8Unsafe()), base::Value(manifest_url),
455 base::Value(deleted));
456 }
457
OnAppCacheDetailsReady(const base::FilePath & partition_path,const std::string & manifest_url,std::unique_ptr<std::vector<blink::mojom::AppCacheResourceInfo>> resource_info_vector)458 void AppCacheInternalsUI::OnAppCacheDetailsReady(
459 const base::FilePath& partition_path,
460 const std::string& manifest_url,
461 std::unique_ptr<std::vector<blink::mojom::AppCacheResourceInfo>>
462 resource_info_vector) {
463 if (resource_info_vector) {
464 web_ui()->CallJavascriptFunctionUnsafe(
465 kFunctionOnAppCacheDetailsReady, base::Value(manifest_url),
466 base::Value(partition_path.AsUTF8Unsafe()),
467 *GetListValueForAppCacheResourceInfoVector(resource_info_vector.get()));
468 } else {
469 web_ui()->CallJavascriptFunctionUnsafe(
470 kFunctionOnAppCacheDetailsReady, base::Value(manifest_url),
471 base::Value(partition_path.AsUTF8Unsafe()));
472 }
473 }
474
OnFileDetailsReady(const ProxyResponseEnquiry & response_enquiry,scoped_refptr<AppCacheResponseInfo> response_info,scoped_refptr<net::IOBuffer> response_data,int data_length)475 void AppCacheInternalsUI::OnFileDetailsReady(
476 const ProxyResponseEnquiry& response_enquiry,
477 scoped_refptr<AppCacheResponseInfo> response_info,
478 scoped_refptr<net::IOBuffer> response_data,
479 int data_length) {
480 std::string headers;
481 headers.append("<hr><pre>");
482 headers.append(net::EscapeForHTML(
483 response_info->http_response_info().headers->GetStatusLine()));
484 headers.push_back('\n');
485
486 size_t iter = 0;
487 std::string name, value;
488 while (response_info->http_response_info().headers->EnumerateHeaderLines(
489 &iter, &name, &value)) {
490 headers.append(net::EscapeForHTML(name));
491 headers.append(": ");
492 headers.append(net::EscapeForHTML(value));
493 headers.push_back('\n');
494 }
495 headers.append("</pre>");
496
497 std::string hex_dump = base::StringPrintf(
498 "<hr><pre> Showing %d of %d bytes\n\n", static_cast<int>(data_length),
499 static_cast<int>(response_info->response_data_size()));
500 net::ViewCacheHelper::HexDump(response_data->data(), data_length, &hex_dump);
501 if (data_length < response_info->response_data_size())
502 hex_dump.append("\nNote: data is truncated...");
503 hex_dump.append("</pre>");
504 web_ui()->CallJavascriptFunctionUnsafe(
505 kFunctionOnFileDetailsReady,
506 *GetDictionaryValueForResponseEnquiry(response_enquiry),
507 base::Value(headers), base::Value(hex_dump));
508 }
509
OnFileDetailsFailed(const ProxyResponseEnquiry & response_enquiry,int net_result_code)510 void AppCacheInternalsUI::OnFileDetailsFailed(
511 const ProxyResponseEnquiry& response_enquiry,
512 int net_result_code) {
513 web_ui()->CallJavascriptFunctionUnsafe(
514 kFunctionOnFileDetailsFailed,
515 *GetDictionaryValueForResponseEnquiry(response_enquiry),
516 base::Value(net_result_code));
517 }
518
GetBrowserContext()519 BrowserContext* AppCacheInternalsUI::GetBrowserContext() {
520 return web_ui()->GetWebContents()->GetBrowserContext();
521 }
522
GetProxyForPartitionPath(const base::FilePath & partition_path)523 AppCacheInternalsUI::Proxy* AppCacheInternalsUI::GetProxyForPartitionPath(
524 const base::FilePath& partition_path) {
525 for (const scoped_refptr<Proxy>& proxy : appcache_proxies_) {
526 if (proxy->partition_path_ == partition_path)
527 return proxy.get();
528 }
529 NOTREACHED();
530 return nullptr;
531 }
532
533 } // namespace content
534