Commit d3d50e00 authored by tbarzic@chromium.org's avatar tbarzic@chromium.org

Postpone setting up file handler's file permissions if handler is running lazy background page.

We have to wait until handler's extension host loads before we can setup file access permissions
with ChilsProcessSecurityPolicy.
We can't get the extensions host process id before that.

BUG=chromium-os:29475
TEST=*FileBrowser*

Review URL: https://chromiumcodereview.appspot.com/10067021

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132458 0039d316-1c4b-4281-b951-d872f2087c98
parent 4dcf83c6
...@@ -8,13 +8,18 @@ ...@@ -8,13 +8,18 @@
#include "base/scoped_temp_dir.h" #include "base/scoped_temp_dir.h"
#include "base/stringprintf.h" #include "base/stringprintf.h"
#include "chrome/browser/chromeos/gdata/gdata_file_system_proxy.h" #include "chrome/browser/chromeos/gdata/gdata_file_system_proxy.h"
#include "chrome/browser/chromeos/gdata/gdata_util.h"
#include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/notification_service.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_context.h"
#include "webkit/fileapi/file_system_mount_point_provider.h" #include "webkit/fileapi/file_system_mount_point_provider.h"
#include "chrome/browser/chromeos/gdata/gdata_util.h"
#include "webkit/chromeos/fileapi/remote_file_system_proxy.h" #include "webkit/chromeos/fileapi/remote_file_system_proxy.h"
using ::testing::_; using ::testing::_;
...@@ -34,6 +39,33 @@ const char kFileBrowserExtensionId[] = "ddammdhioacbehjngdmkjcjbnfginlla"; ...@@ -34,6 +39,33 @@ const char kFileBrowserExtensionId[] = "ddammdhioacbehjngdmkjcjbnfginlla";
const int kComponentFlags = ExtensionApiTest::kFlagEnableFileAccess | const int kComponentFlags = ExtensionApiTest::kFlagEnableFileAccess |
ExtensionApiTest::kFlagLoadAsComponent; ExtensionApiTest::kFlagLoadAsComponent;
// Helper class to wait for a background page to load or close again.
// TODO(tbarzic): We can probably share this with e.g.
// lazy_background_page_apitest.
class BackgroundObserver {
public:
BackgroundObserver()
: page_created_(chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
content::NotificationService::AllSources()),
page_closed_(chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
content::NotificationService::AllSources()) {
}
// TODO(tbarzic): Use this for file handlers in the rest of the tests
// (instead of calling chrome.test.succeed in js).
void WaitUntilLoaded() {
page_created_.Wait();
}
void WaitUntilClosed() {
page_closed_.Wait();
}
private:
ui_test_utils::WindowedNotificationObserver page_created_;
ui_test_utils::WindowedNotificationObserver page_closed_;
};
// Returns the expected URL for the given path. // Returns the expected URL for the given path.
GURL GetExpectedURL(const std::string& path) { GURL GetExpectedURL(const std::string& path) {
return GURL( return GURL(
...@@ -118,6 +150,11 @@ class FileSystemExtensionApiTest : public ExtensionApiTest { ...@@ -118,6 +150,11 @@ class FileSystemExtensionApiTest : public ExtensionApiTest {
virtual ~FileSystemExtensionApiTest() {} virtual ~FileSystemExtensionApiTest() {}
void SetUpCommandLine(CommandLine* command_line) {
ExtensionApiTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
}
// Adds a local mount point at at mount point /tmp. // Adds a local mount point at at mount point /tmp.
void AddTmpMountPoint() { void AddTmpMountPoint() {
fileapi::ExternalFileSystemMountPointProvider* provider = fileapi::ExternalFileSystemMountPointProvider* provider =
...@@ -126,6 +163,17 @@ class FileSystemExtensionApiTest : public ExtensionApiTest { ...@@ -126,6 +163,17 @@ class FileSystemExtensionApiTest : public ExtensionApiTest {
provider->AddLocalMountPoint(test_mount_point_); provider->AddLocalMountPoint(test_mount_point_);
} }
// Loads the extension, which temporarily starts the lazy background page
// to dispatch the onInstalled event. We wait until it shuts down again.
const Extension* LoadExtensionAndWait(const std::string& test_name) {
BackgroundObserver page_complete;
FilePath extdir = test_data_dir_.AppendASCII(test_name);
const Extension* extension = LoadExtension(extdir);
if (extension)
page_complete.WaitUntilClosed();
return extension;
}
private: private:
FilePath test_mount_point_; FilePath test_mount_point_;
}; };
...@@ -191,6 +239,14 @@ IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserTest) { ...@@ -191,6 +239,14 @@ IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserTest) {
"filebrowser_component", "read.html", kComponentFlags)) << message_; "filebrowser_component", "read.html", kComponentFlags)) << message_;
} }
IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserTestLazy) {
AddTmpMountPoint();
ASSERT_TRUE(LoadExtensionAndWait("filesystem_handler_lazy_background"))
<< message_;
ASSERT_TRUE(RunExtensionSubtest(
"filebrowser_component", "read.html", kComponentFlags)) << message_;
}
IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserTestWrite) { IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserTestWrite) {
AddTmpMountPoint(); AddTmpMountPoint();
ASSERT_TRUE(RunExtensionTest("filesystem_handler_write")) << message_; ASSERT_TRUE(RunExtensionTest("filesystem_handler_write")) << message_;
......
...@@ -576,7 +576,7 @@ bool GetFileTasksFileBrowserFunction::RunImpl() { ...@@ -576,7 +576,7 @@ bool GetFileTasksFileBrowserFunction::RunImpl() {
return true; return true;
} }
class ExecuteTasksFileBrowserFunction::Executor: public FileTaskExecutor { class ExecuteTasksFileBrowserFunction::Executor : public FileTaskExecutor {
public: public:
Executor(Profile* profile, Executor(Profile* profile,
const GURL& source_url, const GURL& source_url,
...@@ -584,13 +584,22 @@ class ExecuteTasksFileBrowserFunction::Executor: public FileTaskExecutor { ...@@ -584,13 +584,22 @@ class ExecuteTasksFileBrowserFunction::Executor: public FileTaskExecutor {
const std::string& action_id, const std::string& action_id,
ExecuteTasksFileBrowserFunction* function) ExecuteTasksFileBrowserFunction* function)
: FileTaskExecutor(profile, source_url, extension_id, action_id), : FileTaskExecutor(profile, source_url, extension_id, action_id),
function_(function) function_(function) {
{} }
virtual ~Executor() OVERRIDE {
if (function_)
function_->OnTaskExecuted(false);
}
protected: protected:
// FileTaskExecutor overrides. // FileTaskExecutor overrides.
virtual Browser* browser() { return function_->GetCurrentBrowser(); } virtual Browser* browser() { return function_->GetCurrentBrowser(); }
virtual void Done(bool success) { function_->SendResponse(success); } virtual void Done(bool success) {
function_->OnTaskExecuted(success);
// Let's make sure |function_| gets notified only once.
function_ = NULL;
}
private: private:
scoped_refptr<ExecuteTasksFileBrowserFunction> function_; scoped_refptr<ExecuteTasksFileBrowserFunction> function_;
...@@ -637,6 +646,7 @@ bool ExecuteTasksFileBrowserFunction::RunImpl() { ...@@ -637,6 +646,7 @@ bool ExecuteTasksFileBrowserFunction::RunImpl() {
scoped_refptr<Executor> executor = scoped_refptr<Executor> executor =
new Executor(profile(), source_url(), extension_id, action_id, this); new Executor(profile(), source_url(), extension_id, action_id, this);
if (!executor->Execute(file_urls)) if (!executor->Execute(file_urls))
return false; return false;
...@@ -644,6 +654,10 @@ bool ExecuteTasksFileBrowserFunction::RunImpl() { ...@@ -644,6 +654,10 @@ bool ExecuteTasksFileBrowserFunction::RunImpl() {
return true; return true;
} }
void ExecuteTasksFileBrowserFunction::OnTaskExecuted(bool success) {
SendResponse(success);
}
FileBrowserFunction::FileBrowserFunction() { FileBrowserFunction::FileBrowserFunction() {
} }
......
...@@ -104,6 +104,8 @@ class ExecuteTasksFileBrowserFunction : public AsyncExtensionFunction { ...@@ -104,6 +104,8 @@ class ExecuteTasksFileBrowserFunction : public AsyncExtensionFunction {
ExecuteTasksFileBrowserFunction(); ExecuteTasksFileBrowserFunction();
virtual ~ExecuteTasksFileBrowserFunction(); virtual ~ExecuteTasksFileBrowserFunction();
void OnTaskExecuted(bool success);
protected: protected:
// AsyncExtensionFunction overrides. // AsyncExtensionFunction overrides.
virtual bool RunImpl() OVERRIDE; virtual bool RunImpl() OVERRIDE;
......
...@@ -14,8 +14,11 @@ ...@@ -14,8 +14,11 @@
#include "chrome/browser/chromeos/gdata/gdata_util.h" #include "chrome/browser/chromeos/gdata/gdata_util.h"
#include "chrome/browser/chromeos/extensions/file_manager_util.h" #include "chrome/browser/chromeos/extensions/file_manager_util.h"
#include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/lazy_background_task_queue.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
...@@ -449,11 +452,6 @@ class FileTaskExecutor::ExecuteTasksFileSystemCallbackDispatcher { ...@@ -449,11 +452,6 @@ class FileTaskExecutor::ExecuteTasksFileSystemCallbackDispatcher {
} }
} }
ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
handler_pid_,
final_file_path,
GetAccessPermissionsForHandler(handler_extension_.get(), action_id_));
// Grant access to this particular file to target extension. This will // Grant access to this particular file to target extension. This will
// ensure that the target extension can access only this FS entry and // ensure that the target extension can access only this FS entry and
// prevent from traversing FS hierarchy upward. // prevent from traversing FS hierarchy upward.
...@@ -491,8 +489,8 @@ FileTaskExecutor::FileTaskExecutor(Profile* profile, ...@@ -491,8 +489,8 @@ FileTaskExecutor::FileTaskExecutor(Profile* profile,
: profile_(profile), : profile_(profile),
source_url_(source_url), source_url_(source_url),
extension_id_(extension_id), extension_id_(extension_id),
action_id_(action_id) action_id_(action_id) {
{} }
FileTaskExecutor::~FileTaskExecutor() {} FileTaskExecutor::~FileTaskExecutor() {}
...@@ -508,8 +506,10 @@ bool FileTaskExecutor::Execute(const std::vector<GURL>& file_urls) { ...@@ -508,8 +506,10 @@ bool FileTaskExecutor::Execute(const std::vector<GURL>& file_urls) {
return false; return false;
int handler_pid = ExtractProcessFromExtensionId(handler->id(), profile_); int handler_pid = ExtractProcessFromExtensionId(handler->id(), profile_);
if (handler_pid < 0) if (handler_pid <= 0) {
return false; if (!handler->has_lazy_background_page())
return false;
}
// Get local file system instance on file thread. // Get local file system instance on file thread.
BrowserThread::PostTask( BrowserThread::PostTask(
...@@ -547,21 +547,6 @@ void FileTaskExecutor::ExecuteFailedOnUIThread() { ...@@ -547,21 +547,6 @@ void FileTaskExecutor::ExecuteFailedOnUIThread() {
Done(false); Done(false);
} }
void FileTaskExecutor::SetupFileAccessPermissionsForGDataCache(
const FileDefinitionList& file_list,
int handler_pid) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
for (FileDefinitionList::const_iterator iter = file_list.begin();
iter != file_list.end();
++iter) {
if (!gdata::util::IsUnderGDataMountPoint(iter->absolute_path))
continue;
gdata::util::SetPermissionsForGDataCacheFiles(profile_, handler_pid,
iter->absolute_path);
}
}
void FileTaskExecutor::ExecuteFileActionsOnUIThread( void FileTaskExecutor::ExecuteFileActionsOnUIThread(
const std::string& file_system_name, const std::string& file_system_name,
const GURL& file_system_root, const GURL& file_system_root,
...@@ -581,13 +566,47 @@ void FileTaskExecutor::ExecuteFileActionsOnUIThread( ...@@ -581,13 +566,47 @@ void FileTaskExecutor::ExecuteFileActionsOnUIThread(
return; return;
} }
InitHandlerHostFileAccessPermissions(file_list, extension, action_id_);
if (handler_pid > 0) {
SetupPermissionsAndDispatchEvent(file_system_name, file_system_root,
file_list, handler_pid, NULL);
} else {
// We have to wake the handler background page before we proceed.
extensions::LazyBackgroundTaskQueue* queue =
ExtensionSystem::Get(profile_)->lazy_background_task_queue();
if (!queue->ShouldEnqueueTask(profile_, extension)) {
Done(false);
return;
}
queue->AddPendingTask(
profile_, extension_id_,
base::Bind(&FileTaskExecutor::SetupPermissionsAndDispatchEvent, this,
file_system_name, file_system_root, file_list, handler_pid));
}
}
void FileTaskExecutor::SetupPermissionsAndDispatchEvent(
const std::string& file_system_name,
const GURL& file_system_root,
const FileDefinitionList& file_list,
int handler_pid_in,
ExtensionHost* host) {
int handler_pid = host ? host->render_process_host()->GetID() :
handler_pid_in;
if (handler_pid <= 0) {
Done(false);
return;
}
ExtensionEventRouter* event_router = profile_->GetExtensionEventRouter(); ExtensionEventRouter* event_router = profile_->GetExtensionEventRouter();
if (!event_router) { if (!event_router) {
Done(false); Done(false);
return; return;
} }
SetupFileAccessPermissionsForGDataCache(file_list, handler_pid); SetupHandlerHostFileAccessPermissions(handler_pid);
scoped_ptr<ListValue> event_args(new ListValue()); scoped_ptr<ListValue> event_args(new ListValue());
event_args->Append(Value::CreateStringValue(action_id_)); event_args->Append(Value::CreateStringValue(action_id_));
...@@ -623,8 +642,46 @@ void FileTaskExecutor::ExecuteFileActionsOnUIThread( ...@@ -623,8 +642,46 @@ void FileTaskExecutor::ExecuteFileActionsOnUIThread(
extension_id_, std::string("fileBrowserHandler.onExecute"), extension_id_, std::string("fileBrowserHandler.onExecute"),
json_args, profile_, json_args, profile_,
GURL()); GURL());
Done(true); Done(true);
} }
void FileTaskExecutor::InitHandlerHostFileAccessPermissions(
const FileDefinitionList& file_list,
const Extension* handler_extension,
const std::string& action_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
for (FileDefinitionList::const_iterator iter = file_list.begin();
iter != file_list.end();
++iter) {
// Setup permission for file's absolute file.
handler_host_permissions_.push_back(std::make_pair(
iter->absolute_path,
GetAccessPermissionsForHandler(handler_extension, action_id)));
if (!gdata::util::IsUnderGDataMountPoint(iter->absolute_path))
continue;
// If the file is on gdata mount point, we'll have to give handler host
// permissions for file's gdata cache paths.
// This has to be called on UI thread.
gdata::util::InsertGDataCachePathsPermissions(profile_, iter->absolute_path,
&handler_host_permissions_);
}
}
void FileTaskExecutor::SetupHandlerHostFileAccessPermissions(int handler_pid) {
for (size_t i = 0; i < handler_host_permissions_.size(); i++) {
content::ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
handler_pid,
handler_host_permissions_[i].first,
handler_host_permissions_[i].second);
}
// We don't need this anymore.
handler_host_permissions_.clear();
}
} // namespace file_handler_util } // namespace file_handler_util
...@@ -6,11 +6,14 @@ ...@@ -6,11 +6,14 @@
#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_HANDLER_UTIL_H_ #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_HANDLER_UTIL_H_
#pragma once #pragma once
#include <vector>
#include "base/platform_file.h" #include "base/platform_file.h"
#include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/url_pattern_set.h" #include "chrome/common/extensions/url_pattern_set.h"
class Browser; class Browser;
class ExtensionHost;
class FileBrowserHandler; class FileBrowserHandler;
class GURL; class GURL;
class Profile; class Profile;
...@@ -89,6 +92,7 @@ class FileTaskExecutor : public base::RefCountedThreadSafe<FileTaskExecutor> { ...@@ -89,6 +92,7 @@ class FileTaskExecutor : public base::RefCountedThreadSafe<FileTaskExecutor> {
FilePath absolute_path; FilePath absolute_path;
bool is_directory; bool is_directory;
}; };
typedef std::vector<FileDefinition> FileDefinitionList; typedef std::vector<FileDefinition> FileDefinitionList;
class ExecuteTasksFileSystemCallbackDispatcher; class ExecuteTasksFileSystemCallbackDispatcher;
void RequestFileEntryOnFileThread( void RequestFileEntryOnFileThread(
...@@ -96,20 +100,35 @@ class FileTaskExecutor : public base::RefCountedThreadSafe<FileTaskExecutor> { ...@@ -96,20 +100,35 @@ class FileTaskExecutor : public base::RefCountedThreadSafe<FileTaskExecutor> {
const scoped_refptr<const Extension>& handler, const scoped_refptr<const Extension>& handler,
int handler_pid, int handler_pid,
const std::vector<GURL>& file_urls); const std::vector<GURL>& file_urls);
void SetupFileAccessPermissionsForGDataCache(
const FileDefinitionList& file_list, void ExecuteFailedOnUIThread();
int handler_pid);
void RespondFailedOnUIThread(base::PlatformFileError error_code);
void ExecuteFileActionsOnUIThread(const std::string& file_system_name, void ExecuteFileActionsOnUIThread(const std::string& file_system_name,
const GURL& file_system_root, const GURL& file_system_root,
const FileDefinitionList& file_list, const FileDefinitionList& file_list,
int handler_id); int handler_id);
void ExecuteFailedOnUIThread(); void SetupPermissionsAndDispatchEvent(const std::string& file_system_name,
const GURL& file_system_root,
const FileDefinitionList& file_list,
int handler_pid_in,
ExtensionHost* host);
// Populates |handler_host_permissions| with file path-permissions pairs that
// will be given to the handler extension host process.
void InitHandlerHostFileAccessPermissions(
const FileDefinitionList& file_list,
const Extension* handler_extension,
const std::string& action_id);
// Registers file permissions from |handler_host_permissions_| with
// ChildProcessSecurityPolicy for process with id |handler_pid|.
void SetupHandlerHostFileAccessPermissions(int handler_pid);
Profile* profile_; Profile* profile_;
const GURL source_url_; const GURL source_url_;
const std::string extension_id_; const std::string extension_id_;
const std::string action_id_; const std::string action_id_;
// (File path, permission for file path) pairs for the handler.
std::vector<std::pair<FilePath, int> > handler_host_permissions_;
}; };
} // namespace file_handler_util } // namespace file_handler_util
......
...@@ -184,16 +184,18 @@ FilePath ExtractGDataPath(const FilePath& path) { ...@@ -184,16 +184,18 @@ FilePath ExtractGDataPath(const FilePath& path) {
return extracted; return extracted;
} }
void InsertGDataCachePathsPermissions(
Profile* profile,
const FilePath& gdata_path,
std::vector<std::pair<FilePath, int> >* cache_paths ) {
DCHECK(cache_paths);
void SetPermissionsForGDataCacheFiles(Profile* profile,
int pid,
const FilePath& path) {
GDataFileSystem* file_system = GetGDataFileSystem(profile); GDataFileSystem* file_system = GetGDataFileSystem(profile);
if (!file_system) if (!file_system)
return; return;
GDataFileProperties file_properties; GDataFileProperties file_properties;
file_system->GetFileInfoFromPath(path, &file_properties); file_system->GetFileInfoFromPath(gdata_path, &file_properties);
std::string resource_id = file_properties.resource_id; std::string resource_id = file_properties.resource_id;
std::string file_md5 = file_properties.file_md5; std::string file_md5 = file_properties.file_md5;
...@@ -202,25 +204,31 @@ void SetPermissionsForGDataCacheFiles(Profile* profile, ...@@ -202,25 +204,31 @@ void SetPermissionsForGDataCacheFiles(Profile* profile,
// operations (when fileEntry.file() is called), so read only permissions // operations (when fileEntry.file() is called), so read only permissions
// should be sufficient for all cache paths. For the rest of supported // should be sufficient for all cache paths. For the rest of supported
// operations the file access check is done for gdata/ paths. // operations the file access check is done for gdata/ paths.
std::vector<std::pair<FilePath, int> > cache_paths; cache_paths->push_back(std::make_pair(
cache_paths.push_back(std::make_pair(
file_system->GetCacheFilePath(resource_id, file_md5, file_system->GetCacheFilePath(resource_id, file_md5,
GDataRootDirectory::CACHE_TYPE_PERSISTENT, GDataRootDirectory::CACHE_TYPE_PERSISTENT,
GDataFileSystem::CACHED_FILE_FROM_SERVER), GDataFileSystem::CACHED_FILE_FROM_SERVER),
kReadOnlyFilePermissions)); kReadOnlyFilePermissions));
// TODO(tbarzic): When we start supporting openFile operation, we may have to // TODO(tbarzic): When we start supporting openFile operation, we may have to
// change permission for localy modified files to match handler's permissions. // change permission for localy modified files to match handler's permissions.
cache_paths.push_back(std::make_pair( cache_paths->push_back(std::make_pair(
file_system->GetCacheFilePath(resource_id, file_md5, file_system->GetCacheFilePath(resource_id, file_md5,
GDataRootDirectory::CACHE_TYPE_PERSISTENT, GDataRootDirectory::CACHE_TYPE_PERSISTENT,
GDataFileSystem::CACHED_FILE_LOCALLY_MODIFIED), GDataFileSystem::CACHED_FILE_LOCALLY_MODIFIED),
kReadOnlyFilePermissions)); kReadOnlyFilePermissions));
cache_paths.push_back(std::make_pair( cache_paths->push_back(std::make_pair(
file_system->GetCacheFilePath(resource_id, file_md5, file_system->GetCacheFilePath(resource_id, file_md5,
GDataRootDirectory::CACHE_TYPE_TMP, GDataRootDirectory::CACHE_TYPE_TMP,
GDataFileSystem::CACHED_FILE_FROM_SERVER), GDataFileSystem::CACHED_FILE_FROM_SERVER),
kReadOnlyFilePermissions)); kReadOnlyFilePermissions));
}
void SetPermissionsForGDataCacheFiles(Profile* profile,
int pid,
const FilePath& path) {
std::vector<std::pair<FilePath, int> > cache_paths;
InsertGDataCachePathsPermissions(profile, path, &cache_paths);
for (size_t i = 0; i < cache_paths.size(); i++) { for (size_t i = 0; i < cache_paths.size(); i++) {
content::ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile( content::ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
pid, cache_paths[i].first, cache_paths[i].second); pid, cache_paths[i].first, cache_paths[i].second);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <vector>
#include "googleurl/src/gurl.h" #include "googleurl/src/gurl.h"
...@@ -43,6 +44,13 @@ bool IsUnderGDataMountPoint(const FilePath& path); ...@@ -43,6 +44,13 @@ bool IsUnderGDataMountPoint(const FilePath& path);
// Examples: ExtractGDatPath("/special/gdata/foo.txt") => "gdata/foo.txt" // Examples: ExtractGDatPath("/special/gdata/foo.txt") => "gdata/foo.txt"
FilePath ExtractGDataPath(const FilePath& path); FilePath ExtractGDataPath(const FilePath& path);
// Returns vector of all possible cache paths for a given path on gdata mount
// point.
void InsertGDataCachePathsPermissions(
Profile* profile_,
const FilePath& gdata_path,
std::vector<std::pair<FilePath, int> >* cache_paths);
// Grants read-only file access permissions to the process whose id is |pid| // Grants read-only file access permissions to the process whose id is |pid|
// with ChildProcessSecurityPolicy for all possible cache paths that may be // with ChildProcessSecurityPolicy for all possible cache paths that may be
// given to the specified file. // given to the specified file.
......
// 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.
/*
This extension is a file intent handler with transient background page and does
the following during the test:
1. It first registers content hander.
2. When content handler callback is invoked, opens tab.html page and passes
file url via persistent localStorage var.
3. Tries to resolve target file url and reads its content.
4. Send file content to file browser extension.
*/
function errorCallback(error) {
var msg = '';
if (!error.code) {
msg = error.message;
} else {
switch (error.code) {
case FileError.QUOTA_EXCEEDED_ERR:
msg = 'QUOTA_EXCEEDED_ERR';
break;
case FileError.NOT_FOUND_ERR:
msg = 'NOT_FOUND_ERR';
break;
case FileError.SECURITY_ERR:
msg = 'SECURITY_ERR';
break;
case FileError.INVALID_MODIFICATION_ERR:
msg = 'INVALID_MODIFICATION_ERR';
break;
case FileError.INVALID_STATE_ERR:
msg = 'INVALID_STATE_ERR';
break;
default:
msg = 'Unknown Error';
break;
};
}
// The ID of the extension we want to talk to.
var fileBrowserExtensionId = "ddammdhioacbehjngdmkjcjbnfginlla";
chrome.extension.sendRequest(fileBrowserExtensionId,
{fileContent: null,
error: {message: "File handler error: " + msg}},
function(response) {});
};
function runFileSystemHandlerTest(entries) {
if (!entries || entries.length != 1 || !entries[0]) {
errorCallback({message: "Invalid file entries"});
return;
}
localStorage.entryURL = entries[0].toURL();
chrome.tabs.create({url: 'tab.html'});
};
chrome.fileBrowserHandler.onExecute.addListener(function(id, details) {
if (id != "AbcAction" && id != "BaseAction" && id != "123Action") {
errorCallback({message: "Unexpected action id: " + id});
return;
}
var file_entries = details.entries;
if (!file_entries || file_entries.length != 1) {
errorCallback({message: "Unexpected file url list"});
return;
}
chrome.tabs.get(details.tab_id, function(tab) {
if (tab.title != "file browser component test") {
errorCallback({message: "Unexpected tab title: " + tab.title});
return;
}
runFileSystemHandlerTest(file_entries);
});
});
{
"key": "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQChptAQ0n4R56N03nWQ1ogR7DVRBjGo80Vw6G9KLjzZv44D8rq5Q5IkeQrtKgWyZfXevlsCe3LaLo18rcz8iZx6lK2xhLdUR+ORjsjuBfdEL5a5cWeRTSxf75AcqndQsmpwMBdrMTCZ8jQNusUI+XlrihLNNJuI5TM4vNINI5bYFQIBIw==",
"name": "ChromeOS file system intent hanlder extension",
"version": "1.1",
"manifest_version": 2,
"description": "Tests of chrome.fileSystem.* methods",
"background": {
"transient": true,
"persistent": false,
"scripts": ["background.js"]
},
"file_browser_handlers": [
{
"id" : "AbcAction",
"default_title" : "abc file action.",
"default_icon" : "icon.png",
"file_filters" : [ "filesystem:*.aBc", "filesystem:*.abcfile" ]
},
{
"id" : "123Action",
"default_title" : "123 file action",
"default_icon" : "icon.png",
"file_filters" : [ "filesystem:*.123", "filesystem:*.1234" ]
},
{
"id" : "BaseAction",
"default_title" : "Base action",
"default_icon" : "icon.png",
"file_filters" : [ "filesystem:*", "filesystem:*.*" ]
}
],
"permissions": [
"fileBrowserHandler",
"tabs",
"unlimitedStorage",
"experimental"
]
}
<!--
* 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.
-->
<script src="tab.js"></script>
<html><body><div id="content"></div></body></html>
// 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.
// The ID of the extension we want to talk to.
var fileBrowserExtensionId = "ddammdhioacbehjngdmkjcjbnfginlla";
function errorCallback(error) {
var msg = '';
if (!error.code) {
msg = error.message;
} else {
switch (error.code) {
case FileError.QUOTA_EXCEEDED_ERR:
msg = 'QUOTA_EXCEEDED_ERR';
break;
case FileError.NOT_FOUND_ERR:
msg = 'NOT_FOUND_ERR';
break;
case FileError.SECURITY_ERR:
msg = 'SECURITY_ERR';
break;
case FileError.INVALID_MODIFICATION_ERR:
msg = 'INVALID_MODIFICATION_ERR';
break;
case FileError.INVALID_STATE_ERR:
msg = 'INVALID_STATE_ERR';
break;
default:
msg = 'Unknown Error';
break;
};
}
chrome.extension.sendRequest(fileBrowserExtensionId,
{fileContent: null,
error: {message: "File handler error: " + msg}},
function(response) {});
};
function onGotEntryByUrl(entry) {
var reader = new FileReader();
reader.onloadend = function(e) {
// Send data back to the file browser extension
chrome.extension.sendRequest(
fileBrowserExtensionId,
{fileContent: reader.result, error: null},
function(response) {});
};
reader.onerror = function(e) {
errorCallback(reader.error);
};
entry.file(function(file) {
reader.readAsText(file);
},
errorCallback);
};
function readEntryByUrl(entryUrl) {
window.webkitResolveLocalFileSystemURL(entryUrl, onGotEntryByUrl,
errorCallback);
};
readEntryByUrl(localStorage.entryURL);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment