Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Side by Side Diff: chrome/browser/devtools/devtools_file_helper.cc

Issue 11570081: Support file system access in DevTools with isolated file system. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Pavel's comments addressed Created 7 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/devtools/devtools_file_helper.h" 5 #include "chrome/browser/devtools/devtools_file_helper.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
11 #include "base/file_util.h" 11 #include "base/file_util.h"
12 #include "base/lazy_instance.h" 12 #include "base/lazy_instance.h"
13 #include "base/md5.h" 13 #include "base/md5.h"
14 #include "base/utf_string_conversions.h"
14 #include "base/value_conversions.h" 15 #include "base/value_conversions.h"
15 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/download/download_prefs.h" 17 #include "chrome/browser/download/download_prefs.h"
17 #include "chrome/browser/prefs/pref_service.h" 18 #include "chrome/browser/prefs/pref_service.h"
18 #include "chrome/browser/prefs/scoped_user_pref_update.h" 19 #include "chrome/browser/prefs/scoped_user_pref_update.h"
19 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/chrome_select_file_policy.h" 21 #include "chrome/browser/ui/chrome_select_file_policy.h"
21 #include "chrome/common/pref_names.h" 22 #include "chrome/common/pref_names.h"
22 #include "content/public/browser/browser_context.h" 23 #include "content/public/browser/browser_context.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/child_process_security_policy.h"
23 #include "content/public/browser/download_manager.h" 26 #include "content/public/browser/download_manager.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "grit/generated_resources.h"
24 #include "ui/base/dialogs/select_file_dialog.h" 31 #include "ui/base/dialogs/select_file_dialog.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "webkit/fileapi/isolated_context.h"
25 34
26 using base::Bind; 35 using base::Bind;
27 using base::Callback; 36 using base::Callback;
28 using content::BrowserContext; 37 using content::BrowserContext;
29 using content::BrowserThread; 38 using content::BrowserThread;
30 using content::DownloadManager; 39 using content::DownloadManager;
40 using content::RenderViewHost;
41 using content::WebContents;
31 42
32 namespace { 43 namespace {
33 44
34 base::LazyInstance<FilePath>::Leaky 45 base::LazyInstance<FilePath>::Leaky
35 g_last_save_path = LAZY_INSTANCE_INITIALIZER; 46 g_last_save_path = LAZY_INSTANCE_INITIALIZER;
36 47
37 } // namespace 48 } // namespace
38 49
39 namespace { 50 namespace {
40 51
41 typedef Callback<void(const FilePath&)> SelectedCallback; 52 typedef Callback<void(const FilePath&)> SelectedCallback;
42 typedef Callback<void(void)> CanceledCallback; 53 typedef Callback<void(void)> CanceledCallback;
43 54
55 const char kMagicFileName[] = ".allow-devtools-edit";
56
44 class SelectFileDialog : public ui::SelectFileDialog::Listener, 57 class SelectFileDialog : public ui::SelectFileDialog::Listener,
45 public base::RefCounted<SelectFileDialog> { 58 public base::RefCounted<SelectFileDialog> {
46 public: 59 public:
47 SelectFileDialog(const SelectedCallback& selected_callback, 60 SelectFileDialog(const SelectedCallback& selected_callback,
48 const CanceledCallback& canceled_callback) 61 const CanceledCallback& canceled_callback)
49 : selected_callback_(selected_callback), 62 : selected_callback_(selected_callback),
50 canceled_callback_(canceled_callback) { 63 canceled_callback_(canceled_callback) {
51 select_file_dialog_ = ui::SelectFileDialog::Create( 64 select_file_dialog_ = ui::SelectFileDialog::Create(
52 this, new ChromeSelectFilePolicy(NULL)); 65 this, new ChromeSelectFilePolicy(NULL));
53 } 66 }
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 file_util::WriteFile(path, content.c_str(), content.length()); 111 file_util::WriteFile(path, content.c_str(), content.length());
99 } 112 }
100 113
101 void AppendToFile(const FilePath& path, const std::string& content) { 114 void AppendToFile(const FilePath& path, const std::string& content) {
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
103 DCHECK(!path.empty()); 116 DCHECK(!path.empty());
104 117
105 file_util::AppendToFile(path, content.c_str(), content.length()); 118 file_util::AppendToFile(path, content.c_str(), content.length());
106 } 119 }
107 120
121 fileapi::IsolatedContext* isolated_context() {
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
123 fileapi::IsolatedContext* isolated_context =
124 fileapi::IsolatedContext::GetInstance();
125 DCHECK(isolated_context);
126 return isolated_context;
127 }
128
129 std::string RegisterFilesystem(WebContents* web_contents,
130 const FilePath& path,
131 std::string* registered_name) {
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
133 std::string filesystem_id = isolated_context()->RegisterFileSystemForPath(
134 fileapi::kFileSystemTypeNativeLocal, path, registered_name);
135
136 content::ChildProcessSecurityPolicy* policy =
137 content::ChildProcessSecurityPolicy::GetInstance();
138 RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
139 int renderer_id = render_view_host->GetProcess()->GetID();
140 policy->GrantReadWriteFileSystem(renderer_id, filesystem_id);
141
142 // We only need file level access for reading FileEntries. Saving FileEntries
143 // just needs the file system to have read/write access, which is granted
144 // above if required.
145 if (!policy->CanReadFile(renderer_id, path))
146 policy->GrantReadFile(renderer_id, path);
147
148 return filesystem_id;
149 }
150
151 bool CheckSecurityFileExistsInFolder(const FilePath& path) {
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
pfeldman 2012/12/28 15:09:58 inline
153 FilePath security_file_path = path.Append(FILE_PATH_LITERAL(kMagicFileName));
154 return file_util::PathExists(security_file_path);
155 }
156
157 typedef Callback<void(const std::vector<FilePath>&)> CheckFoldersCallback;
158
159 void FoldersCheckedOnFileThread(const CheckFoldersCallback& callback,
160 const std::vector<FilePath>& permitted_paths) {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
162 callback.Run(permitted_paths);
163 }
164
165 void CheckFoldersOnFileThread(const std::vector<FilePath>& file_paths,
166 const CheckFoldersCallback& callback) {
167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
168 std::vector<FilePath> permitted_paths;
169 std::vector<FilePath>::const_iterator it;
170 for (it = file_paths.begin(); it != file_paths.end(); ++it) {
171 if (CheckSecurityFileExistsInFolder(*it))
172 permitted_paths.push_back(*it);
173 }
174 BrowserThread::PostTask(
175 BrowserThread::UI, FROM_HERE,
176 Bind(&FoldersCheckedOnFileThread, callback, permitted_paths));
177 }
178
179 void CheckFolders(const std::vector<FilePath>& file_paths,
180 const CheckFoldersCallback& callback) {
181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
182 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
183 Bind(&CheckFoldersOnFileThread,
184 file_paths,
185 callback));
186 }
187
188 typedef Callback<void(const FilePath&, bool)> CheckFolderCallback;
189
190 void FolderCheckedOnFileThread(const CheckFolderCallback& callback,
191 const FilePath& path,
192 bool permitted) {
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
pfeldman 2012/12/28 15:09:58 inline
194 callback.Run(path, permitted);
195 }
196
197 void CheckFolderOnFileThread(const FilePath& path,
198 const CheckFolderCallback& callback) {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
200 bool permitted = CheckSecurityFileExistsInFolder(path);
201 BrowserThread::PostTask(
202 BrowserThread::UI, FROM_HERE,
203 Bind(&FolderCheckedOnFileThread, callback, path, permitted));
204 }
205
206 void CheckFolder(const FilePath& path, const CheckFolderCallback& callback) {
pfeldman 2012/12/28 15:09:58 Please inline it.
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
209 Bind(&CheckFolderOnFileThread, path, callback));
210 }
211
108 } // namespace 212 } // namespace
109 213
110 DevToolsFileHelper::DevToolsFileHelper(Profile* profile) : profile_(profile), 214 DevToolsFileHelper::Filesystem::Filesystem() {
111 weak_factory_(this) { 215 }
216
217 DevToolsFileHelper::Filesystem::Filesystem(const std::string& filesystem_id,
218 const std::string& registered_name,
219 const std::string& filesystem_path)
220 : filesystem_id(filesystem_id),
221 registered_name(registered_name),
222 filesystem_path(filesystem_path) {
223 }
224
225 DevToolsFileHelper::DevToolsFileHelper(WebContents* web_contents,
226 Profile* profile)
227 : web_contents_(web_contents), profile_(profile), weak_factory_(this) {
112 } 228 }
113 229
114 DevToolsFileHelper::~DevToolsFileHelper() { 230 DevToolsFileHelper::~DevToolsFileHelper() {
115 } 231 }
116 232
117 void DevToolsFileHelper::Save(const std::string& url, 233 void DevToolsFileHelper::Save(const std::string& url,
118 const std::string& content, 234 const std::string& content,
119 bool save_as, 235 bool save_as,
120 const SaveCallback& callback) { 236 const SaveCallback& callback) {
121 PathsMap::iterator it = saved_files_.find(url); 237 PathsMap::iterator it = saved_files_.find(url);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 } 279 }
164 280
165 void DevToolsFileHelper::Append(const std::string& url, 281 void DevToolsFileHelper::Append(const std::string& url,
166 const std::string& content, 282 const std::string& content,
167 const AppendCallback& callback) { 283 const AppendCallback& callback) {
168 PathsMap::iterator it = saved_files_.find(url); 284 PathsMap::iterator it = saved_files_.find(url);
169 if (it == saved_files_.end()) 285 if (it == saved_files_.end())
170 return; 286 return;
171 callback.Run(); 287 callback.Run();
172 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 288 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
173 base::Bind(&AppendToFile, it->second, content)); 289 Bind(&AppendToFile, it->second, content));
174 } 290 }
175 291
176 void DevToolsFileHelper::SaveAsFileSelected(const std::string& url, 292 void DevToolsFileHelper::SaveAsFileSelected(const std::string& url,
177 const std::string& content, 293 const std::string& content,
178 const SaveCallback& callback, 294 const SaveCallback& callback,
179 const FilePath& path) { 295 const FilePath& path) {
180 *g_last_save_path.Pointer() = path; 296 *g_last_save_path.Pointer() = path;
181 saved_files_[url] = path; 297 saved_files_[url] = path;
182 298
183 DictionaryPrefUpdate update(profile_->GetPrefs(), 299 DictionaryPrefUpdate update(profile_->GetPrefs(),
184 prefs::kDevToolsEditedFiles); 300 prefs::kDevToolsEditedFiles);
185 DictionaryValue* files_map = update.Get(); 301 DictionaryValue* files_map = update.Get();
186 files_map->SetWithoutPathExpansion(base::MD5String(url), 302 files_map->SetWithoutPathExpansion(base::MD5String(url),
187 base::CreateFilePathValue(path)); 303 base::CreateFilePathValue(path));
188 callback.Run(); 304 callback.Run();
189 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 305 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
190 base::Bind(&WriteToFile, path, content)); 306 Bind(&WriteToFile, path, content));
191 } 307 }
192 308
193 void DevToolsFileHelper::SaveAsFileSelectionCanceled() { 309 void DevToolsFileHelper::SaveAsFileSelectionCanceled() {
194 } 310 }
311
312 void DevToolsFileHelper::AddFilesystem(const AddFilesystemCallback& callback) {
313 scoped_refptr<SelectFileDialog> select_file_dialog = new SelectFileDialog(
314 Bind(&DevToolsFileHelper::FolderSelected,
315 weak_factory_.GetWeakPtr(),
316 callback),
317 Bind(&DevToolsFileHelper::FolderSelectionCanceled,
318 weak_factory_.GetWeakPtr(),
319 callback));
320 select_file_dialog->Show(ui::SelectFileDialog::SELECT_FOLDER, FilePath());
321 }
322
323 void DevToolsFileHelper::FolderSelected(const AddFilesystemCallback& callback,
324 const FilePath& path) {
325 CheckFolder(path, Bind(&DevToolsFileHelper::SelectedFilesystemChecked,
pfeldman 2012/12/28 15:09:58 CheckFolders(std::vector(1, path))
326 weak_factory_.GetWeakPtr(),
327 callback));
328 }
329
330 void DevToolsFileHelper::SelectedFilesystemChecked(
331 const AddFilesystemCallback& callback,
332 const FilePath& path,
333 bool permitted) {
334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
335 if (!permitted) {
336 std::string error_string = l10n_util::GetStringFUTF8(
337 IDS_DEV_TOOLS_MAGIC_FILE_NOT_EXISTS_MESSAGE,
338 UTF8ToUTF16(kMagicFileName));
339 callback.Run(error_string, Filesystem());
340 return;
341 }
342
343 std::string registered_name;
344 std::string filesystem_id = RegisterFilesystem(web_contents_,
345 path,
346 &registered_name);
347 std::string filesystem_path = path.AsUTF8Unsafe();
348
349 DictionaryPrefUpdate update(profile_->GetPrefs(),
350 prefs::kDevToolsFilesystemPaths);
351 DictionaryValue* filesystems_paths_value = update.Get();
352 filesystems_paths_value->Set(filesystem_path, Value::CreateNullValue());
353
354 Filesystem filesystem(filesystem_id, registered_name, filesystem_path);
355 callback.Run("", filesystem);
356 }
357
358 void DevToolsFileHelper::FolderSelectionCanceled(
359 const AddFilesystemCallback& callback) {
360 callback.Run("", Filesystem());
361 }
362
363 void DevToolsFileHelper::RequestFilesystems(
364 const RequestFilesystemsCallback& callback) {
365 const DictionaryValue* filesystems_paths_value =
366 profile_->GetPrefs()->GetDictionary(prefs::kDevToolsFilesystemPaths);
367 std::vector<FilePath> saved_paths;
368 DictionaryValue::key_iterator it = filesystems_paths_value->begin_keys();
369 for (; it != filesystems_paths_value->end_keys(); ++it) {
370 std::string filesystem_path = *it;
371 FilePath path = FilePath::FromUTF8Unsafe(filesystem_path);
372 saved_paths.push_back(path);
373 }
374
375 CheckFolders(saved_paths,
376 Bind(&DevToolsFileHelper::RegisterPermittedFilesystems,
377 weak_factory_.GetWeakPtr(),
378 callback));
379 }
380
381 void DevToolsFileHelper::RegisterPermittedFilesystems(
382 const RequestFilesystemsCallback& callback,
383 const std::vector<FilePath>& permitted_paths) {
384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
385 std::vector<Filesystem> filesystems;
386 std::vector<FilePath>::const_iterator it;
387 for (it = permitted_paths.begin(); it != permitted_paths.end(); ++it) {
388 std::string registered_name;
389 std::string filesystem_id = RegisterFilesystem(web_contents_,
390 *it,
391 &registered_name);
392 std::string filesystem_path = it->AsUTF8Unsafe();
393 Filesystem filesystem(filesystem_id, registered_name, filesystem_path);
394 filesystems.push_back(filesystem);
395 }
396 callback.Run(filesystems);
397 }
398
399 void DevToolsFileHelper::RemoveFilesystem(const std::string& filesystem_path) {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
401 FilePath path = FilePath::FromUTF8Unsafe(filesystem_path);
402 isolated_context()->RevokeFileSystemByPath(path);
403
404 DictionaryPrefUpdate update(profile_->GetPrefs(),
405 prefs::kDevToolsFilesystemPaths);
406 DictionaryValue* filesystems_paths_value = update.Get();
407 filesystems_paths_value->RemoveWithoutPathExpansion(filesystem_path, NULL);
408 }
OLDNEW
« no previous file with comments | « chrome/browser/devtools/devtools_file_helper.h ('k') | chrome/browser/devtools/devtools_window.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698