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