diff options
author | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-08 00:05:32 +0000 |
---|---|---|
committer | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-08 00:05:32 +0000 |
commit | ffc7b4d4d78923095866c6ee60ce7b7daefe89f8 (patch) | |
tree | 6fe017ff0b18981c8cf9d2a740b6bc20973a85dc | |
parent | b1c4de4c2e2713ed8431d230d1e638efefaa7693 (diff) | |
download | chromium_src-ffc7b4d4d78923095866c6ee60ce7b7daefe89f8.zip chromium_src-ffc7b4d4d78923095866c6ee60ce7b7daefe89f8.tar.gz chromium_src-ffc7b4d4d78923095866c6ee60ce7b7daefe89f8.tar.bz2 |
Implement extension API chrome.fileSystem.getDisplayPath().
This allows platform apps to get the full path of file entries in isolated
file systems for display purposes.
BUG=130452
TEST=Test added
Review URL: https://chromiumcodereview.appspot.com/10477009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141119 0039d316-1c4b-4281-b951-d872f2087c98
20 files changed, 255 insertions, 8 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 new file mode 100644 index 0000000..d9a3104 --- /dev/null +++ b/chrome/browser/extensions/api/file_system/file_system_api.cc @@ -0,0 +1,60 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/file_system/file_system_api.h" + +#include "base/file_path.h" +#include "chrome/common/extensions/api/file_system.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 "webkit/fileapi/file_system_util.h" +#include "webkit/fileapi/isolated_context.h" + +namespace GetDisplayPath = extensions::api::file_system::GetDisplayPath; + +namespace extensions { + +const char kInvalidParameters[] = "Invalid parameters"; +const char kSecurityError[] = "Security error"; + +bool FileSystemGetDisplayPathFunction::RunImpl() { + scoped_ptr<GetDisplayPath::Params> params(GetDisplayPath::Params::Create( + *args_)); + EXTENSION_FUNCTION_VALIDATE(params.get()); + + std::string filesystem_id; + if (!fileapi::CrackIsolatedFileSystemName(params->fsname, &filesystem_id)) { + error_ = kInvalidParameters; + return false; + } + + fileapi::IsolatedContext* context = fileapi::IsolatedContext::GetInstance(); + FilePath relative_path = FilePath::FromUTF8Unsafe(params->fspath); + FilePath virtual_path = context->CreateVirtualPath(filesystem_id, + relative_path); + FilePath file_path; + if (!context->CrackIsolatedPath(virtual_path, + &filesystem_id, + NULL, + &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 false; + } + + result_.reset(base::Value::CreateStringValue(file_path.value())); + return true; +} + +} // 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 new file mode 100644 index 0000000..67a56e6 --- /dev/null +++ b/chrome/browser/extensions/api/file_system/file_system_api.h @@ -0,0 +1,24 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_ +#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_ +#pragma once + +#include "chrome/browser/extensions/extension_function.h" + +namespace extensions { + +class FileSystemGetDisplayPathFunction : public SyncExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION_NAME("fileSystem.getDisplayPath"); + + protected: + virtual ~FileSystemGetDisplayPathFunction() {} + virtual bool RunImpl() OVERRIDE; +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_ diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc index fbb99a4..bf9df1c 100644 --- a/chrome/browser/extensions/platform_app_browsertest.cc +++ b/chrome/browser/extensions/platform_app_browsertest.cc @@ -240,4 +240,13 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNothing) { ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_nothing")) << message_; } + +// Test that platform apps can use the chrome.fileSystem.getDisplayPath +// function to get the native file system path of a file they are launched with. +IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, GetDisplayPath) { + SetCommandLineArg("platform_apps/launch_files/test.txt"); + ASSERT_TRUE(RunPlatformAppTest("platform_apps/get_display_path")) + << message_; +} + #endif // defined(OS_CHROMEOS) diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index bd41b87..60f0bf6 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -139,6 +139,8 @@ 'browser/extensions/api/extension_action/extension_page_actions_api.h', 'browser/extensions/api/extension_action/extension_page_actions_api_constants.cc', 'browser/extensions/api/extension_action/extension_page_actions_api_constants.h', + 'browser/extensions/api/file_system/file_system_api.cc', + 'browser/extensions/api/file_system/file_system_api.h', 'browser/extensions/api/idltest/idltest_api.cc', 'browser/extensions/api/idltest/idltest_api.h', 'browser/extensions/api/identity/identity_api.cc', diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index ac2d56c..072b810 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json @@ -110,6 +110,10 @@ "extension_types": ["extension", "packaged_app", "platform_app"], "location": "component" }, + "fileSystem": { + "channel": "dev", + "extension_types": ["platform_app"] + }, "geolocation": { "channel": "stable", "extension_types": [ diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp index d94c83c..e2bc07b 100644 --- a/chrome/common/extensions/api/api.gyp +++ b/chrome/common/extensions/api/api.gyp @@ -37,6 +37,7 @@ 'experimental_serial.idl', 'experimental_socket.idl', 'experimental_usb.idl', + 'file_system.idl', ], 'cc_dir': 'chrome/common/extensions/api', 'root_namespace': 'extensions::api', diff --git a/chrome/common/extensions/api/file_system.idl b/chrome/common/extensions/api/file_system.idl new file mode 100644 index 0000000..502a26c --- /dev/null +++ b/chrome/common/extensions/api/file_system.idl @@ -0,0 +1,14 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// File-level comment to appease parser. Eventually this will not be necessary. + +[nodoc] namespace fileSystem { + callback GetDisplayPathCallback = void (DOMString displayPath); + + interface Functions { + static void getDisplayPath(DOMString fsname, DOMString fspath, + GetDisplayPathCallback onSuccess); + }; +}; diff --git a/chrome/common/extensions/extension_permission_set.cc b/chrome/common/extensions/extension_permission_set.cc index fb392dd..52a292b 100644 --- a/chrome/common/extensions/extension_permission_set.cc +++ b/chrome/common/extensions/extension_permission_set.cc @@ -241,6 +241,9 @@ void ExtensionAPIPermission::RegisterAllPermissions( kFileBrowserHandler, "fileBrowserHandler", 0, ExtensionPermissionMessage::kNone, kFlagCannotBeOptional); info->RegisterPermission( + kFileSystem, "fileSystem", 0, + ExtensionPermissionMessage::kNone, kFlagNone); + info->RegisterPermission( kHistory, "history", IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY, ExtensionPermissionMessage::kBrowsingHistory, kFlagNone); diff --git a/chrome/common/extensions/extension_permission_set.h b/chrome/common/extensions/extension_permission_set.h index d8be820..83c4f0e 100644 --- a/chrome/common/extensions/extension_permission_set.h +++ b/chrome/common/extensions/extension_permission_set.h @@ -119,6 +119,7 @@ class ExtensionAPIPermission { kExperimental, kFileBrowserHandler, kFileBrowserPrivate, + kFileSystem, kGeolocation, kHistory, kIdle, diff --git a/chrome/common/extensions/extension_permission_set_unittest.cc b/chrome/common/extensions/extension_permission_set_unittest.cc index 6b560ee..b0020b5 100644 --- a/chrome/common/extensions/extension_permission_set_unittest.cc +++ b/chrome/common/extensions/extension_permission_set_unittest.cc @@ -622,6 +622,7 @@ TEST(ExtensionPermissionsTest, PermissionMessages) { // Platform apps. TODO(miket): must we skip? skip.insert(ExtensionAPIPermission::kSocket); skip.insert(ExtensionAPIPermission::kUsb); + skip.insert(ExtensionAPIPermission::kFileSystem); ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance(); ExtensionAPIPermissionSet permissions = info->GetAll(); diff --git a/chrome/renderer/extensions/experimental.app_custom_bindings.cc b/chrome/renderer/extensions/experimental.app_custom_bindings.cc index 683f883..65f7a6d 100644 --- a/chrome/renderer/extensions/experimental.app_custom_bindings.cc +++ b/chrome/renderer/extensions/experimental.app_custom_bindings.cc @@ -30,9 +30,8 @@ static v8::Handle<v8::Value> GetIsolatedFileSystem( GURL context_url = UserScriptSlave::GetDataSourceURLForFrame(webframe); CHECK(context_url.SchemeIs(chrome::kExtensionScheme)); - std::string name(fileapi::GetFileSystemName(context_url.GetOrigin(), - fileapi::kFileSystemTypeIsolated)); - name.append(file_system_id); + std::string name(fileapi::GetIsolatedFileSystemName(context_url.GetOrigin(), + file_system_id)); std::string root(fileapi::GetFileSystemRootURI(context_url.GetOrigin(), fileapi::kFileSystemTypeIsolated).spec()); diff --git a/chrome/renderer/extensions/media_gallery_custom_bindings.cc b/chrome/renderer/extensions/media_gallery_custom_bindings.cc index baedab9..2b8a6d3 100644 --- a/chrome/renderer/extensions/media_gallery_custom_bindings.cc +++ b/chrome/renderer/extensions/media_gallery_custom_bindings.cc @@ -57,10 +57,7 @@ v8::Handle<v8::Value> MediaGalleryCustomBindings::GetMediaFileSystemObject( const GURL origin = GURL(webframe->document().securityOrigin().toString()); const GURL root_url = fileapi::GetFileSystemRootURI(origin, fileapi::kFileSystemTypeIsolated); - const std::string fsname_prefix = - fileapi::GetFileSystemName(origin, fileapi::kFileSystemTypeIsolated); - const std::string fsname = - base::StringPrintf("%s_%s", fsname_prefix.c_str(), fsid.c_str()); + const std::string fsname = fileapi::GetIsolatedFileSystemName(origin, fsid); const std::string url = base::StringPrintf("%s%s/%s/", root_url.spec().c_str(), fsid.c_str(), diff --git a/chrome/test/data/extensions/platform_apps/get_display_path/manifest.json b/chrome/test/data/extensions/platform_apps/get_display_path/manifest.json new file mode 100644 index 0000000..526abff --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/get_display_path/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "Platform App fileSystem.getDisplayPath test", + "platform_app": true, + "version": "1", + "manifest_version": 2, + "intents": { + "http://webintents.org/view": { + "type": [ + "text/*" + ], + "title": "Test editor" + } + }, + "permissions": ["experimental", "fileSystem"], + "background": { + "scripts": ["test.js"] + } +} diff --git a/chrome/test/data/extensions/platform_apps/get_display_path/test.js b/chrome/test/data/extensions/platform_apps/get_display_path/test.js new file mode 100644 index 0000000..2ab01ea --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/get_display_path/test.js @@ -0,0 +1,27 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test that there is a launchData.intent, it is set up proerly, and that the +// FileEntry in launchData.intent.data can be read. +function onLaunched(launchData) { + chrome.test.runTests([ + function testIntent() { + chrome.test.assertFalse(!launchData, "No launchData"); + chrome.test.assertFalse(!launchData.intent, "No launchData.intent"); + chrome.test.assertEq(launchData.intent.action, + "http://webintents.org/view"); + chrome.test.assertEq(launchData.intent.type, + "chrome-extension://fileentry"); + chrome.test.assertFalse(!launchData.intent.data, + "No launchData.intent.data"); + var entry = launchData.intent.data; + chrome.fileSystem.getDisplayPath(entry.filesystem.name, + entry.fullPath.slice(1), chrome.test.callbackPass(function(path) { + chrome.test.assertFalse(path.indexOf('test.txt') == -1); + })); + } + ]); +} + +chrome.experimental.app.onLaunched.addListener(onLaunched); diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc index 5ae03e7..d8d4415 100644 --- a/content/browser/child_process_security_policy_impl.cc +++ b/content/browser/child_process_security_policy_impl.cc @@ -465,7 +465,7 @@ bool ChildProcessSecurityPolicyImpl::CanRequestURL( } bool ChildProcessSecurityPolicyImpl::CanReadFile(int child_id, - const FilePath& file) { + const FilePath& file) { return HasPermissionsForFile(child_id, file, kReadFilePermissions); } @@ -476,6 +476,13 @@ bool ChildProcessSecurityPolicyImpl::CanReadDirectory( kEnumerateDirectoryPermissions); } +bool ChildProcessSecurityPolicyImpl::CanReadFileSystem( + int child_id, const std::string& filesystem_id) { + return HasPermissionsForFileSystem(child_id, + filesystem_id, + kReadFilePermissions); +} + bool ChildProcessSecurityPolicyImpl::HasPermissionsForFile( int child_id, const FilePath& file, int permissions) { base::AutoLock lock(lock_); diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h index d150e3f..330efb3 100644 --- a/content/browser/child_process_security_policy_impl.h +++ b/content/browser/child_process_security_policy_impl.h @@ -46,6 +46,8 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl const std::string& filesystem_id) OVERRIDE; virtual void GrantScheme(int child_id, const std::string& scheme) OVERRIDE; virtual bool CanReadFile(int child_id, const FilePath& file) OVERRIDE; + virtual bool CanReadFileSystem(int child_id, + const std::string& filesystem_id) OVERRIDE; // Pseudo schemes are treated differently than other schemes because they // cannot be requested like normal URLs. There is no mechanism for revoking diff --git a/content/public/browser/child_process_security_policy.h b/content/public/browser/child_process_security_policy.h index aecfdd1..141713b 100644 --- a/content/public/browser/child_process_security_policy.h +++ b/content/public/browser/child_process_security_policy.h @@ -96,6 +96,11 @@ class ChildProcessSecurityPolicy { // Grants the child process the capability to access URLs of the provided // scheme. virtual void GrantScheme(int child_id, const std::string& scheme) = 0; + + // Returns true iff read access has been granted to the file system with + // |filesystem_id|. + virtual bool CanReadFileSystem(int child_id, + const std::string& filesystem_id) = 0; }; }; // namespace content diff --git a/webkit/fileapi/file_system_util.cc b/webkit/fileapi/file_system_util.cc index 985c021..285351a 100644 --- a/webkit/fileapi/file_system_util.cc +++ b/webkit/fileapi/file_system_util.cc @@ -276,4 +276,34 @@ WebKit::WebFileError PlatformFileErrorToWebFileError( } } +std::string GetIsolatedFileSystemName(const GURL& origin_url, + const std::string& filesystem_id) { + std::string name(fileapi::GetFileSystemName(origin_url, + fileapi::kFileSystemTypeIsolated)); + name.append("_"); + name.append(filesystem_id); + return name; +} + +bool CrackIsolatedFileSystemName(const std::string& filesystem_name, + std::string* filesystem_id) { + DCHECK(filesystem_id); + + // |filesystem_name| is of the form {origin}:isolated_{filesystem_id}. + std::string start_token(":"); + start_token = start_token.append(kIsolatedName).append("_"); + size_t pos = filesystem_name.find(start_token); + if (pos == std::string::npos) + return false; + if (pos == 0) + return false; + + *filesystem_id = filesystem_name.substr(pos + start_token.length(), + std::string::npos); + if (filesystem_id->empty()) + return false; + + return true; +} + } // namespace fileapi diff --git a/webkit/fileapi/file_system_util.h b/webkit/fileapi/file_system_util.h index f23f177..841a30c 100644 --- a/webkit/fileapi/file_system_util.h +++ b/webkit/fileapi/file_system_util.h @@ -124,6 +124,20 @@ FILEAPI_EXPORT FilePath StringToFilePath(const std::string& file_path_string); FILEAPI_EXPORT WebKit::WebFileError PlatformFileErrorToWebFileError( base::PlatformFileError error_code); +// Generate a file system name for the given arguments. Should only be used by +// platform apps. +FILEAPI_EXPORT std::string GetIsolatedFileSystemName( + const GURL& origin_url, + const std::string& filesystem_id); + +// Find the file system id from |filesystem_name|. Should only be used by +// platform apps. This function will return false if the file system name is +// not of the form {origin}:Isolated_{id}, and will also check that there is an +// origin and id present. It will not check that the origin or id are valid. +FILEAPI_EXPORT bool CrackIsolatedFileSystemName( + const std::string& filesystem_name, + std::string* filesystem_id); + } // namespace fileapi #endif // WEBKIT_FILEAPI_FILE_SYSTEM_UTIL_H_ diff --git a/webkit/fileapi/file_system_util_unittest.cc b/webkit/fileapi/file_system_util_unittest.cc index 7f567c0..6ac85e4 100644 --- a/webkit/fileapi/file_system_util_unittest.cc +++ b/webkit/fileapi/file_system_util_unittest.cc @@ -157,5 +157,34 @@ TEST_F(FileSystemUtilTest, VirtualPathGetComponents) { } } +TEST_F(FileSystemUtilTest, GetIsolatedFileSystemName) { + GURL origin_url("http://foo"); + std::string fsname1 = GetIsolatedFileSystemName(origin_url, "bar"); + EXPECT_EQ("http_foo_0:Isolated_bar", fsname1); +} + +TEST_F(FileSystemUtilTest, CrackIsolatedFileSystemName) { + std::string fsid; + EXPECT_TRUE(CrackIsolatedFileSystemName("foo:Isolated_bar", &fsid)); + EXPECT_EQ("bar", fsid); + EXPECT_TRUE(CrackIsolatedFileSystemName("foo:Isolated__bar", &fsid)); + EXPECT_EQ("_bar", fsid); + EXPECT_TRUE(CrackIsolatedFileSystemName("foo::Isolated_bar", &fsid)); + EXPECT_EQ("bar", fsid); +} + +TEST_F(FileSystemUtilTest, RejectBadIsolatedFileSystemName) { + std::string fsid; + EXPECT_FALSE(CrackIsolatedFileSystemName("foobar", &fsid)); + EXPECT_FALSE(CrackIsolatedFileSystemName("foo:_bar", &fsid)); + EXPECT_FALSE(CrackIsolatedFileSystemName("foo:Isolatedbar", &fsid)); + EXPECT_FALSE(CrackIsolatedFileSystemName("fooIsolatedbar", &fsid)); + EXPECT_FALSE(CrackIsolatedFileSystemName("foo:Persistent", &fsid)); + EXPECT_FALSE(CrackIsolatedFileSystemName("foo:Temporary", &fsid)); + EXPECT_FALSE(CrackIsolatedFileSystemName("foo:External", &fsid)); + EXPECT_FALSE(CrackIsolatedFileSystemName(":Isolated_bar", &fsid)); + EXPECT_FALSE(CrackIsolatedFileSystemName("foo:Isolated_", &fsid)); +} + } // namespace (anonymous) } // namespace fileapi |