summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--base/base.gypi1
-rw-r--r--base/platform_file.h38
-rw-r--r--base/scoped_callback_factory.h133
-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
10 files changed, 539 insertions, 17 deletions
diff --git a/base/base.gypi b/base/base.gypi
index a5fdfc6..75fcf5b 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -186,6 +186,7 @@
'safe_strerror_posix.h',
'scoped_bstr_win.cc',
'scoped_bstr_win.h',
+ 'scoped_callback_factory.h',
'scoped_cftyperef.h',
'scoped_comptr_win.h',
'scoped_handle.h',
diff --git a/base/platform_file.h b/base/platform_file.h
index 3571e24..43f8511 100644
--- a/base/platform_file.h
+++ b/base/platform_file.h
@@ -54,6 +54,44 @@ PlatformFile CreatePlatformFile(const std::wstring& name,
// Closes a file handle
bool ClosePlatformFile(PlatformFile file);
+// Use this class to pass ownership of a PlatformFile to a receiver that may or
+// may not want to accept it. This class does not own the storage for the
+// PlatformFile.
+//
+// EXAMPLE:
+//
+// void MaybeProcessFile(PassPlatformFile pass_file) {
+// if (...) {
+// PlatformFile file = pass_file.ReleaseValue();
+// // Now, we are responsible for closing |file|.
+// }
+// }
+//
+// void OpenAndMaybeProcessFile(const FilePath& path) {
+// PlatformFile file = CreatePlatformFile(path, ...);
+// MaybeProcessFile(PassPlatformFile(&file));
+// if (file != kInvalidPlatformFileValue)
+// ClosePlatformFile(file);
+// }
+//
+class PassPlatformFile {
+ public:
+ explicit PassPlatformFile(PlatformFile* value) : value_(value) {
+ }
+
+ // Called to retrieve the PlatformFile stored in this object. The caller
+ // gains ownership of the PlatformFile and is now responsible for closing it.
+ // Any subsequent calls to this method will return an invalid PlatformFile.
+ PlatformFile ReleaseValue() {
+ PlatformFile temp = *value_;
+ *value_ = kInvalidPlatformFileValue;
+ return temp;
+ }
+
+ private:
+ PlatformFile* value_;
+};
+
} // namespace base
#endif // BASE_PLATFORM_FILE_H_
diff --git a/base/scoped_callback_factory.h b/base/scoped_callback_factory.h
new file mode 100644
index 0000000..a2fc1f0
--- /dev/null
+++ b/base/scoped_callback_factory.h
@@ -0,0 +1,133 @@
+// 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.
+
+// ScopedCallbackFactory helps in cases where you wish to allocate a Callback
+// (see base/callback.h), but need to prevent any pending callbacks from
+// executing when your object gets destroyed.
+//
+// EXAMPLE:
+//
+// void GatherDataAsynchronously(Callback1<Data>::Type* callback);
+//
+// class MyClass {
+// public:
+// MyClass() : factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+// }
+//
+// void Process() {
+// GatherDataAsynchronously(factory_.NewCallback(&MyClass::GotData));
+// }
+//
+// private:
+// void GotData(const Data& data) {
+// ...
+// }
+//
+// base::ScopedCallbackFactory<MyClass> factory_;
+// };
+//
+// In the above example, the Process function calls GatherDataAsynchronously to
+// kick off some asynchronous processing that upon completion will notify a
+// callback. If in the meantime, the MyClass instance is destroyed, when the
+// callback runs, it will notice that the MyClass instance is dead, and it will
+// avoid calling the GotData method.
+
+#ifndef BASE_SCOPED_CALLBACK_FACTORY_H_
+#define BASE_SCOPED_CALLBACK_FACTORY_H_
+
+#include "base/callback.h"
+#include "base/weak_ptr.h"
+
+namespace base {
+
+template <class T>
+class ScopedCallbackFactory {
+ public:
+ explicit ScopedCallbackFactory(T* obj) : weak_factory_(obj) {
+ }
+
+ typename Callback0::Type* NewCallback(
+ void (T::*method)()) {
+ return new CallbackImpl<void (T::*)(), Tuple0 >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1>
+ typename Callback1<Arg1>::Type* NewCallback(
+ void (T::*method)(Arg1)) {
+ return new CallbackImpl<void (T::*)(Arg1), Tuple1<Arg1> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1, typename Arg2>
+ typename Callback2<Arg1, Arg2>::Type* NewCallback(
+ void (T::*method)(Arg1, Arg2)) {
+ return new CallbackImpl<void (T::*)(Arg1, Arg2), Tuple2<Arg1, Arg2> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3>
+ typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback(
+ void (T::*method)(Arg1, Arg2, Arg3)) {
+ return new CallbackImpl<void (T::*)(Arg1, Arg2, Arg3),
+ Tuple3<Arg1, Arg2, Arg3> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback(
+ void (T::*method)(Arg1, Arg2, Arg3, Arg4)) {
+ return new CallbackImpl<void (T::*)(Arg1, Arg2, Arg3, Arg4),
+ Tuple4<Arg1, Arg2, Arg3, Arg4> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5>
+ typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback(
+ void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) {
+ return new CallbackImpl<void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5),
+ Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ void RevokeAll() { weak_factory_.InvalidateWeakPtrs(); }
+ bool HasPendingCallbacks() const { return weak_factory_.HasWeakPtrs(); }
+
+ private:
+ template <typename Method>
+ class CallbackStorage {
+ public:
+ CallbackStorage(const WeakPtr<T>& obj, Method meth)
+ : obj_(obj),
+ meth_(meth) {
+ }
+
+ protected:
+ WeakPtr<T> obj_;
+ Method meth_;
+ };
+
+ template <typename Method, typename Params>
+ class CallbackImpl : public CallbackStorage<Method>,
+ public CallbackRunner<Params> {
+ public:
+ CallbackImpl(const WeakPtr<T>& obj, Method meth)
+ : CallbackStorage<Method>(obj, meth) {
+ }
+ virtual void RunWithParams(const Params& params) {
+ // Use "this->" to force C++ to look inside our templatized base class;
+ // see Effective C++, 3rd Ed, item 43, p210 for details.
+ if (!this->obj_)
+ return;
+ DispatchToMethod(this->obj_.get(), this->meth_, params);
+ }
+ };
+
+ WeakPtrFactory<T> weak_factory_;
+};
+
+} // namespace base
+
+#endif // BASE_SCOPED_CALLBACK_FACTORY_H_
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',