summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authordarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-30 23:05:15 +0000
committerdarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-30 23:05:15 +0000
commit21ae1f956c163bc0e3b3e239b5c027a7ac93ae7f (patch)
tree4eee3fe37f83559b1a97f75dcdef0337b68e2cf1 /chrome
parent0436fcd542e8ce436fe9395a64cc03fa369276b1 (diff)
downloadchromium_src-21ae1f956c163bc0e3b3e239b5c027a7ac93ae7f.zip
chromium_src-21ae1f956c163bc0e3b3e239b5c027a7ac93ae7f.tar.gz
chromium_src-21ae1f956c163bc0e3b3e239b5c027a7ac93ae7f.tar.bz2
Asynchronously open the temp file used for Pepper StreamToFile, and delete the
temp file once we are done with it. We observe ResourceHandle::OnRequestClosed as a signal of when we should delete the temp file. This corresponds to the WebURLLoader being closed (or canceled). This patch also includes some helpers: base/scoped_callback_factory.h This class makes it easy to allocate Callbacks that hold a weak reference back to the owning class. It works just like ScopedRunnableMethodFactory but for Callbacks instead of RunnableMethods. base/platform_file.h Added a PassPlatformFile class that is useful for cases where a callback may decide not to take ownership of a PlatformFile (as can happen when using ScopedCallbackFactory). chrome/file_system_proxy.{h,cc} This class provides static methods for executing file system commands on the FILE thread. It routes callbacks back to the originating thread to deliver results (file handles, etc.). Note: this file declares a few functions that are not yet used. I anticipate that we'll make use of these and add more functions here to support the Pepper and OWP FileSystem APIs. chrome/chrome_thread_relay.{h,cc} This class is a helper class for proxying calls over to a background ChromeThread and then returning results to the originating ChromeThread. R=brettw BUG=49789 TEST=(more to be added in third_party/ppapi/tests) Review URL: http://codereview.chromium.org/2878062 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54402 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/chrome_thread_relay.cc26
-rw-r--r--chrome/browser/chrome_thread_relay.h55
-rw-r--r--chrome/browser/file_system_proxy.cc180
-rw-r--r--chrome/browser/file_system_proxy.h49
-rw-r--r--chrome/browser/renderer_host/redirect_to_file_resource_handler.cc58
-rw-r--r--chrome/browser/renderer_host/redirect_to_file_resource_handler.h12
-rw-r--r--chrome/chrome_browser.gypi4
7 files changed, 367 insertions, 17 deletions
diff --git a/chrome/browser/chrome_thread_relay.cc b/chrome/browser/chrome_thread_relay.cc
new file mode 100644
index 0000000..e773f1d
--- /dev/null
+++ b/chrome/browser/chrome_thread_relay.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2010 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/chrome_thread_relay.h"
+
+ChromeThreadRelay::ChromeThreadRelay() {
+ if (!ChromeThread::GetCurrentThreadIdentifier(&origin_thread_id_))
+ NOTREACHED() << "Must be created on a valid ChromeThread";
+}
+
+void ChromeThreadRelay::Start(ChromeThread::ID target_thread_id,
+ const tracked_objects::Location& from_here) {
+ ChromeThread::PostTask(
+ target_thread_id,
+ from_here,
+ NewRunnableMethod(this, &ChromeThreadRelay::ProcessOnTargetThread));
+}
+
+void ChromeThreadRelay::ProcessOnTargetThread() {
+ RunWork();
+ ChromeThread::PostTask(
+ origin_thread_id_,
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromeThreadRelay::RunCallback));
+}
diff --git a/chrome/browser/chrome_thread_relay.h b/chrome/browser/chrome_thread_relay.h
new file mode 100644
index 0000000..657e587
--- /dev/null
+++ b/chrome/browser/chrome_thread_relay.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2010 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.
+
+// ChromeThreadRelay provides a convenient way to bounce work to a specific
+// ChromeThread and then return results back to the originating thread.
+//
+// EXAMPLE:
+//
+// class MyRelay : public ChromeThreadRelay {
+// public:
+// MyRelay(const Params& params) : params_(params) {
+// }
+// protected:
+// virtual void RunWork() {
+// results_ = DoWork(params_);
+// }
+// virtual void RunCallback() {
+// ... use results_ on the originating thread ...
+// }
+// private:
+// Params params_;
+// Results_ results_;
+// };
+
+#ifndef CHROME_BROWSER_CHROME_THREAD_RELAY_H_
+#define CHROME_BROWSER_CHROME_THREAD_RELAY_H_
+
+#include "base/ref_counted.h"
+#include "chrome/browser/chrome_thread.h"
+
+class ChromeThreadRelay
+ : public base::RefCountedThreadSafe<ChromeThreadRelay> {
+ public:
+ ChromeThreadRelay();
+
+ void Start(ChromeThread::ID target_thread_id,
+ const tracked_objects::Location& from_here);
+
+ protected:
+ friend class base::RefCountedThreadSafe<ChromeThreadRelay>;
+ virtual ~ChromeThreadRelay() {}
+
+ // Called to perform work on the FILE thread.
+ virtual void RunWork() = 0;
+
+ // Called to notify the callback on the origin thread.
+ virtual void RunCallback() = 0;
+
+ private:
+ void ProcessOnTargetThread();
+ ChromeThread::ID origin_thread_id_;
+};
+
+#endif // CHROME_BROWSER_CHROME_THREAD_RELAY_H_
diff --git a/chrome/browser/file_system_proxy.cc b/chrome/browser/file_system_proxy.cc
new file mode 100644
index 0000000..1cf7b55
--- /dev/null
+++ b/chrome/browser/file_system_proxy.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2010 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/file_system_proxy.h"
+
+#include "base/file_util.h"
+#include "chrome/browser/chrome_thread_relay.h"
+
+namespace {
+
+class RelayCreateOrOpen : public ChromeThreadRelay {
+ public:
+ RelayCreateOrOpen(
+ const FilePath& file_path,
+ int file_flags,
+ FileSystemProxy::CreateOrOpenCallback* callback)
+ : file_path_(file_path),
+ file_flags_(file_flags),
+ callback_(callback),
+ file_handle_(base::kInvalidPlatformFileValue),
+ created_(false) {
+ DCHECK(callback);
+ }
+
+ protected:
+ virtual ~RelayCreateOrOpen() {
+ if (file_handle_ != base::kInvalidPlatformFileValue)
+ FileSystemProxy::Close(file_handle_, NULL);
+ }
+
+ virtual void RunWork() {
+ file_handle_ = base::CreatePlatformFile(file_path_, file_flags_, &created_);
+ }
+
+ virtual void RunCallback() {
+ callback_->Run(base::PassPlatformFile(&file_handle_), created_);
+ delete callback_;
+ }
+
+ private:
+ FilePath file_path_;
+ int file_flags_;
+ FileSystemProxy::CreateOrOpenCallback* callback_;
+ base::PlatformFile file_handle_;
+ bool created_;
+};
+
+class RelayCreateTemporary : public ChromeThreadRelay {
+ public:
+ explicit RelayCreateTemporary(
+ FileSystemProxy::CreateTemporaryCallback* callback)
+ : callback_(callback),
+ file_handle_(base::kInvalidPlatformFileValue) {
+ DCHECK(callback);
+ }
+
+ protected:
+ virtual ~RelayCreateTemporary() {
+ if (file_handle_ != base::kInvalidPlatformFileValue)
+ FileSystemProxy::Close(file_handle_, NULL);
+ }
+
+ virtual void RunWork() {
+ // TODO(darin): file_util should have a variant of CreateTemporaryFile
+ // that returns a FilePath and a PlatformFile.
+ file_util::CreateTemporaryFile(&file_path_);
+
+ // Use a fixed set of flags that are appropriate for writing to a temporary
+ // file from the IO thread using a net::FileStream.
+ int file_flags =
+ base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_ASYNC |
+ base::PLATFORM_FILE_TEMPORARY;
+ file_handle_ = base::CreatePlatformFile(file_path_, file_flags, NULL);
+ }
+
+ virtual void RunCallback() {
+ callback_->Run(base::PassPlatformFile(&file_handle_), file_path_);
+ delete callback_;
+ }
+
+ private:
+ FileSystemProxy::CreateTemporaryCallback* callback_;
+ base::PlatformFile file_handle_;
+ FilePath file_path_;
+};
+
+class RelayWithStatusCallback : public ChromeThreadRelay {
+ public:
+ explicit RelayWithStatusCallback(FileSystemProxy::StatusCallback* callback)
+ : callback_(callback),
+ succeeded_(false) {
+ // It is OK for callback to be NULL.
+ }
+
+ protected:
+ virtual void RunCallback() {
+ // The caller may not have been interested in the result.
+ if (callback_) {
+ callback_->Run(succeeded_);
+ delete callback_;
+ }
+ }
+
+ void SetStatus(bool succeeded) { succeeded_ = succeeded; }
+
+ private:
+ FileSystemProxy::StatusCallback* callback_;
+ bool succeeded_;
+};
+
+class RelayClose : public RelayWithStatusCallback {
+ public:
+ RelayClose(base::PlatformFile file_handle,
+ FileSystemProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ file_handle_(file_handle) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ SetStatus(base::ClosePlatformFile(file_handle_));
+ }
+
+ private:
+ base::PlatformFile file_handle_;
+};
+
+class RelayDelete : public RelayWithStatusCallback {
+ public:
+ RelayDelete(const FilePath& file_path,
+ bool recursive,
+ FileSystemProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ file_path_(file_path),
+ recursive_(recursive) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ SetStatus(file_util::Delete(file_path_, recursive_));
+ }
+
+ private:
+ FilePath file_path_;
+ bool recursive_;
+};
+
+void Start(const tracked_objects::Location& from_here,
+ scoped_refptr<ChromeThreadRelay> relay) {
+ relay->Start(ChromeThread::FILE, from_here);
+}
+
+} // namespace
+
+void FileSystemProxy::CreateOrOpen(const FilePath& file_path, int file_flags,
+ CreateOrOpenCallback* callback) {
+ Start(FROM_HERE, new RelayCreateOrOpen(file_path, file_flags, callback));
+}
+
+void FileSystemProxy::CreateTemporary(CreateTemporaryCallback* callback) {
+ Start(FROM_HERE, new RelayCreateTemporary(callback));
+}
+
+void FileSystemProxy::Close(base::PlatformFile file_handle,
+ StatusCallback* callback) {
+ Start(FROM_HERE, new RelayClose(file_handle, callback));
+}
+
+void FileSystemProxy::Delete(const FilePath& file_path,
+ StatusCallback* callback) {
+ Start(FROM_HERE, new RelayDelete(file_path, false, callback));
+}
+
+void FileSystemProxy::RecursiveDelete(const FilePath& file_path,
+ StatusCallback* callback) {
+ Start(FROM_HERE, new RelayDelete(file_path, true, callback));
+}
diff --git a/chrome/browser/file_system_proxy.h b/chrome/browser/file_system_proxy.h
new file mode 100644
index 0000000..74cd215
--- /dev/null
+++ b/chrome/browser/file_system_proxy.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 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_FILE_SYSTEM_PROXY_H_
+#define CHROME_BROWSER_FILE_SYSTEM_PROXY_H_
+
+#include "base/callback.h"
+#include "base/platform_file.h"
+#include "base/ref_counted.h"
+
+// This class provides asynchronous access to common file routines.
+class FileSystemProxy {
+ public:
+ // This callback is used by methods that report success with a bool. It is
+ // valid to pass NULL as the callback parameter to any function that takes a
+ // StatusCallback, in which case the operation will complete silently.
+ typedef Callback1<bool /* succeeded */>::Type StatusCallback;
+
+ // Creates or opens a file with the given flags. It is invalid to pass NULL
+ // for the callback.
+ typedef Callback2<base::PassPlatformFile, bool /* created */>::Type
+ CreateOrOpenCallback;
+ static void CreateOrOpen(const FilePath& file_path,
+ int file_flags,
+ CreateOrOpenCallback* callback);
+
+ // Creates a temporary file for writing. The path and an open file handle
+ // are returned. It is invalid to pass NULL for the callback.
+ typedef Callback2<base::PassPlatformFile, FilePath>::Type
+ CreateTemporaryCallback;
+ static void CreateTemporary(CreateTemporaryCallback* callback);
+
+ // Close the given file handle.
+ static void Close(base::PlatformFile, StatusCallback* callback);
+
+ // Deletes a file or empty directory.
+ static void Delete(const FilePath& file_path,
+ StatusCallback* callback);
+
+ // Deletes a directory and all of its contents.
+ static void RecursiveDelete(const FilePath& file_path,
+ StatusCallback* callback);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FileSystemProxy);
+};
+
+#endif // CHROME_BROWSER_FILE_SYSTEM_PROXY_H_
diff --git a/chrome/browser/renderer_host/redirect_to_file_resource_handler.cc b/chrome/browser/renderer_host/redirect_to_file_resource_handler.cc
index 4f523b7..11beb73 100644
--- a/chrome/browser/renderer_host/redirect_to_file_resource_handler.cc
+++ b/chrome/browser/renderer_host/redirect_to_file_resource_handler.cc
@@ -5,9 +5,13 @@
#include "chrome/browser/renderer_host/redirect_to_file_resource_handler.h"
#include "base/file_util.h"
+#include "base/logging.h"
#include "base/platform_file.h"
+#include "base/task.h"
+#include "chrome/browser/file_system_proxy.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/resource_response.h"
+#include "net/base/file_stream.h"
#include "net/base/io_buffer.h"
#include "net/base/mime_sniffer.h"
#include "net/base/net_errors.h"
@@ -19,7 +23,8 @@ RedirectToFileResourceHandler::RedirectToFileResourceHandler(
ResourceHandler* next_handler,
int process_id,
ResourceDispatcherHost* host)
- : host_(host),
+ : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ host_(host),
next_handler_(next_handler),
process_id_(process_id),
request_id_(-1),
@@ -50,8 +55,7 @@ bool RedirectToFileResourceHandler::OnResponseStarted(
int request_id,
ResourceResponse* response) {
if (response->response_head.status.is_success()) {
- // TODO(darin): Move this file creation to a background thread.
- file_util::CreateTemporaryFile(&file_path_);
+ DCHECK(!file_path_.empty());
response->response_head.download_file_path = file_path_;
}
return next_handler_->OnResponseStarted(request_id, response);
@@ -60,6 +64,17 @@ bool RedirectToFileResourceHandler::OnResponseStarted(
bool RedirectToFileResourceHandler::OnWillStart(int request_id,
const GURL& url,
bool* defer) {
+ request_id_ = request_id;
+ if (file_path_.empty()) {
+ // Defer starting the request until we have created the temporary file.
+ // TODO(darin): This is sub-optimal. We should not delay starting the
+ // network request like this.
+ *defer = true;
+ FileSystemProxy::CreateTemporary(
+ callback_factory_.NewCallback(
+ &RedirectToFileResourceHandler::DidCreateTemporaryFile));
+ return true;
+ }
return next_handler_->OnWillStart(request_id, url, defer);
}
@@ -103,18 +118,9 @@ bool RedirectToFileResourceHandler::OnReadCompleted(int request_id,
DCHECK(new_offset <= buf_->capacity());
buf_->set_offset(new_offset);
- if (!file_stream_.IsOpen()) {
- int rv = file_stream_.Open(file_path_, base::PLATFORM_FILE_OPEN |
- base::PLATFORM_FILE_WRITE |
- base::PLATFORM_FILE_ASYNC);
- if (rv != net::OK)
- return false;
- }
-
if (BufIsFull())
host_->PauseRequest(process_id_, request_id, true);
- request_id_ = request_id;
return WriteMore();
}
@@ -127,9 +133,30 @@ bool RedirectToFileResourceHandler::OnResponseCompleted(
void RedirectToFileResourceHandler::OnRequestClosed() {
next_handler_->OnRequestClosed();
+
+ // The renderer no longer has a WebURLLoader open to this request, so we can
+ // close and unlink the file.
+
+ // We require this explicit call to Close since file_stream_ was constructed
+ // directly from a PlatformFile.
+ file_stream_->Close();
+ file_stream_.reset();
+
+ FileSystemProxy::Delete(file_path_, NULL);
}
RedirectToFileResourceHandler::~RedirectToFileResourceHandler() {
+ DCHECK(!file_stream_.get());
+}
+
+void RedirectToFileResourceHandler::DidCreateTemporaryFile(
+ base::PassPlatformFile file_handle,
+ FilePath file_path) {
+ file_path_ = file_path;
+ file_stream_.reset(new net::FileStream(file_handle.ReleaseValue(),
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_ASYNC));
+ host_->StartDeferredRequest(process_id_, request_id_);
}
void RedirectToFileResourceHandler::DidWriteToFile(int result) {
@@ -148,6 +175,7 @@ void RedirectToFileResourceHandler::DidWriteToFile(int result) {
}
bool RedirectToFileResourceHandler::WriteMore() {
+ DCHECK(file_stream_.get());
for (;;) {
if (write_cursor_ == buf_->offset()) {
// We've caught up to the network load, but it may be in the process of
@@ -163,9 +191,9 @@ bool RedirectToFileResourceHandler::WriteMore() {
if (write_callback_pending_)
return true;
DCHECK(write_cursor_ < buf_->offset());
- int rv = file_stream_.Write(buf_->StartOfBuffer() + write_cursor_,
- buf_->offset() - write_cursor_,
- &write_callback_);
+ int rv = file_stream_->Write(buf_->StartOfBuffer() + write_cursor_,
+ buf_->offset() - write_cursor_,
+ &write_callback_);
if (rv == net::ERR_IO_PENDING) {
write_callback_pending_ = true;
return true;
diff --git a/chrome/browser/renderer_host/redirect_to_file_resource_handler.h b/chrome/browser/renderer_host/redirect_to_file_resource_handler.h
index f9d2b57..5dd4111 100644
--- a/chrome/browser/renderer_host/redirect_to_file_resource_handler.h
+++ b/chrome/browser/renderer_host/redirect_to_file_resource_handler.h
@@ -6,14 +6,18 @@
#define CHROME_BROWSER_RENDERER_HOST_REDIRECT_TO_FILE_RESOURCE_HANDLER_H_
#include "base/file_path.h"
+#include "base/platform_file.h"
#include "base/ref_counted.h"
+#include "base/scoped_callback_factory.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/renderer_host/resource_handler.h"
#include "net/base/completion_callback.h"
-#include "net/base/file_stream.h"
+class RefCountedPlatformFile;
class ResourceDispatcherHost;
namespace net {
+class FileStream;
class GrowableIOBuffer;
}
@@ -42,10 +46,14 @@ class RedirectToFileResourceHandler : public ResourceHandler {
private:
virtual ~RedirectToFileResourceHandler();
+ void DidCreateTemporaryFile(base::PassPlatformFile file_handle,
+ FilePath file_path);
void DidWriteToFile(int result);
bool WriteMore();
bool BufIsFull() const;
+ base::ScopedCallbackFactory<RedirectToFileResourceHandler> callback_factory_;
+
ResourceDispatcherHost* host_;
scoped_refptr<ResourceHandler> next_handler_;
int process_id_;
@@ -63,7 +71,7 @@ class RedirectToFileResourceHandler : public ResourceHandler {
int write_cursor_;
FilePath file_path_;
- net::FileStream file_stream_;
+ scoped_ptr<net::FileStream> file_stream_;
net::CompletionCallbackImpl<RedirectToFileResourceHandler> write_callback_;
bool write_callback_pending_;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 1b5ea58..25f9996 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -346,6 +346,8 @@
'browser/chrome_plugin_host.h',
'browser/chrome_thread.cc',
'browser/chrome_thread.h',
+ 'browser/chrome_thread_relay.cc',
+ 'browser/chrome_thread_relay.h',
'browser/chromeos/notifications/balloon_collection_impl.h',
'browser/chromeos/notifications/balloon_collection_impl.cc',
'browser/chromeos/notifications/balloon_view.h',
@@ -1390,6 +1392,8 @@
'browser/file_watcher_inotify.cc',
'browser/file_watcher_mac.cc',
'browser/file_watcher_win.cc',
+ 'browser/file_system_proxy.cc',
+ 'browser/file_system_proxy.h',
'browser/find_bar.h',
'browser/find_bar_controller.cc',
'browser/find_bar_controller.h',