Chromium Code Reviews| 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..5145dc18ef2a589aa701f71c004bf7ac36e949bd 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,25 @@ |
| #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 "content/public/common/content_client.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 +53,8 @@ namespace { |
| typedef Callback<void(const FilePath&)> SelectedCallback; |
| typedef Callback<void(void)> CanceledCallback; |
| +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.
|
| + |
| class SelectFileDialog : public ui::SelectFileDialog::Listener, |
| public base::RefCounted<SelectFileDialog> { |
| public: |
| @@ -105,10 +119,79 @@ 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)); |
| + CHECK(content::GetContentClient()->HasWebUIScheme(web_contents->GetURL())); |
| + 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; |
| +} |
| + |
| +typedef Callback<void(const std::vector<FilePath>&)> ValidateFoldersCallback; |
| + |
| +void RunFoldersValidationCallback( |
| + const ValidateFoldersCallback& callback, |
| + const std::vector<FilePath>& permitted_paths) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + callback.Run(permitted_paths); |
| +} |
| + |
| +void ValidateFoldersOnFileThread(const std::vector<FilePath>& file_paths, |
| + const ValidateFoldersCallback& 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) { |
| + 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.
|
| + if (file_util::PathExists(security_file_path)) |
| + permitted_paths.push_back(*it); |
| + } |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + 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.
|
| +} |
| + |
| } // 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 +253,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 +270,116 @@ 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) { |
|
kinuko
2013/01/04 14:20:55
nit: In most other places we use 'FileSystem' (cap
vsevik
2013/01/09 11:54:40
Done.
|
| + scoped_refptr<SelectFileDialog> select_file_dialog = new SelectFileDialog( |
| + Bind(&DevToolsFileHelper::InnerAddFilesystem, |
| + weak_factory_.GetWeakPtr(), |
| + callback), |
| + Bind(&DevToolsFileHelper::CancelFilesystemAdding, |
| + weak_factory_.GetWeakPtr(), |
| + callback)); |
|
kinuko
2013/01/04 14:20:55
Bind(callback, "", Filesystem()) might be simpler?
vsevik
2013/01/09 11:54:40
Done.
|
| + select_file_dialog->Show(ui::SelectFileDialog::SELECT_FOLDER, FilePath()); |
| +} |
| + |
| +void DevToolsFileHelper::InnerAddFilesystem( |
| + const AddFilesystemCallback& callback, |
| + const FilePath& path) { |
| + std::vector<FilePath> file_paths(1, path); |
| + ValidateFoldersCallback validate_folders_callback = Bind( |
| + &DevToolsFileHelper::AddValidatedFilesystem, |
| + weak_factory_.GetWeakPtr(), |
| + callback); |
| + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| + Bind(&ValidateFoldersOnFileThread, |
| + file_paths, |
| + validate_folders_callback)); |
| +} |
| + |
| +void DevToolsFileHelper::AddValidatedFilesystem( |
| + const AddFilesystemCallback& callback, |
| + const std::vector<FilePath>& permitted_paths) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + if (permitted_paths.empty()) { |
| + std::string error_string = l10n_util::GetStringFUTF8( |
| + IDS_DEV_TOOLS_MAGIC_FILE_NOT_EXISTS_MESSAGE, |
| + 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
|
| + callback.Run(error_string, Filesystem()); |
| + return; |
| + } |
| + FilePath path = permitted_paths.at(0); |
| + 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::CancelFilesystemAdding( |
| + 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); |
| + } |
| + |
| + ValidateFoldersCallback validate_folders_callback = Bind( |
| + &DevToolsFileHelper::RestoreValidatedFilesystems, |
| + weak_factory_.GetWeakPtr(), |
| + callback); |
| + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| + Bind(&ValidateFoldersOnFileThread, |
| + saved_paths, |
| + validate_folders_callback)); |
| +} |
| + |
| +void DevToolsFileHelper::RestoreValidatedFilesystems( |
| + 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); |
|
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.
|
| + 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); |
|
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.
|
| +} |