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

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: Added fs name / root url generation in browser process as recommended by kinuko@ and addressed tsep… 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"
23 #include "content/public/browser/browser_thread.h" 24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/child_process_security_policy.h"
24 #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"
25 #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/file_system_util.h"
35 #include "webkit/fileapi/isolated_context.h"
26 36
27 using base::Bind; 37 using base::Bind;
28 using base::Callback; 38 using base::Callback;
29 using content::BrowserContext; 39 using content::BrowserContext;
30 using content::BrowserThread; 40 using content::BrowserThread;
31 using content::DownloadManager; 41 using content::DownloadManager;
42 using content::RenderViewHost;
43 using content::WebContents;
32 44
33 namespace { 45 namespace {
34 46
35 base::LazyInstance<FilePath>::Leaky 47 base::LazyInstance<FilePath>::Leaky
36 g_last_save_path = LAZY_INSTANCE_INITIALIZER; 48 g_last_save_path = LAZY_INSTANCE_INITIALIZER;
37 49
38 } // namespace 50 } // namespace
39 51
40 namespace { 52 namespace {
41 53
42 typedef Callback<void(const FilePath&)> SelectedCallback; 54 typedef Callback<void(const FilePath&)> SelectedCallback;
43 typedef Callback<void(void)> CanceledCallback; 55 typedef Callback<void(void)> CanceledCallback;
44 56
57 const FilePath::CharType kMagicFileName[] =
58 FILE_PATH_LITERAL(".allow-devtools-edit");
59
45 class SelectFileDialog : public ui::SelectFileDialog::Listener, 60 class SelectFileDialog : public ui::SelectFileDialog::Listener,
46 public base::RefCounted<SelectFileDialog> { 61 public base::RefCounted<SelectFileDialog> {
47 public: 62 public:
48 SelectFileDialog(const SelectedCallback& selected_callback, 63 SelectFileDialog(const SelectedCallback& selected_callback,
49 const CanceledCallback& canceled_callback) 64 const CanceledCallback& canceled_callback)
50 : selected_callback_(selected_callback), 65 : selected_callback_(selected_callback),
51 canceled_callback_(canceled_callback) { 66 canceled_callback_(canceled_callback) {
52 select_file_dialog_ = ui::SelectFileDialog::Create( 67 select_file_dialog_ = ui::SelectFileDialog::Create(
53 this, new ChromeSelectFilePolicy(NULL)); 68 this, new ChromeSelectFilePolicy(NULL));
54 } 69 }
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 file_util::WriteFile(path, content.c_str(), content.length()); 114 file_util::WriteFile(path, content.c_str(), content.length());
100 } 115 }
101 116
102 void AppendToFile(const FilePath& path, const std::string& content) { 117 void AppendToFile(const FilePath& path, const std::string& content) {
103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
104 DCHECK(!path.empty()); 119 DCHECK(!path.empty());
105 120
106 file_util::AppendToFile(path, content.c_str(), content.length()); 121 file_util::AppendToFile(path, content.c_str(), content.length());
107 } 122 }
108 123
124 fileapi::IsolatedContext* isolated_context() {
125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
126 fileapi::IsolatedContext* isolated_context =
127 fileapi::IsolatedContext::GetInstance();
128 DCHECK(isolated_context);
129 return isolated_context;
130 }
131
132 std::string RegisterFileSystem(WebContents* web_contents,
133 const FilePath& path,
134 std::string* registered_name) {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
136 CHECK(content::GetContentClient()->HasWebUIScheme(web_contents->GetURL()));
137 std::string file_system_id = isolated_context()->RegisterFileSystemForPath(
138 fileapi::kFileSystemTypeNativeLocal, path, registered_name);
139
140 content::ChildProcessSecurityPolicy* policy =
141 content::ChildProcessSecurityPolicy::GetInstance();
142 RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
143 int renderer_id = render_view_host->GetProcess()->GetID();
144 policy->GrantReadWriteFileSystem(renderer_id, file_system_id);
145
146 // We only need file level access for reading FileEntries. Saving FileEntries
147 // just needs the file system to have read/write access, which is granted
148 // above if required.
149 if (!policy->CanReadFile(renderer_id, path))
150 policy->GrantReadFile(renderer_id, path);
151
152 return file_system_id;
153 }
154
155 typedef Callback<void(const std::vector<FilePath>&)> ValidateFoldersCallback;
156
157 void ValidateFoldersOnFileThread(const std::vector<FilePath>& file_paths,
158 const ValidateFoldersCallback& callback) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
160 std::vector<FilePath> permitted_paths;
161 std::vector<FilePath>::const_iterator it;
162 for (it = file_paths.begin(); it != file_paths.end(); ++it) {
163 FilePath security_file_path = it->Append(kMagicFileName);
164 if (file_util::PathExists(security_file_path))
165 permitted_paths.push_back(*it);
166 }
167 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
168 Bind(callback, permitted_paths));
169 }
170
171 DevToolsFileHelper::FileSystem CreateFileSystemStruct(
172 WebContents* web_contents,
173 const std::string& file_system_id,
174 const std::string& registered_name,
175 const std::string& file_system_path) {
176 const GURL origin = web_contents->GetURL().GetOrigin();
177 std::string file_system_name = fileapi::GetIsolatedFileSystemName(
178 origin,
179 file_system_id);
180 std::string root_url = fileapi::GetIsolatedFileSystemRootURIString(
181 origin,
182 file_system_id,
183 registered_name);
184 return DevToolsFileHelper::FileSystem(file_system_name,
185 root_url,
186 file_system_path);
187 }
188
109 } // namespace 189 } // namespace
110 190
111 DevToolsFileHelper::DevToolsFileHelper(Profile* profile) : profile_(profile), 191 DevToolsFileHelper::FileSystem::FileSystem() {
112 weak_factory_(this) { 192 }
193
194 DevToolsFileHelper::FileSystem::FileSystem(const std::string& file_system_name,
195 const std::string& root_url,
196 const std::string& file_system_path)
197 : file_system_name(file_system_name),
198 root_url(root_url),
199 file_system_path(file_system_path) {
200 }
201
202 DevToolsFileHelper::DevToolsFileHelper(WebContents* web_contents,
203 Profile* profile)
204 : web_contents_(web_contents),
205 profile_(profile),
206 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
113 } 207 }
114 208
115 DevToolsFileHelper::~DevToolsFileHelper() { 209 DevToolsFileHelper::~DevToolsFileHelper() {
116 } 210 }
117 211
118 void DevToolsFileHelper::Save(const std::string& url, 212 void DevToolsFileHelper::Save(const std::string& url,
119 const std::string& content, 213 const std::string& content,
120 bool save_as, 214 bool save_as,
121 const SaveCallback& callback) { 215 const SaveCallback& callback) {
122 PathsMap::iterator it = saved_files_.find(url); 216 PathsMap::iterator it = saved_files_.find(url);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 } 258 }
165 259
166 void DevToolsFileHelper::Append(const std::string& url, 260 void DevToolsFileHelper::Append(const std::string& url,
167 const std::string& content, 261 const std::string& content,
168 const AppendCallback& callback) { 262 const AppendCallback& callback) {
169 PathsMap::iterator it = saved_files_.find(url); 263 PathsMap::iterator it = saved_files_.find(url);
170 if (it == saved_files_.end()) 264 if (it == saved_files_.end())
171 return; 265 return;
172 callback.Run(); 266 callback.Run();
173 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 267 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
174 base::Bind(&AppendToFile, it->second, content)); 268 Bind(&AppendToFile, it->second, content));
175 } 269 }
176 270
177 void DevToolsFileHelper::SaveAsFileSelected(const std::string& url, 271 void DevToolsFileHelper::SaveAsFileSelected(const std::string& url,
178 const std::string& content, 272 const std::string& content,
179 const SaveCallback& callback, 273 const SaveCallback& callback,
180 const FilePath& path) { 274 const FilePath& path) {
181 *g_last_save_path.Pointer() = path; 275 *g_last_save_path.Pointer() = path;
182 saved_files_[url] = path; 276 saved_files_[url] = path;
183 277
184 DictionaryPrefUpdate update(profile_->GetPrefs(), 278 DictionaryPrefUpdate update(profile_->GetPrefs(),
185 prefs::kDevToolsEditedFiles); 279 prefs::kDevToolsEditedFiles);
186 DictionaryValue* files_map = update.Get(); 280 DictionaryValue* files_map = update.Get();
187 files_map->SetWithoutPathExpansion(base::MD5String(url), 281 files_map->SetWithoutPathExpansion(base::MD5String(url),
188 base::CreateFilePathValue(path)); 282 base::CreateFilePathValue(path));
189 callback.Run(); 283 callback.Run();
190 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 284 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
191 base::Bind(&WriteToFile, path, content)); 285 Bind(&WriteToFile, path, content));
192 } 286 }
193 287
194 void DevToolsFileHelper::SaveAsFileSelectionCanceled() { 288 void DevToolsFileHelper::SaveAsFileSelectionCanceled() {
195 } 289 }
290
291 void DevToolsFileHelper::AddFileSystem(const AddFileSystemCallback& callback) {
292 scoped_refptr<SelectFileDialog> select_file_dialog = new SelectFileDialog(
293 Bind(&DevToolsFileHelper::InnerAddFileSystem,
294 weak_factory_.GetWeakPtr(),
295 callback),
296 Bind(callback, "", FileSystem()));
297 select_file_dialog->Show(ui::SelectFileDialog::SELECT_FOLDER, FilePath());
298 }
299
300 void DevToolsFileHelper::InnerAddFileSystem(
301 const AddFileSystemCallback& callback,
302 const FilePath& path) {
303 std::vector<FilePath> file_paths(1, path);
304 ValidateFoldersCallback validate_folders_callback = Bind(
305 &DevToolsFileHelper::AddValidatedFileSystem,
306 weak_factory_.GetWeakPtr(),
307 callback);
308 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
309 Bind(&ValidateFoldersOnFileThread,
310 file_paths,
311 validate_folders_callback));
312 }
313
314 void DevToolsFileHelper::AddValidatedFileSystem(
315 const AddFileSystemCallback& callback,
316 const std::vector<FilePath>& permitted_paths) {
317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
318 if (permitted_paths.empty()) {
319 std::string magic_file_name = FilePath(kMagicFileName).AsUTF8Unsafe();
320 std::string error_string = l10n_util::GetStringFUTF8(
321 IDS_DEV_TOOLS_MAGIC_FILE_NOT_EXISTS_MESSAGE,
322 UTF8ToUTF16(magic_file_name));
323 callback.Run(error_string, FileSystem());
324 return;
325 }
326 FilePath path = permitted_paths.at(0);
327 std::string registered_name;
328 std::string file_system_id = RegisterFileSystem(web_contents_,
329 path,
330 &registered_name);
331 std::string file_system_path = path.AsUTF8Unsafe();
332
333 DictionaryPrefUpdate update(profile_->GetPrefs(),
334 prefs::kDevToolsFileSystemPaths);
335 DictionaryValue* file_systems_paths_value = update.Get();
336 file_systems_paths_value->Set(file_system_path, Value::CreateNullValue());
337
338 FileSystem filesystem = CreateFileSystemStruct(web_contents_,
339 file_system_id,
340 registered_name,
341 file_system_path);
342 callback.Run("", filesystem);
343 }
344
345 void DevToolsFileHelper::RequestFileSystems(
346 const RequestFileSystemsCallback& callback) {
347 const DictionaryValue* file_systems_paths_value =
348 profile_->GetPrefs()->GetDictionary(prefs::kDevToolsFileSystemPaths);
349 std::vector<FilePath> saved_paths;
350 DictionaryValue::key_iterator it = file_systems_paths_value->begin_keys();
351 for (; it != file_systems_paths_value->end_keys(); ++it) {
352 std::string file_system_path = *it;
353 FilePath path = FilePath::FromUTF8Unsafe(file_system_path);
354 saved_paths.push_back(path);
355 }
356
357 ValidateFoldersCallback validate_folders_callback = Bind(
358 &DevToolsFileHelper::RestoreValidatedFileSystems,
359 weak_factory_.GetWeakPtr(),
360 callback);
361 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
362 Bind(&ValidateFoldersOnFileThread,
363 saved_paths,
364 validate_folders_callback));
365 }
366
367 void DevToolsFileHelper::RestoreValidatedFileSystems(
368 const RequestFileSystemsCallback& callback,
369 const std::vector<FilePath>& permitted_paths) {
370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
371 std::vector<FileSystem> file_systems;
372 std::vector<FilePath>::const_iterator it;
373 for (it = permitted_paths.begin(); it != permitted_paths.end(); ++it) {
374 std::string registered_name;
375 std::string file_system_id = RegisterFileSystem(web_contents_,
376 *it,
377 &registered_name);
378 std::string file_system_path = it->AsUTF8Unsafe();
379 FileSystem filesystem = CreateFileSystemStruct(web_contents_,
380 file_system_id,
381 registered_name,
382 file_system_path);
383 file_systems.push_back(filesystem);
384 }
385 callback.Run(file_systems);
386 }
387
388 void DevToolsFileHelper::RemoveFileSystem(const std::string& file_system_path) {
389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
390 FilePath path = FilePath::FromUTF8Unsafe(file_system_path);
391 isolated_context()->RevokeFileSystemByPath(path);
392
393 DictionaryPrefUpdate update(profile_->GetPrefs(),
394 prefs::kDevToolsFileSystemPaths);
395 DictionaryValue* file_systems_paths_value = update.Get();
396 file_systems_paths_value->RemoveWithoutPathExpansion(file_system_path, NULL);
397 }
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