15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/extensions/extension_error_ui_util.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file_path.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file_util.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/string16.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/devtools/devtools_window.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/browser/extension_error.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "extensions/browser/extension_registry.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/browser/file_highlighter.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "extensions/common/constants.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "extensions/common/extension.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace error_ui_util { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keys for objects passed to and from extension error UI. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPathSuffixKey[] = "pathSuffix"; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kTitleKey[] = "title"; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string ReadFileToString(const base::FilePath& path) { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string data; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ReadFileToString(path, &data); 43a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return data; 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetManifestFileCallback(base::DictionaryValue* results, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& key, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& specific, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const RequestFileSourceCallback& response, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& contents) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ManifestHighlighter highlighter(contents, key, specific); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) highlighter.SetHighlightedRegions(results); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response.Run(*results); 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetSourceFileCallback(base::DictionaryValue* results, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int line_number, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const RequestFileSourceCallback& response, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& contents) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SourceHighlighter highlighter(contents, line_number); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) highlighter.SetHighlightedRegions(results); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response.Run(*results); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HandleRequestFileSource(const base::DictionaryValue* args, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const RequestFileSourceCallback& response) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Three required arguments: extension_id, path_suffix, and error_message. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string extension_id; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::FilePath::StringType path_suffix_string; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::string16 error_message; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!args->GetString(kPathSuffixKey, &path_suffix_string) || 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !args->GetString(ExtensionError::kExtensionIdKey, &extension_id) || 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !args->GetString(ExtensionError::kMessageKey, &error_message)) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionRegistry::Get(profile)->GetExtensionById( 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension_id, ExtensionRegistry::EVERYTHING); 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extension) { 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Under no circumstances should we ever need to reference a file outside of 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the extension's directory. If it tries to, abort. 9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::FilePath path_suffix(path_suffix_string); 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (path_suffix.ReferencesParent()) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath path = extension->path().Append(path_suffix); 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Setting the title and the error message is the same for all file types. 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<base::DictionaryValue> results(new base::DictionaryValue); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) results->SetString(kTitleKey, 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::UTF8ToUTF16(extension->name()) + 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ASCIIToUTF16(": ") + 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path.BaseName().LossyDisplayName()); 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) results->SetString(ExtensionError::kMessageKey, error_message); 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Callback<void(const std::string&)> reply; 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (path_suffix_string == kManifestFilename) { 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string manifest_key; 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!args->GetString(ManifestError::kManifestKeyKey, &manifest_key)) { 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // A "specific" location is optional. 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string specific; 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args->GetString(ManifestError::kManifestSpecificKey, &specific); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reply = base::Bind(&GetManifestFileCallback, 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Owned(results.release()), 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) manifest_key, 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) specific, 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) response); 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int line_number = 0; 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args->GetInteger(RuntimeError::kLineNumberKey, &line_number); 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reply = base::Bind(&GetSourceFileCallback, 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Owned(results.release()), 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_number, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::PostTaskAndReplyWithResult(content::BrowserThread::GetBlockingPool(), 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ReadFileToString, path), 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reply); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HandleOpenDevTools(const base::DictionaryValue* args) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int render_process_id = 0; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int render_view_id = 0; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The render view and render process ids are required. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!args->GetInteger(RuntimeError::kRenderProcessIdKey, 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &render_process_id) || 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !args->GetInteger(RuntimeError::kRenderViewIdKey, &render_view_id)) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderViewHost* rvh = 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderViewHost::FromID(render_process_id, render_view_id); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's possible that the render view was closed since we last updated the 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // links. Handle this gracefully. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!rvh) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::WebContents* web_contents = 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::WebContents::FromRenderViewHost(rvh); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!web_contents) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we include a url, we should inspect it specifically (and not just the 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // render view). 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::string16 url; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (args->GetString(RuntimeError::kUrlKey, &url)) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Line and column numbers are optional; default to the first line. 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int line_number = 1; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int column_number = 1; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) args->GetInteger(RuntimeError::kLineNumberKey, &line_number); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) args->GetInteger(RuntimeError::kColumnNumberKey, &column_number); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Line/column numbers are reported in display-friendly 1-based numbers, 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but are inspected in zero-based numbers. 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DevToolsWindow::OpenDevToolsWindow( 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DevToolsToggleAction::Reveal(url, line_number - 1, column_number - 1)); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DevToolsWindow::OpenDevToolsWindow(web_contents); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Once we open the inspector, we focus on the appropriate tab... 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Browser* browser = chrome::FindBrowserWithWebContents(web_contents); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ... but some pages (popups and apps) don't have tabs, and some (background 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pages) don't have an associated browser. For these, the inspector opens in 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a new window, and our work is done. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!browser || !browser->is_type_tabbed()) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_strip->ActivateTabAt(tab_strip->GetIndexOfWebContents(web_contents), 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); // Not through direct user gesture. 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace error_ui_util 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)