summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorhashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-11 04:50:16 +0000
committerhashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-11 04:50:16 +0000
commit16353271e5229a678ea6c4faa2e8f7b06f5599a6 (patch)
treedf4cb2c5eff84976d29c305581213e9b3bda49ff /webkit
parenta70fcc778be6675b740f6a921a9d69bdda7f9a1c (diff)
downloadchromium_src-16353271e5229a678ea6c4faa2e8f7b06f5599a6.zip
chromium_src-16353271e5229a678ea6c4faa2e8f7b06f5599a6.tar.gz
chromium_src-16353271e5229a678ea6c4faa2e8f7b06f5599a6.tar.bz2
webkit: Add UploadFileSystemFileElementReader
BUG=141834 TEST=content_unittests --gtest_filter="UploadFileSystemFileElementReaderTest.*" TBR=jam@chromium.org for content/content_tests.gypi Review URL: https://codereview.chromium.org/11818017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@176264 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r--webkit/fileapi/upload_file_system_file_element_reader.cc111
-rw-r--r--webkit/fileapi/upload_file_system_file_element_reader.h64
-rw-r--r--webkit/fileapi/upload_file_system_file_element_reader_unittest.cc286
-rw-r--r--webkit/fileapi/webkit_fileapi.gypi2
4 files changed, 463 insertions, 0 deletions
diff --git a/webkit/fileapi/upload_file_system_file_element_reader.cc b/webkit/fileapi/upload_file_system_file_element_reader.cc
new file mode 100644
index 0000000..212640a
--- /dev/null
+++ b/webkit/fileapi/upload_file_system_file_element_reader.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2013 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/fileapi/upload_file_system_file_element_reader.h"
+
+#include "base/bind.h"
+#include "net/base/net_errors.h"
+#include "webkit/blob/file_stream_reader.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_url.h"
+
+namespace fileapi {
+
+UploadFileSystemFileElementReader::UploadFileSystemFileElementReader(
+ FileSystemContext* file_system_context,
+ const GURL& url,
+ uint64 range_offset,
+ uint64 range_length,
+ const base::Time& expected_modification_time)
+ : file_system_context_(file_system_context),
+ url_(url),
+ range_offset_(range_offset),
+ range_length_(range_length),
+ expected_modification_time_(expected_modification_time),
+ stream_length_(0),
+ position_(0),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+}
+
+UploadFileSystemFileElementReader::~UploadFileSystemFileElementReader() {
+}
+
+int UploadFileSystemFileElementReader::Init(
+ const net::CompletionCallback& callback) {
+ // Reset states.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ stream_length_ = 0;
+ position_ = 0;
+
+ // Initialize the stream reader and the length.
+ stream_reader_.reset(
+ file_system_context_->CreateFileStreamReader(
+ FileSystemURL(url_), range_offset_, expected_modification_time_));
+ DCHECK(stream_reader_);
+
+ const int result = stream_reader_->GetLength(
+ base::Bind(&UploadFileSystemFileElementReader::OnGetLength,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+ if (result >= 0) {
+ stream_length_ = result;
+ return net::OK;
+ }
+ return result;
+}
+
+uint64 UploadFileSystemFileElementReader::GetContentLength() const {
+ return std::min(stream_length_, range_length_);
+}
+
+uint64 UploadFileSystemFileElementReader::BytesRemaining() const {
+ return GetContentLength() - position_;
+}
+
+int UploadFileSystemFileElementReader::Read(
+ net::IOBuffer* buf,
+ int buf_length,
+ const net::CompletionCallback& callback) {
+ DCHECK_LT(0, buf_length);
+ DCHECK(stream_reader_);
+
+ const uint64 num_bytes_to_read =
+ std::min(BytesRemaining(), static_cast<uint64>(buf_length));
+
+ if (num_bytes_to_read == 0)
+ return 0;
+
+ const int result = stream_reader_->Read(
+ buf, num_bytes_to_read,
+ base::Bind(&UploadFileSystemFileElementReader::OnRead,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+ if (result >= 0)
+ OnRead(net::CompletionCallback(), result);
+ return result;
+}
+
+void UploadFileSystemFileElementReader::OnGetLength(
+ const net::CompletionCallback& callback,
+ int64 result) {
+ if (result >= 0) {
+ stream_length_ = result;
+ callback.Run(net::OK);
+ return;
+ }
+ callback.Run(result);
+}
+
+void UploadFileSystemFileElementReader::OnRead(
+ const net::CompletionCallback& callback,
+ int result) {
+ if (result > 0) {
+ position_ += result;
+ DCHECK_LE(position_, GetContentLength());
+ }
+ if (!callback.is_null())
+ callback.Run(result);
+}
+
+} // namespace fileapi
diff --git a/webkit/fileapi/upload_file_system_file_element_reader.h b/webkit/fileapi/upload_file_system_file_element_reader.h
new file mode 100644
index 0000000..19b3db1
--- /dev/null
+++ b/webkit/fileapi/upload_file_system_file_element_reader.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2013 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 WEBKIT_FILEAPI_UPLOAD_FILE_SYSTEM_FILE_ELEMENT_READER_H_
+#define WEBKIT_FILEAPI_UPLOAD_FILE_SYSTEM_FILE_ELEMENT_READER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/time.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/upload_element_reader.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace webkit_blob {
+class FileStreamReader;
+}
+
+namespace fileapi {
+
+class FileSystemContext;
+
+// An UploadElementReader implementation for filesystem file.
+class WEBKIT_STORAGE_EXPORT UploadFileSystemFileElementReader
+ : public net::UploadElementReader {
+ public:
+ UploadFileSystemFileElementReader(
+ FileSystemContext* file_system_context,
+ const GURL& url,
+ uint64 range_offset,
+ uint64 range_length,
+ const base::Time& expected_modification_time);
+ virtual ~UploadFileSystemFileElementReader();
+
+ // UploadElementReader overrides:
+ virtual int Init(const net::CompletionCallback& callback) OVERRIDE;
+ virtual uint64 GetContentLength() const OVERRIDE;
+ virtual uint64 BytesRemaining() const OVERRIDE;
+ virtual int Read(net::IOBuffer* buf,
+ int buf_length,
+ const net::CompletionCallback& callback) OVERRIDE;
+
+ private:
+ void OnGetLength(const net::CompletionCallback& callback, int64 result);
+ void OnRead(const net::CompletionCallback& callback, int result);
+
+ scoped_refptr<FileSystemContext> file_system_context_;
+ const GURL url_;
+ const uint64 range_offset_;
+ const uint64 range_length_;
+ const base::Time expected_modification_time_;
+
+ scoped_ptr<webkit_blob::FileStreamReader> stream_reader_;
+
+ uint64 stream_length_;
+ uint64 position_;
+
+ base::WeakPtrFactory<UploadFileSystemFileElementReader> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(UploadFileSystemFileElementReader);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_FILEAPI_UPLOAD_FILE_SYSTEM_FILE_ELEMENT_READER_H_
diff --git a/webkit/fileapi/upload_file_system_file_element_reader_unittest.cc b/webkit/fileapi/upload_file_system_file_element_reader_unittest.cc
new file mode 100644
index 0000000..ba9ce01
--- /dev/null
+++ b/webkit/fileapi/upload_file_system_file_element_reader_unittest.cc
@@ -0,0 +1,286 @@
+// Copyright (c) 2013 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/fileapi/upload_file_system_file_element_reader.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop.h"
+#include "net/base/io_buffer.h"
+#include "net/base/test_completion_callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_file_util.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/fileapi/file_system_task_runners.h"
+#include "webkit/fileapi/file_system_url.h"
+#include "webkit/fileapi/mock_file_system_options.h"
+
+namespace fileapi {
+
+namespace {
+
+const char kFileSystemURLOrigin[] = "http://remote";
+const fileapi::FileSystemType kFileSystemType =
+ fileapi::kFileSystemTypeTemporary;
+
+} // namespace
+
+class UploadFileSystemFileElementReaderTest : public testing::Test {
+ public:
+ UploadFileSystemFileElementReaderTest()
+ : message_loop_(MessageLoop::TYPE_IO) {}
+
+ virtual void SetUp() OVERRIDE {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ file_system_context_ = new fileapi::FileSystemContext(
+ fileapi::FileSystemTaskRunners::CreateMockTaskRunners(),
+ NULL,
+ NULL,
+ temp_dir_.path(),
+ fileapi::CreateDisallowFileAccessOptions());
+
+ file_system_context_->OpenFileSystem(
+ GURL(kFileSystemURLOrigin),
+ kFileSystemType,
+ true, // create
+ base::Bind(&UploadFileSystemFileElementReaderTest::OnValidateFileSystem,
+ base::Unretained(this)));
+ MessageLoop::current()->RunUntilIdle();
+ ASSERT_TRUE(file_system_root_url_.is_valid());
+
+ // Prepare a file on file system.
+ const char kTestData[] = "abcdefghijklmnop0123456789";
+ file_data_.assign(kTestData, kTestData + arraysize(kTestData) - 1);
+ const char kFilename[] = "File.dat";
+ file_url_ = GetFileSystemURL(kFilename);
+ WriteFileSystemFile(kFilename, &file_data_[0], file_data_.size(),
+ &file_modification_time_);
+
+ // Create and initialize a reader.
+ reader_.reset(new UploadFileSystemFileElementReader(
+ file_system_context_, file_url_, 0, kuint64max,
+ file_modification_time_));
+ net::TestCompletionCallback callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(callback.callback()));
+ EXPECT_EQ(net::OK, callback.WaitForResult());
+ EXPECT_EQ(file_data_.size(), reader_->GetContentLength());
+ EXPECT_EQ(file_data_.size(), reader_->BytesRemaining());
+ EXPECT_FALSE(reader_->IsInMemory());
+ }
+
+ protected:
+ GURL GetFileSystemURL(const std::string& filename) {
+ return GURL(file_system_root_url_.spec() + filename);
+ }
+
+ void WriteFileSystemFile(const std::string& filename,
+ const char* buf,
+ int buf_size,
+ base::Time* modification_time) {
+ fileapi::FileSystemURL url(GURL(kFileSystemURLOrigin),
+ kFileSystemType,
+ FilePath().AppendASCII(filename));
+
+ fileapi::FileSystemFileUtil* file_util =
+ file_system_context_->GetFileUtil(kFileSystemType);
+
+ fileapi::FileSystemOperationContext context(file_system_context_);
+ context.set_allowed_bytes_growth(1024);
+
+ base::PlatformFile handle = base::kInvalidPlatformFileValue;
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK, file_util->CreateOrOpen(
+ &context,
+ url,
+ base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE,
+ &handle,
+ &created));
+ EXPECT_TRUE(created);
+ ASSERT_NE(base::kInvalidPlatformFileValue, handle);
+ ASSERT_EQ(buf_size,
+ base::WritePlatformFile(handle, 0 /* offset */, buf, buf_size));
+ base::ClosePlatformFile(handle);
+
+ base::PlatformFileInfo file_info;
+ FilePath platform_path;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ file_util->GetFileInfo(&context, url, &file_info,
+ &platform_path));
+ *modification_time = file_info.last_modified;
+ }
+
+ void OnValidateFileSystem(base::PlatformFileError result,
+ const std::string& name,
+ const GURL& root) {
+ ASSERT_EQ(base::PLATFORM_FILE_OK, result);
+ ASSERT_TRUE(root.is_valid());
+ file_system_root_url_ = root;
+ }
+
+ MessageLoop message_loop_;
+ base::ScopedTempDir temp_dir_;
+ scoped_refptr<FileSystemContext> file_system_context_;
+ GURL file_system_root_url_;
+ std::vector<char> file_data_;
+ GURL file_url_;
+ base::Time file_modification_time_;
+ scoped_ptr<UploadFileSystemFileElementReader> reader_;
+};
+
+TEST_F(UploadFileSystemFileElementReaderTest, ReadAll) {
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(file_data_.size());
+ net::TestCompletionCallback read_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback.callback()));
+ EXPECT_EQ(buf->size(), read_callback.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
+ // Try to read again.
+ EXPECT_EQ(0, reader_->Read(buf, buf->size(), read_callback.callback()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, ReadPartially) {
+ const size_t kHalfSize = file_data_.size() / 2;
+ ASSERT_EQ(file_data_.size(), kHalfSize * 2);
+
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(kHalfSize);
+
+ net::TestCompletionCallback read_callback1;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback1.callback()));
+ EXPECT_EQ(buf->size(), read_callback1.WaitForResult());
+ EXPECT_EQ(file_data_.size() - buf->size(), reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.begin() + kHalfSize,
+ buf->data()));
+
+ net::TestCompletionCallback read_callback2;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback2.callback()));
+ EXPECT_EQ(buf->size(), read_callback2.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin() + kHalfSize, file_data_.end(),
+ buf->data()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, ReadTooMuch) {
+ const size_t kTooLargeSize = file_data_.size() * 2;
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(kTooLargeSize);
+ net::TestCompletionCallback read_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback.callback()));
+ EXPECT_EQ(static_cast<int>(file_data_.size()), read_callback.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, MultipleInit) {
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(file_data_.size());
+
+ // Read all.
+ net::TestCompletionCallback read_callback1;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback1.callback()));
+ EXPECT_EQ(buf->size(), read_callback1.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
+
+ // Call Init() again to reset the state.
+ net::TestCompletionCallback init_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
+ EXPECT_EQ(net::OK, init_callback.WaitForResult());
+ EXPECT_EQ(file_data_.size(), reader_->GetContentLength());
+ EXPECT_EQ(file_data_.size(), reader_->BytesRemaining());
+
+ // Read again.
+ net::TestCompletionCallback read_callback2;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback2.callback()));
+ EXPECT_EQ(buf->size(), read_callback2.WaitForResult());
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, InitDuringAsyncOperation) {
+ scoped_refptr<net::IOBufferWithSize> buf =
+ new net::IOBufferWithSize(file_data_.size());
+
+ // Start reading all.
+ net::TestCompletionCallback read_callback1;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback1.callback()));
+
+ // Call Init to cancel the previous read.
+ net::TestCompletionCallback init_callback1;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback1.callback()));
+
+ // Call Init again to cancel the previous init.
+ net::TestCompletionCallback init_callback2;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback2.callback()));
+ EXPECT_EQ(net::OK, init_callback2.WaitForResult());
+ EXPECT_EQ(file_data_.size(), reader_->GetContentLength());
+ EXPECT_EQ(file_data_.size(), reader_->BytesRemaining());
+
+ // Read half.
+ scoped_refptr<net::IOBufferWithSize> buf2 =
+ new net::IOBufferWithSize(file_data_.size() / 2);
+ net::TestCompletionCallback read_callback2;
+ EXPECT_EQ(net::ERR_IO_PENDING, reader_->Read(buf2, buf2->size(),
+ read_callback2.callback()));
+ EXPECT_EQ(buf2->size(), read_callback2.WaitForResult());
+ EXPECT_EQ(file_data_.size() - buf2->size(), reader_->BytesRemaining());
+ EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.begin() + buf2->size(),
+ buf2->data()));
+
+ // Make sure callbacks are not called for cancelled operations.
+ EXPECT_FALSE(read_callback1.have_result());
+ EXPECT_FALSE(init_callback1.have_result());
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, Range) {
+ const int kOffset = 2;
+ const int kLength = file_data_.size() - kOffset * 3;
+ reader_.reset(new UploadFileSystemFileElementReader(
+ file_system_context_, file_url_, kOffset, kLength, base::Time()));
+ net::TestCompletionCallback init_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
+ EXPECT_EQ(net::OK, init_callback.WaitForResult());
+ EXPECT_EQ(static_cast<uint64>(kLength), reader_->GetContentLength());
+ EXPECT_EQ(static_cast<uint64>(kLength), reader_->BytesRemaining());
+ scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(kLength);
+ net::TestCompletionCallback read_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Read(buf, buf->size(),
+ read_callback.callback()));
+ EXPECT_EQ(kLength, read_callback.WaitForResult());
+ EXPECT_TRUE(std::equal(file_data_.begin() + kOffset,
+ file_data_.begin() + kOffset + kLength,
+ buf->data()));
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, FileChanged) {
+ // Expect one second before the actual modification time to simulate change.
+ const base::Time expected_modification_time =
+ file_modification_time_ - base::TimeDelta::FromSeconds(1);
+ reader_.reset(new UploadFileSystemFileElementReader(
+ file_system_context_, file_url_, 0, kuint64max,
+ expected_modification_time));
+ net::TestCompletionCallback init_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
+ EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED, init_callback.WaitForResult());
+}
+
+TEST_F(UploadFileSystemFileElementReaderTest, WrongURL) {
+ const GURL wrong_url = GetFileSystemURL("wrong_file_name.dat");
+ reader_.reset(new UploadFileSystemFileElementReader(
+ file_system_context_, wrong_url, 0, kuint64max, base::Time()));
+ net::TestCompletionCallback init_callback;
+ ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
+ EXPECT_EQ(net::ERR_FILE_NOT_FOUND, init_callback.WaitForResult());
+}
+
+} // namespace fileapi
diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi
index 69162bf..39288ee 100644
--- a/webkit/fileapi/webkit_fileapi.gypi
+++ b/webkit/fileapi/webkit_fileapi.gypi
@@ -106,6 +106,8 @@
'../fileapi/task_runner_bound_observer_list.h',
'../fileapi/test_mount_point_provider.cc',
'../fileapi/test_mount_point_provider.h',
+ '../fileapi/upload_file_system_file_element_reader.cc',
+ '../fileapi/upload_file_system_file_element_reader.h',
'../fileapi/webfilewriter_base.cc',
'../fileapi/webfilewriter_base.h',
],