Index: chrome/browser/devtools/devtools_file_helper.cc |
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc |
index e7657a52a8643310b9d6549d96de411b92a3b6fd..affbd4f69b88c75911dc18b35504547f5b821a57 100644 |
--- a/chrome/browser/devtools/devtools_file_helper.cc |
+++ b/chrome/browser/devtools/devtools_file_helper.cc |
@@ -11,6 +11,7 @@ |
#include "base/file_util.h" |
#include "base/lazy_instance.h" |
#include "base/md5.h" |
+#include "base/utf_string_conversions.h" |
#include "base/value_conversions.h" |
#include "chrome/browser/browser_process.h" |
#include "chrome/browser/download/download_prefs.h" |
@@ -20,14 +21,24 @@ |
#include "chrome/browser/ui/chrome_select_file_policy.h" |
#include "chrome/common/pref_names.h" |
#include "content/public/browser/browser_context.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/child_process_security_policy.h" |
#include "content/public/browser/download_manager.h" |
+#include "content/public/browser/render_process_host.h" |
+#include "content/public/browser/render_view_host.h" |
+#include "content/public/browser/web_contents.h" |
+#include "grit/generated_resources.h" |
#include "ui/base/dialogs/select_file_dialog.h" |
+#include "ui/base/l10n/l10n_util.h" |
+#include "webkit/fileapi/isolated_context.h" |
using base::Bind; |
using base::Callback; |
using content::BrowserContext; |
using content::BrowserThread; |
using content::DownloadManager; |
+using content::RenderViewHost; |
+using content::WebContents; |
namespace { |
@@ -41,6 +52,8 @@ namespace { |
typedef Callback<void(const FilePath&)> SelectedCallback; |
typedef Callback<void(void)> CanceledCallback; |
+const char kMagicFileName[] = ".allow-devtools-edit"; |
+ |
class SelectFileDialog : public ui::SelectFileDialog::Listener, |
public base::RefCounted<SelectFileDialog> { |
public: |
@@ -105,10 +118,113 @@ void AppendToFile(const FilePath& path, const std::string& content) { |
file_util::AppendToFile(path, content.c_str(), content.length()); |
} |
+fileapi::IsolatedContext* isolated_context() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ fileapi::IsolatedContext* isolated_context = |
+ fileapi::IsolatedContext::GetInstance(); |
+ DCHECK(isolated_context); |
+ return isolated_context; |
+} |
+ |
+std::string RegisterFilesystem(WebContents* web_contents, |
+ const FilePath& path, |
+ std::string* registered_name) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ std::string filesystem_id = isolated_context()->RegisterFileSystemForPath( |
+ fileapi::kFileSystemTypeNativeLocal, path, registered_name); |
+ |
+ content::ChildProcessSecurityPolicy* policy = |
+ content::ChildProcessSecurityPolicy::GetInstance(); |
+ RenderViewHost* render_view_host = web_contents->GetRenderViewHost(); |
+ int renderer_id = render_view_host->GetProcess()->GetID(); |
+ policy->GrantReadWriteFileSystem(renderer_id, filesystem_id); |
+ |
+ // We only need file level access for reading FileEntries. Saving FileEntries |
+ // just needs the file system to have read/write access, which is granted |
+ // above if required. |
+ if (!policy->CanReadFile(renderer_id, path)) |
+ policy->GrantReadFile(renderer_id, path); |
+ |
+ return filesystem_id; |
+} |
+ |
+bool CheckSecurityFileExistsInFolder(const FilePath& path) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
pfeldman
2012/12/28 15:09:58
inline
|
+ FilePath security_file_path = path.Append(FILE_PATH_LITERAL(kMagicFileName)); |
+ return file_util::PathExists(security_file_path); |
+} |
+ |
+typedef Callback<void(const std::vector<FilePath>&)> CheckFoldersCallback; |
+ |
+void FoldersCheckedOnFileThread(const CheckFoldersCallback& callback, |
+ const std::vector<FilePath>& permitted_paths) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ callback.Run(permitted_paths); |
+} |
+ |
+void CheckFoldersOnFileThread(const std::vector<FilePath>& file_paths, |
+ const CheckFoldersCallback& callback) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ std::vector<FilePath> permitted_paths; |
+ std::vector<FilePath>::const_iterator it; |
+ for (it = file_paths.begin(); it != file_paths.end(); ++it) { |
+ if (CheckSecurityFileExistsInFolder(*it)) |
+ permitted_paths.push_back(*it); |
+ } |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ Bind(&FoldersCheckedOnFileThread, callback, permitted_paths)); |
+} |
+ |
+void CheckFolders(const std::vector<FilePath>& file_paths, |
+ const CheckFoldersCallback& callback) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
+ Bind(&CheckFoldersOnFileThread, |
+ file_paths, |
+ callback)); |
+} |
+ |
+typedef Callback<void(const FilePath&, bool)> CheckFolderCallback; |
+ |
+void FolderCheckedOnFileThread(const CheckFolderCallback& callback, |
+ const FilePath& path, |
+ bool permitted) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
pfeldman
2012/12/28 15:09:58
inline
|
+ callback.Run(path, permitted); |
+} |
+ |
+void CheckFolderOnFileThread(const FilePath& path, |
+ const CheckFolderCallback& callback) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ bool permitted = CheckSecurityFileExistsInFolder(path); |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ Bind(&FolderCheckedOnFileThread, callback, path, permitted)); |
+} |
+ |
+void CheckFolder(const FilePath& path, const CheckFolderCallback& callback) { |
pfeldman
2012/12/28 15:09:58
Please inline it.
|
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
+ Bind(&CheckFolderOnFileThread, path, callback)); |
+} |
+ |
} // namespace |
-DevToolsFileHelper::DevToolsFileHelper(Profile* profile) : profile_(profile), |
- weak_factory_(this) { |
+DevToolsFileHelper::Filesystem::Filesystem() { |
+} |
+ |
+DevToolsFileHelper::Filesystem::Filesystem(const std::string& filesystem_id, |
+ const std::string& registered_name, |
+ const std::string& filesystem_path) |
+ : filesystem_id(filesystem_id), |
+ registered_name(registered_name), |
+ filesystem_path(filesystem_path) { |
+} |
+ |
+DevToolsFileHelper::DevToolsFileHelper(WebContents* web_contents, |
+ Profile* profile) |
+ : web_contents_(web_contents), profile_(profile), weak_factory_(this) { |
} |
DevToolsFileHelper::~DevToolsFileHelper() { |
@@ -170,7 +286,7 @@ void DevToolsFileHelper::Append(const std::string& url, |
return; |
callback.Run(); |
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
- base::Bind(&AppendToFile, it->second, content)); |
+ Bind(&AppendToFile, it->second, content)); |
} |
void DevToolsFileHelper::SaveAsFileSelected(const std::string& url, |
@@ -187,8 +303,106 @@ void DevToolsFileHelper::SaveAsFileSelected(const std::string& url, |
base::CreateFilePathValue(path)); |
callback.Run(); |
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
- base::Bind(&WriteToFile, path, content)); |
+ Bind(&WriteToFile, path, content)); |
} |
void DevToolsFileHelper::SaveAsFileSelectionCanceled() { |
} |
+ |
+void DevToolsFileHelper::AddFilesystem(const AddFilesystemCallback& callback) { |
+ scoped_refptr<SelectFileDialog> select_file_dialog = new SelectFileDialog( |
+ Bind(&DevToolsFileHelper::FolderSelected, |
+ weak_factory_.GetWeakPtr(), |
+ callback), |
+ Bind(&DevToolsFileHelper::FolderSelectionCanceled, |
+ weak_factory_.GetWeakPtr(), |
+ callback)); |
+ select_file_dialog->Show(ui::SelectFileDialog::SELECT_FOLDER, FilePath()); |
+} |
+ |
+void DevToolsFileHelper::FolderSelected(const AddFilesystemCallback& callback, |
+ const FilePath& path) { |
+ CheckFolder(path, Bind(&DevToolsFileHelper::SelectedFilesystemChecked, |
pfeldman
2012/12/28 15:09:58
CheckFolders(std::vector(1, path))
|
+ weak_factory_.GetWeakPtr(), |
+ callback)); |
+} |
+ |
+void DevToolsFileHelper::SelectedFilesystemChecked( |
+ const AddFilesystemCallback& callback, |
+ const FilePath& path, |
+ bool permitted) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (!permitted) { |
+ std::string error_string = l10n_util::GetStringFUTF8( |
+ IDS_DEV_TOOLS_MAGIC_FILE_NOT_EXISTS_MESSAGE, |
+ UTF8ToUTF16(kMagicFileName)); |
+ callback.Run(error_string, Filesystem()); |
+ return; |
+ } |
+ |
+ std::string registered_name; |
+ std::string filesystem_id = RegisterFilesystem(web_contents_, |
+ path, |
+ ®istered_name); |
+ std::string filesystem_path = path.AsUTF8Unsafe(); |
+ |
+ DictionaryPrefUpdate update(profile_->GetPrefs(), |
+ prefs::kDevToolsFilesystemPaths); |
+ DictionaryValue* filesystems_paths_value = update.Get(); |
+ filesystems_paths_value->Set(filesystem_path, Value::CreateNullValue()); |
+ |
+ Filesystem filesystem(filesystem_id, registered_name, filesystem_path); |
+ callback.Run("", filesystem); |
+} |
+ |
+void DevToolsFileHelper::FolderSelectionCanceled( |
+ const AddFilesystemCallback& callback) { |
+ callback.Run("", Filesystem()); |
+} |
+ |
+void DevToolsFileHelper::RequestFilesystems( |
+ const RequestFilesystemsCallback& callback) { |
+ const DictionaryValue* filesystems_paths_value = |
+ profile_->GetPrefs()->GetDictionary(prefs::kDevToolsFilesystemPaths); |
+ std::vector<FilePath> saved_paths; |
+ DictionaryValue::key_iterator it = filesystems_paths_value->begin_keys(); |
+ for (; it != filesystems_paths_value->end_keys(); ++it) { |
+ std::string filesystem_path = *it; |
+ FilePath path = FilePath::FromUTF8Unsafe(filesystem_path); |
+ saved_paths.push_back(path); |
+ } |
+ |
+ CheckFolders(saved_paths, |
+ Bind(&DevToolsFileHelper::RegisterPermittedFilesystems, |
+ weak_factory_.GetWeakPtr(), |
+ callback)); |
+} |
+ |
+void DevToolsFileHelper::RegisterPermittedFilesystems( |
+ const RequestFilesystemsCallback& callback, |
+ const std::vector<FilePath>& permitted_paths) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ std::vector<Filesystem> filesystems; |
+ std::vector<FilePath>::const_iterator it; |
+ for (it = permitted_paths.begin(); it != permitted_paths.end(); ++it) { |
+ std::string registered_name; |
+ std::string filesystem_id = RegisterFilesystem(web_contents_, |
+ *it, |
+ ®istered_name); |
+ std::string filesystem_path = it->AsUTF8Unsafe(); |
+ Filesystem filesystem(filesystem_id, registered_name, filesystem_path); |
+ filesystems.push_back(filesystem); |
+ } |
+ callback.Run(filesystems); |
+} |
+ |
+void DevToolsFileHelper::RemoveFilesystem(const std::string& filesystem_path) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ FilePath path = FilePath::FromUTF8Unsafe(filesystem_path); |
+ isolated_context()->RevokeFileSystemByPath(path); |
+ |
+ DictionaryPrefUpdate update(profile_->GetPrefs(), |
+ prefs::kDevToolsFilesystemPaths); |
+ DictionaryValue* filesystems_paths_value = update.Get(); |
+ filesystems_paths_value->RemoveWithoutPathExpansion(filesystem_path, NULL); |
+} |