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

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: Renamed methods and added CHECK() Created 7 years, 11 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 "content/public/common/content_client.h"
31 #include "grit/generated_resources.h"
24 #include "ui/base/dialogs/select_file_dialog.h" 32 #include "ui/base/dialogs/select_file_dialog.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "webkit/fileapi/isolated_context.h"
25 35
26 using base::Bind; 36 using base::Bind;
27 using base::Callback; 37 using base::Callback;
28 using content::BrowserContext; 38 using content::BrowserContext;
29 using content::BrowserThread; 39 using content::BrowserThread;
30 using content::DownloadManager; 40 using content::DownloadManager;
41 using content::RenderViewHost;
42 using content::WebContents;
31 43
32 namespace { 44 namespace {
33 45
34 base::LazyInstance<FilePath>::Leaky 46 base::LazyInstance<FilePath>::Leaky
35 g_last_save_path = LAZY_INSTANCE_INITIALIZER; 47 g_last_save_path = LAZY_INSTANCE_INITIALIZER;
36 48
37 } // namespace 49 } // namespace
38 50
39 namespace { 51 namespace {
40 52
41 typedef Callback<void(const FilePath&)> SelectedCallback; 53 typedef Callback<void(const FilePath&)> SelectedCallback;
42 typedef Callback<void(void)> CanceledCallback; 54 typedef Callback<void(void)> CanceledCallback;
43 55
56 const char kMagicFileName[] = ".allow-devtools-edit";
kinuko 2013/01/04 14:20:55 const FilePath::CharType kMagicFileName[]
vsevik 2013/01/09 11:54:40 Done.
57
44 class SelectFileDialog : public ui::SelectFileDialog::Listener, 58 class SelectFileDialog : public ui::SelectFileDialog::Listener,
45 public base::RefCounted<SelectFileDialog> { 59 public base::RefCounted<SelectFileDialog> {
46 public: 60 public:
47 SelectFileDialog(const SelectedCallback& selected_callback, 61 SelectFileDialog(const SelectedCallback& selected_callback,
48 const CanceledCallback& canceled_callback) 62 const CanceledCallback& canceled_callback)
49 : selected_callback_(selected_callback), 63 : selected_callback_(selected_callback),
50 canceled_callback_(canceled_callback) { 64 canceled_callback_(canceled_callback) {
51 select_file_dialog_ = ui::SelectFileDialog::Create( 65 select_file_dialog_ = ui::SelectFileDialog::Create(
52 this, new ChromeSelectFilePolicy(NULL)); 66 this, new ChromeSelectFilePolicy(NULL));
53 } 67 }
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 file_util::WriteFile(path, content.c_str(), content.length()); 112 file_util::WriteFile(path, content.c_str(), content.length());
99 } 113 }
100 114
101 void AppendToFile(const FilePath& path, const std::string& content) { 115 void AppendToFile(const FilePath& path, const std::string& content) {
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
103 DCHECK(!path.empty()); 117 DCHECK(!path.empty());
104 118
105 file_util::AppendToFile(path, content.c_str(), content.length()); 119 file_util::AppendToFile(path, content.c_str(), content.length());
106 } 120 }
107 121
122 fileapi::IsolatedContext* isolated_context() {
123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
124 fileapi::IsolatedContext* isolated_context =
125 fileapi::IsolatedContext::GetInstance();
126 DCHECK(isolated_context);
127 return isolated_context;
128 }
129
130 std::string RegisterFilesystem(WebContents* web_contents,
131 const FilePath& path,
132 std::string* registered_name) {
133 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
134 CHECK(content::GetContentClient()->HasWebUIScheme(web_contents->GetURL()));
135 std::string filesystem_id = isolated_context()->RegisterFileSystemForPath(
136 fileapi::kFileSystemTypeNativeLocal, path, registered_name);
137
138 content::ChildProcessSecurityPolicy* policy =
139 content::ChildProcessSecurityPolicy::GetInstance();
140 RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
141 int renderer_id = render_view_host->GetProcess()->GetID();
142 policy->GrantReadWriteFileSystem(renderer_id, filesystem_id);
143
144 // We only need file level access for reading FileEntries. Saving FileEntries
145 // just needs the file system to have read/write access, which is granted
146 // above if required.
147 if (!policy->CanReadFile(renderer_id, path))
148 policy->GrantReadFile(renderer_id, path);
149
150 return filesystem_id;
151 }
152
153 typedef Callback<void(const std::vector<FilePath>&)> ValidateFoldersCallback;
154
155 void RunFoldersValidationCallback(
156 const ValidateFoldersCallback& callback,
157 const std::vector<FilePath>& permitted_paths) {
158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
159 callback.Run(permitted_paths);
160 }
161
162 void ValidateFoldersOnFileThread(const std::vector<FilePath>& file_paths,
163 const ValidateFoldersCallback& callback) {
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
165 std::vector<FilePath> permitted_paths;
166 std::vector<FilePath>::const_iterator it;
167 for (it = file_paths.begin(); it != file_paths.end(); ++it) {
168 FilePath security_file_path = it->Append(FILE_PATH_LITERAL(kMagicFileName));
kinuko 2013/01/04 14:20:55 This wouldn't work on windows (the macro works onl
vsevik 2013/01/09 11:54:40 Done, moved FILE_PATH_LITERAL to line 56.
169 if (file_util::PathExists(security_file_path))
170 permitted_paths.push_back(*it);
171 }
172 BrowserThread::PostTask(
173 BrowserThread::UI, FROM_HERE,
174 Bind(&RunFoldersValidationCallback, callback, permitted_paths));
kinuko 2013/01/04 14:20:55 Unless you really want to check the callback runs
vsevik 2013/01/09 11:54:40 Done.
175 }
176
108 } // namespace 177 } // namespace
109 178
110 DevToolsFileHelper::DevToolsFileHelper(Profile* profile) : profile_(profile), 179 DevToolsFileHelper::Filesystem::Filesystem() {
111 weak_factory_(this) { 180 }
181
182 DevToolsFileHelper::Filesystem::Filesystem(const std::string& filesystem_id,
183 const std::string& registered_name,
184 const std::string& filesystem_path)
185 : filesystem_id(filesystem_id),
186 registered_name(registered_name),
187 filesystem_path(filesystem_path) {
188 }
189
190 DevToolsFileHelper::DevToolsFileHelper(WebContents* web_contents,
191 Profile* profile)
192 : web_contents_(web_contents),
193 profile_(profile),
194 weak_factory_(this) {
112 } 195 }
113 196
114 DevToolsFileHelper::~DevToolsFileHelper() { 197 DevToolsFileHelper::~DevToolsFileHelper() {
115 } 198 }
116 199
117 void DevToolsFileHelper::Save(const std::string& url, 200 void DevToolsFileHelper::Save(const std::string& url,
118 const std::string& content, 201 const std::string& content,
119 bool save_as, 202 bool save_as,
120 const SaveCallback& callback) { 203 const SaveCallback& callback) {
121 PathsMap::iterator it = saved_files_.find(url); 204 PathsMap::iterator it = saved_files_.find(url);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 } 246 }
164 247
165 void DevToolsFileHelper::Append(const std::string& url, 248 void DevToolsFileHelper::Append(const std::string& url,
166 const std::string& content, 249 const std::string& content,
167 const AppendCallback& callback) { 250 const AppendCallback& callback) {
168 PathsMap::iterator it = saved_files_.find(url); 251 PathsMap::iterator it = saved_files_.find(url);
169 if (it == saved_files_.end()) 252 if (it == saved_files_.end())
170 return; 253 return;
171 callback.Run(); 254 callback.Run();
172 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 255 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
173 base::Bind(&AppendToFile, it->second, content)); 256 Bind(&AppendToFile, it->second, content));
174 } 257 }
175 258
176 void DevToolsFileHelper::SaveAsFileSelected(const std::string& url, 259 void DevToolsFileHelper::SaveAsFileSelected(const std::string& url,
177 const std::string& content, 260 const std::string& content,
178 const SaveCallback& callback, 261 const SaveCallback& callback,
179 const FilePath& path) { 262 const FilePath& path) {
180 *g_last_save_path.Pointer() = path; 263 *g_last_save_path.Pointer() = path;
181 saved_files_[url] = path; 264 saved_files_[url] = path;
182 265
183 DictionaryPrefUpdate update(profile_->GetPrefs(), 266 DictionaryPrefUpdate update(profile_->GetPrefs(),
184 prefs::kDevToolsEditedFiles); 267 prefs::kDevToolsEditedFiles);
185 DictionaryValue* files_map = update.Get(); 268 DictionaryValue* files_map = update.Get();
186 files_map->SetWithoutPathExpansion(base::MD5String(url), 269 files_map->SetWithoutPathExpansion(base::MD5String(url),
187 base::CreateFilePathValue(path)); 270 base::CreateFilePathValue(path));
188 callback.Run(); 271 callback.Run();
189 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 272 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
190 base::Bind(&WriteToFile, path, content)); 273 Bind(&WriteToFile, path, content));
191 } 274 }
192 275
193 void DevToolsFileHelper::SaveAsFileSelectionCanceled() { 276 void DevToolsFileHelper::SaveAsFileSelectionCanceled() {
194 } 277 }
278
279 void DevToolsFileHelper::AddFilesystem(const AddFilesystemCallback& callback) {
kinuko 2013/01/04 14:20:55 nit: In most other places we use 'FileSystem' (cap
vsevik 2013/01/09 11:54:40 Done.
280 scoped_refptr<SelectFileDialog> select_file_dialog = new SelectFileDialog(
281 Bind(&DevToolsFileHelper::InnerAddFilesystem,
282 weak_factory_.GetWeakPtr(),
283 callback),
284 Bind(&DevToolsFileHelper::CancelFilesystemAdding,
285 weak_factory_.GetWeakPtr(),
286 callback));
kinuko 2013/01/04 14:20:55 Bind(callback, "", Filesystem()) might be simpler?
vsevik 2013/01/09 11:54:40 Done.
287 select_file_dialog->Show(ui::SelectFileDialog::SELECT_FOLDER, FilePath());
288 }
289
290 void DevToolsFileHelper::InnerAddFilesystem(
291 const AddFilesystemCallback& callback,
292 const FilePath& path) {
293 std::vector<FilePath> file_paths(1, path);
294 ValidateFoldersCallback validate_folders_callback = Bind(
295 &DevToolsFileHelper::AddValidatedFilesystem,
296 weak_factory_.GetWeakPtr(),
297 callback);
298 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
299 Bind(&ValidateFoldersOnFileThread,
300 file_paths,
301 validate_folders_callback));
302 }
303
304 void DevToolsFileHelper::AddValidatedFilesystem(
305 const AddFilesystemCallback& callback,
306 const std::vector<FilePath>& permitted_paths) {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
308 if (permitted_paths.empty()) {
309 std::string error_string = l10n_util::GetStringFUTF8(
310 IDS_DEV_TOOLS_MAGIC_FILE_NOT_EXISTS_MESSAGE,
311 UTF8ToUTF16(kMagicFileName));
kinuko 2013/01/04 14:20:55 FilePathStringToWebString(kMagicFileName)
vsevik 2013/01/09 11:54:40 I don't need WebString at this point as GetStringF
312 callback.Run(error_string, Filesystem());
313 return;
314 }
315 FilePath path = permitted_paths.at(0);
316 std::string registered_name;
317 std::string filesystem_id = RegisterFilesystem(web_contents_,
318 path,
319 &registered_name);
320 std::string filesystem_path = path.AsUTF8Unsafe();
321
322 DictionaryPrefUpdate update(profile_->GetPrefs(),
323 prefs::kDevToolsFilesystemPaths);
324 DictionaryValue* filesystems_paths_value = update.Get();
325 filesystems_paths_value->Set(filesystem_path, Value::CreateNullValue());
326
327 Filesystem filesystem(filesystem_id, registered_name, filesystem_path);
328 callback.Run("", filesystem);
329 }
330
331 void DevToolsFileHelper::CancelFilesystemAdding(
332 const AddFilesystemCallback& callback) {
333 callback.Run("", Filesystem());
334 }
335
336 void DevToolsFileHelper::RequestFilesystems(
337 const RequestFilesystemsCallback& callback) {
338 const DictionaryValue* filesystems_paths_value =
339 profile_->GetPrefs()->GetDictionary(prefs::kDevToolsFilesystemPaths);
340 std::vector<FilePath> saved_paths;
341 DictionaryValue::key_iterator it = filesystems_paths_value->begin_keys();
342 for (; it != filesystems_paths_value->end_keys(); ++it) {
343 std::string filesystem_path = *it;
344 FilePath path = FilePath::FromUTF8Unsafe(filesystem_path);
345 saved_paths.push_back(path);
346 }
347
348 ValidateFoldersCallback validate_folders_callback = Bind(
349 &DevToolsFileHelper::RestoreValidatedFilesystems,
350 weak_factory_.GetWeakPtr(),
351 callback);
352 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
353 Bind(&ValidateFoldersOnFileThread,
354 saved_paths,
355 validate_folders_callback));
356 }
357
358 void DevToolsFileHelper::RestoreValidatedFilesystems(
359 const RequestFilesystemsCallback& callback,
360 const std::vector<FilePath>& permitted_paths) {
361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
362 std::vector<Filesystem> filesystems;
363 std::vector<FilePath>::const_iterator it;
364 for (it = permitted_paths.begin(); it != permitted_paths.end(); ++it) {
365 std::string registered_name;
366 std::string filesystem_id = RegisterFilesystem(web_contents_,
367 *it,
368 &registered_name);
kinuko 2013/01/04 14:20:55 nit: indent
vsevik 2013/01/09 11:54:40 Done.
vsevik 2013/01/09 11:54:40 Done.
369 std::string filesystem_path = it->AsUTF8Unsafe();
370 Filesystem filesystem(filesystem_id, registered_name, filesystem_path);
371 filesystems.push_back(filesystem);
372 }
373 callback.Run(filesystems);
374 }
375
376 void DevToolsFileHelper::RemoveFilesystem(const std::string& filesystem_path) {
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 FilePath path = FilePath::FromUTF8Unsafe(filesystem_path);
379 isolated_context()->RevokeFileSystemByPath(path);
380
381 DictionaryPrefUpdate update(profile_->GetPrefs(),
382 prefs::kDevToolsFilesystemPaths);
383 DictionaryValue* filesystems_paths_value = update.Get();
384 filesystems_paths_value->RemoveWithoutPathExpansion(filesystem_path, NULL);
kinuko 2013/01/04 14:20:55 These file paths look to be saved/removed per prof
vsevik 2013/01/09 11:54:40 This is correct and intended behavior.
385 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698