common_web_contents_delegate.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. // Copyright (c) 2015 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/browser/common_web_contents_delegate.h"
  5. #include <set>
  6. #include <string>
  7. #include <vector>
  8. #include "atom/browser/atom_browser_context.h"
  9. #include "atom/browser/native_window.h"
  10. #include "atom/browser/ui/file_dialog.h"
  11. #include "atom/browser/web_contents_preferences.h"
  12. #include "atom/browser/web_dialog_helper.h"
  13. #include "atom/common/atom_constants.h"
  14. #include "atom/common/options_switches.h"
  15. #include "base/files/file_util.h"
  16. #include "chrome/browser/printing/print_preview_message_handler.h"
  17. #include "chrome/browser/printing/print_view_manager_basic.h"
  18. #include "chrome/browser/ssl/security_state_tab_helper.h"
  19. #include "chrome/browser/ui/browser_dialogs.h"
  20. #include "chrome/common/pref_names.h"
  21. #include "components/prefs/pref_service.h"
  22. #include "components/prefs/scoped_user_pref_update.h"
  23. #include "components/security_state/content/content_utils.h"
  24. #include "components/security_state/core/security_state.h"
  25. #include "content/public/browser/browser_thread.h"
  26. #include "content/public/browser/child_process_security_policy.h"
  27. #include "content/public/browser/render_process_host.h"
  28. #include "content/public/browser/render_view_host.h"
  29. #include "content/public/browser/render_widget_host.h"
  30. #include "content/public/browser/security_style_explanation.h"
  31. #include "content/public/browser/security_style_explanations.h"
  32. #include "storage/browser/fileapi/isolated_context.h"
  33. using content::BrowserThread;
  34. namespace atom {
  35. namespace {
  36. const char kRootName[] = "<root>";
  37. struct FileSystem {
  38. FileSystem() {}
  39. FileSystem(const std::string& file_system_name,
  40. const std::string& root_url,
  41. const std::string& file_system_path)
  42. : file_system_name(file_system_name),
  43. root_url(root_url),
  44. file_system_path(file_system_path) {}
  45. std::string file_system_name;
  46. std::string root_url;
  47. std::string file_system_path;
  48. };
  49. std::string RegisterFileSystem(content::WebContents* web_contents,
  50. const base::FilePath& path) {
  51. auto* isolated_context = storage::IsolatedContext::GetInstance();
  52. std::string root_name(kRootName);
  53. std::string file_system_id = isolated_context->RegisterFileSystemForPath(
  54. storage::kFileSystemTypeNativeLocal, std::string(), path, &root_name);
  55. content::ChildProcessSecurityPolicy* policy =
  56. content::ChildProcessSecurityPolicy::GetInstance();
  57. content::RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
  58. int renderer_id = render_view_host->GetProcess()->GetID();
  59. policy->GrantReadFileSystem(renderer_id, file_system_id);
  60. policy->GrantWriteFileSystem(renderer_id, file_system_id);
  61. policy->GrantCreateFileForFileSystem(renderer_id, file_system_id);
  62. policy->GrantDeleteFromFileSystem(renderer_id, file_system_id);
  63. if (!policy->CanReadFile(renderer_id, path))
  64. policy->GrantReadFile(renderer_id, path);
  65. return file_system_id;
  66. }
  67. FileSystem CreateFileSystemStruct(content::WebContents* web_contents,
  68. const std::string& file_system_id,
  69. const std::string& file_system_path) {
  70. const GURL origin = web_contents->GetURL().GetOrigin();
  71. std::string file_system_name =
  72. storage::GetIsolatedFileSystemName(origin, file_system_id);
  73. std::string root_url = storage::GetIsolatedFileSystemRootURIString(
  74. origin, file_system_id, kRootName);
  75. return FileSystem(file_system_name, root_url, file_system_path);
  76. }
  77. std::unique_ptr<base::DictionaryValue> CreateFileSystemValue(
  78. const FileSystem& file_system) {
  79. std::unique_ptr<base::DictionaryValue> file_system_value(
  80. new base::DictionaryValue());
  81. file_system_value->SetString("fileSystemName", file_system.file_system_name);
  82. file_system_value->SetString("rootURL", file_system.root_url);
  83. file_system_value->SetString("fileSystemPath", file_system.file_system_path);
  84. return file_system_value;
  85. }
  86. void WriteToFile(const base::FilePath& path, const std::string& content) {
  87. DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  88. DCHECK(!path.empty());
  89. base::WriteFile(path, content.data(), content.size());
  90. }
  91. void AppendToFile(const base::FilePath& path, const std::string& content) {
  92. DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  93. DCHECK(!path.empty());
  94. base::AppendToFile(path, content.data(), content.size());
  95. }
  96. PrefService* GetPrefService(content::WebContents* web_contents) {
  97. auto* context = web_contents->GetBrowserContext();
  98. return static_cast<atom::AtomBrowserContext*>(context)->prefs();
  99. }
  100. std::set<std::string> GetAddedFileSystemPaths(
  101. content::WebContents* web_contents) {
  102. auto* pref_service = GetPrefService(web_contents);
  103. const base::DictionaryValue* file_system_paths_value =
  104. pref_service->GetDictionary(prefs::kDevToolsFileSystemPaths);
  105. std::set<std::string> result;
  106. if (file_system_paths_value) {
  107. base::DictionaryValue::Iterator it(*file_system_paths_value);
  108. for (; !it.IsAtEnd(); it.Advance()) {
  109. result.insert(it.key());
  110. }
  111. }
  112. return result;
  113. }
  114. bool IsDevToolsFileSystemAdded(content::WebContents* web_contents,
  115. const std::string& file_system_path) {
  116. auto file_system_paths = GetAddedFileSystemPaths(web_contents);
  117. return file_system_paths.find(file_system_path) != file_system_paths.end();
  118. }
  119. } // namespace
  120. CommonWebContentsDelegate::CommonWebContentsDelegate()
  121. : devtools_file_system_indexer_(new DevToolsFileSystemIndexer) {}
  122. CommonWebContentsDelegate::~CommonWebContentsDelegate() {}
  123. void CommonWebContentsDelegate::InitWithWebContents(
  124. content::WebContents* web_contents,
  125. AtomBrowserContext* browser_context) {
  126. browser_context_ = browser_context;
  127. web_contents->SetDelegate(this);
  128. printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
  129. printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents);
  130. // Determien whether the WebContents is offscreen.
  131. auto* web_preferences = WebContentsPreferences::From(web_contents);
  132. offscreen_ =
  133. !web_preferences || web_preferences->IsEnabled(options::kOffscreen);
  134. // Create InspectableWebContents.
  135. web_contents_.reset(brightray::InspectableWebContents::Create(web_contents));
  136. web_contents_->SetDelegate(this);
  137. }
  138. void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) {
  139. SetOwnerWindow(GetWebContents(), owner_window);
  140. }
  141. void CommonWebContentsDelegate::SetOwnerWindow(
  142. content::WebContents* web_contents,
  143. NativeWindow* owner_window) {
  144. owner_window_ = owner_window ? owner_window->GetWeakPtr() : nullptr;
  145. auto relay = std::make_unique<NativeWindowRelay>(owner_window_);
  146. auto* relay_key = relay->key;
  147. if (owner_window) {
  148. #if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
  149. autofill_popup_.reset(new AutofillPopup());
  150. #endif
  151. web_contents->SetUserData(relay_key, std::move(relay));
  152. } else {
  153. web_contents->RemoveUserData(relay_key);
  154. relay.reset();
  155. }
  156. }
  157. void CommonWebContentsDelegate::ResetManagedWebContents(bool async) {
  158. if (async) {
  159. base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
  160. web_contents_.release());
  161. } else {
  162. web_contents_.reset();
  163. }
  164. }
  165. content::WebContents* CommonWebContentsDelegate::GetWebContents() const {
  166. if (!web_contents_)
  167. return nullptr;
  168. return web_contents_->GetWebContents();
  169. }
  170. content::WebContents* CommonWebContentsDelegate::GetDevToolsWebContents()
  171. const {
  172. if (!web_contents_)
  173. return nullptr;
  174. return web_contents_->GetDevToolsWebContents();
  175. }
  176. content::WebContents* CommonWebContentsDelegate::OpenURLFromTab(
  177. content::WebContents* source,
  178. const content::OpenURLParams& params) {
  179. content::NavigationController::LoadURLParams load_url_params(params.url);
  180. load_url_params.referrer = params.referrer;
  181. load_url_params.transition_type = params.transition;
  182. load_url_params.extra_headers = params.extra_headers;
  183. load_url_params.should_replace_current_entry =
  184. params.should_replace_current_entry;
  185. load_url_params.is_renderer_initiated = params.is_renderer_initiated;
  186. load_url_params.should_clear_history_list = true;
  187. source->GetController().LoadURLWithParams(load_url_params);
  188. return source;
  189. }
  190. bool CommonWebContentsDelegate::CanOverscrollContent() const {
  191. return false;
  192. }
  193. content::ColorChooser* CommonWebContentsDelegate::OpenColorChooser(
  194. content::WebContents* web_contents,
  195. SkColor color,
  196. const std::vector<content::ColorSuggestion>& suggestions) {
  197. return chrome::ShowColorChooser(web_contents, color);
  198. }
  199. void CommonWebContentsDelegate::RunFileChooser(
  200. content::RenderFrameHost* render_frame_host,
  201. const content::FileChooserParams& params) {
  202. if (!web_dialog_helper_)
  203. web_dialog_helper_.reset(new WebDialogHelper(owner_window(), offscreen_));
  204. web_dialog_helper_->RunFileChooser(render_frame_host, params);
  205. }
  206. void CommonWebContentsDelegate::EnumerateDirectory(content::WebContents* guest,
  207. int request_id,
  208. const base::FilePath& path) {
  209. if (!web_dialog_helper_)
  210. web_dialog_helper_.reset(new WebDialogHelper(owner_window(), offscreen_));
  211. web_dialog_helper_->EnumerateDirectory(guest, request_id, path);
  212. }
  213. void CommonWebContentsDelegate::EnterFullscreenModeForTab(
  214. content::WebContents* source,
  215. const GURL& origin) {
  216. if (!owner_window_)
  217. return;
  218. SetHtmlApiFullscreen(true);
  219. owner_window_->NotifyWindowEnterHtmlFullScreen();
  220. source->GetRenderViewHost()->GetWidget()->WasResized();
  221. }
  222. void CommonWebContentsDelegate::ExitFullscreenModeForTab(
  223. content::WebContents* source) {
  224. if (!owner_window_)
  225. return;
  226. SetHtmlApiFullscreen(false);
  227. owner_window_->NotifyWindowLeaveHtmlFullScreen();
  228. source->GetRenderViewHost()->GetWidget()->WasResized();
  229. }
  230. bool CommonWebContentsDelegate::IsFullscreenForTabOrPending(
  231. const content::WebContents* source) const {
  232. return html_fullscreen_;
  233. }
  234. blink::WebSecurityStyle CommonWebContentsDelegate::GetSecurityStyle(
  235. content::WebContents* web_contents,
  236. content::SecurityStyleExplanations* security_style_explanations) {
  237. SecurityStateTabHelper* helper =
  238. SecurityStateTabHelper::FromWebContents(web_contents);
  239. DCHECK(helper);
  240. security_state::SecurityInfo security_info;
  241. helper->GetSecurityInfo(&security_info);
  242. return security_state::GetSecurityStyle(security_info,
  243. security_style_explanations);
  244. }
  245. void CommonWebContentsDelegate::DevToolsSaveToFile(const std::string& url,
  246. const std::string& content,
  247. bool save_as) {
  248. base::FilePath path;
  249. auto it = saved_files_.find(url);
  250. if (it != saved_files_.end() && !save_as) {
  251. path = it->second;
  252. } else {
  253. file_dialog::DialogSettings settings;
  254. settings.parent_window = owner_window();
  255. settings.force_detached = offscreen_;
  256. settings.title = url;
  257. settings.default_path = base::FilePath::FromUTF8Unsafe(url);
  258. if (!file_dialog::ShowSaveDialog(settings, &path)) {
  259. base::Value url_value(url);
  260. web_contents_->CallClientFunction("DevToolsAPI.canceledSaveURL",
  261. &url_value, nullptr, nullptr);
  262. return;
  263. }
  264. }
  265. saved_files_[url] = path;
  266. BrowserThread::PostTaskAndReply(
  267. BrowserThread::FILE, FROM_HERE,
  268. base::BindOnce(&WriteToFile, path, content),
  269. base::BindOnce(&CommonWebContentsDelegate::OnDevToolsSaveToFile,
  270. base::Unretained(this), url));
  271. }
  272. void CommonWebContentsDelegate::DevToolsAppendToFile(
  273. const std::string& url,
  274. const std::string& content) {
  275. auto it = saved_files_.find(url);
  276. if (it == saved_files_.end())
  277. return;
  278. BrowserThread::PostTaskAndReply(
  279. BrowserThread::FILE, FROM_HERE,
  280. base::BindOnce(&AppendToFile, it->second, content),
  281. base::BindOnce(&CommonWebContentsDelegate::OnDevToolsAppendToFile,
  282. base::Unretained(this), url));
  283. }
  284. void CommonWebContentsDelegate::DevToolsRequestFileSystems() {
  285. auto file_system_paths = GetAddedFileSystemPaths(GetDevToolsWebContents());
  286. if (file_system_paths.empty()) {
  287. base::ListValue empty_file_system_value;
  288. web_contents_->CallClientFunction("DevToolsAPI.fileSystemsLoaded",
  289. &empty_file_system_value, nullptr,
  290. nullptr);
  291. return;
  292. }
  293. std::vector<FileSystem> file_systems;
  294. for (const auto& file_system_path : file_system_paths) {
  295. base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
  296. std::string file_system_id =
  297. RegisterFileSystem(GetDevToolsWebContents(), path);
  298. FileSystem file_system = CreateFileSystemStruct(
  299. GetDevToolsWebContents(), file_system_id, file_system_path);
  300. file_systems.push_back(file_system);
  301. }
  302. base::ListValue file_system_value;
  303. for (const auto& file_system : file_systems)
  304. file_system_value.Append(CreateFileSystemValue(file_system));
  305. web_contents_->CallClientFunction("DevToolsAPI.fileSystemsLoaded",
  306. &file_system_value, nullptr, nullptr);
  307. }
  308. void CommonWebContentsDelegate::DevToolsAddFileSystem(
  309. const base::FilePath& file_system_path) {
  310. base::FilePath path = file_system_path;
  311. if (path.empty()) {
  312. std::vector<base::FilePath> paths;
  313. file_dialog::DialogSettings settings;
  314. settings.parent_window = owner_window();
  315. settings.force_detached = offscreen_;
  316. settings.properties = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
  317. if (!file_dialog::ShowOpenDialog(settings, &paths))
  318. return;
  319. path = paths[0];
  320. }
  321. std::string file_system_id =
  322. RegisterFileSystem(GetDevToolsWebContents(), path);
  323. if (IsDevToolsFileSystemAdded(GetDevToolsWebContents(), path.AsUTF8Unsafe()))
  324. return;
  325. FileSystem file_system = CreateFileSystemStruct(
  326. GetDevToolsWebContents(), file_system_id, path.AsUTF8Unsafe());
  327. std::unique_ptr<base::DictionaryValue> file_system_value(
  328. CreateFileSystemValue(file_system));
  329. auto* pref_service = GetPrefService(GetDevToolsWebContents());
  330. DictionaryPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths);
  331. update.Get()->SetWithoutPathExpansion(path.AsUTF8Unsafe(),
  332. std::make_unique<base::Value>());
  333. web_contents_->CallClientFunction("DevToolsAPI.fileSystemAdded",
  334. file_system_value.get(), nullptr, nullptr);
  335. }
  336. void CommonWebContentsDelegate::DevToolsRemoveFileSystem(
  337. const base::FilePath& file_system_path) {
  338. if (!web_contents_)
  339. return;
  340. std::string path = file_system_path.AsUTF8Unsafe();
  341. storage::IsolatedContext::GetInstance()->RevokeFileSystemByPath(
  342. file_system_path);
  343. auto* pref_service = GetPrefService(GetDevToolsWebContents());
  344. DictionaryPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths);
  345. update.Get()->RemoveWithoutPathExpansion(path, nullptr);
  346. base::Value file_system_path_value(path);
  347. web_contents_->CallClientFunction("DevToolsAPI.fileSystemRemoved",
  348. &file_system_path_value, nullptr, nullptr);
  349. }
  350. void CommonWebContentsDelegate::DevToolsIndexPath(
  351. int request_id,
  352. const std::string& file_system_path) {
  353. if (!IsDevToolsFileSystemAdded(GetDevToolsWebContents(), file_system_path)) {
  354. OnDevToolsIndexingDone(request_id, file_system_path);
  355. return;
  356. }
  357. if (devtools_indexing_jobs_.count(request_id) != 0)
  358. return;
  359. devtools_indexing_jobs_[request_id] =
  360. scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
  361. devtools_file_system_indexer_->IndexPath(
  362. file_system_path,
  363. base::Bind(
  364. &CommonWebContentsDelegate::OnDevToolsIndexingWorkCalculated,
  365. base::Unretained(this), request_id, file_system_path),
  366. base::Bind(&CommonWebContentsDelegate::OnDevToolsIndexingWorked,
  367. base::Unretained(this), request_id, file_system_path),
  368. base::Bind(&CommonWebContentsDelegate::OnDevToolsIndexingDone,
  369. base::Unretained(this), request_id,
  370. file_system_path)));
  371. }
  372. void CommonWebContentsDelegate::DevToolsStopIndexing(int request_id) {
  373. auto it = devtools_indexing_jobs_.find(request_id);
  374. if (it == devtools_indexing_jobs_.end())
  375. return;
  376. it->second->Stop();
  377. devtools_indexing_jobs_.erase(it);
  378. }
  379. void CommonWebContentsDelegate::DevToolsSearchInPath(
  380. int request_id,
  381. const std::string& file_system_path,
  382. const std::string& query) {
  383. if (!IsDevToolsFileSystemAdded(GetDevToolsWebContents(), file_system_path)) {
  384. OnDevToolsSearchCompleted(request_id, file_system_path,
  385. std::vector<std::string>());
  386. return;
  387. }
  388. devtools_file_system_indexer_->SearchInPath(
  389. file_system_path, query,
  390. base::Bind(&CommonWebContentsDelegate::OnDevToolsSearchCompleted,
  391. base::Unretained(this), request_id, file_system_path));
  392. }
  393. void CommonWebContentsDelegate::OnDevToolsSaveToFile(const std::string& url) {
  394. // Notify DevTools.
  395. base::Value url_value(url);
  396. web_contents_->CallClientFunction("DevToolsAPI.savedURL", &url_value, nullptr,
  397. nullptr);
  398. }
  399. void CommonWebContentsDelegate::OnDevToolsAppendToFile(const std::string& url) {
  400. // Notify DevTools.
  401. base::Value url_value(url);
  402. web_contents_->CallClientFunction("DevToolsAPI.appendedToURL", &url_value,
  403. nullptr, nullptr);
  404. }
  405. void CommonWebContentsDelegate::OnDevToolsIndexingWorkCalculated(
  406. int request_id,
  407. const std::string& file_system_path,
  408. int total_work) {
  409. base::Value request_id_value(request_id);
  410. base::Value file_system_path_value(file_system_path);
  411. base::Value total_work_value(total_work);
  412. web_contents_->CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated",
  413. &request_id_value, &file_system_path_value,
  414. &total_work_value);
  415. }
  416. void CommonWebContentsDelegate::OnDevToolsIndexingWorked(
  417. int request_id,
  418. const std::string& file_system_path,
  419. int worked) {
  420. base::Value request_id_value(request_id);
  421. base::Value file_system_path_value(file_system_path);
  422. base::Value worked_value(worked);
  423. web_contents_->CallClientFunction("DevToolsAPI.indexingWorked",
  424. &request_id_value, &file_system_path_value,
  425. &worked_value);
  426. }
  427. void CommonWebContentsDelegate::OnDevToolsIndexingDone(
  428. int request_id,
  429. const std::string& file_system_path) {
  430. devtools_indexing_jobs_.erase(request_id);
  431. base::Value request_id_value(request_id);
  432. base::Value file_system_path_value(file_system_path);
  433. web_contents_->CallClientFunction("DevToolsAPI.indexingDone",
  434. &request_id_value, &file_system_path_value,
  435. nullptr);
  436. }
  437. void CommonWebContentsDelegate::OnDevToolsSearchCompleted(
  438. int request_id,
  439. const std::string& file_system_path,
  440. const std::vector<std::string>& file_paths) {
  441. base::ListValue file_paths_value;
  442. for (const auto& file_path : file_paths) {
  443. file_paths_value.AppendString(file_path);
  444. }
  445. base::Value request_id_value(request_id);
  446. base::Value file_system_path_value(file_system_path);
  447. web_contents_->CallClientFunction("DevToolsAPI.searchCompleted",
  448. &request_id_value, &file_system_path_value,
  449. &file_paths_value);
  450. }
  451. void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) {
  452. // Window is already in fullscreen mode, save the state.
  453. if (enter_fullscreen && owner_window_->IsFullscreen()) {
  454. native_fullscreen_ = true;
  455. html_fullscreen_ = true;
  456. return;
  457. }
  458. // Exit html fullscreen state but not window's fullscreen mode.
  459. if (!enter_fullscreen && native_fullscreen_) {
  460. html_fullscreen_ = false;
  461. return;
  462. }
  463. owner_window_->SetFullScreen(enter_fullscreen);
  464. html_fullscreen_ = enter_fullscreen;
  465. native_fullscreen_ = false;
  466. }
  467. } // namespace atom