summaryrefslogtreecommitdiffstats
path: root/webkit/blob/local_file_reader.cc
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 11:23:23 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 11:23:23 +0000
commit192bd691ed6eedb3e08b5b619019cb7cb4300b84 (patch)
treea9164dc70a18a2e008d28103d582a83841e7bc8a /webkit/blob/local_file_reader.cc
parenta91ef5e4ab532cc708ad90a1ddb890bb1c839300 (diff)
downloadchromium_src-192bd691ed6eedb3e08b5b619019cb7cb4300b84.zip
chromium_src-192bd691ed6eedb3e08b5b619019cb7cb4300b84.tar.gz
chromium_src-192bd691ed6eedb3e08b5b619019cb7cb4300b84.tar.bz2
Separate FileStream related code out of BlobURLRequestJob
This patch separates FileStream related code out of BlobURLRequestJob to: - make BlobURLRequesetJob's responsibility simpler and clearer by moving file-related details out of the class - remove blocking file operation on IO thread Long-term goal includes using the same reader class/interface to FileSystemURLRequestJob and other fileapi streaming related code. (Simplified the patch from the previous version: was: "Add FileStreamInterface for fileapi/blob stream related operations") BUG=114999,75548 TEST=blob tests Review URL: https://chromiumcodereview.appspot.com/9651032 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126623 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/blob/local_file_reader.cc')
-rw-r--r--webkit/blob/local_file_reader.cc174
1 files changed, 174 insertions, 0 deletions
diff --git a/webkit/blob/local_file_reader.cc b/webkit/blob/local_file_reader.cc
new file mode 100644
index 0000000..3de9427
--- /dev/null
+++ b/webkit/blob/local_file_reader.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/blob/local_file_reader.h"
+
+#include "base/file_util.h"
+#include "base/file_util_proxy.h"
+#include "base/logging.h"
+#include "base/message_loop_proxy.h"
+#include "base/platform_file.h"
+#include "net/base/file_stream.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+namespace webkit_blob {
+
+namespace {
+
+const int kOpenFlagsForRead = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_ASYNC;
+
+int PlatformFileErrorToNetError(base::PlatformFileError file_error) {
+ switch (file_error) {
+ case base::PLATFORM_FILE_OK:
+ return net::OK;
+ case base::PLATFORM_FILE_ERROR_NOT_FOUND:
+ return net::ERR_FILE_NOT_FOUND;
+ case base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
+ return net::ERR_ACCESS_DENIED;
+ default:
+ return net::ERR_FAILED;
+ }
+}
+
+// Verify if the underlying file has not been modified.
+bool VerifySnapshotTime(const base::Time& expected_modification_time,
+ const base::PlatformFileInfo& file_info) {
+ return expected_modification_time.is_null() ||
+ expected_modification_time.ToTimeT() ==
+ file_info.last_modified.ToTimeT();
+}
+
+void DidGetFileInfoForGetLength(const net::CompletionCallback& callback,
+ const base::Time& expected_modification_time,
+ int64 initial_offset,
+ base::PlatformFileError error,
+ const base::PlatformFileInfo& file_info) {
+ if (file_info.is_directory) {
+ callback.Run(net::ERR_FILE_NOT_FOUND);
+ return;
+ }
+ if (error != base::PLATFORM_FILE_OK) {
+ callback.Run(PlatformFileErrorToNetError(error));
+ return;
+ }
+ if (!VerifySnapshotTime(expected_modification_time, file_info)) {
+ callback.Run(net::ERR_UPLOAD_FILE_CHANGED);
+ return;
+ }
+ callback.Run(file_info.size - initial_offset);
+}
+
+} // namespace
+
+class LocalFileReader::OpenFileStreamHelper {
+ public:
+ OpenFileStreamHelper() : result_(net::OK) {}
+
+ void OpenAndSeekOnFileThread(const FilePath& file_path,
+ int64 initial_offset,
+ const base::Time& expected_modification_time) {
+ base::PlatformFileInfo file_info;
+ const bool result = file_util::GetFileInfo(file_path, &file_info);
+ if (!result) {
+ result_ = net::ERR_FAILED;
+ return;
+ }
+
+ if (!VerifySnapshotTime(expected_modification_time, file_info)) {
+ result_ = net::ERR_UPLOAD_FILE_CHANGED;
+ return;
+ }
+
+ stream_impl_.reset(new net::FileStream(NULL));
+ result_ = stream_impl_->OpenSync(file_path, kOpenFlagsForRead);
+ if (result_ != net::OK) {
+ stream_impl_.reset();
+ return;
+ }
+
+ const int64 returned_offset = stream_impl_->Seek(
+ net::FROM_BEGIN, initial_offset);
+ if (returned_offset != initial_offset) {
+ result_ = net::ERR_FAILED;
+ return;
+ }
+
+ result_ = net::OK;
+ }
+
+ void Reply(const OpenFileStreamCallback& callback) {
+ callback.Run(result_, stream_impl_.Pass());
+ }
+
+ private:
+ base::WeakPtr<LocalFileReader> stream_;
+ scoped_ptr<net::FileStream> stream_impl_;
+ int result_;
+};
+
+LocalFileReader::LocalFileReader(
+ base::MessageLoopProxy* file_thread_proxy,
+ const FilePath& file_path,
+ int64 initial_offset,
+ const base::Time& expected_modification_time)
+ : file_thread_proxy_(file_thread_proxy),
+ file_path_(file_path),
+ initial_offset_(initial_offset),
+ expected_modification_time_(expected_modification_time),
+ has_pending_open_(false),
+ weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
+
+LocalFileReader::~LocalFileReader() {}
+
+int LocalFileReader::Read(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) {
+ DCHECK(!has_pending_open_);
+ if (stream_impl_.get())
+ return stream_impl_->Read(buf, buf_len, callback);
+ return Open(base::Bind(&LocalFileReader::DidOpen, weak_factory_.GetWeakPtr(),
+ make_scoped_refptr(buf), buf_len, callback));
+}
+
+int LocalFileReader::GetLength(const net::CompletionCallback& callback) {
+ const bool posted = base::FileUtilProxy::GetFileInfo(
+ file_thread_proxy_, file_path_,
+ base::Bind(&DidGetFileInfoForGetLength, callback,
+ expected_modification_time_, initial_offset_));
+ DCHECK(posted);
+ return net::ERR_IO_PENDING;
+}
+
+int LocalFileReader::Open(const OpenFileStreamCallback& callback) {
+ DCHECK(!has_pending_open_);
+ DCHECK(!stream_impl_.get());
+ has_pending_open_ = true;
+ OpenFileStreamHelper* helper = new OpenFileStreamHelper;
+ const bool posted = file_thread_proxy_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&OpenFileStreamHelper::OpenAndSeekOnFileThread,
+ base::Unretained(helper), file_path_, initial_offset_,
+ expected_modification_time_),
+ base::Bind(&OpenFileStreamHelper::Reply, base::Owned(helper), callback));
+ DCHECK(posted);
+ return net::ERR_IO_PENDING;
+}
+
+void LocalFileReader::DidOpen(net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback,
+ int error,
+ scoped_ptr<net::FileStream> stream_impl) {
+ DCHECK(has_pending_open_);
+ DCHECK(!stream_impl_.get());
+ stream_impl_ = stream_impl.Pass();
+ has_pending_open_ = false;
+ error = stream_impl_->Read(buf, buf_len, callback);
+ if (error != net::ERR_IO_PENDING)
+ callback.Run(error);
+}
+
+} // namespace webkit_blob