diff options
author | victorw@chromium.org <victorw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-03 00:24:57 +0000 |
---|---|---|
committer | victorw@chromium.org <victorw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-03 00:24:57 +0000 |
commit | e0d8cbdb23b9a8446ffb1b8355652f2b167238f1 (patch) | |
tree | d7acb45db42060eed51b4ece5955ad3d042922ea | |
parent | a0181609ceca468ce66eca453dcce4283a7bdcec (diff) | |
download | chromium_src-e0d8cbdb23b9a8446ffb1b8355652f2b167238f1.zip chromium_src-e0d8cbdb23b9a8446ffb1b8355652f2b167238f1.tar.gz chromium_src-e0d8cbdb23b9a8446ffb1b8355652f2b167238f1.tar.bz2 |
Add getFileSize support to chromium
The current implementation only allows getting file size
if the child process has been granted permission to upload file.
May need to update the policy checking code if getFileSize
is needed in other cases.
Here is the webkit implementation to support this:
https://bugs.webkit.org/show_bug.cgi?id=26521
TEST=none
BUG=9102
Review URL: http://codereview.chromium.org/131082
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19866 0039d316-1c4b-4281-b951-d872f2087c98
19 files changed, 332 insertions, 1 deletions
@@ -1,7 +1,7 @@ vars = { "webkit_trunk": "http://svn.webkit.org/repository/webkit/trunk", - "webkit_revision": "45492", + "webkit_revision": "45494", } diff --git a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc index 58d549a..a1d6638 100644 --- a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc +++ b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc @@ -52,6 +52,12 @@ void BrowserWebKitClientImpl::prefetchHostName(const WebKit::WebString&) { NOTREACHED(); } +bool BrowserWebKitClientImpl::getFileSize(const WebKit::WebString& path, + long long& result) { + NOTREACHED(); + return false; +} + WebKit::WebString BrowserWebKitClientImpl::defaultLocale() { NOTREACHED(); return WebKit::WebString(); diff --git a/chrome/browser/in_process_webkit/browser_webkitclient_impl.h b/chrome/browser/in_process_webkit/browser_webkitclient_impl.h index 52ee5e2..4f7abf0 100644 --- a/chrome/browser/in_process_webkit/browser_webkitclient_impl.h +++ b/chrome/browser/in_process_webkit/browser_webkitclient_impl.h @@ -22,6 +22,7 @@ class BrowserWebKitClientImpl : public webkit_glue::WebKitClientImpl { virtual WebKit::WebString cookies(const WebKit::WebURL& url, const WebKit::WebURL& policy_url); virtual void prefetchHostName(const WebKit::WebString&); + virtual bool getFileSize(const WebKit::WebString& path, long long& result); virtual WebKit::WebString defaultLocale(); virtual WebKit::WebThemeEngine* themeEngine(); virtual WebKit::WebURLLoader* createURLLoader(); diff --git a/chrome/browser/renderer_host/file_system_accessor.cc b/chrome/browser/renderer_host/file_system_accessor.cc new file mode 100644 index 0000000..295b1f7 --- /dev/null +++ b/chrome/browser/renderer_host/file_system_accessor.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2006-2009 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/renderer_host/file_system_accessor.h" + +#include "base/file_util.h" +#include "base/message_loop.h" +#include "chrome/browser/chrome_thread.h" + +FileSystemAccessor::FileSystemAccessor(void* param, FileSizeCallback* callback) + : param_(param), callback_(callback) { + caller_loop_ = MessageLoop::current(); +} + +FileSystemAccessor::~FileSystemAccessor() { +} + +void FileSystemAccessor::RequestFileSize(const FilePath& path, + void* param, + FileSizeCallback* callback) { + // Getting file size could take long time if it lives on a network share, + // so run it on FILE thread. + ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask( + FROM_HERE, + NewRunnableMethod(new FileSystemAccessor(param, callback), + &FileSystemAccessor::GetFileSize, path)); +} + +void FileSystemAccessor::GetFileSize(const FilePath& path) { + int64 result; + // Set result to -1 if failed to get file size. + if (!file_util::GetFileSize(path, &result)) + result = -1; + + // Pass the result back to the caller thread. + caller_loop_->PostTask( + FROM_HERE, + NewRunnableMethod(this, &FileSystemAccessor::GetFileSizeCompleted, result)); +} + +void FileSystemAccessor::GetFileSizeCompleted(int64 result) { + callback_->Run(result, param_); +} diff --git a/chrome/browser/renderer_host/file_system_accessor.h b/chrome/browser/renderer_host/file_system_accessor.h new file mode 100644 index 0000000..b280705 --- /dev/null +++ b/chrome/browser/renderer_host/file_system_accessor.h @@ -0,0 +1,74 @@ +// Copyright (c) 2006-2009 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. +// +// FileSystemAccessor provides functions so consumers can do file access +// asynchronously. It would PostTask to FILE thread to access file info, then on +// completion PostTask back to the caller thread and pass the result back. +// Here is an example on how to use it to get file size: +// 1. Define a callback function so FileSystemAccessor could run it after the +// task has been completed: +// void Foo::GetFileSizeCallback(int64 result, void* param) { +// } +// 2. Call static function FileSystemAccessor::RequestFileSize, provide file +// path, param (any object you want to pass back to the callback function) +// and callback: +// FileSystemAccessor::RequestFileSize( +// path, +// param, +// NewCallback(this, &Foo::GetFileSizeCallback)); +// 3. FileSystemAceessor would PostTask to FILE thread to get file size, then +// on completion it would PostTask back to the current thread and run +// Foo::GetFileSizeCallback. +// + +#ifndef CHROME_BROWSER_RENDERER_HOST_FILE_SYSTEM_ACCESSOR_H_ +#define CHROME_BROWSER_RENDERER_HOST_FILE_SYSTEM_ACCESSOR_H_ + +#include "base/file_path.h" +#include "base/scoped_ptr.h" +#include "base/ref_counted.h" +#include "base/task.h" + +class MessageLoop; + +class FileSystemAccessor + : public base::RefCountedThreadSafe<FileSystemAccessor> { + public: + typedef Callback2<int64, void*>::Type FileSizeCallback; + + virtual ~FileSystemAccessor(); + + // Request to get file size. + // + // param is an object that is owned by the caller and needs to pass back to + // the caller by FileSystemAccessor through the callback function. + // It can be set to NULL if no object needs to pass back. + // + // FileSizeCallback function is defined as: + // void f(int64 result, void* param); + // Variable result has the file size. If the file does not exist or there is + // error accessing the file, result is set to -1. If the given path is a + // directory, result is set to 0. + static void RequestFileSize(const FilePath& path, + void* param, + FileSizeCallback* callback); + + private: + FileSystemAccessor(void* param, FileSizeCallback* callback); + + // Get file size on the worker thread and pass result back to the caller + // thread. + void GetFileSize(const FilePath& path); + + // Getting file size completed, callback to reply message. + void GetFileSizeCompleted(int64 result); + + MessageLoop* caller_loop_; + void* param_; + scoped_ptr<FileSizeCallback> callback_; + + DISALLOW_COPY_AND_ASSIGN(FileSystemAccessor); +}; + +#endif // CHROME_BROWSER_RENDERER_HOST_FILE_SYSTEM_ACCESSOR_H_ diff --git a/chrome/browser/renderer_host/file_system_accessor_unittest.cc b/chrome/browser/renderer_host/file_system_accessor_unittest.cc new file mode 100644 index 0000000..ad60112 --- /dev/null +++ b/chrome/browser/renderer_host/file_system_accessor_unittest.cc @@ -0,0 +1,117 @@ +// Copyright (c) 2006-2009 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 "base/file_util.h" +#include "base/message_loop.h" +#include "base/timer.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/renderer_host/file_system_accessor.h" +#include "chrome/test/file_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +class FileSystemAccessorTest : public testing::Test { + protected: + virtual void SetUp() { + // Make sure the current thread has a message loop. + EXPECT_TRUE(MessageLoop::current() != NULL); + + // Create FILE thread which is used to do file access. + file_thread_.reset(new ChromeThread(ChromeThread::FILE)); + EXPECT_TRUE(ChromeThread::GetMessageLoop(ChromeThread::FILE) == NULL); + + // Start FILE thread and verify FILE message loop exists. + file_thread_->Start(); + EXPECT_TRUE(file_thread_->message_loop() != NULL); + } + + virtual void TearDown() { + file_thread_->Stop(); + EXPECT_TRUE(ChromeThread::GetMessageLoop(ChromeThread::FILE) == NULL); + } + + void TestGetFileSize(const FilePath& path, + void* param, + int64 expected_result, + void* expected_param) { + // Initialize the actual result not equal to the expected result. + result_ = expected_result + 1; + param_ = NULL; + + FileSystemAccessor::RequestFileSize( + path, + param, + NewCallback(this, &FileSystemAccessorTest::GetFileSizeCallback)); + + // Time out if getting file size takes more than 10 seconds. + const int kGetFileSizeTimeoutSeconds = 10; + base::OneShotTimer<MessageLoop> timer; + timer.Start(base::TimeDelta::FromSeconds(kGetFileSizeTimeoutSeconds), + MessageLoop::current(), &MessageLoop::Quit); + + MessageLoop::current()->Run(); + + EXPECT_EQ(expected_result, result_); + EXPECT_EQ(expected_param, param_); + } + + private: + void GetFileSizeCallback(int64 result, void* param) { + result_ = result; + param_ = param; + MessageLoop::current()->Quit(); + } + + scoped_ptr<ChromeThread> file_thread_; + FilePath temp_file_; + int64 result_; + void* param_; + MessageLoop loop_; +}; + +TEST_F(FileSystemAccessorTest, GetFileSize) { + const std::string data("This is test data."); + + FilePath path; + FILE* file = file_util::CreateAndOpenTemporaryFile(&path); + EXPECT_TRUE(file != NULL); + size_t bytes_written = fwrite(data.data(), 1, data.length(), file); + EXPECT_TRUE(file_util::CloseFile(file)); + + FileAutoDeleter deleter(path); + + TestGetFileSize(path, NULL, bytes_written, NULL); +} + +TEST_F(FileSystemAccessorTest, GetFileSizeWithParam) { + const std::string data("This is test data."); + + FilePath path; + FILE* file = file_util::CreateAndOpenTemporaryFile(&path); + EXPECT_TRUE(file != NULL); + size_t bytes_written = fwrite(data.data(), 1, data.length(), file); + EXPECT_TRUE(file_util::CloseFile(file)); + + FileAutoDeleter deleter(path); + + int param = 100; + TestGetFileSize(path, static_cast<void*>(¶m), + bytes_written, static_cast<void*>(¶m)); +} + +TEST_F(FileSystemAccessorTest, GetFileSizeEmptyFile) { + FilePath path; + EXPECT_TRUE(file_util::CreateTemporaryFileName(&path)); + FileAutoDeleter deleter(path); + + TestGetFileSize(path, NULL, 0, NULL); +} + +TEST_F(FileSystemAccessorTest, GetFileSizeNotFound) { + FilePath path; + EXPECT_TRUE(file_util::CreateNewTempDirectory( + FILE_PATH_LITERAL("chrome_test_"), &path)); + FileAutoDeleter deleter(path); + + TestGetFileSize(path.Append(FILE_PATH_LITERAL("foo.txt")), NULL, -1, NULL); +} diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.cc b/chrome/browser/renderer_host/render_sandbox_host_linux.cc index ef47f92..2724e00 100644 --- a/chrome/browser/renderer_host/render_sandbox_host_linux.cc +++ b/chrome/browser/renderer_host/render_sandbox_host_linux.cc @@ -114,6 +114,10 @@ class SandboxIPCProcess : public WebKitClient { virtual void prefetchHostName(const WebString&) { } + virtual bool getFileSize(const WebString& path, long long& result) { + return false; + } + virtual WebURLLoader* createURLLoader() { return NULL; } virtual void getPluginList(bool refresh, WebPluginListBuilder*) { } diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 2a745ec..53baac3 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -10,6 +10,7 @@ #include "base/histogram.h" #include "base/process_util.h" #include "base/thread.h" +#include "chrome/browser/child_process_security_policy.h" #include "chrome/browser/chrome_plugin_browsing_context.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/extensions/extension_message_service.h" @@ -19,6 +20,7 @@ #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/audio_renderer_host.h" #include "chrome/browser/renderer_host/browser_render_process_host.h" +#include "chrome/browser/renderer_host/file_system_accessor.h" #include "chrome/browser/renderer_host/render_widget_helper.h" #include "chrome/browser/spellchecker.h" #include "chrome/browser/worker_host/worker_service.h" @@ -323,6 +325,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { OnCloseIdleConnections) IPC_MESSAGE_HANDLER(ViewHostMsg_SetCacheMode, OnSetCacheMode) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileSize, + OnGetFileSize) IPC_MESSAGE_UNHANDLED( handled = false) @@ -913,3 +917,31 @@ void ResourceMessageFilter::OnSetCacheMode(bool enabled) { net::HttpCache::NORMAL : net::HttpCache::DISABLE; request_context_->http_transaction_factory()->GetCache()->set_mode(mode); } + +void ResourceMessageFilter::OnGetFileSize(const FilePath& path, + IPC::Message* reply_msg) { + // Increase the ref count to ensure ResourceMessageFilter won't be destroyed + // before GetFileSize callback is done. + AddRef(); + + // Get file size only when the child process has been granted permission to + // upload the file. + if (ChildProcessSecurityPolicy::GetInstance()->CanUploadFile( + render_process_id_, path)) { + FileSystemAccessor::RequestFileSize( + path, + reply_msg, + NewCallback(this, &ResourceMessageFilter::ReplyGetFileSize)); + } else { + ReplyGetFileSize(-1, reply_msg); + } +} + +void ResourceMessageFilter::ReplyGetFileSize(int64 result, void* param) { + IPC::Message* reply_msg = static_cast<IPC::Message*>(param); + ViewHostMsg_GetFileSize::WriteReplyParams(reply_msg, result); + Send(reply_msg); + + // Getting file size callback done, decrease the ref count. + Release(); +} diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index d5b8057..6ab9c3c 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -218,6 +218,9 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnCloseIdleConnections(); void OnSetCacheMode(bool enabled); + void OnGetFileSize(const FilePath& path, IPC::Message* reply_msg); + void ReplyGetFileSize(int64 result, void* param); + #if defined(OS_LINUX) void SendDelayedReply(IPC::Message* reply_msg); void DoOnGetScreenInfo(gfx::NativeViewId view, IPC::Message* reply_msg); diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index a153017..bdd4e17 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1307,6 +1307,8 @@ 'browser/renderer_host/download_resource_handler.h', 'browser/renderer_host/download_throttling_resource_handler.cc', 'browser/renderer_host/download_throttling_resource_handler.h', + 'browser/renderer_host/file_system_accessor.cc', + 'browser/renderer_host/file_system_accessor.h', 'browser/renderer_host/render_process_host.cc', 'browser/renderer_host/render_process_host.h', 'browser/renderer_host/render_sandbox_host_linux.h', @@ -3504,6 +3506,7 @@ 'browser/privacy_blacklist/blacklist_unittest.cc', 'browser/profile_manager_unittest.cc', 'browser/renderer_host/audio_renderer_host_unittest.cc', + 'browser/renderer_host/file_system_accessor_unittest.cc', 'browser/renderer_host/render_view_host_manager_unittest.cc', 'browser/renderer_host/render_view_host_unittest.cc', 'browser/renderer_host/render_widget_host_unittest.cc', diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index dc94406..20414c6 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1413,6 +1413,11 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_MESSAGE_CONTROL1(ViewHostMsg_SetCacheMode, bool /* enabled */) + // Get file size in bytes. Set result to -1 if failed to get the file size. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetFileSize, + FilePath /* path */, + int64 /* result */) + //--------------------------------------------------------------------------- // Utility process host messages: // These are messages from the utility process to the browser. They're here diff --git a/chrome/renderer/renderer_webkitclient_impl.cc b/chrome/renderer/renderer_webkitclient_impl.cc index a193447..5662bfa 100644 --- a/chrome/renderer/renderer_webkitclient_impl.cc +++ b/chrome/renderer/renderer_webkitclient_impl.cc @@ -77,6 +77,18 @@ void RendererWebKitClientImpl::prefetchHostName(const WebString& hostname) { } } +bool RendererWebKitClientImpl::getFileSize(const WebString& path, + long long& result) { + if (RenderThread::current()->Send(new ViewHostMsg_GetFileSize( + FilePath(webkit_glue::WebStringToFilePathString(path)), + &result))) { + return result >= 0; + } else { + result = -1; + return false; + } +} + WebString RendererWebKitClientImpl::defaultLocale() { // TODO(darin): Eliminate this webkit_glue call. return WideToUTF16(webkit_glue::GetWebKitLocale()); diff --git a/chrome/renderer/renderer_webkitclient_impl.h b/chrome/renderer/renderer_webkitclient_impl.h index 27d11f8..d6d9b33 100644 --- a/chrome/renderer/renderer_webkitclient_impl.h +++ b/chrome/renderer/renderer_webkitclient_impl.h @@ -33,6 +33,7 @@ class RendererWebKitClientImpl : public webkit_glue::WebKitClientImpl { virtual WebKit::WebString cookies( const WebKit::WebURL& url, const WebKit::WebURL& first_party_for_cookies); virtual void prefetchHostName(const WebKit::WebString&); + virtual bool getFileSize(const WebKit::WebString& path, long long& result); virtual WebKit::WebString defaultLocale(); virtual void suddenTerminationChanged(bool enabled); diff --git a/chrome/worker/worker_webkitclient_impl.cc b/chrome/worker/worker_webkitclient_impl.cc index 1861b64..a159938 100644 --- a/chrome/worker/worker_webkitclient_impl.cc +++ b/chrome/worker/worker_webkitclient_impl.cc @@ -52,6 +52,12 @@ void WorkerWebKitClientImpl::prefetchHostName(const WebKit::WebString&) { NOTREACHED(); } +bool WorkerWebKitClientImpl::getFileSize(const WebKit::WebString& path, + long long& result) { + NOTREACHED(); + return false; +} + WebKit::WebString WorkerWebKitClientImpl::defaultLocale() { NOTREACHED(); return WebKit::WebString(); diff --git a/chrome/worker/worker_webkitclient_impl.h b/chrome/worker/worker_webkitclient_impl.h index 474e1b2..cebe706 100644 --- a/chrome/worker/worker_webkitclient_impl.h +++ b/chrome/worker/worker_webkitclient_impl.h @@ -22,6 +22,7 @@ class WorkerWebKitClientImpl : public webkit_glue::WebKitClientImpl { virtual WebKit::WebString cookies(const WebKit::WebURL& url, const WebKit::WebURL& policy_url); virtual void prefetchHostName(const WebKit::WebString&); + virtual bool getFileSize(const WebKit::WebString& path, long long& result); virtual WebKit::WebString defaultLocale(); }; diff --git a/webkit/api/public/WebKitClient.h b/webkit/api/public/WebKitClient.h index 4ebbb25..4de58c3 100644 --- a/webkit/api/public/WebKitClient.h +++ b/webkit/api/public/WebKitClient.h @@ -82,6 +82,10 @@ namespace WebKit { // A suggestion to prefetch IP information for the given hostname. virtual void prefetchHostName(const WebString&) = 0; + // File ---------------------------------------------------------------- + + virtual bool getFileSize(const WebString& path, long long& result) = 0; + // Returns a new WebURLLoader instance. virtual WebURLLoader* createURLLoader() = 0; diff --git a/webkit/api/src/ChromiumBridge.cpp b/webkit/api/src/ChromiumBridge.cpp index 3fdef0a..4d05a2e 100644 --- a/webkit/api/src/ChromiumBridge.cpp +++ b/webkit/api/src/ChromiumBridge.cpp @@ -148,6 +148,13 @@ void ChromiumBridge::prefetchDNS(const String& hostname) webKitClient()->prefetchHostName(hostname); } +// File ------------------------------------------------------------------------ + +bool ChromiumBridge::getFileSize(const String& path, long long& result) +{ + return webKitClient()->getFileSize(path, result); +} + // Font ----------------------------------------------------------------------- #if PLATFORM(WIN_OS) diff --git a/webkit/tools/test_shell/test_shell_webkit_init.h b/webkit/tools/test_shell/test_shell_webkit_init.h index c5b419b..8b832ae 100644 --- a/webkit/tools/test_shell/test_shell_webkit_init.h +++ b/webkit/tools/test_shell/test_shell_webkit_init.h @@ -5,6 +5,7 @@ #ifndef WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_WEBKIT_INIT_H_ #define WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_WEBKIT_INIT_H_ +#include "base/file_util.h" #include "base/path_service.h" #include "base/stats_counters.h" #include "base/string_util.h" @@ -96,6 +97,11 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl { virtual void prefetchHostName(const WebKit::WebString&) { } + virtual bool getFileSize(const WebKit::WebString& path, long long& result) { + return file_util::GetFileSize( + FilePath(webkit_glue::WebStringToFilePathString(path)), &result); + } + virtual WebKit::WebData loadResource(const char* name) { if (!strcmp(name, "deleteButton")) { // Create a red 30x30 square. diff --git a/webkit/tools/test_shell/test_worker/test_worker_main.cc b/webkit/tools/test_shell/test_worker/test_worker_main.cc index 366b217..29f739a 100644 --- a/webkit/tools/test_shell/test_worker/test_worker_main.cc +++ b/webkit/tools/test_shell/test_worker/test_worker_main.cc @@ -76,6 +76,11 @@ class WorkerWebKitClientImpl : public webkit_glue::WebKitClientImpl { NOTREACHED(); } + virtual bool getFileSize(const WebKit::WebString& path, long long& result) { + NOTREACHED(); + return false; + } + virtual WebKit::WebString defaultLocale() { NOTREACHED(); return WebKit::WebString(); |