diff options
author | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-13 09:18:29 +0000 |
---|---|---|
committer | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-13 09:18:29 +0000 |
commit | 7bc8299dccc300184e850e1a76db110a85234db1 (patch) | |
tree | 668a92aea8b994e089644b20c1d7832e935a4c1a /chrome | |
parent | 82222efbc0eb7758d69671099971f1b6dd3eb20d (diff) | |
download | chromium_src-7bc8299dccc300184e850e1a76db110a85234db1.zip chromium_src-7bc8299dccc300184e850e1a76db110a85234db1.tar.gz chromium_src-7bc8299dccc300184e850e1a76db110a85234db1.tar.bz2 |
Allow platform apps to get writable FileEntry objects from readable ones.
This propts the user to choose a path to save to, using the file entry passed
in as a reference of where to save to.
BUG=130196
TEST=Manual testing performed
Review URL: https://chromiumcodereview.appspot.com/10539101
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141878 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/extensions/api/file_system/file_system_api.cc | 171 | ||||
-rw-r--r-- | chrome/browser/extensions/api/file_system/file_system_api.h | 15 | ||||
-rw-r--r-- | chrome/browser/extensions/shell_window_registry.cc | 13 | ||||
-rw-r--r-- | chrome/browser/extensions/shell_window_registry.h | 7 | ||||
-rw-r--r-- | chrome/chrome_renderer.gypi | 4 | ||||
-rw-r--r-- | chrome/common/extensions/api/file_system.idl | 3 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_dispatcher.cc | 10 | ||||
-rw-r--r-- | chrome/renderer/extensions/file_system_natives.cc (renamed from chrome/renderer/extensions/experimental.app_custom_bindings.cc) | 4 | ||||
-rw-r--r-- | chrome/renderer/extensions/file_system_natives.h (renamed from chrome/renderer/extensions/experimental.app_custom_bindings.h) | 12 | ||||
-rw-r--r-- | chrome/renderer/resources/extensions/experimental.app_custom_bindings.js | 4 | ||||
-rw-r--r-- | chrome/renderer/resources/extensions/file_system_custom_bindings.js | 42 |
11 files changed, 246 insertions, 39 deletions
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc index 7c3fa9a..bbf689e 100644 --- a/chrome/browser/extensions/api/file_system/file_system_api.cc +++ b/chrome/browser/extensions/api/file_system/file_system_api.cc @@ -5,26 +5,42 @@ #include "chrome/browser/extensions/api/file_system/file_system_api.h" #include "base/file_path.h" +#include "chrome/browser/extensions/shell_window_registry.h" +#include "chrome/browser/platform_util.h" +#include "chrome/browser/ui/extensions/shell_window.h" +#include "chrome/browser/ui/select_file_dialog.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/web_contents.h" #include "webkit/fileapi/file_system_util.h" #include "webkit/fileapi/isolated_context.h" -namespace extensions { - const char kInvalidParameters[] = "Invalid parameters"; const char kSecurityError[] = "Security error"; +const char kInvalidCallingPage[] = "Invalid calling page"; +const char kUserCancelled[] = "User cancelled"; -bool FileSystemGetDisplayPathFunction::RunImpl() { - std::string filesystem_name; - std::string filesystem_path; - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); - EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); +namespace { +bool GetFilePathOfFileEntry(const std::string& filesystem_name, + const std::string& filesystem_path, + const content::RenderViewHost* render_view_host, + FilePath* file_path, + std::string* error) { std::string filesystem_id; if (!fileapi::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) { - error_ = kInvalidParameters; + *error = kInvalidParameters; + return false; + } + + // Only return the display path if the process has read access to the + // filesystem. + content::ChildProcessSecurityPolicy* policy = + content::ChildProcessSecurityPolicy::GetInstance(); + if (!policy->CanReadFileSystem(render_view_host->GetProcess()->GetID(), + filesystem_id)) { + *error = kSecurityError; return false; } @@ -32,22 +48,30 @@ bool FileSystemGetDisplayPathFunction::RunImpl() { FilePath relative_path = FilePath::FromUTF8Unsafe(filesystem_path); FilePath virtual_path = context->CreateVirtualPath(filesystem_id, relative_path); - FilePath file_path; if (!context->CrackIsolatedPath(virtual_path, &filesystem_id, NULL, - &file_path)) { - error_ = kInvalidParameters; + file_path)) { + *error = kInvalidParameters; return false; } - // Only return the display path if the process has read access to the - // filesystem. - content::ChildProcessSecurityPolicy* policy = - content::ChildProcessSecurityPolicy::GetInstance(); - if (!policy->CanReadFileSystem(render_view_host_->GetProcess()->GetID(), - filesystem_id)) { - error_ = kSecurityError; + return true; +} + +} // namespace + +namespace extensions { + +bool FileSystemGetDisplayPathFunction::RunImpl() { + std::string filesystem_name; + std::string filesystem_path; + EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); + EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); + + FilePath file_path; + if (!GetFilePathOfFileEntry(filesystem_name, filesystem_path, + render_view_host_, &file_path, &error_)) { return false; } @@ -55,4 +79,115 @@ bool FileSystemGetDisplayPathFunction::RunImpl() { return true; } +// Handles showing a dialog to the user to ask for the filename for a file to +// save. +class FileSystemGetWritableFileEntryFunction::FilePicker + : public SelectFileDialog::Listener { + public: + FilePicker(FileSystemGetWritableFileEntryFunction* function, + content::WebContents* web_contents, + const FilePath& suggested_path) + : suggested_path_(suggested_path), + function_(function) { + select_file_dialog_ = SelectFileDialog::Create(this); + SelectFileDialog::FileTypeInfo file_type_info; + FilePath::StringType extension = suggested_path.Extension(); + if (!extension.empty()) { + extension.erase(extension.begin()); // drop the . + file_type_info.extensions.resize(1); + file_type_info.extensions[0].push_back(extension); + } + file_type_info.include_all_files = true; + gfx::NativeWindow owning_window = web_contents ? + platform_util::GetTopLevel(web_contents->GetNativeView()) : NULL; + + select_file_dialog_->SelectFile(SelectFileDialog::SELECT_SAVEAS_FILE, + string16(), + suggested_path, + &file_type_info, 0, FILE_PATH_LITERAL(""), + web_contents, owning_window, NULL); + } + + virtual ~FilePicker() {} + + private: + // SelectFileDialog::Listener implementation. + virtual void FileSelected(const FilePath& path, + int index, + void* params) OVERRIDE { + function_->FileSelected(path); + delete this; + } + + virtual void FileSelectionCanceled(void* params) OVERRIDE { + function_->FileSelectionCanceled(); + delete this; + } + + FilePath suggested_path_; + + // For managing select file dialogs. + scoped_refptr<SelectFileDialog> select_file_dialog_; + scoped_refptr<FileSystemGetWritableFileEntryFunction> function_; + + DISALLOW_COPY_AND_ASSIGN(FilePicker); +}; + +bool FileSystemGetWritableFileEntryFunction::RunImpl() { + std::string filesystem_name; + std::string filesystem_path; + EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); + EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); + + FilePath suggested_path; + if (!GetFilePathOfFileEntry(filesystem_name, filesystem_path, + render_view_host_, &suggested_path, &error_)) { + return false; + } + + ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); + DCHECK(registry); + ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( + render_view_host()); + if (!shell_window) { + error_ = kInvalidCallingPage; + return false; + } + + // The file picker will hold a reference to this function instance, preventing + // its destruction (and subsequent sending of the function response) until the + // user has selected a file or cancelled the picker. At that point, the picker + // will delete itself, which will also free the function instance. + new FilePicker(this, shell_window->web_contents(), suggested_path); + return true; +} + +void FileSystemGetWritableFileEntryFunction::FileSelected( + const FilePath& path) { + std::set<FilePath> filesets; + filesets.insert(path); + + fileapi::IsolatedContext* isolated_context = + fileapi::IsolatedContext::GetInstance(); + DCHECK(isolated_context); + std::string filesystem_id = isolated_context->RegisterIsolatedFileSystem( + filesets); + + content::ChildProcessSecurityPolicy* policy = + content::ChildProcessSecurityPolicy::GetInstance(); + int renderer_id = render_view_host_->GetProcess()->GetID(); + policy->GrantReadWriteFileSystem(renderer_id, filesystem_id); + + DictionaryValue* dict = new DictionaryValue(); + result_.reset(dict); + dict->SetString("fileSystemId", filesystem_id); + dict->SetString("baseName", path.BaseName().AsUTF8Unsafe()); + SendResponse(true); +} + +void FileSystemGetWritableFileEntryFunction::FileSelectionCanceled() { + error_ = kUserCancelled; + SendResponse(false); +} + } // namespace extensions diff --git a/chrome/browser/extensions/api/file_system/file_system_api.h b/chrome/browser/extensions/api/file_system/file_system_api.h index 67a56e6..0757736 100644 --- a/chrome/browser/extensions/api/file_system/file_system_api.h +++ b/chrome/browser/extensions/api/file_system/file_system_api.h @@ -19,6 +19,21 @@ class FileSystemGetDisplayPathFunction : public SyncExtensionFunction { virtual bool RunImpl() OVERRIDE; }; +class FileSystemGetWritableFileEntryFunction : public AsyncExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION_NAME("fileSystem.getWritableFileEntry"); + + protected: + virtual ~FileSystemGetWritableFileEntryFunction() {} + virtual bool RunImpl() OVERRIDE; + + private: + class FilePicker; + + void FileSelected(const FilePath& path); + void FileSelectionCanceled(); +}; + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_ diff --git a/chrome/browser/extensions/shell_window_registry.cc b/chrome/browser/extensions/shell_window_registry.cc index ab91fe8..7934901 100644 --- a/chrome/browser/extensions/shell_window_registry.cc +++ b/chrome/browser/extensions/shell_window_registry.cc @@ -6,6 +6,8 @@ #include "chrome/browser/profiles/profile_dependency_manager.h" #include "chrome/browser/ui/extensions/shell_window.h" #include "chrome/common/extensions/extension.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" ShellWindowRegistry::ShellWindowRegistry() {} @@ -45,6 +47,17 @@ ShellWindowRegistry::ShellWindowSet ShellWindowRegistry::GetShellWindowsForApp( return app_windows; } +ShellWindow* ShellWindowRegistry::GetShellWindowForRenderViewHost( + content::RenderViewHost* render_view_host) const { + for (ShellWindowSet::const_iterator i = shell_windows_.begin(); + i != shell_windows_.end(); ++i) { + if ((*i)->web_contents()->GetRenderViewHost() == render_view_host) + return *i; + } + + return NULL; +} + /////////////////////////////////////////////////////////////////////////////// // Factory boilerplate diff --git a/chrome/browser/extensions/shell_window_registry.h b/chrome/browser/extensions/shell_window_registry.h index 52b5e18..9dd7051 100644 --- a/chrome/browser/extensions/shell_window_registry.h +++ b/chrome/browser/extensions/shell_window_registry.h @@ -17,6 +17,10 @@ class Profile; class ShellWindow; +namespace content { +class RenderViewHost; +} + // The ShellWindowRegistry tracks the ShellWindows for all platform apps for a // particular profile. // This class is planned to evolve into tracking all PlatformApps for a @@ -57,6 +61,9 @@ class ShellWindowRegistry : public ProfileKeyedService { ShellWindowSet GetShellWindowsForApp(const std::string app_id) const; const ShellWindowSet& shell_windows() const { return shell_windows_; } + ShellWindow* GetShellWindowForRenderViewHost( + content::RenderViewHost* render_view_host) const; + private: class Factory : public ProfileKeyedServiceFactory { public: diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index 9273650..ffd0eec 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -78,8 +78,6 @@ 'renderer/extensions/context_menus_custom_bindings.h', 'renderer/extensions/event_bindings.cc', 'renderer/extensions/event_bindings.h', - 'renderer/extensions/experimental.app_custom_bindings.cc', - 'renderer/extensions/experimental.app_custom_bindings.h', 'renderer/extensions/experimental.usb_custom_bindings.cc', 'renderer/extensions/experimental.usb_custom_bindings.h', 'renderer/extensions/extension_custom_bindings.cc', @@ -97,6 +95,8 @@ 'renderer/extensions/file_browser_handler_custom_bindings.h', 'renderer/extensions/file_browser_private_custom_bindings.cc', 'renderer/extensions/file_browser_private_custom_bindings.h', + 'renderer/extensions/file_system_natives.cc', + 'renderer/extensions/file_system_natives.h', 'renderer/extensions/i18n_custom_bindings.cc', 'renderer/extensions/i18n_custom_bindings.h', 'renderer/extensions/media_gallery_custom_bindings.cc', diff --git a/chrome/common/extensions/api/file_system.idl b/chrome/common/extensions/api/file_system.idl index a4e6e9d..7881f3d 100644 --- a/chrome/common/extensions/api/file_system.idl +++ b/chrome/common/extensions/api/file_system.idl @@ -6,9 +6,12 @@ [nodoc] namespace fileSystem { callback GetDisplayPathCallback = void (DOMString displayPath); + callback FileEntryCallback = void ([instanceOf=fileEntry] object fileEntry); interface Functions { static void getDisplayPath([instanceOf=FileEntry] object fileEntry, GetDisplayPathCallback onSuccess); + static void getWritableFileEntry([instanceOf=FileEntry] object fileEntry, + FileEntryCallback onSuccess); }; }; diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc index 23af146..add0813 100644 --- a/chrome/renderer/extensions/extension_dispatcher.cc +++ b/chrome/renderer/extensions/extension_dispatcher.cc @@ -25,7 +25,6 @@ #include "chrome/renderer/extensions/chrome_v8_extension.h" #include "chrome/renderer/extensions/context_menus_custom_bindings.h" #include "chrome/renderer/extensions/event_bindings.h" -#include "chrome/renderer/extensions/experimental.app_custom_bindings.h" #include "chrome/renderer/extensions/experimental.usb_custom_bindings.h" #include "chrome/renderer/extensions/extension_custom_bindings.h" #include "chrome/renderer/extensions/extension_groups.h" @@ -33,6 +32,7 @@ #include "chrome/renderer/extensions/extension_request_sender.h" #include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h" #include "chrome/renderer/extensions/file_browser_private_custom_bindings.h" +#include "chrome/renderer/extensions/file_system_natives.h" #include "chrome/renderer/extensions/i18n_custom_bindings.h" #include "chrome/renderer/extensions/media_gallery_custom_bindings.h" #include "chrome/renderer/extensions/miscellaneous_bindings.h" @@ -78,13 +78,13 @@ using extensions::ApiDefinitionsNatives; using extensions::AppWindowCustomBindings; using extensions::ContextMenusCustomBindings; using extensions::Extension; -using extensions::ExperimentalAppCustomBindings; using extensions::ExperimentalUsbCustomBindings; using extensions::ExtensionAPI; using extensions::ExtensionCustomBindings; using extensions::Feature; using extensions::FileBrowserHandlerCustomBindings; using extensions::FileBrowserPrivateCustomBindings; +using extensions::FileSystemNatives; using extensions::I18NCustomBindings; using extensions::MiscellaneousBindings; using extensions::MediaGalleryCustomBindings; @@ -500,6 +500,10 @@ void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system, scoped_ptr<NativeHandler>( new SetIconNatives(this, request_sender_.get()))); + // Natives used by multiple APIs. + module_system->RegisterNativeHandler("file_system_natives", + scoped_ptr<NativeHandler>(new FileSystemNatives())); + // Custom bindings. module_system->RegisterNativeHandler("app", scoped_ptr<NativeHandler>(new AppBindings(this, context))); @@ -512,8 +516,6 @@ void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system, new ExtensionCustomBindings(this))); module_system->RegisterNativeHandler("experimental_mediaGalleries", scoped_ptr<NativeHandler>(new MediaGalleryCustomBindings())); - module_system->RegisterNativeHandler("experimental_app", - scoped_ptr<NativeHandler>(new ExperimentalAppCustomBindings())); module_system->RegisterNativeHandler("experimental_usb", scoped_ptr<NativeHandler>(new ExperimentalUsbCustomBindings())); module_system->RegisterNativeHandler("file_browser_handler", diff --git a/chrome/renderer/extensions/experimental.app_custom_bindings.cc b/chrome/renderer/extensions/file_system_natives.cc index 65f7a6d..7ed653f 100644 --- a/chrome/renderer/extensions/experimental.app_custom_bindings.cc +++ b/chrome/renderer/extensions/file_system_natives.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/renderer/extensions/experimental.app_custom_bindings.h" +#include "chrome/renderer/extensions/file_system_natives.h" #include <string> @@ -48,7 +48,7 @@ static v8::Handle<v8::Value> GetIsolatedFileSystem( namespace extensions { -ExperimentalAppCustomBindings::ExperimentalAppCustomBindings() +FileSystemNatives::FileSystemNatives() : ChromeV8Extension(NULL) { RouteStaticFunction("GetIsolatedFileSystem", &GetIsolatedFileSystem); } diff --git a/chrome/renderer/extensions/experimental.app_custom_bindings.h b/chrome/renderer/extensions/file_system_natives.h index aa11c49a..d873f5c 100644 --- a/chrome/renderer/extensions/experimental.app_custom_bindings.h +++ b/chrome/renderer/extensions/file_system_natives.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_RENDERER_EXTENSIONS_EXPERIMENTAL_APP_CUSTOM_BINDINGS_H_ -#define CHROME_RENDERER_EXTENSIONS_EXPERIMENTAL_APP_CUSTOM_BINDINGS_H_ +#ifndef CHROME_RENDERER_EXTENSIONS_FILE_SYSTEM_NATIVES_H_ +#define CHROME_RENDERER_EXTENSIONS_FILE_SYSTEM_NATIVES_H_ #pragma once #include "base/compiler_specific.h" @@ -12,14 +12,14 @@ namespace extensions { // Custom bindings for the nativeFileSystem API. -class ExperimentalAppCustomBindings : public ChromeV8Extension { +class FileSystemNatives : public ChromeV8Extension { public: - ExperimentalAppCustomBindings(); + FileSystemNatives(); private: - DISALLOW_COPY_AND_ASSIGN(ExperimentalAppCustomBindings); + DISALLOW_COPY_AND_ASSIGN(FileSystemNatives); }; } // namespace extensions -#endif // CHROME_RENDERER_EXTENSIONS_EXPERIMENTAL_APP_CUSTOM_BINDINGS_H_ +#endif // CHROME_RENDERER_EXTENSIONS_FILE_SYSTEM_NATIVES_H_ diff --git a/chrome/renderer/resources/extensions/experimental.app_custom_bindings.js b/chrome/renderer/resources/extensions/experimental.app_custom_bindings.js index 8f0cd1c..52284c7 100644 --- a/chrome/renderer/resources/extensions/experimental.app_custom_bindings.js +++ b/chrome/renderer/resources/extensions/experimental.app_custom_bindings.js @@ -5,8 +5,8 @@ // Custom bindings for the experimental.app API. var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -var experimentalAppNatives = requireNative('experimental_app'); -var GetIsolatedFileSystem = experimentalAppNatives.GetIsolatedFileSystem; +var fileSystemHelpers = requireNative('file_system_natives'); +var GetIsolatedFileSystem = fileSystemHelpers.GetIsolatedFileSystem; chromeHidden.registerCustomHook('experimental.app', function(bindingsAPI) { chrome.experimental.app.onLaunched.dispatch = diff --git a/chrome/renderer/resources/extensions/file_system_custom_bindings.js b/chrome/renderer/resources/extensions/file_system_custom_bindings.js index 0e6da3a..1847279 100644 --- a/chrome/renderer/resources/extensions/file_system_custom_bindings.js +++ b/chrome/renderer/resources/extensions/file_system_custom_bindings.js @@ -5,12 +5,44 @@ // Custom bindings for the fileSystem API. var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); +var fileSystemNatives = requireNative('file_system_natives'); +var GetIsolatedFileSystem = fileSystemNatives.GetIsolatedFileSystem; chromeHidden.registerCustomHook('fileSystem', function(bindingsAPI) { - bindingsAPI.apiFunctions.setUpdateArgumentsPostValidate( - 'getDisplayPath', function(fileEntry, callback) { - var fileSystemName = fileEntry.filesystem.name; - var relativePath = fileEntry.fullPath.slice(1); - return [fileSystemName, relativePath, callback]; + var apiFunctions = bindingsAPI.apiFunctions; + function bindFileEntryFunction(functionName) { + apiFunctions.setUpdateArgumentsPostValidate( + functionName, function(fileEntry, callback) { + var fileSystemName = fileEntry.filesystem.name; + var relativePath = fileEntry.fullPath.slice(1); + return [fileSystemName, relativePath, callback]; + }); + } + ['getDisplayPath', 'getWritableFileEntry'].forEach(bindFileEntryFunction); + + apiFunctions.setCustomCallback('getWritableFileEntry', + function(name, request, response) { + if (request.callback && response) { + var callback = request.callback; + request.callback = null; + + var fileSystemId = response.fileSystemId; + var baseName = response.baseName; + var fs = GetIsolatedFileSystem(fileSystemId); + + try { + fs.root.getFile(baseName, {}, function(fileEntry) { + callback(fileEntry); + }, function(fileError) { + chrome.extension.lastError = + 'Error getting fileEntry, code: ' + fileError.code; + callback(); + }); + } catch (e) { + chrome.extension.lastError = + 'Error in event handler for onLaunched: ' + e.stack; + callback(); + } + } }); }); |