Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / devtools / devtools_file_helper.cc
blob46ae91528be230e7ec3c89435822a49d371b662f
1 // Copyright (c) 2012 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 "chrome/browser/devtools/devtools_file_helper.h"
7 #include <set>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/file_util.h"
13 #include "base/lazy_instance.h"
14 #include "base/md5.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/prefs/scoped_user_pref_update.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/value_conversions.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/download/download_prefs.h"
21 #include "chrome/browser/platform_util.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/ui/chrome_select_file_policy.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/browser_context.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/child_process_security_policy.h"
28 #include "content/public/browser/download_manager.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_contents_view.h"
33 #include "content/public/common/content_client.h"
34 #include "content/public/common/url_constants.h"
35 #include "grit/generated_resources.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/shell_dialogs/select_file_dialog.h"
38 #include "webkit/browser/fileapi/file_system_url.h"
39 #include "webkit/browser/fileapi/isolated_context.h"
40 #include "webkit/common/fileapi/file_system_util.h"
42 using base::Bind;
43 using base::Callback;
44 using content::BrowserContext;
45 using content::BrowserThread;
46 using content::DownloadManager;
47 using content::RenderViewHost;
48 using content::WebContents;
49 using std::set;
51 namespace {
53 base::LazyInstance<base::FilePath>::Leaky
54 g_last_save_path = LAZY_INSTANCE_INITIALIZER;
56 } // namespace
58 namespace {
60 typedef Callback<void(const base::FilePath&)> SelectedCallback;
61 typedef Callback<void(void)> CanceledCallback;
63 class SelectFileDialog : public ui::SelectFileDialog::Listener,
64 public base::RefCounted<SelectFileDialog> {
65 public:
66 SelectFileDialog(const SelectedCallback& selected_callback,
67 const CanceledCallback& canceled_callback,
68 WebContents* web_contents)
69 : selected_callback_(selected_callback),
70 canceled_callback_(canceled_callback),
71 web_contents_(web_contents) {
72 select_file_dialog_ = ui::SelectFileDialog::Create(
73 this, new ChromeSelectFilePolicy(web_contents));
76 void Show(ui::SelectFileDialog::Type type,
77 const base::FilePath& default_path) {
78 AddRef(); // Balanced in the three listener outcomes.
79 select_file_dialog_->SelectFile(
80 type,
81 base::string16(),
82 default_path,
83 NULL,
85 base::FilePath::StringType(),
86 platform_util::GetTopLevel(web_contents_->GetView()->GetNativeView()),
87 NULL);
90 // ui::SelectFileDialog::Listener implementation.
91 virtual void FileSelected(const base::FilePath& path,
92 int index,
93 void* params) OVERRIDE {
94 selected_callback_.Run(path);
95 Release(); // Balanced in ::Show.
98 virtual void MultiFilesSelected(const std::vector<base::FilePath>& files,
99 void* params) OVERRIDE {
100 Release(); // Balanced in ::Show.
101 NOTREACHED() << "Should not be able to select multiple files";
104 virtual void FileSelectionCanceled(void* params) OVERRIDE {
105 canceled_callback_.Run();
106 Release(); // Balanced in ::Show.
109 private:
110 friend class base::RefCounted<SelectFileDialog>;
111 virtual ~SelectFileDialog() {}
113 scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
114 SelectedCallback selected_callback_;
115 CanceledCallback canceled_callback_;
116 WebContents* web_contents_;
118 DISALLOW_COPY_AND_ASSIGN(SelectFileDialog);
121 void WriteToFile(const base::FilePath& path, const std::string& content) {
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
123 DCHECK(!path.empty());
125 file_util::WriteFile(path, content.c_str(), content.length());
128 void AppendToFile(const base::FilePath& path, const std::string& content) {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
130 DCHECK(!path.empty());
132 file_util::AppendToFile(path, content.c_str(), content.length());
135 fileapi::IsolatedContext* isolated_context() {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137 fileapi::IsolatedContext* isolated_context =
138 fileapi::IsolatedContext::GetInstance();
139 DCHECK(isolated_context);
140 return isolated_context;
143 std::string RegisterFileSystem(WebContents* web_contents,
144 const base::FilePath& path,
145 std::string* registered_name) {
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
147 CHECK(web_contents->GetURL().SchemeIs(chrome::kChromeDevToolsScheme));
148 std::string file_system_id = isolated_context()->RegisterFileSystemForPath(
149 fileapi::kFileSystemTypeNativeLocal, path, registered_name);
151 content::ChildProcessSecurityPolicy* policy =
152 content::ChildProcessSecurityPolicy::GetInstance();
153 RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
154 int renderer_id = render_view_host->GetProcess()->GetID();
155 policy->GrantReadFileSystem(renderer_id, file_system_id);
156 policy->GrantWriteFileSystem(renderer_id, file_system_id);
157 policy->GrantCreateFileForFileSystem(renderer_id, file_system_id);
158 policy->GrantDeleteFromFileSystem(renderer_id, file_system_id);
160 // We only need file level access for reading FileEntries. Saving FileEntries
161 // just needs the file system to have read/write access, which is granted
162 // above if required.
163 if (!policy->CanReadFile(renderer_id, path))
164 policy->GrantReadFile(renderer_id, path);
166 return file_system_id;
169 DevToolsFileHelper::FileSystem CreateFileSystemStruct(
170 WebContents* web_contents,
171 const std::string& file_system_id,
172 const std::string& registered_name,
173 const std::string& file_system_path) {
174 const GURL origin = web_contents->GetURL().GetOrigin();
175 std::string file_system_name = fileapi::GetIsolatedFileSystemName(
176 origin,
177 file_system_id);
178 std::string root_url = fileapi::GetIsolatedFileSystemRootURIString(
179 origin,
180 file_system_id,
181 registered_name);
182 return DevToolsFileHelper::FileSystem(file_system_name,
183 root_url,
184 file_system_path);
187 set<std::string> GetAddedFileSystemPaths(Profile* profile) {
188 const base::DictionaryValue* file_systems_paths_value =
189 profile->GetPrefs()->GetDictionary(prefs::kDevToolsFileSystemPaths);
190 set<std::string> result;
191 for (base::DictionaryValue::Iterator it(*file_systems_paths_value);
192 !it.IsAtEnd(); it.Advance()) {
193 result.insert(it.key());
195 return result;
198 } // namespace
200 DevToolsFileHelper::FileSystem::FileSystem() {
203 DevToolsFileHelper::FileSystem::FileSystem(const std::string& file_system_name,
204 const std::string& root_url,
205 const std::string& file_system_path)
206 : file_system_name(file_system_name),
207 root_url(root_url),
208 file_system_path(file_system_path) {
211 DevToolsFileHelper::DevToolsFileHelper(WebContents* web_contents,
212 Profile* profile)
213 : web_contents_(web_contents),
214 profile_(profile),
215 weak_factory_(this) {
218 DevToolsFileHelper::~DevToolsFileHelper() {
221 void DevToolsFileHelper::Save(const std::string& url,
222 const std::string& content,
223 bool save_as,
224 const SaveCallback& saveCallback,
225 const SaveCallback& cancelCallback) {
226 PathsMap::iterator it = saved_files_.find(url);
227 if (it != saved_files_.end() && !save_as) {
228 SaveAsFileSelected(url, content, saveCallback, it->second);
229 return;
232 const base::DictionaryValue* file_map =
233 profile_->GetPrefs()->GetDictionary(prefs::kDevToolsEditedFiles);
234 base::FilePath initial_path;
236 const base::Value* path_value;
237 if (file_map->Get(base::MD5String(url), &path_value))
238 base::GetValueAsFilePath(*path_value, &initial_path);
240 if (initial_path.empty()) {
241 GURL gurl(url);
242 std::string suggested_file_name = gurl.is_valid() ?
243 gurl.ExtractFileName() : url;
245 if (suggested_file_name.length() > 64)
246 suggested_file_name = suggested_file_name.substr(0, 64);
248 if (!g_last_save_path.Pointer()->empty()) {
249 initial_path = g_last_save_path.Pointer()->DirName().AppendASCII(
250 suggested_file_name);
251 } else {
252 base::FilePath download_path = DownloadPrefs::FromDownloadManager(
253 BrowserContext::GetDownloadManager(profile_))->DownloadPath();
254 initial_path = download_path.AppendASCII(suggested_file_name);
258 scoped_refptr<SelectFileDialog> select_file_dialog = new SelectFileDialog(
259 Bind(&DevToolsFileHelper::SaveAsFileSelected,
260 weak_factory_.GetWeakPtr(),
261 url,
262 content,
263 saveCallback),
264 Bind(&DevToolsFileHelper::SaveAsFileSelectionCanceled,
265 weak_factory_.GetWeakPtr(),
266 cancelCallback),
267 web_contents_);
268 select_file_dialog->Show(ui::SelectFileDialog::SELECT_SAVEAS_FILE,
269 initial_path);
272 void DevToolsFileHelper::Append(const std::string& url,
273 const std::string& content,
274 const AppendCallback& callback) {
275 PathsMap::iterator it = saved_files_.find(url);
276 if (it == saved_files_.end())
277 return;
278 callback.Run();
279 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
280 Bind(&AppendToFile, it->second, content));
283 void DevToolsFileHelper::SaveAsFileSelected(const std::string& url,
284 const std::string& content,
285 const SaveCallback& callback,
286 const base::FilePath& path) {
287 *g_last_save_path.Pointer() = path;
288 saved_files_[url] = path;
290 DictionaryPrefUpdate update(profile_->GetPrefs(),
291 prefs::kDevToolsEditedFiles);
292 base::DictionaryValue* files_map = update.Get();
293 files_map->SetWithoutPathExpansion(base::MD5String(url),
294 base::CreateFilePathValue(path));
295 callback.Run();
296 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
297 Bind(&WriteToFile, path, content));
300 void DevToolsFileHelper::SaveAsFileSelectionCanceled(
301 const SaveCallback& callback) {
302 callback.Run();
305 void DevToolsFileHelper::AddFileSystem(
306 const AddFileSystemCallback& callback,
307 const ShowInfoBarCallback& show_info_bar_callback) {
308 scoped_refptr<SelectFileDialog> select_file_dialog = new SelectFileDialog(
309 Bind(&DevToolsFileHelper::InnerAddFileSystem,
310 weak_factory_.GetWeakPtr(),
311 callback,
312 show_info_bar_callback),
313 Bind(callback, FileSystem()),
314 web_contents_);
315 select_file_dialog->Show(ui::SelectFileDialog::SELECT_FOLDER,
316 base::FilePath());
319 void DevToolsFileHelper::UpgradeDraggedFileSystemPermissions(
320 const std::string& file_system_url,
321 const AddFileSystemCallback& callback,
322 const ShowInfoBarCallback& show_info_bar_callback) {
323 fileapi::FileSystemURL root_url =
324 isolated_context()->CrackURL(GURL(file_system_url));
325 if (!root_url.is_valid() || !root_url.path().empty()) {
326 callback.Run(FileSystem());
327 return;
330 std::vector<fileapi::MountPoints::MountPointInfo> mount_points;
331 isolated_context()->GetDraggedFileInfo(root_url.filesystem_id(),
332 &mount_points);
334 std::vector<fileapi::MountPoints::MountPointInfo>::const_iterator it =
335 mount_points.begin();
336 for (; it != mount_points.end(); ++it)
337 InnerAddFileSystem(callback, show_info_bar_callback, it->path);
340 void DevToolsFileHelper::InnerAddFileSystem(
341 const AddFileSystemCallback& callback,
342 const ShowInfoBarCallback& show_info_bar_callback,
343 const base::FilePath& path) {
344 std::string file_system_path = path.AsUTF8Unsafe();
346 const base::DictionaryValue* file_systems_paths_value =
347 profile_->GetPrefs()->GetDictionary(prefs::kDevToolsFileSystemPaths);
348 if (file_systems_paths_value->HasKey(file_system_path)) {
349 callback.Run(FileSystem());
350 return;
353 std::string path_display_name = path.AsEndingWithSeparator().AsUTF8Unsafe();
354 base::string16 message = l10n_util::GetStringFUTF16(
355 IDS_DEV_TOOLS_CONFIRM_ADD_FILE_SYSTEM_MESSAGE,
356 base::UTF8ToUTF16(path_display_name));
357 show_info_bar_callback.Run(
358 message,
359 Bind(&DevToolsFileHelper::AddUserConfirmedFileSystem,
360 weak_factory_.GetWeakPtr(),
361 callback, path));
364 void DevToolsFileHelper::AddUserConfirmedFileSystem(
365 const AddFileSystemCallback& callback,
366 const base::FilePath& path,
367 bool allowed) {
368 if (!allowed) {
369 callback.Run(FileSystem());
370 return;
372 std::string registered_name;
373 std::string file_system_id = RegisterFileSystem(web_contents_,
374 path,
375 &registered_name);
376 std::string file_system_path = path.AsUTF8Unsafe();
378 DictionaryPrefUpdate update(profile_->GetPrefs(),
379 prefs::kDevToolsFileSystemPaths);
380 base::DictionaryValue* file_systems_paths_value = update.Get();
381 file_systems_paths_value->SetWithoutPathExpansion(
382 file_system_path, base::Value::CreateNullValue());
384 FileSystem filesystem = CreateFileSystemStruct(web_contents_,
385 file_system_id,
386 registered_name,
387 file_system_path);
388 callback.Run(filesystem);
391 void DevToolsFileHelper::RequestFileSystems(
392 const RequestFileSystemsCallback& callback) {
393 set<std::string> file_system_paths = GetAddedFileSystemPaths(profile_);
394 set<std::string>::const_iterator it = file_system_paths.begin();
395 std::vector<FileSystem> file_systems;
396 for (; it != file_system_paths.end(); ++it) {
397 std::string file_system_path = *it;
398 base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
400 std::string registered_name;
401 std::string file_system_id = RegisterFileSystem(web_contents_,
402 path,
403 &registered_name);
404 FileSystem filesystem = CreateFileSystemStruct(web_contents_,
405 file_system_id,
406 registered_name,
407 file_system_path);
408 file_systems.push_back(filesystem);
410 callback.Run(file_systems);
413 void DevToolsFileHelper::RemoveFileSystem(const std::string& file_system_path) {
414 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415 base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
416 isolated_context()->RevokeFileSystemByPath(path);
418 DictionaryPrefUpdate update(profile_->GetPrefs(),
419 prefs::kDevToolsFileSystemPaths);
420 base::DictionaryValue* file_systems_paths_value = update.Get();
421 file_systems_paths_value->RemoveWithoutPathExpansion(file_system_path, NULL);
424 bool DevToolsFileHelper::IsFileSystemAdded(
425 const std::string& file_system_path) {
426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
427 set<std::string> file_system_paths = GetAddedFileSystemPaths(profile_);
428 return file_system_paths.find(file_system_path) != file_system_paths.end();