OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 ®istered_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 ®istered_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 } | |
OLD | NEW |