summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/child/resource_dispatcher_unittest.cc1
-rw-r--r--net/base/upload_data.cc37
-rw-r--r--net/base/upload_data.h83
-rw-r--r--net/base/upload_file_element_reader.cc48
-rw-r--r--net/base/upload_file_element_reader.h31
-rw-r--r--net/base/upload_file_element_reader_unittest.cc133
-rw-r--r--net/net.gyp2
7 files changed, 335 insertions, 0 deletions
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc
index c0a2ba1..349ce8c 100644
--- a/content/child/resource_dispatcher_unittest.cc
+++ b/content/child/resource_dispatcher_unittest.cc
@@ -14,6 +14,7 @@
#include "content/common/resource_messages.h"
#include "content/public/common/resource_response.h"
#include "net/base/net_errors.h"
+#include "net/base/upload_data.h"
#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/common/appcache/appcache_interfaces.h"
diff --git a/net/base/upload_data.cc b/net/base/upload_data.cc
new file mode 100644
index 0000000..48cb202
--- /dev/null
+++ b/net/base/upload_data.cc
@@ -0,0 +1,37 @@
+// 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 "net/base/upload_data.h"
+
+#include "base/logging.h"
+
+namespace net {
+
+UploadData::UploadData()
+ : identifier_(0),
+ is_chunked_(false),
+ last_chunk_appended_(false) {
+}
+
+void UploadData::AppendBytes(const char* bytes, int bytes_len) {
+ DCHECK(!is_chunked_);
+ if (bytes_len > 0) {
+ elements_.push_back(new UploadElement());
+ elements_.back()->SetToBytes(bytes, bytes_len);
+ }
+}
+
+void UploadData::AppendFileRange(const base::FilePath& file_path,
+ uint64 offset, uint64 length,
+ const base::Time& expected_modification_time) {
+ DCHECK(!is_chunked_);
+ elements_.push_back(new UploadElement());
+ elements_.back()->SetToFilePathRange(file_path, offset, length,
+ expected_modification_time);
+}
+
+UploadData::~UploadData() {
+}
+
+} // namespace net
diff --git a/net/base/upload_data.h b/net/base/upload_data.h
new file mode 100644
index 0000000..b782ab4
--- /dev/null
+++ b/net/base/upload_data.h
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef NET_BASE_UPLOAD_DATA_H_
+#define NET_BASE_UPLOAD_DATA_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
+#include "base/supports_user_data.h"
+#include "net/base/net_export.h"
+#include "net/base/upload_element.h"
+
+namespace base {
+class FilePath;
+class Time;
+} // namespace base
+
+namespace net {
+
+//-----------------------------------------------------------------------------
+// A very concrete class representing the data to be uploaded as part of a
+// URLRequest.
+//
+// Until there is a more abstract class for this, this one derives from
+// SupportsUserData to allow users to stash random data by
+// key and ensure its destruction when UploadData is finally deleted.
+class NET_EXPORT UploadData
+ : public base::RefCounted<UploadData>,
+ public base::SupportsUserData {
+ public:
+ UploadData();
+
+ void AppendBytes(const char* bytes, int bytes_len);
+
+ void AppendFileRange(const base::FilePath& file_path,
+ uint64 offset, uint64 length,
+ const base::Time& expected_modification_time);
+
+ // Initializes the object to send chunks of upload data over time rather
+ // than all at once. Chunked data may only contain bytes, not files.
+ void set_is_chunked(bool set) { is_chunked_ = set; }
+ bool is_chunked() const { return is_chunked_; }
+
+ // set_last_chunk_appended() is only used for serialization.
+ void set_last_chunk_appended(bool set) { last_chunk_appended_ = set; }
+ bool last_chunk_appended() const { return last_chunk_appended_; }
+
+ const ScopedVector<UploadElement>& elements() const {
+ return elements_;
+ }
+
+ ScopedVector<UploadElement>* elements_mutable() {
+ return &elements_;
+ }
+
+ void swap_elements(ScopedVector<UploadElement>* elements) {
+ elements_.swap(*elements);
+ }
+
+ // Identifies a particular upload instance, which is used by the cache to
+ // formulate a cache key. This value should be unique across browser
+ // sessions. A value of 0 is used to indicate an unspecified identifier.
+ void set_identifier(int64 id) { identifier_ = id; }
+ int64 identifier() const { return identifier_; }
+
+ private:
+ friend class base::RefCounted<UploadData>;
+
+ virtual ~UploadData();
+
+ ScopedVector<UploadElement> elements_;
+ int64 identifier_;
+ bool is_chunked_;
+ bool last_chunk_appended_;
+
+ DISALLOW_COPY_AND_ASSIGN(UploadData);
+};
+
+} // namespace net
+
+#endif // NET_BASE_UPLOAD_DATA_H_
diff --git a/net/base/upload_file_element_reader.cc b/net/base/upload_file_element_reader.cc
index 82159e4..f320157 100644
--- a/net/base/upload_file_element_reader.cc
+++ b/net/base/upload_file_element_reader.cc
@@ -247,4 +247,52 @@ UploadFileElementReader::ScopedOverridingContentLengthForTests::
overriding_content_length = 0;
}
+UploadFileElementReaderSync::UploadFileElementReaderSync(
+ const base::FilePath& path,
+ uint64 range_offset,
+ uint64 range_length,
+ const base::Time& expected_modification_time)
+ : path_(path),
+ range_offset_(range_offset),
+ range_length_(range_length),
+ expected_modification_time_(expected_modification_time),
+ content_length_(0),
+ bytes_remaining_(0) {
+}
+
+UploadFileElementReaderSync::~UploadFileElementReaderSync() {
+}
+
+int UploadFileElementReaderSync::Init(const CompletionCallback& callback) {
+ bytes_remaining_ = 0;
+ content_length_ = 0;
+ file_stream_.reset();
+
+ const int result = InitInternal(path_, range_offset_, range_length_,
+ expected_modification_time_,
+ &file_stream_, &content_length_);
+ bytes_remaining_ = GetContentLength();
+ return result;
+}
+
+uint64 UploadFileElementReaderSync::GetContentLength() const {
+ return content_length_;
+}
+
+uint64 UploadFileElementReaderSync::BytesRemaining() const {
+ return bytes_remaining_;
+}
+
+int UploadFileElementReaderSync::Read(IOBuffer* buf,
+ int buf_length,
+ const CompletionCallback& callback) {
+ const int result = ReadInternal(buf, buf_length, BytesRemaining(),
+ file_stream_.get());
+ if (result > 0) {
+ DCHECK_GE(bytes_remaining_, static_cast<uint64>(result));
+ bytes_remaining_ -= result;
+ }
+ return result;
+}
+
} // namespace net
diff --git a/net/base/upload_file_element_reader.h b/net/base/upload_file_element_reader.h
index 2c8ef10..a805c7a 100644
--- a/net/base/upload_file_element_reader.h
+++ b/net/base/upload_file_element_reader.h
@@ -106,6 +106,37 @@ class NET_EXPORT UploadFileElementReader : public UploadElementReader {
DISALLOW_COPY_AND_ASSIGN(UploadFileElementReader);
};
+// An UploadElementReader implementation for file which performs file operation
+// synchronously.
+// Use this class only if the thread is IO allowed.
+class NET_EXPORT UploadFileElementReaderSync : public UploadElementReader {
+ public:
+ UploadFileElementReaderSync(const base::FilePath& path,
+ uint64 range_offset,
+ uint64 range_length,
+ const base::Time& expected_modification_time);
+ virtual ~UploadFileElementReaderSync();
+
+ // UploadElementReader overrides:
+ virtual int Init(const CompletionCallback& callback) OVERRIDE;
+ virtual uint64 GetContentLength() const OVERRIDE;
+ virtual uint64 BytesRemaining() const OVERRIDE;
+ virtual int Read(IOBuffer* buf,
+ int buf_length,
+ const CompletionCallback& callback) OVERRIDE;
+
+ private:
+ const base::FilePath path_;
+ const uint64 range_offset_;
+ const uint64 range_length_;
+ const base::Time expected_modification_time_;
+ scoped_ptr<FileStream> file_stream_;
+ uint64 content_length_;
+ uint64 bytes_remaining_;
+
+ DISALLOW_COPY_AND_ASSIGN(UploadFileElementReaderSync);
+};
+
} // namespace net
#endif // NET_BASE_UPLOAD_FILE_ELEMENT_READER_H_
diff --git a/net/base/upload_file_element_reader_unittest.cc b/net/base/upload_file_element_reader_unittest.cc
index d98262b..52f0f27 100644
--- a/net/base/upload_file_element_reader_unittest.cc
+++ b/net/base/upload_file_element_reader_unittest.cc
@@ -234,4 +234,137 @@ TEST_F(UploadFileElementReaderTest, WrongPath) {
EXPECT_EQ(ERR_FILE_NOT_FOUND, init_callback.WaitForResult());
}
+
+class UploadFileElementReaderSyncTest : public PlatformTest {
+ protected:
+ virtual void SetUp() OVERRIDE {
+ // Some tests (*.ReadPartially) rely on bytes_.size() being even.
+ const char kData[] = "123456789abcdefghi";
+ bytes_.assign(kData, kData + arraysize(kData) - 1);
+
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
+ &temp_file_path_));
+ ASSERT_EQ(
+ static_cast<int>(bytes_.size()),
+ file_util::WriteFile(temp_file_path_, &bytes_[0], bytes_.size()));
+
+ reader_.reset(new UploadFileElementReaderSync(
+ temp_file_path_, 0, kuint64max, base::Time()));
+ ASSERT_EQ(OK, reader_->Init(CompletionCallback()));
+ EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
+ EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
+ EXPECT_FALSE(reader_->IsInMemory());
+ }
+
+ std::vector<char> bytes_;
+ scoped_ptr<UploadElementReader> reader_;
+ base::ScopedTempDir temp_dir_;
+ base::FilePath temp_file_path_;
+};
+
+TEST_F(UploadFileElementReaderSyncTest, ReadPartially) {
+ const size_t kHalfSize = bytes_.size() / 2;
+ ASSERT_EQ(bytes_.size(), kHalfSize * 2);
+ std::vector<char> buf(kHalfSize);
+ scoped_refptr<IOBuffer> wrapped_buffer = new WrappedIOBuffer(&buf[0]);
+ EXPECT_EQ(
+ static_cast<int>(buf.size()),
+ reader_->Read(wrapped_buffer.get(), buf.size(), CompletionCallback()));
+ EXPECT_EQ(bytes_.size() - buf.size(), reader_->BytesRemaining());
+ EXPECT_EQ(std::vector<char>(bytes_.begin(), bytes_.begin() + kHalfSize), buf);
+
+ EXPECT_EQ(
+ static_cast<int>(buf.size()),
+ reader_->Read(wrapped_buffer.get(), buf.size(), CompletionCallback()));
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_EQ(std::vector<char>(bytes_.begin() + kHalfSize, bytes_.end()), buf);
+}
+
+TEST_F(UploadFileElementReaderSyncTest, ReadAll) {
+ std::vector<char> buf(bytes_.size());
+ scoped_refptr<IOBuffer> wrapped_buffer = new WrappedIOBuffer(&buf[0]);
+ EXPECT_EQ(
+ static_cast<int>(buf.size()),
+ reader_->Read(wrapped_buffer.get(), buf.size(), CompletionCallback()));
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_EQ(bytes_, buf);
+ // Try to read again.
+ EXPECT_EQ(
+ 0, reader_->Read(wrapped_buffer.get(), buf.size(), CompletionCallback()));
+}
+
+TEST_F(UploadFileElementReaderSyncTest, ReadTooMuch) {
+ const size_t kTooLargeSize = bytes_.size() * 2;
+ std::vector<char> buf(kTooLargeSize);
+ scoped_refptr<IOBuffer> wrapped_buffer = new WrappedIOBuffer(&buf[0]);
+ EXPECT_EQ(
+ static_cast<int>(bytes_.size()),
+ reader_->Read(wrapped_buffer.get(), buf.size(), CompletionCallback()));
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ buf.resize(bytes_.size()); // Resize to compare.
+ EXPECT_EQ(bytes_, buf);
+}
+
+TEST_F(UploadFileElementReaderSyncTest, MultipleInit) {
+ std::vector<char> buf(bytes_.size());
+ scoped_refptr<IOBuffer> wrapped_buffer = new WrappedIOBuffer(&buf[0]);
+
+ // Read all.
+ EXPECT_EQ(
+ static_cast<int>(buf.size()),
+ reader_->Read(wrapped_buffer.get(), buf.size(), CompletionCallback()));
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_EQ(bytes_, buf);
+
+ // Call Init() again to reset the state.
+ ASSERT_EQ(OK, reader_->Init(CompletionCallback()));
+ EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
+ EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
+
+ // Read again.
+ EXPECT_EQ(
+ static_cast<int>(buf.size()),
+ reader_->Read(wrapped_buffer.get(), buf.size(), CompletionCallback()));
+ EXPECT_EQ(0U, reader_->BytesRemaining());
+ EXPECT_EQ(bytes_, buf);
+}
+
+TEST_F(UploadFileElementReaderSyncTest, Range) {
+ const uint64 kOffset = 2;
+ const uint64 kLength = bytes_.size() - kOffset * 3;
+ reader_.reset(new UploadFileElementReaderSync(
+ temp_file_path_, kOffset, kLength, base::Time()));
+ ASSERT_EQ(OK, reader_->Init(CompletionCallback()));
+ EXPECT_EQ(kLength, reader_->GetContentLength());
+ EXPECT_EQ(kLength, reader_->BytesRemaining());
+ std::vector<char> buf(kLength);
+ scoped_refptr<IOBuffer> wrapped_buffer = new WrappedIOBuffer(&buf[0]);
+ EXPECT_EQ(static_cast<int>(kLength),
+ reader_->Read(wrapped_buffer.get(), kLength, CompletionCallback()));
+ const std::vector<char> expected(bytes_.begin() + kOffset,
+ bytes_.begin() + kOffset + kLength);
+ EXPECT_EQ(expected, buf);
+}
+
+TEST_F(UploadFileElementReaderSyncTest, FileChanged) {
+ base::File::Info info;
+ ASSERT_TRUE(base::GetFileInfo(temp_file_path_, &info));
+
+ // Expect one second before the actual modification time to simulate change.
+ const base::Time expected_modification_time =
+ info.last_modified - base::TimeDelta::FromSeconds(1);
+ reader_.reset(new UploadFileElementReaderSync(
+ temp_file_path_, 0, kuint64max, expected_modification_time));
+ EXPECT_EQ(ERR_UPLOAD_FILE_CHANGED, reader_->Init(CompletionCallback()));
+}
+
+TEST_F(UploadFileElementReaderSyncTest, WrongPath) {
+ const base::FilePath wrong_path(FILE_PATH_LITERAL("wrong_path"));
+ reader_.reset(new UploadFileElementReaderSync(
+ wrong_path, 0, kuint64max, base::Time()));
+ ASSERT_EQ(ERR_FILE_NOT_FOUND, reader_->Init(CompletionCallback()));
+}
+
} // namespace net
diff --git a/net/net.gyp b/net/net.gyp
index 5a884e2..d3952ef 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -220,6 +220,8 @@
'base/test_data_stream.h',
'base/upload_bytes_element_reader.cc',
'base/upload_bytes_element_reader.h',
+ 'base/upload_data.cc',
+ 'base/upload_data.h',
'base/upload_data_stream.cc',
'base/upload_data_stream.h',
'base/upload_element.cc',