summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorrdsmith@chromium.org <rdsmith@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-04 18:20:56 +0000
committerrdsmith@chromium.org <rdsmith@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-04 18:20:56 +0000
commitd7db4f62b576074b5b5f62d156e335855dc51bdb (patch)
treeab1dbcbdf199ac0a8eaec3e2ad49753d216d42b3 /content
parentf7bc735b65da49b5df9fb82a69dcbab08ebb1061 (diff)
downloadchromium_src-d7db4f62b576074b5b5f62d156e335855dc51bdb.zip
chromium_src-d7db4f62b576074b5b5f62d156e335855dc51bdb.tar.gz
chromium_src-d7db4f62b576074b5b5f62d156e335855dc51bdb.tar.bz2
Use ByteStream in downloads system to decouple source and sink.
BUG=123192 BUG=93006 BUG=111588 Review URL: https://chromiumcodereview.appspot.com/10392111 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140328 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/download/base_file.cc7
-rw-r--r--content/browser/download/byte_stream.cc100
-rw-r--r--content/browser/download/byte_stream.h26
-rw-r--r--content/browser/download/byte_stream_unittest.cc112
-rw-r--r--content/browser/download/download_buffer.cc71
-rw-r--r--content/browser/download/download_buffer.h70
-rw-r--r--content/browser/download/download_buffer_unittest.cc123
-rw-r--r--content/browser/download/download_file.h10
-rw-r--r--content/browser/download/download_file_impl.cc141
-rw-r--r--content/browser/download/download_file_impl.h33
-rw-r--r--content/browser/download/download_file_manager.cc128
-rw-r--r--content/browser/download/download_file_manager.h23
-rw-r--r--content/browser/download/download_file_manager_unittest.cc326
-rw-r--r--content/browser/download/download_file_unittest.cc278
-rw-r--r--content/browser/download/download_item_impl_unittest.cc31
-rw-r--r--content/browser/download/download_manager_impl_unittest.cc110
-rw-r--r--content/browser/download/download_net_log_parameters.cc16
-rw-r--r--content/browser/download/download_net_log_parameters.h17
-rw-r--r--content/browser/download/download_resource_handler.cc241
-rw-r--r--content/browser/download/download_resource_handler.h48
-rw-r--r--content/browser/download/download_stats.cc42
-rw-r--r--content/browser/download/download_stats.h14
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host_impl.cc2
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host_unittest.cc49
-rw-r--r--content/browser/renderer_host/x509_user_cert_resource_handler.cc23
-rw-r--r--content/browser/renderer_host/x509_user_cert_resource_handler.h7
-rw-r--r--content/content_browser.gypi2
-rw-r--r--content/content_tests.gypi1
-rw-r--r--content/test/test_file_error_injector.cc10
29 files changed, 951 insertions, 1110 deletions
diff --git a/content/browser/download/base_file.cc b/content/browser/download/base_file.cc
index 9516fb3..05dc9d3 100644
--- a/content/browser/download/base_file.cc
+++ b/content/browser/download/base_file.cc
@@ -272,13 +272,6 @@ net::Error BaseFile::AppendDataToFile(const char* data, size_t data_len) {
download_stats::APPEND_TO_DETACHED_FILE_COUNT);
}
- if (bound_net_log_.IsLoggingAllEvents()) {
- bound_net_log_.AddEvent(
- net::NetLog::TYPE_DOWNLOAD_FILE_WRITTEN,
- make_scoped_refptr(new net::NetLogIntegerParameter(
- "byte_count", data_len)));
- }
-
if (!file_stream_.get())
return LOG_ERROR("get", net::ERR_INVALID_HANDLE);
diff --git a/content/browser/download/byte_stream.cc b/content/browser/download/byte_stream.cc
index a5e06a7..381ae23 100644
--- a/content/browser/download/byte_stream.cc
+++ b/content/browser/download/byte_stream.cc
@@ -23,7 +23,7 @@ static const int kFractionBufferBeforeSending = 3;
// before we update the input window.
static const int kFractionReadBeforeWindowUpdate = 3;
-class ByteStreamOutputImpl;
+class ByteStreamReaderImpl;
// A poor man's weak pointer; a RefCountedThreadSafe boolean that can be
// cleared in an object destructor and accessed to check for object
@@ -44,30 +44,30 @@ struct LifetimeFlag : public base::RefCountedThreadSafe<LifetimeFlag> {
DISALLOW_COPY_AND_ASSIGN(LifetimeFlag);
};
-// For both ByteStreamInputImpl and ByteStreamOutputImpl, Construction and
+// For both ByteStreamWriterImpl and ByteStreamReaderImpl, Construction and
// SetPeer may happen anywhere; all other operations on each class must
// happen in the context of their SequencedTaskRunner.
-class ByteStreamInputImpl : public content::ByteStreamInput {
+class ByteStreamWriterImpl : public content::ByteStreamWriter {
public:
- ByteStreamInputImpl(scoped_refptr<base::SequencedTaskRunner> task_runner,
+ ByteStreamWriterImpl(scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<LifetimeFlag> lifetime_flag,
size_t buffer_size);
- virtual ~ByteStreamInputImpl();
+ virtual ~ByteStreamWriterImpl();
// Must be called before any operations are performed.
- void SetPeer(ByteStreamOutputImpl* peer,
+ void SetPeer(ByteStreamReaderImpl* peer,
scoped_refptr<base::SequencedTaskRunner> peer_task_runner,
scoped_refptr<LifetimeFlag> peer_lifetime_flag);
- // Overridden from ByteStreamInput.
+ // Overridden from ByteStreamWriter.
virtual bool Write(scoped_refptr<net::IOBuffer> buffer,
size_t byte_count) OVERRIDE;
virtual void Close(content::DownloadInterruptReason status) OVERRIDE;
virtual void RegisterCallback(const base::Closure& source_callback) OVERRIDE;
- // PostTask target from |ByteStreamOutputImpl::MaybeUpdateInput|.
+ // PostTask target from |ByteStreamReaderImpl::MaybeUpdateInput|.
static void UpdateWindow(scoped_refptr<LifetimeFlag> lifetime_flag,
- ByteStreamInputImpl* target,
+ ByteStreamWriterImpl* target,
size_t bytes_consumed);
private:
@@ -102,36 +102,36 @@ class ByteStreamInputImpl : public content::ByteStreamInput {
// Only valid to access on peer_task_runner_ if
// |*peer_lifetime_flag_ == true|
- ByteStreamOutputImpl* peer_;
+ ByteStreamReaderImpl* peer_;
};
-class ByteStreamOutputImpl : public content::ByteStreamOutput {
+class ByteStreamReaderImpl : public content::ByteStreamReader {
public:
- ByteStreamOutputImpl(scoped_refptr<base::SequencedTaskRunner> task_runner,
+ ByteStreamReaderImpl(scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<LifetimeFlag> lifetime_flag,
size_t buffer_size);
- virtual ~ByteStreamOutputImpl();
+ virtual ~ByteStreamReaderImpl();
// Must be called before any operations are performed.
- void SetPeer(ByteStreamInputImpl* peer,
+ void SetPeer(ByteStreamWriterImpl* peer,
scoped_refptr<base::SequencedTaskRunner> peer_task_runner,
scoped_refptr<LifetimeFlag> peer_lifetime_flag);
- // Overridden from ByteStreamOutput.
+ // Overridden from ByteStreamReader.
virtual StreamState Read(scoped_refptr<net::IOBuffer>* data,
size_t* length) OVERRIDE;
virtual content::DownloadInterruptReason GetStatus() const OVERRIDE;
virtual void RegisterCallback(const base::Closure& sink_callback) OVERRIDE;
- // PostTask target from |ByteStreamInputImpl::MaybePostToPeer| and
- // |ByteStreamInputImpl::Close|.
+ // PostTask target from |ByteStreamWriterImpl::MaybePostToPeer| and
+ // |ByteStreamWriterImpl::Close|.
// Receive data from our peer.
// static because it may be called after the object it is targeting
// has been destroyed. It may not access |*target|
// if |*object_lifetime_flag| is false.
static void TransferData(
scoped_refptr<LifetimeFlag> object_lifetime_flag,
- ByteStreamOutputImpl* target,
+ ByteStreamReaderImpl* target,
scoped_ptr<ContentVector> transfer_buffer,
size_t transfer_buffer_bytes,
bool source_complete,
@@ -178,10 +178,10 @@ class ByteStreamOutputImpl : public content::ByteStreamOutput {
// Only valid to access on peer_task_runner_ if
// |*peer_lifetime_flag_ == true|
- ByteStreamInputImpl* peer_;
+ ByteStreamWriterImpl* peer_;
};
-ByteStreamInputImpl::ByteStreamInputImpl(
+ByteStreamWriterImpl::ByteStreamWriterImpl(
scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<LifetimeFlag> lifetime_flag,
size_t buffer_size)
@@ -195,12 +195,12 @@ ByteStreamInputImpl::ByteStreamInputImpl(
my_lifetime_flag_->is_alive_ = true;
}
-ByteStreamInputImpl::~ByteStreamInputImpl() {
+ByteStreamWriterImpl::~ByteStreamWriterImpl() {
my_lifetime_flag_->is_alive_ = false;
}
-void ByteStreamInputImpl::SetPeer(
- ByteStreamOutputImpl* peer,
+void ByteStreamWriterImpl::SetPeer(
+ ByteStreamReaderImpl* peer,
scoped_refptr<base::SequencedTaskRunner> peer_task_runner,
scoped_refptr<LifetimeFlag> peer_lifetime_flag) {
peer_ = peer;
@@ -208,7 +208,7 @@ void ByteStreamInputImpl::SetPeer(
peer_lifetime_flag_ = peer_lifetime_flag;
}
-bool ByteStreamInputImpl::Write(
+bool ByteStreamWriterImpl::Write(
scoped_refptr<net::IOBuffer> buffer, size_t byte_count) {
DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
@@ -222,21 +222,21 @@ bool ByteStreamInputImpl::Write(
return (input_contents_size_ + output_size_used_ <= total_buffer_size_);
}
-void ByteStreamInputImpl::Close(
+void ByteStreamWriterImpl::Close(
content::DownloadInterruptReason status) {
DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
PostToPeer(true, status);
}
-void ByteStreamInputImpl::RegisterCallback(
+void ByteStreamWriterImpl::RegisterCallback(
const base::Closure& source_callback) {
DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
space_available_callback_ = source_callback;
}
// static
-void ByteStreamInputImpl::UpdateWindow(
- scoped_refptr<LifetimeFlag> lifetime_flag, ByteStreamInputImpl* target,
+void ByteStreamWriterImpl::UpdateWindow(
+ scoped_refptr<LifetimeFlag> lifetime_flag, ByteStreamWriterImpl* target,
size_t bytes_consumed) {
// If the target object isn't alive anymore, we do nothing.
if (!lifetime_flag->is_alive_) return;
@@ -244,7 +244,7 @@ void ByteStreamInputImpl::UpdateWindow(
target->UpdateWindowInternal(bytes_consumed);
}
-void ByteStreamInputImpl::UpdateWindowInternal(size_t bytes_consumed) {
+void ByteStreamWriterImpl::UpdateWindowInternal(size_t bytes_consumed) {
DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
DCHECK_GE(output_size_used_, bytes_consumed);
output_size_used_ -= bytes_consumed;
@@ -259,7 +259,7 @@ void ByteStreamInputImpl::UpdateWindowInternal(size_t bytes_consumed) {
space_available_callback_.Run();
}
-void ByteStreamInputImpl::PostToPeer(
+void ByteStreamWriterImpl::PostToPeer(
bool complete, content::DownloadInterruptReason status) {
DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
// Valid contexts in which to call.
@@ -276,7 +276,7 @@ void ByteStreamInputImpl::PostToPeer(
}
peer_task_runner_->PostTask(
FROM_HERE, base::Bind(
- &ByteStreamOutputImpl::TransferData,
+ &ByteStreamReaderImpl::TransferData,
peer_lifetime_flag_,
peer_,
base::Passed(transfer_buffer.Pass()),
@@ -285,7 +285,7 @@ void ByteStreamInputImpl::PostToPeer(
status));
}
-ByteStreamOutputImpl::ByteStreamOutputImpl(
+ByteStreamReaderImpl::ByteStreamReaderImpl(
scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<LifetimeFlag> lifetime_flag,
size_t buffer_size)
@@ -300,12 +300,12 @@ ByteStreamOutputImpl::ByteStreamOutputImpl(
my_lifetime_flag_->is_alive_ = true;
}
-ByteStreamOutputImpl::~ByteStreamOutputImpl() {
+ByteStreamReaderImpl::~ByteStreamReaderImpl() {
my_lifetime_flag_->is_alive_ = false;
}
-void ByteStreamOutputImpl::SetPeer(
- ByteStreamInputImpl* peer,
+void ByteStreamReaderImpl::SetPeer(
+ ByteStreamWriterImpl* peer,
scoped_refptr<base::SequencedTaskRunner> peer_task_runner,
scoped_refptr<LifetimeFlag> peer_lifetime_flag) {
peer_ = peer;
@@ -313,8 +313,8 @@ void ByteStreamOutputImpl::SetPeer(
peer_lifetime_flag_ = peer_lifetime_flag;
}
-ByteStreamOutputImpl::StreamState
-ByteStreamOutputImpl::Read(scoped_refptr<net::IOBuffer>* data,
+ByteStreamReaderImpl::StreamState
+ByteStreamReaderImpl::Read(scoped_refptr<net::IOBuffer>* data,
size_t* length) {
DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
@@ -334,13 +334,13 @@ ByteStreamOutputImpl::Read(scoped_refptr<net::IOBuffer>* data,
}
content::DownloadInterruptReason
-ByteStreamOutputImpl::GetStatus() const {
+ByteStreamReaderImpl::GetStatus() const {
DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
DCHECK(received_status_);
return status_;
}
-void ByteStreamOutputImpl::RegisterCallback(
+void ByteStreamReaderImpl::RegisterCallback(
const base::Closure& sink_callback) {
DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
@@ -348,9 +348,9 @@ void ByteStreamOutputImpl::RegisterCallback(
}
// static
-void ByteStreamOutputImpl::TransferData(
+void ByteStreamReaderImpl::TransferData(
scoped_refptr<LifetimeFlag> object_lifetime_flag,
- ByteStreamOutputImpl* target,
+ ByteStreamReaderImpl* target,
scoped_ptr<ContentVector> transfer_buffer,
size_t buffer_size,
bool source_complete,
@@ -362,7 +362,7 @@ void ByteStreamOutputImpl::TransferData(
transfer_buffer.Pass(), buffer_size, source_complete, status);
}
-void ByteStreamOutputImpl::TransferDataInternal(
+void ByteStreamReaderImpl::TransferDataInternal(
scoped_ptr<ContentVector> transfer_buffer,
size_t buffer_size,
bool source_complete,
@@ -393,7 +393,7 @@ void ByteStreamOutputImpl::TransferDataInternal(
// Decide whether or not to send the input a window update.
// Currently we do that whenever we've got unreported consumption
// greater than 1/3 of total size.
-void ByteStreamOutputImpl::MaybeUpdateInput() {
+void ByteStreamReaderImpl::MaybeUpdateInput() {
DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
if (unreported_consumed_bytes_ <=
@@ -402,7 +402,7 @@ void ByteStreamOutputImpl::MaybeUpdateInput() {
peer_task_runner_->PostTask(
FROM_HERE, base::Bind(
- &ByteStreamInputImpl::UpdateWindow,
+ &ByteStreamWriterImpl::UpdateWindow,
peer_lifetime_flag_,
peer_,
unreported_consumed_bytes_));
@@ -413,22 +413,22 @@ void ByteStreamOutputImpl::MaybeUpdateInput() {
namespace content {
-ByteStreamOutput::~ByteStreamOutput() { }
+ByteStreamReader::~ByteStreamReader() { }
-ByteStreamInput::~ByteStreamInput() { }
+ByteStreamWriter::~ByteStreamWriter() { }
void CreateByteStream(
scoped_refptr<base::SequencedTaskRunner> input_task_runner,
scoped_refptr<base::SequencedTaskRunner> output_task_runner,
size_t buffer_size,
- scoped_ptr<ByteStreamInput>* input,
- scoped_ptr<ByteStreamOutput>* output) {
+ scoped_ptr<ByteStreamWriter>* input,
+ scoped_ptr<ByteStreamReader>* output) {
scoped_refptr<LifetimeFlag> input_flag(new LifetimeFlag());
scoped_refptr<LifetimeFlag> output_flag(new LifetimeFlag());
- ByteStreamInputImpl* in = new ByteStreamInputImpl(
+ ByteStreamWriterImpl* in = new ByteStreamWriterImpl(
input_task_runner, input_flag, buffer_size);
- ByteStreamOutputImpl* out = new ByteStreamOutputImpl(
+ ByteStreamReaderImpl* out = new ByteStreamReaderImpl(
output_task_runner, output_flag, buffer_size);
in->SetPeer(out, output_task_runner, output_flag);
diff --git a/content/browser/download/byte_stream.h b/content/browser/download/byte_stream.h
index 8265b8d..f5be75a 100644
--- a/content/browser/download/byte_stream.h
+++ b/content/browser/download/byte_stream.h
@@ -26,15 +26,15 @@ namespace content {
// sink, which may be on different threads. It is intended to be the
// only connection between source and sink; they need have no
// direct awareness of each other aside from the byte stream. The source and
-// the sink have different interfaces to a byte stream, |ByteStreamInput|
-// and |ByteStreamOutput|. A pair of connected interfaces is generated by
+// the sink have different interfaces to a byte stream, |ByteStreamWriter|
+// and |ByteStreamReader|. A pair of connected interfaces is generated by
// calling |CreateByteStream|.
//
-// The source adds bytes to the bytestream via |ByteStreamInput::Write|
-// and the sink retrieves bytes already written via |ByteStreamOutput::Read|.
+// The source adds bytes to the bytestream via |ByteStreamWriter::Write|
+// and the sink retrieves bytes already written via |ByteStreamReader::Read|.
//
// When the source has no more data to add, it will call
-// |ByteStreamInput::Close| to indicate that. Errors at the source
+// |ByteStreamWriter::Close| to indicate that. Errors at the source
// are indicated to the sink via a non-DOWNLOAD_INTERRUPT_REASON_NONE code.
//
// Normally the source is not managed after the relationship is setup;
@@ -58,9 +58,9 @@ namespace content {
//
// Class methods are virtual to allow mocking for tests; these classes
// aren't intended to be base classes for other classes.
-class CONTENT_EXPORT ByteStreamInput {
+class CONTENT_EXPORT ByteStreamWriter {
public:
- virtual ~ByteStreamInput() = 0;
+ virtual ~ByteStreamWriter() = 0;
// Always adds the data passed into the ByteStream. Returns true
// if more data may be added without exceeding the class limit
@@ -75,21 +75,22 @@ public:
// Register a callback to be called when the stream transitions from
// full to having space available. The callback will always be
- // called on the task runner associated with the ByteStreamInput.
+ // called on the task runner associated with the ByteStreamWriter.
// This callback will only be called if a call to Write has previously
// returned false (i.e. the ByteStream has been filled).
// Multiple calls to this function are supported, though note that it
// is the callers responsibility to handle races with space becoming
// available (i.e. in the case of that race either of the before
// or after callbacks may be called).
+ // The callback will not be called after ByteStreamWriter destruction.
virtual void RegisterCallback(const base::Closure& source_callback) = 0;
};
-class CONTENT_EXPORT ByteStreamOutput {
+class CONTENT_EXPORT ByteStreamReader {
public:
enum StreamState { STREAM_EMPTY, STREAM_HAS_DATA, STREAM_COMPLETE };
- virtual ~ByteStreamOutput() = 0;
+ virtual ~ByteStreamReader() = 0;
// Returns STREAM_EMPTY if there is no data on the ByteStream and
// Close() has not been called, and STREAM_COMPLETE if there
@@ -109,6 +110,7 @@ class CONTENT_EXPORT ByteStreamOutput {
// though note that it is the callers responsibility to handle races
// with data becoming available (i.e. in the case of that race
// either of the before or after callbacks may be called).
+ // The callback will not be called after ByteStreamReader destruction.
virtual void RegisterCallback(const base::Closure& sink_callback) = 0;
};
@@ -116,8 +118,8 @@ CONTENT_EXPORT void CreateByteStream(
scoped_refptr<base::SequencedTaskRunner> input_task_runner,
scoped_refptr<base::SequencedTaskRunner> output_task_runner,
size_t buffer_size,
- scoped_ptr<ByteStreamInput>* input,
- scoped_ptr<ByteStreamOutput>* output);
+ scoped_ptr<ByteStreamWriter>* input,
+ scoped_ptr<ByteStreamReader>* output);
} // namespace content
diff --git a/content/browser/download/byte_stream_unittest.cc b/content/browser/download/byte_stream_unittest.cc
index 44bca9a..483641a 100644
--- a/content/browser/download/byte_stream_unittest.cc
+++ b/content/browser/download/byte_stream_unittest.cc
@@ -85,7 +85,7 @@ class ByteStreamTest : public testing::Test {
// ByteStream, returning the result of the ByteStream::Write.
// Separate function to avoid duplication of buffer_size in test
// calls.
- bool Write(content::ByteStreamInput* byte_stream_input,
+ bool Write(content::ByteStreamWriter* byte_stream_input,
size_t buffer_size) {
return byte_stream_input->Write(NewIOBuffer(buffer_size), buffer_size);
}
@@ -139,11 +139,11 @@ ByteStreamTest::ByteStreamTest()
: producing_seed_key_(0),
consuming_seed_key_(0) { }
-// Confirm that filling and emptying the pipe works properly, and that
+// Confirm that filling and emptying the stream works properly, and that
// we get full triggers when we expect.
TEST_F(ByteStreamTest, ByteStream_PushBack) {
- scoped_ptr<content::ByteStreamInput> byte_stream_input;
- scoped_ptr<content::ByteStreamOutput> byte_stream_output;
+ scoped_ptr<content::ByteStreamWriter> byte_stream_input;
+ scoped_ptr<content::ByteStreamReader> byte_stream_output;
content::CreateByteStream(
message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
3 * 1024, &byte_stream_input, &byte_stream_output);
@@ -163,27 +163,27 @@ TEST_F(ByteStreamTest, ByteStream_PushBack) {
// have the same contents?
scoped_refptr<net::IOBuffer> output_io_buffer;
size_t output_length;
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_COMPLETE,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_COMPLETE,
byte_stream_output->Read(&output_io_buffer, &output_length));
}
@@ -191,8 +191,8 @@ TEST_F(ByteStreamTest, ByteStream_PushBack) {
// that we're getting pushback even when data's split across the two
// objects
TEST_F(ByteStreamTest, ByteStream_PushBackSplit) {
- scoped_ptr<content::ByteStreamInput> byte_stream_input;
- scoped_ptr<content::ByteStreamOutput> byte_stream_output;
+ scoped_ptr<content::ByteStreamWriter> byte_stream_input;
+ scoped_ptr<content::ByteStreamReader> byte_stream_output;
content::CreateByteStream(
message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
9 * 1024, &byte_stream_input, &byte_stream_output);
@@ -214,35 +214,35 @@ TEST_F(ByteStreamTest, ByteStream_PushBackSplit) {
// have the same contents?
scoped_refptr<net::IOBuffer> output_io_buffer;
size_t output_length;
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
}
// Confirm that a Close() notification transmits in-order
-// with data on the pipe.
+// with data on the stream.
TEST_F(ByteStreamTest, ByteStream_CompleteTransmits) {
- scoped_ptr<content::ByteStreamInput> byte_stream_input;
- scoped_ptr<content::ByteStreamOutput> byte_stream_output;
+ scoped_ptr<content::ByteStreamWriter> byte_stream_input;
+ scoped_ptr<content::ByteStreamReader> byte_stream_output;
scoped_refptr<net::IOBuffer> output_io_buffer;
size_t output_length;
@@ -251,11 +251,11 @@ TEST_F(ByteStreamTest, ByteStream_CompleteTransmits) {
content::CreateByteStream(
message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
3 * 1024, &byte_stream_input, &byte_stream_output);
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
byte_stream_input->Close(content::DOWNLOAD_INTERRUPT_REASON_NONE);
message_loop_.RunAllPending();
- ASSERT_EQ(content::ByteStreamOutput::STREAM_COMPLETE,
+ ASSERT_EQ(content::ByteStreamReader::STREAM_COMPLETE,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
byte_stream_output->GetStatus());
@@ -264,15 +264,15 @@ TEST_F(ByteStreamTest, ByteStream_CompleteTransmits) {
content::CreateByteStream(
message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
3 * 1024, &byte_stream_input, &byte_stream_output);
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(Write(byte_stream_input.get(), 1024));
byte_stream_input->Close(content::DOWNLOAD_INTERRUPT_REASON_NONE);
message_loop_.RunAllPending();
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- ASSERT_EQ(content::ByteStreamOutput::STREAM_COMPLETE,
+ ASSERT_EQ(content::ByteStreamReader::STREAM_COMPLETE,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
byte_stream_output->GetStatus());
@@ -281,12 +281,12 @@ TEST_F(ByteStreamTest, ByteStream_CompleteTransmits) {
content::CreateByteStream(
message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
3 * 1024, &byte_stream_input, &byte_stream_output);
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
byte_stream_input->Close(
content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED);
message_loop_.RunAllPending();
- ASSERT_EQ(content::ByteStreamOutput::STREAM_COMPLETE,
+ ASSERT_EQ(content::ByteStreamReader::STREAM_COMPLETE,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED,
byte_stream_output->GetStatus());
@@ -295,16 +295,16 @@ TEST_F(ByteStreamTest, ByteStream_CompleteTransmits) {
content::CreateByteStream(
message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
3 * 1024, &byte_stream_input, &byte_stream_output);
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(Write(byte_stream_input.get(), 1024));
byte_stream_input->Close(
content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED);
message_loop_.RunAllPending();
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- ASSERT_EQ(content::ByteStreamOutput::STREAM_COMPLETE,
+ ASSERT_EQ(content::ByteStreamReader::STREAM_COMPLETE,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED,
byte_stream_output->GetStatus());
@@ -316,8 +316,8 @@ TEST_F(ByteStreamTest, ByteStream_SinkCallback) {
EXPECT_CALL(*task_runner.get(), RunsTasksOnCurrentThread())
.WillRepeatedly(Return(true));
- scoped_ptr<content::ByteStreamInput> byte_stream_input;
- scoped_ptr<content::ByteStreamOutput> byte_stream_output;
+ scoped_ptr<content::ByteStreamWriter> byte_stream_input;
+ scoped_ptr<content::ByteStreamReader> byte_stream_output;
content::CreateByteStream(
message_loop_.message_loop_proxy(), task_runner,
10000, &byte_stream_input, &byte_stream_output);
@@ -327,7 +327,7 @@ TEST_F(ByteStreamTest, ByteStream_SinkCallback) {
base::Closure intermediate_callback;
// Note that the specifics of when the callbacks are called with regard
- // to how much data is pushed onto the pipe is not (currently) part
+ // to how much data is pushed onto the stream is not (currently) part
// of the interface contract. If it becomes part of the contract, the
// tests below should get much more precise.
@@ -353,10 +353,10 @@ TEST_F(ByteStreamTest, ByteStream_SinkCallback) {
EXPECT_EQ(1, num_callbacks);
// Check data and stream state.
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
// Confirm callback *isn't* called at less than 33% (by lack of
@@ -366,7 +366,7 @@ TEST_F(ByteStreamTest, ByteStream_SinkCallback) {
// This reflects an implementation artifact that data goes with callbacks,
// which should not be considered part of the interface guarantee.
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
}
@@ -377,8 +377,8 @@ TEST_F(ByteStreamTest, ByteStream_SourceCallback) {
EXPECT_CALL(*task_runner.get(), RunsTasksOnCurrentThread())
.WillRepeatedly(Return(true));
- scoped_ptr<content::ByteStreamInput> byte_stream_input;
- scoped_ptr<content::ByteStreamOutput> byte_stream_output;
+ scoped_ptr<content::ByteStreamWriter> byte_stream_input;
+ scoped_ptr<content::ByteStreamReader> byte_stream_output;
content::CreateByteStream(
task_runner, message_loop_.message_loop_proxy(),
10000, &byte_stream_input, &byte_stream_output);
@@ -388,7 +388,7 @@ TEST_F(ByteStreamTest, ByteStream_SourceCallback) {
base::Closure intermediate_callback;
// Note that the specifics of when the callbacks are called with regard
- // to how much data is pulled from the pipe is not (currently) part
+ // to how much data is pulled from the stream is not (currently) part
// of the interface contract. If it becomes part of the contract, the
// tests below should get much more precise.
@@ -406,7 +406,7 @@ TEST_F(ByteStreamTest, ByteStream_SourceCallback) {
// Allow bytes to transition (needed for message passing implementation),
// and get and validate the data.
message_loop_.RunAllPending();
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
@@ -417,7 +417,7 @@ TEST_F(ByteStreamTest, ByteStream_SourceCallback) {
// Grab data, triggering callback. Recorded on dispatch, but doesn't
// happen because it's caught by the mock.
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
::testing::Mock::VerifyAndClearExpectations(task_runner.get());
EXPECT_CALL(*task_runner.get(), RunsTasksOnCurrentThread())
@@ -433,13 +433,13 @@ TEST_F(ByteStreamTest, ByteStream_SourceCallback) {
EXPECT_CALL(*task_runner.get(), PostDelayedTask(_, _, 0))
.WillOnce(DoAll(SaveArg<1>(&intermediate_callback),
Return(true)));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
::testing::Mock::VerifyAndClearExpectations(task_runner.get());
EXPECT_CALL(*task_runner.get(), RunsTasksOnCurrentThread())
.WillRepeatedly(Return(true));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_EQ(1, num_callbacks);
intermediate_callback.Run();
@@ -455,8 +455,8 @@ TEST_F(ByteStreamTest, ByteStream_SinkInterrupt) {
EXPECT_CALL(*task_runner.get(), RunsTasksOnCurrentThread())
.WillRepeatedly(Return(true));
- scoped_ptr<content::ByteStreamInput> byte_stream_input;
- scoped_ptr<content::ByteStreamOutput> byte_stream_output;
+ scoped_ptr<content::ByteStreamWriter> byte_stream_input;
+ scoped_ptr<content::ByteStreamReader> byte_stream_output;
content::CreateByteStream(
message_loop_.message_loop_proxy(), task_runner,
10000, &byte_stream_input, &byte_stream_output);
@@ -494,10 +494,10 @@ TEST_F(ByteStreamTest, ByteStream_SinkInterrupt) {
EXPECT_EQ(1, num_alt_callbacks);
// Final cleanup.
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
}
@@ -509,8 +509,8 @@ TEST_F(ByteStreamTest, ByteStream_SourceInterrupt) {
EXPECT_CALL(*task_runner.get(), RunsTasksOnCurrentThread())
.WillRepeatedly(Return(true));
- scoped_ptr<content::ByteStreamInput> byte_stream_input;
- scoped_ptr<content::ByteStreamOutput> byte_stream_output;
+ scoped_ptr<content::ByteStreamWriter> byte_stream_input;
+ scoped_ptr<content::ByteStreamReader> byte_stream_output;
content::CreateByteStream(
task_runner, message_loop_.message_loop_proxy(),
10000, &byte_stream_input, &byte_stream_output);
@@ -529,7 +529,7 @@ TEST_F(ByteStreamTest, ByteStream_SourceInterrupt) {
message_loop_.RunAllPending();
// Initial get should not trigger callback.
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
message_loop_.RunAllPending();
@@ -540,7 +540,7 @@ TEST_F(ByteStreamTest, ByteStream_SourceInterrupt) {
Return(true)));
// Second get *should* trigger callback.
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
::testing::Mock::VerifyAndClearExpectations(task_runner.get());
EXPECT_CALL(*task_runner.get(), RunsTasksOnCurrentThread())
@@ -559,13 +559,13 @@ TEST_F(ByteStreamTest, ByteStream_SourceInterrupt) {
EXPECT_CALL(*task_runner.get(), PostDelayedTask(_, _, 0))
.WillOnce(DoAll(SaveArg<1>(&intermediate_callback),
Return(true)));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_HAS_DATA,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_HAS_DATA,
byte_stream_output->Read(&output_io_buffer, &output_length));
::testing::Mock::VerifyAndClearExpectations(task_runner.get());
EXPECT_CALL(*task_runner.get(), RunsTasksOnCurrentThread())
.WillRepeatedly(Return(true));
EXPECT_TRUE(ValidateIOBuffer(output_io_buffer, output_length));
- EXPECT_EQ(content::ByteStreamOutput::STREAM_EMPTY,
+ EXPECT_EQ(content::ByteStreamReader::STREAM_EMPTY,
byte_stream_output->Read(&output_io_buffer, &output_length));
}
@@ -576,8 +576,8 @@ TEST_F(ByteStreamTest, ByteStream_ZeroCallback) {
EXPECT_CALL(*task_runner.get(), RunsTasksOnCurrentThread())
.WillRepeatedly(Return(true));
- scoped_ptr<content::ByteStreamInput> byte_stream_input;
- scoped_ptr<content::ByteStreamOutput> byte_stream_output;
+ scoped_ptr<content::ByteStreamWriter> byte_stream_input;
+ scoped_ptr<content::ByteStreamReader> byte_stream_output;
content::CreateByteStream(
message_loop_.message_loop_proxy(), task_runner,
10000, &byte_stream_input, &byte_stream_output);
diff --git a/content/browser/download/download_buffer.cc b/content/browser/download/download_buffer.cc
deleted file mode 100644
index c8d5c80..0000000
--- a/content/browser/download/download_buffer.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2011 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 "content/browser/download/download_buffer.h"
-
-#include "net/base/io_buffer.h"
-
-namespace content {
-
-net::IOBuffer* AssembleData(const ContentVector& contents, size_t* num_bytes) {
- if (num_bytes)
- *num_bytes = 0;
-
- size_t data_len;
- // Determine how large a buffer we need.
- size_t assembly_buffer_length = 0;
- for (size_t i = 0; i < contents.size(); ++i) {
- data_len = contents[i].second;
- assembly_buffer_length += data_len;
- }
-
- // 0-length IOBuffers are not allowed.
- if (assembly_buffer_length == 0)
- return NULL;
-
- net::IOBuffer* assembly_buffer = new net::IOBuffer(assembly_buffer_length);
-
- // Copy the data into |assembly_buffer|.
- size_t bytes_copied = 0;
- for (size_t i = 0; i < contents.size(); ++i) {
- net::IOBuffer* data = contents[i].first;
- data_len = contents[i].second;
- DCHECK(data != NULL);
- DCHECK_LE(bytes_copied + data_len, assembly_buffer_length);
- memcpy(assembly_buffer->data() + bytes_copied, data->data(), data_len);
- bytes_copied += data_len;
- }
- DCHECK_EQ(assembly_buffer_length, bytes_copied);
-
- if (num_bytes)
- *num_bytes = assembly_buffer_length;
-
- return assembly_buffer;
-}
-
-DownloadBuffer::DownloadBuffer() {
-}
-
-DownloadBuffer::~DownloadBuffer() {
-}
-
-size_t DownloadBuffer::AddData(net::IOBuffer* io_buffer, size_t byte_count) {
- base::AutoLock auto_lock(lock_);
- contents_.push_back(std::make_pair(io_buffer, byte_count));
- return contents_.size();
-}
-
-ContentVector* DownloadBuffer::ReleaseContents() {
- base::AutoLock auto_lock(lock_);
- ContentVector* other_contents = new ContentVector;
- other_contents->swap(contents_);
- return other_contents;
-}
-
-size_t DownloadBuffer::size() const {
- base::AutoLock auto_lock(lock_);
- return contents_.size();
-}
-
-} // namespace content
diff --git a/content/browser/download/download_buffer.h b/content/browser/download/download_buffer.h
deleted file mode 100644
index 35d4a56..0000000
--- a/content/browser/download/download_buffer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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 CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_BUFFER_H_
-#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_BUFFER_H_
-#pragma once
-
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "content/common/content_export.h"
-
-namespace net {
-class IOBuffer;
-}
-
-namespace content {
-
-typedef std::pair<scoped_refptr<net::IOBuffer>, size_t> ContentElement;
-typedef std::vector<ContentElement> ContentVector;
-
-// Helper function for ContentVector.
-// Assembles the data from |contents| and returns it in an |IOBuffer|.
-// The number of bytes in the |IOBuffer| is returned in |*num_bytes|
-// (if |num_bytes| is not NULL).
-// If |contents| is empty, returns NULL as an |IOBuffer| is not allowed
-// to have 0 bytes.
-CONTENT_EXPORT net::IOBuffer* AssembleData(const ContentVector& contents,
- size_t* num_bytes);
-
-// |DownloadBuffer| is a thread-safe wrapper around |ContentVector|.
-//
-// It is created and populated on the IO thread, and passed to the
-// FILE thread for writing. In order to avoid flooding the FILE thread with
-// too many small write messages, each write is appended to the
-// |DownloadBuffer| while waiting for the task to run on the FILE
-// thread. Access to the write buffers is synchronized via the lock.
-class CONTENT_EXPORT DownloadBuffer
- : public base::RefCountedThreadSafe<DownloadBuffer> {
- public:
- DownloadBuffer();
-
- // Adds data to the buffers.
- // Returns the number of |IOBuffer|s in the ContentVector.
- size_t AddData(net::IOBuffer* io_buffer, size_t byte_count);
-
- // Retrieves the ContentVector of buffers, clearing the contents.
- // The caller takes ownership.
- ContentVector* ReleaseContents();
-
- // Gets the number of |IOBuffers| we have.
- size_t size() const;
-
- private:
- friend class base::RefCountedThreadSafe<DownloadBuffer>;
-
- // Do not allow explicit destruction by anyone else.
- ~DownloadBuffer();
-
- mutable base::Lock lock_;
- ContentVector contents_;
-
- DISALLOW_COPY_AND_ASSIGN(DownloadBuffer);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_BUFFER_H_
diff --git a/content/browser/download/download_buffer_unittest.cc b/content/browser/download/download_buffer_unittest.cc
deleted file mode 100644
index 137e612..0000000
--- a/content/browser/download/download_buffer_unittest.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (c) 2011 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 "content/browser/download/download_buffer.h"
-
-#include <string.h>
-
-#include "net/base/io_buffer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-namespace {
-
-const char* kTestData[] = {
- "Four score and twenty years ago",
- "Our four (or five) fathers",
- "Danced and sang in the woods"
-};
-const size_t kTestDataQty = arraysize(kTestData);
-
-class DownloadBufferTest : public testing::Test {
- public:
- DownloadBufferTest() {
- }
- ~DownloadBufferTest() {
- }
-
- void CreateBuffer() {
- EXPECT_EQ(0u, content_buffer_.size());
-
- for (size_t i = 0; i < kTestDataQty; ++i) {
- net::StringIOBuffer* io_buffer = new net::StringIOBuffer(kTestData[i]);
- content_buffer_.push_back(std::make_pair(io_buffer, io_buffer->size()));
- EXPECT_EQ(i + 1, content_buffer_.size());
- }
- }
-
- ContentVector* content_buffer() {
- return &content_buffer_;
- }
-
- private:
- ContentVector content_buffer_;
-};
-
-TEST_F(DownloadBufferTest, CreateContentVector) {
- CreateBuffer();
-
- ContentVector* contents = content_buffer();
-
- EXPECT_EQ(kTestDataQty, content_buffer()->size());
- EXPECT_EQ(kTestDataQty, contents->size());
-
- for (size_t i = 0; i < kTestDataQty; ++i) {
- size_t io_buffer_size = strlen(kTestData[i]);
- EXPECT_STREQ(kTestData[i], (*contents)[i].first->data());
- EXPECT_EQ(io_buffer_size, (*contents)[i].second);
- }
-}
-
-TEST_F(DownloadBufferTest, CreateDownloadBuffer) {
- scoped_refptr<DownloadBuffer> content_buffer(new DownloadBuffer);
- EXPECT_EQ(0u, content_buffer->size());
-
- for (size_t i = 0; i < kTestDataQty; ++i) {
- net::StringIOBuffer* io_buffer = new net::StringIOBuffer(kTestData[i]);
- EXPECT_EQ(i + 1, content_buffer->AddData(io_buffer, io_buffer->size()));
- }
- scoped_ptr<ContentVector> contents(content_buffer->ReleaseContents());
-
- EXPECT_EQ(0u, content_buffer->size());
- EXPECT_EQ(kTestDataQty, contents->size());
-
- for (size_t i = 0; i < kTestDataQty; ++i) {
- size_t io_buffer_size = strlen(kTestData[i]);
- EXPECT_STREQ(kTestData[i], (*contents)[i].first->data());
- EXPECT_EQ(io_buffer_size, (*contents)[i].second);
- }
-}
-
-TEST_F(DownloadBufferTest, AssembleData) {
- CreateBuffer();
-
- size_t assembled_bytes = 0;
- scoped_refptr<net::IOBuffer> assembled_buffer =
- AssembleData(*content_buffer(), &assembled_bytes);
-
- // Did not change the content buffer.
- EXPECT_EQ(kTestDataQty, content_buffer()->size());
-
- // Verify the data.
- size_t total_size = 0;
- for (size_t i = 0; i < kTestDataQty; ++i) {
- size_t len = strlen(kTestData[i]);
- // assembled_buffer->data() may not be NULL-terminated, so we can't use
- // EXPECT_STREQ().
- EXPECT_EQ(
- 0, memcmp(kTestData[i], assembled_buffer->data() + total_size, len));
- total_size += len;
- }
- // Verify the data length.
- EXPECT_EQ(total_size, assembled_bytes);
-}
-
-TEST_F(DownloadBufferTest, AssembleDataWithEmptyBuffer) {
- ContentVector buffer;
- EXPECT_EQ(0u, buffer.size());
-
- size_t assembled_bytes = 0;
- scoped_refptr<net::IOBuffer> assembled_buffer =
- AssembleData(buffer, &assembled_bytes);
-
- // Did not change the content buffer.
- EXPECT_EQ(0u, buffer.size());
- EXPECT_EQ(0u, assembled_bytes);
- EXPECT_TRUE(NULL == assembled_buffer.get());
-}
-
-} // namespace
-
-} // namespace content
diff --git a/content/browser/download/download_file.h b/content/browser/download/download_file.h
index 0b1f5ff..ef6e64e 100644
--- a/content/browser/download/download_file.h
+++ b/content/browser/download/download_file.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -30,11 +30,6 @@ class CONTENT_EXPORT DownloadFile {
// Returns net::OK on success, or a network error code on failure.
virtual net::Error Initialize() = 0;
- // Write a new chunk of data to the file.
- // Returns net::OK on success (all bytes written to the file),
- // or a network error code on failure.
- virtual net::Error AppendDataToFile(const char* data, size_t data_len) = 0;
-
// Rename the download file.
// Returns net::OK on success, or a network error code on failure.
virtual net::Error Rename(const FilePath& full_path) = 0;
@@ -45,9 +40,6 @@ class CONTENT_EXPORT DownloadFile {
// Abort the download and automatically close the file.
virtual void Cancel() = 0;
- // Indicate that the download has finished. No new data will be received.
- virtual void Finish() = 0;
-
// Informs the OS that this file came from the internet.
virtual void AnnotateWithSourceInformation() = 0;
diff --git a/content/browser/download/download_file_impl.cc b/content/browser/download/download_file_impl.cc
index ae8d4ec..ee588b8 100644
--- a/content/browser/download/download_file_impl.cc
+++ b/content/browser/download/download_file_impl.cc
@@ -6,20 +6,30 @@
#include <string>
+#include "base/bind.h"
#include "base/file_util.h"
+#include "base/message_loop_proxy.h"
+#include "base/time.h"
+#include "content/browser/download/byte_stream.h"
#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_interrupt_reasons_impl.h"
+#include "content/browser/download/download_net_log_parameters.h"
#include "content/browser/power_save_blocker.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
+#include "content/browser/download/download_stats.h"
+#include "net/base/io_buffer.h"
using content::BrowserThread;
using content::DownloadId;
using content::DownloadManager;
const int kUpdatePeriodMs = 500;
+const int kMaxTimeBlockingFileThreadMs = 1000;
DownloadFileImpl::DownloadFileImpl(
const DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
DownloadRequestHandleInterface* request_handle,
DownloadManager* download_manager,
bool calculate_hash,
@@ -33,21 +43,35 @@ DownloadFileImpl::DownloadFileImpl(
info->save_info.hash_state,
info->save_info.file_stream,
bound_net_log),
+ stream_reader_(stream.Pass()),
id_(info->download_id),
request_handle_(request_handle),
download_manager_(download_manager),
+ bytes_seen_(0),
+ bound_net_log_(bound_net_log),
+ weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
power_save_blocker_(power_save_blocker.Pass()) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
}
DownloadFileImpl::~DownloadFileImpl() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
}
// BaseFile delegated functions.
net::Error DownloadFileImpl::Initialize() {
update_timer_.reset(new base::RepeatingTimer<DownloadFileImpl>());
- return file_.Initialize();
+ net::Error result = file_.Initialize();
+ if (result != net::OK)
+ return result;
+
+ stream_reader_->RegisterCallback(
+ base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr()));
+
+ download_start_ = base::TimeTicks::Now();
+ // Initial pull from the straw.
+ StreamActive();
+
+ return result;
}
net::Error DownloadFileImpl::AppendDataToFile(const char* data,
@@ -72,11 +96,6 @@ void DownloadFileImpl::Cancel() {
file_.Cancel();
}
-void DownloadFileImpl::Finish() {
- file_.Finish();
- update_timer_.reset();
-}
-
void DownloadFileImpl::AnnotateWithSourceInformation() {
file_.AnnotateWithSourceInformation();
}
@@ -135,6 +154,114 @@ std::string DownloadFileImpl::DebugString() const {
file_.DebugString().c_str());
}
+void DownloadFileImpl::StreamActive() {
+ base::TimeTicks start(base::TimeTicks::Now());
+ base::TimeTicks now;
+ scoped_refptr<net::IOBuffer> incoming_data;
+ size_t incoming_data_size = 0;
+ size_t total_incoming_data_size = 0;
+ size_t num_buffers = 0;
+ content::ByteStreamReader::StreamState state(
+ content::ByteStreamReader::STREAM_EMPTY);
+ content::DownloadInterruptReason reason =
+ content::DOWNLOAD_INTERRUPT_REASON_NONE;
+ base::TimeDelta delta(
+ base::TimeDelta::FromMilliseconds(kMaxTimeBlockingFileThreadMs));
+
+ // Take care of any file local activity required.
+ do {
+ state = stream_reader_->Read(&incoming_data, &incoming_data_size);
+
+ net::Error result = net::OK;
+ switch (state) {
+ case content::ByteStreamReader::STREAM_EMPTY:
+ break;
+ case content::ByteStreamReader::STREAM_HAS_DATA:
+ {
+ ++num_buffers;
+ base::TimeTicks write_start(base::TimeTicks::Now());
+ result = AppendDataToFile(
+ incoming_data.get()->data(), incoming_data_size);
+ disk_writes_time_ += (base::TimeTicks::Now() - write_start);
+ total_incoming_data_size += incoming_data_size;
+ reason = content::ConvertNetErrorToInterruptReason(
+ result, content::DOWNLOAD_INTERRUPT_FROM_DISK);
+ }
+ break;
+ case content::ByteStreamReader::STREAM_COMPLETE:
+ {
+ reason = stream_reader_->GetStatus();
+ SendUpdate();
+ base::TimeTicks close_start(base::TimeTicks::Now());
+ file_.Finish();
+ base::TimeTicks now(base::TimeTicks::Now());
+ disk_writes_time_ += (now - close_start);
+ download_stats::RecordFileBandwidth(
+ bytes_seen_, disk_writes_time_, now - download_start_);
+ update_timer_.reset();
+ }
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ now = base::TimeTicks::Now();
+ } while (state == content::ByteStreamReader::STREAM_HAS_DATA &&
+ reason == content::DOWNLOAD_INTERRUPT_REASON_NONE &&
+ now - start <= delta);
+
+ // If we're stopping to yield the thread, post a task so we come back.
+ if (state == content::ByteStreamReader::STREAM_HAS_DATA &&
+ now - start > delta) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&DownloadFileImpl::StreamActive,
+ weak_factory_.GetWeakPtr()));
+ }
+
+ if (total_incoming_data_size)
+ download_stats::RecordFileThreadReceiveBuffers(num_buffers);
+ bytes_seen_ += total_incoming_data_size;
+
+ download_stats::RecordContiguousWriteTime(now - start);
+
+ // Take care of communication with our controller.
+ if (reason != content::DOWNLOAD_INTERRUPT_REASON_NONE) {
+ // Error case for both upstream source and file write.
+ // Shut down processing and signal an error to our controller.
+ // Our controller will clean us up.
+ stream_reader_->RegisterCallback(base::Closure());
+ weak_factory_.InvalidateWeakPtrs();
+ if (download_manager_.get()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&DownloadManager::OnDownloadInterrupted,
+ download_manager_, id_.local(),
+ BytesSoFar(), GetHashState(), reason));
+ }
+ } else if (state == content::ByteStreamReader::STREAM_COMPLETE) {
+ // Signal successful completion and shut down processing.
+ stream_reader_->RegisterCallback(base::Closure());
+ weak_factory_.InvalidateWeakPtrs();
+ if (download_manager_.get()) {
+ std::string hash;
+ if (!GetHash(&hash) || file_.IsEmptyHash(hash))
+ hash.clear();
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&DownloadManager::OnResponseCompleted,
+ download_manager_, id_.local(),
+ BytesSoFar(), hash));
+ }
+ }
+ if (bound_net_log_.IsLoggingAllEvents()) {
+ bound_net_log_.AddEvent(
+ net::NetLog::TYPE_DOWNLOAD_STREAM_DRAINED,
+ make_scoped_refptr(new download_net_logs::FileStreamDrainedParameters(
+ total_incoming_data_size, num_buffers)));
+ }
+}
+
void DownloadFileImpl::SendUpdate() {
if (download_manager_.get()) {
BrowserThread::PostTask(
diff --git a/content/browser/download/download_file_impl.h b/content/browser/download/download_file_impl.h
index ab39c14..93d6329 100644
--- a/content/browser/download/download_file_impl.h
+++ b/content/browser/download/download_file_impl.h
@@ -10,15 +10,20 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time.h"
#include "base/timer.h"
#include "content/browser/download/base_file.h"
+#include "content/browser/download/byte_stream.h"
#include "content/browser/download/download_request_handle.h"
+#include "net/base/net_log.h"
class PowerSaveBlocker;
struct DownloadCreateInfo;
namespace content {
+class ByteStreamReader;
class DownloadManager;
}
@@ -27,6 +32,7 @@ class CONTENT_EXPORT DownloadFileImpl : virtual public content::DownloadFile {
// Takes ownership of the object pointed to by |request_handle|.
// |bound_net_log| will be used for logging the download file's events.
DownloadFileImpl(const DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
DownloadRequestHandleInterface* request_handle,
content::DownloadManager* download_manager,
bool calculate_hash,
@@ -36,12 +42,9 @@ class CONTENT_EXPORT DownloadFileImpl : virtual public content::DownloadFile {
// DownloadFile functions.
virtual net::Error Initialize() OVERRIDE;
- virtual net::Error AppendDataToFile(const char* data,
- size_t data_len) OVERRIDE;
virtual net::Error Rename(const FilePath& full_path) OVERRIDE;
virtual void Detach() OVERRIDE;
virtual void Cancel() OVERRIDE;
- virtual void Finish() OVERRIDE;
virtual void AnnotateWithSourceInformation() OVERRIDE;
virtual FilePath FullPath() const OVERRIDE;
virtual bool InProgress() const OVERRIDE;
@@ -55,13 +58,28 @@ class CONTENT_EXPORT DownloadFileImpl : virtual public content::DownloadFile {
virtual const content::DownloadId& GlobalId() const OVERRIDE;
virtual std::string DebugString() const OVERRIDE;
+ protected:
+ // For test class overrides.
+ virtual net::Error AppendDataToFile(const char* data,
+ size_t data_len);
+
private:
+ // Called when there's some activity on stream_reader_ that needs to be
+ // handled.
+ void StreamActive();
+
// Send updates on our progress.
void SendUpdate();
// The base file instance.
BaseFile file_;
+ // The stream through which data comes.
+ // TODO(rdsmith): Move this into BaseFile; requires using the same
+ // stream semantics in SavePackage. Alternatively, replace SaveFile
+ // with DownloadFile and get rid of BaseFile.
+ scoped_ptr<content::ByteStreamReader> stream_reader_;
+
// The unique identifier for this download, assigned at creation by
// the DownloadFileManager for its internal record keeping.
content::DownloadId id_;
@@ -76,6 +94,15 @@ class CONTENT_EXPORT DownloadFileImpl : virtual public content::DownloadFile {
// DownloadManager this download belongs to.
scoped_refptr<content::DownloadManager> download_manager_;
+ // Statistics
+ size_t bytes_seen_;
+ base::TimeDelta disk_writes_time_;
+ base::TimeTicks download_start_;
+
+ net::BoundNetLog bound_net_log_;
+
+ base::WeakPtrFactory<DownloadFileImpl> weak_factory_;
+
// RAII handle to keep the system from sleeping while we're downloading.
scoped_ptr<PowerSaveBlocker> power_save_blocker_;
diff --git a/content/browser/download/download_file_manager.cc b/content/browser/download/download_file_manager.cc
index 40f1acb..f74cb28 100644
--- a/content/browser/download/download_file_manager.cc
+++ b/content/browser/download/download_file_manager.cc
@@ -13,7 +13,6 @@
#include "base/stl_util.h"
#include "base/utf_string_conversions.h"
#include "content/browser/download/base_file.h"
-#include "content/browser/download/download_buffer.h"
#include "content/browser/download/download_create_info.h"
#include "content/browser/download/download_file_impl.h"
#include "content/browser/download/download_interrupt_reasons_impl.h"
@@ -41,6 +40,7 @@ class DownloadFileFactoryImpl
virtual content::DownloadFile* CreateFile(
DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
DownloadManager* download_manager,
bool calculate_hash,
@@ -49,12 +49,13 @@ class DownloadFileFactoryImpl
DownloadFile* DownloadFileFactoryImpl::CreateFile(
DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
DownloadManager* download_manager,
bool calculate_hash,
const net::BoundNetLog& bound_net_log) {
return new DownloadFileImpl(
- info, new DownloadRequestHandle(request_handle),
+ info, stream.Pass(), new DownloadRequestHandle(request_handle),
download_manager, calculate_hash,
scoped_ptr<PowerSaveBlocker>(
new PowerSaveBlocker(
@@ -87,19 +88,19 @@ void DownloadFileManager::OnShutdown() {
}
void DownloadFileManager::CreateDownloadFile(
- DownloadCreateInfo* info, const DownloadRequestHandle& request_handle,
+ scoped_ptr<DownloadCreateInfo> info,
+ scoped_ptr<content::ByteStreamReader> stream,
+ const DownloadRequestHandle& request_handle,
DownloadManager* download_manager, bool get_hash,
const net::BoundNetLog& bound_net_log) {
- DCHECK(info);
+ DCHECK(info.get());
VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString();
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- // Life of |info| ends here. No more references to it after this method.
- scoped_ptr<DownloadCreateInfo> infop(info);
-
// Create the download file.
scoped_ptr<DownloadFile> download_file(download_file_factory_->CreateFile(
- info, request_handle, download_manager, get_hash, bound_net_log));
+ info.get(), stream.Pass(), request_handle, download_manager,
+ get_hash, bound_net_log));
net::Error init_result = download_file->Initialize();
if (net::OK != init_result) {
@@ -152,9 +153,11 @@ void DownloadFileManager::UpdateInProgressDownloads() {
}
void DownloadFileManager::StartDownload(
- DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) {
+ scoped_ptr<DownloadCreateInfo> info,
+ scoped_ptr<content::ByteStreamReader> stream,
+ const DownloadRequestHandle& request_handle) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(info);
+ DCHECK(info.get());
DownloadManager* manager = request_handle.GetDownloadManager();
DCHECK(manager); // Checked in |DownloadResourceHandler::StartOnUIThread()|.
@@ -162,114 +165,17 @@ void DownloadFileManager::StartDownload(
// |bound_net_log| will be used for logging the both the download item's and
// the download file's events.
net::BoundNetLog bound_net_log =
- manager->CreateDownloadItem(info, request_handle);
+ manager->CreateDownloadItem(info.get(), request_handle);
bool hash_needed = manager->GenerateFileHash();
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&DownloadFileManager::CreateDownloadFile, this,
- info, request_handle, make_scoped_refptr(manager),
+ base::Passed(info.Pass()), base::Passed(stream.Pass()),
+ request_handle,
+ make_scoped_refptr(manager),
hash_needed, bound_net_log));
}
-// We don't forward an update to the UI thread here, since we want to throttle
-// the UI update rate via a periodic timer. If the user has cancelled the
-// download (in the UI thread), we may receive a few more updates before the IO
-// thread gets the cancel message: we just delete the data since the
-// DownloadFile has been deleted.
-void DownloadFileManager::UpdateDownload(
- DownloadId global_id, content::DownloadBuffer* buffer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- scoped_ptr<content::ContentVector> contents(buffer->ReleaseContents());
-
- download_stats::RecordFileThreadReceiveBuffers(contents->size());
-
- DownloadFile* download_file = GetDownloadFile(global_id);
- bool had_error = false;
- for (size_t i = 0; i < contents->size(); ++i) {
- net::IOBuffer* data = (*contents)[i].first;
- const int data_len = (*contents)[i].second;
- if (!had_error && download_file) {
- net::Error write_result =
- download_file->AppendDataToFile(data->data(), data_len);
- if (write_result != net::OK) {
- // Write failed: interrupt the download.
- DownloadManager* download_manager =
- download_file->GetDownloadManager();
- had_error = true;
-
- int64 bytes_downloaded = download_file->BytesSoFar();
- std::string hash_state(download_file->GetHashState());
-
- // Calling this here in case we get more data, to avoid
- // processing data after an error. That could lead to
- // files that are corrupted if the later processing succeeded.
- CancelDownload(global_id);
- download_file = NULL; // Was deleted in |CancelDownload|.
-
- if (download_manager) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DownloadManager::OnDownloadInterrupted,
- download_manager,
- global_id.local(),
- bytes_downloaded,
- hash_state,
- content::ConvertNetErrorToInterruptReason(
- write_result,
- content::DOWNLOAD_INTERRUPT_FROM_DISK)));
- }
- }
- }
- data->Release();
- }
-}
-
-void DownloadFileManager::OnResponseCompleted(
- DownloadId global_id,
- content::DownloadInterruptReason reason,
- const std::string& security_info) {
- VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id
- << " reason = " << InterruptReasonDebugString(reason)
- << " security_info = \"" << security_info << "\"";
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DownloadFile* download_file = GetDownloadFile(global_id);
- if (!download_file)
- return;
-
- download_file->Finish();
-
- DownloadManager* download_manager = download_file->GetDownloadManager();
- if (!download_manager) {
- CancelDownload(global_id);
- return;
- }
-
- if (reason == content::DOWNLOAD_INTERRUPT_REASON_NONE) {
- std::string hash;
- if (!download_file->GetHash(&hash) ||
- BaseFile::IsEmptyHash(hash)) {
- hash.clear();
- }
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DownloadManager::OnResponseCompleted,
- download_manager, global_id.local(),
- download_file->BytesSoFar(), hash));
- } else {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DownloadManager::OnDownloadInterrupted,
- download_manager,
- global_id.local(),
- download_file->BytesSoFar(),
- download_file->GetHashState(),
- reason));
- }
- // We need to keep the download around until the UI thread has finalized
- // the name.
-}
-
// This method will be sent via a user action, or shutdown on the UI thread, and
// run on the download thread. Since this message has been sent from the UI
// thread, the download may have already completed and won't exist in our map.
diff --git a/content/browser/download/download_file_manager.h b/content/browser/download/download_file_manager.h
index 965a93c..f7737e9 100644
--- a/content/browser/download/download_file_manager.h
+++ b/content/browser/download/download_file_manager.h
@@ -61,7 +61,7 @@ class DownloadRequestHandle;
class FilePath;
namespace content {
-class DownloadBuffer;
+class ByteStreamReader;
class DownloadFile;
class DownloadManager;
}
@@ -86,6 +86,7 @@ class CONTENT_EXPORT DownloadFileManager
virtual content::DownloadFile* CreateFile(
DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
content::DownloadManager* download_manager,
bool calculate_hash,
@@ -101,23 +102,10 @@ class CONTENT_EXPORT DownloadFileManager
virtual void Shutdown();
// Called on UI thread to make DownloadFileManager start the download.
- virtual void StartDownload(DownloadCreateInfo* info,
+ virtual void StartDownload(scoped_ptr<DownloadCreateInfo> info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle);
- // Handlers for notifications sent from the IO thread and run on the
- // FILE thread.
- virtual void UpdateDownload(content::DownloadId global_id,
- content::DownloadBuffer* buffer);
-
- // |reason| is the reason for interruption, if one occurs.
- // |security_info| contains SSL information (cert_id, cert_status,
- // security_bits, ssl_connection_status), which can be used to
- // fine-tune the error message. It is empty if the transaction
- // was not performed securely.
- virtual void OnResponseCompleted(content::DownloadId global_id,
- content::DownloadInterruptReason reason,
- const std::string& security_info);
-
// Handlers for notifications sent from the UI thread and run on the
// FILE thread. These are both terminal actions with respect to the
// download file, as far as the DownloadFileManager is concerned -- if
@@ -186,7 +174,8 @@ class CONTENT_EXPORT DownloadFileManager
// Creates DownloadFile on FILE thread and continues starting the download
// process.
- void CreateDownloadFile(DownloadCreateInfo* info,
+ void CreateDownloadFile(scoped_ptr<DownloadCreateInfo> info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
content::DownloadManager* download_manager,
bool hash_needed,
diff --git a/content/browser/download/download_file_manager_unittest.cc b/content/browser/download/download_file_manager_unittest.cc
index c8556ba..0845bc6 100644
--- a/content/browser/download/download_file_manager_unittest.cc
+++ b/content/browser/download/download_file_manager_unittest.cc
@@ -10,7 +10,7 @@
#include "base/scoped_temp_dir.h"
#include "base/string_number_conversions.h"
#include "content/browser/browser_thread_impl.h"
-#include "content/browser/download/download_buffer.h"
+#include "content/browser/download/byte_stream.h"
#include "content/browser/download/download_create_info.h"
#include "content/browser/download/download_interrupt_reasons_impl.h"
#include "content/browser/download/download_request_handle.h"
@@ -53,6 +53,7 @@ class MockDownloadFileFactory :
virtual content::DownloadFile* CreateFile(
DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
content::DownloadManager* download_manager,
bool calculate_hash,
@@ -66,6 +67,7 @@ class MockDownloadFileFactory :
content::DownloadFile* MockDownloadFileFactory::CreateFile(
DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
content::DownloadManager* download_manager,
bool calculate_hash,
@@ -136,8 +138,7 @@ class DownloadFileManagerTest : public testing::Test {
// calling Release() on |download_manager_| won't ever result in its
// destructor being called and we get a leak.
DownloadFileManagerTest()
- : download_buffer_(new content::DownloadBuffer()),
- ui_thread_(BrowserThread::UI, &loop_),
+ : ui_thread_(BrowserThread::UI, &loop_),
file_thread_(BrowserThread::FILE, &loop_) {
}
@@ -175,7 +176,8 @@ class DownloadFileManagerTest : public testing::Test {
// Start a download.
// |info| is the information needed to create a new download file.
// |id| is the download ID of the new download file.
- void StartDownload(DownloadCreateInfo* info, const DownloadId& id) {
+ void StartDownload(scoped_ptr<DownloadCreateInfo> info,
+ const DownloadId& id) {
// Expected call sequence:
// StartDownload
// DownloadManager::CreateDownloadItem
@@ -191,7 +193,7 @@ class DownloadFileManagerTest : public testing::Test {
info->download_id = id;
// Set expectations and return values.
- EXPECT_CALL(*download_manager_, CreateDownloadItem(info, _))
+ EXPECT_CALL(*download_manager_, CreateDownloadItem(info.get(), _))
.Times(1)
.WillOnce(Return(net::BoundNetLog()));
EXPECT_CALL(*download_manager_, GenerateFileHash())
@@ -199,94 +201,13 @@ class DownloadFileManagerTest : public testing::Test {
.WillRepeatedly(Return(false));
EXPECT_CALL(*download_manager_, StartDownload(id.local()));
- download_file_manager_->StartDownload(info, *request_handle_);
+ download_file_manager_->StartDownload(
+ info.Pass(), scoped_ptr<content::ByteStreamReader>(), *request_handle_);
ProcessAllPendingMessages();
ClearExpectations(id);
}
- // Creates a new |net::IOBuffer| of size |length| with |data|, and attaches
- // it to the download buffer.
- bool UpdateBuffer(const char* data, size_t length) {
- // We are passing ownership of this buffer to the download file manager.
- // NOTE: we are padding io_buffer with one extra character so that the
- // mock testing framework can treat it as a NULL-delimited string.
- net::IOBuffer* io_buffer = new net::IOBuffer(length + 1);
- // We need |AddRef()| because we do a |Release()| in |UpdateDownload()|.
- io_buffer->AddRef();
- memcpy(io_buffer->data(), data, length);
- io_buffer->data()[length] = 0;
-
- download_buffer_->AddData(io_buffer, length);
-
- return true;
- }
-
- // Updates the download file.
- // |id| is the download ID of the download file.
- // |data| is the buffer containing the data.
- // |length| is the length of the data buffer.
- // |error_to_insert| is the error to simulate. For no error, use net::OK.
- void UpdateDownload(const DownloadId& id,
- const char* data,
- size_t length,
- net::Error error_to_insert) {
- // Expected call sequence:
- // Create DownloadBuffer
- // UpdateDownload
- // GetDownloadFile
- // DownloadFile::AppendDataToFile
- //
- // On error:
- // DownloadFile::GetDownloadManager
- // DownloadFile::BytesSoFar
- // CancelDownload
- // Process one message in the message loop
- // DownloadManager::OnDownloadInterrupted
- EXPECT_TRUE(UpdateBuffer(data, length));
- MockDownloadFile* file = download_file_factory_->GetExistingFile(id);
- ASSERT_TRUE(file != NULL);
- byte_count_[id] += length;
-
- // Make sure our comparison string is NULL-terminated.
- char* expected_data = new char[length + 1];
- memcpy(expected_data, data, length);
- expected_data[length] = 0;
-
- EXPECT_CALL(*file, AppendDataToFile(StrEq(expected_data), length))
- .Times(1)
- .WillOnce(Return(error_to_insert));
-
- if (error_to_insert != net::OK) {
- EXPECT_CALL(*file, GetDownloadManager())
- .Times(AtLeast(1));
- EXPECT_CALL(*file, BytesSoFar())
- .Times(AtLeast(1))
- .WillRepeatedly(Return(byte_count_[id]));
- EXPECT_CALL(*file, GetHashState())
- .Times(AtLeast(1));
- EXPECT_CALL(*file, Cancel());
- }
-
- download_file_manager_->UpdateDownload(id, download_buffer_.get());
-
- if (error_to_insert != net::OK) {
- EXPECT_CALL(*download_manager_,
- OnDownloadInterrupted(
- id.local(),
- byte_count_[id],
- "",
- content::ConvertNetErrorToInterruptReason(
- error_to_insert, content::DOWNLOAD_INTERRUPT_FROM_DISK)));
-
- ProcessAllPendingMessages();
- ++error_count_[id];
- }
-
- ClearExpectations(id);
- delete [] expected_data;
- }
-
// Renames the download file.
// |id| is the download ID of the download file.
// |new_path| is the new file path.
@@ -357,67 +278,6 @@ class DownloadFileManagerTest : public testing::Test {
}
}
- // Finish the download operation.
- // |id| is the download ID of the download file.
- // |reason| is the interrupt reason to inject. For no interrupt, use
- // DOWNLOAD_INTERRUPT_REASON_NONE.
- // |security_string| is the extra security information, if interrupted.
- void OnResponseCompleted(const DownloadId& id,
- content::DownloadInterruptReason reason,
- const std::string& security_string) {
- // OnResponseCompleted
- // GetDownloadFile
- // DownloadFile::Finish
- // DownloadFile::GetDownloadManager
- // DownloadFile::BytesSoFar
- // Process one message in the message loop
- //
- // OK:
- // DownloadFile::GetHash
- // DownloadManager::OnResponseCompleted
- //
- // On Error:
- // DownloadManager::OnDownloadInterrupted
- MockDownloadFile* file = download_file_factory_->GetExistingFile(id);
- ASSERT_TRUE(file != NULL);
-
- EXPECT_CALL(*file, Finish());
- EXPECT_CALL(*file, GetDownloadManager());
- if (reason == content::DOWNLOAD_INTERRUPT_REASON_NONE) {
- EXPECT_CALL(*file, GetHash(_))
- .WillOnce(Return(false));
- } else {
- EXPECT_CALL(*file, GetHashState());
- }
- EXPECT_CALL(*file, BytesSoFar())
- .Times(AtLeast(1))
- .WillRepeatedly(Return(byte_count_[id]));
-
- download_file_manager_->OnResponseCompleted(id, reason, security_string);
-
- if (reason == content::DOWNLOAD_INTERRUPT_REASON_NONE) {
- EXPECT_CALL(*download_manager_,
- OnResponseCompleted(id.local(), byte_count_[id], ""))
- .Times(1);
- } else {
- EXPECT_EQ(0, error_count_[id]);
-
- EXPECT_CALL(*download_manager_,
- OnDownloadInterrupted(id.local(),
- byte_count_[id],
- "",
- reason))
- .Times(1);
- }
-
- ProcessAllPendingMessages();
-
- if (reason != content::DOWNLOAD_INTERRUPT_REASON_NONE)
- ++error_count_[id];
-
- ClearExpectations(id);
- }
-
void CleanUp(DownloadId id) {
// Expected calls:
// DownloadFileManager::CancelDownload
@@ -440,7 +300,6 @@ class DownloadFileManagerTest : public testing::Test {
scoped_ptr<MockDownloadRequestHandle> request_handle_;
MockDownloadFileFactory* download_file_factory_;
scoped_refptr<DownloadFileManager> download_file_manager_;
- scoped_refptr<content::DownloadBuffer> download_buffer_;
// Per-download statistics.
std::map<DownloadId, int64> byte_count_;
@@ -470,127 +329,65 @@ const int DownloadFileManagerTest::kDummyChildId = 3;
const int DownloadFileManagerTest::kDummyRequestId = 67;
TEST_F(DownloadFileManagerTest, CancelAtStart) {
- DownloadCreateInfo* info = new DownloadCreateInfo;
+ scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo);
DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
- StartDownload(info, dummy_id);
+ StartDownload(info.Pass(), dummy_id);
CleanUp(dummy_id);
}
TEST_F(DownloadFileManagerTest, CancelBeforeFinished) {
// Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
- DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
-
- StartDownload(info, dummy_id);
-
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- CleanUp(dummy_id);
-}
-
-TEST_F(DownloadFileManagerTest, DownloadWithError) {
- // Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
- DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
-
- StartDownload(info, dummy_id);
-
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2),
- net::ERR_FILE_NO_SPACE);
-}
-
-TEST_F(DownloadFileManagerTest, CompleteDownload) {
- // Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
+ scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo);
DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
- StartDownload(info, dummy_id);
-
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- OnResponseCompleted(dummy_id, content::DOWNLOAD_INTERRUPT_REASON_NONE, "");
-
- CleanUp(dummy_id);
-}
-
-TEST_F(DownloadFileManagerTest, CompleteDownloadWithError) {
- // Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
- DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
-
- StartDownload(info, dummy_id);
-
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- OnResponseCompleted(dummy_id,
- content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED,
- "");
+ StartDownload(info.Pass(), dummy_id);
CleanUp(dummy_id);
}
TEST_F(DownloadFileManagerTest, RenameInProgress) {
// Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
+ scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo);
DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
ScopedTempDir download_dir;
ASSERT_TRUE(download_dir.CreateUniqueTempDir());
- StartDownload(info, dummy_id);
+ StartDownload(info.Pass(), dummy_id);
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
FilePath foo(download_dir.path().Append(FILE_PATH_LITERAL("foo.txt")));
RenameFile(dummy_id, foo, foo, net::OK, IN_PROGRESS, OVERWRITE);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- OnResponseCompleted(dummy_id, content::DOWNLOAD_INTERRUPT_REASON_NONE, "");
CleanUp(dummy_id);
}
TEST_F(DownloadFileManagerTest, RenameInProgressWithUniquification) {
// Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
+ scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo);
DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
ScopedTempDir download_dir;
ASSERT_TRUE(download_dir.CreateUniqueTempDir());
- StartDownload(info, dummy_id);
+ StartDownload(info.Pass(), dummy_id);
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
FilePath foo(download_dir.path().Append(FILE_PATH_LITERAL("foo.txt")));
FilePath unique_foo(foo.InsertBeforeExtension(FILE_PATH_LITERAL(" (1)")));
ASSERT_EQ(0, file_util::WriteFile(foo, "", 0));
RenameFile(dummy_id, foo, unique_foo, net::OK, IN_PROGRESS, DONT_OVERWRITE);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- OnResponseCompleted(dummy_id, content::DOWNLOAD_INTERRUPT_REASON_NONE, "");
CleanUp(dummy_id);
}
TEST_F(DownloadFileManagerTest, RenameInProgressWithError) {
// Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
+ scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo);
DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
ScopedTempDir download_dir;
ASSERT_TRUE(download_dir.CreateUniqueTempDir());
- StartDownload(info, dummy_id);
+ StartDownload(info.Pass(), dummy_id);
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
FilePath foo(download_dir.path().Append(FILE_PATH_LITERAL("foo.txt")));
RenameFile(dummy_id, foo, foo, net::ERR_FILE_PATH_TOO_LONG,
IN_PROGRESS, OVERWRITE);
@@ -598,41 +395,14 @@ TEST_F(DownloadFileManagerTest, RenameInProgressWithError) {
CleanUp(dummy_id);
}
-TEST_F(DownloadFileManagerTest, RenameCompleting) {
+TEST_F(DownloadFileManagerTest, RenameWithUniquification) {
// Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
+ scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo);
DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
ScopedTempDir download_dir;
ASSERT_TRUE(download_dir.CreateUniqueTempDir());
- StartDownload(info, dummy_id);
-
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- OnResponseCompleted(dummy_id, content::DOWNLOAD_INTERRUPT_REASON_NONE, "");
-
- FilePath foo(download_dir.path().Append(FILE_PATH_LITERAL("foo.txt")));
- RenameFile(dummy_id, foo, foo, net::OK, COMPLETE, OVERWRITE);
-
- CleanUp(dummy_id);
-}
-
-TEST_F(DownloadFileManagerTest, RenameCompletingWithUniquification) {
- // Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
- DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
- ScopedTempDir download_dir;
- ASSERT_TRUE(download_dir.CreateUniqueTempDir());
-
- StartDownload(info, dummy_id);
-
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- OnResponseCompleted(dummy_id, content::DOWNLOAD_INTERRUPT_REASON_NONE, "");
+ StartDownload(info.Pass(), dummy_id);
FilePath foo(download_dir.path().Append(FILE_PATH_LITERAL("foo.txt")));
FilePath unique_foo(foo.InsertBeforeExtension(FILE_PATH_LITERAL(" (1)")));
@@ -645,45 +415,18 @@ TEST_F(DownloadFileManagerTest, RenameCompletingWithUniquification) {
CleanUp(dummy_id);
}
-TEST_F(DownloadFileManagerTest, RenameCompletingWithError) {
- // Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
- DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
- ScopedTempDir download_dir;
- ASSERT_TRUE(download_dir.CreateUniqueTempDir());
-
- StartDownload(info, dummy_id);
-
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- OnResponseCompleted(dummy_id, content::DOWNLOAD_INTERRUPT_REASON_NONE, "");
-
- FilePath foo(download_dir.path().Append(FILE_PATH_LITERAL("foo.txt")));
- RenameFile(dummy_id, foo, foo, net::ERR_FILE_PATH_TOO_LONG,
- COMPLETE, OVERWRITE);
-
- CleanUp(dummy_id);
-}
-
TEST_F(DownloadFileManagerTest, RenameTwice) {
// Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
+ scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo);
DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
ScopedTempDir download_dir;
ASSERT_TRUE(download_dir.CreateUniqueTempDir());
- StartDownload(info, dummy_id);
+ StartDownload(info.Pass(), dummy_id);
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
FilePath crfoo(download_dir.path().Append(
FILE_PATH_LITERAL("foo.txt.crdownload")));
RenameFile(dummy_id, crfoo, crfoo, net::OK, IN_PROGRESS, OVERWRITE);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- OnResponseCompleted(dummy_id, content::DOWNLOAD_INTERRUPT_REASON_NONE, "");
FilePath foo(download_dir.path().Append(FILE_PATH_LITERAL("foo.txt")));
RenameFile(dummy_id, foo, foo, net::OK, COMPLETE, OVERWRITE);
@@ -693,22 +436,17 @@ TEST_F(DownloadFileManagerTest, RenameTwice) {
TEST_F(DownloadFileManagerTest, TwoDownloads) {
// Same as StartDownload, at first.
- DownloadCreateInfo* info = new DownloadCreateInfo;
- DownloadCreateInfo* info2 = new DownloadCreateInfo;
+ scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo);
+ scoped_ptr<DownloadCreateInfo> info2(new DownloadCreateInfo);
DownloadId dummy_id(download_manager_.get(), kDummyDownloadId);
DownloadId dummy_id2(download_manager_.get(), kDummyDownloadId2);
ScopedTempDir download_dir;
ASSERT_TRUE(download_dir.CreateUniqueTempDir());
- StartDownload(info, dummy_id);
-
- UpdateDownload(dummy_id, kTestData1, strlen(kTestData1), net::OK);
-
- StartDownload(info2, dummy_id2);
+ StartDownload(info.Pass(), dummy_id);
- UpdateDownload(dummy_id, kTestData2, strlen(kTestData2), net::OK);
+ StartDownload(info2.Pass(), dummy_id2);
- UpdateDownload(dummy_id2, kTestData4, strlen(kTestData4), net::OK);
FilePath crbar(download_dir.path().Append(
FILE_PATH_LITERAL("bar.txt.crdownload")));
RenameFile(dummy_id2, crbar, crbar, net::OK, IN_PROGRESS, OVERWRITE);
@@ -717,14 +455,6 @@ TEST_F(DownloadFileManagerTest, TwoDownloads) {
FILE_PATH_LITERAL("foo.txt.crdownload")));
RenameFile(dummy_id, crfoo, crfoo, net::OK, IN_PROGRESS, OVERWRITE);
- UpdateDownload(dummy_id, kTestData3, strlen(kTestData3), net::OK);
-
- UpdateDownload(dummy_id2, kTestData5, strlen(kTestData5), net::OK);
- UpdateDownload(dummy_id2, kTestData6, strlen(kTestData6), net::OK);
-
- OnResponseCompleted(dummy_id2, content::DOWNLOAD_INTERRUPT_REASON_NONE, "");
-
- OnResponseCompleted(dummy_id, content::DOWNLOAD_INTERRUPT_REASON_NONE, "");
FilePath bar(download_dir.path().Append(FILE_PATH_LITERAL("bar.txt")));
RenameFile(dummy_id2, bar, bar, net::OK, COMPLETE, OVERWRITE);
diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc
index 87526b8..9d1c661 100644
--- a/content/browser/download/download_file_unittest.cc
+++ b/content/browser/download/download_file_unittest.cc
@@ -6,14 +6,17 @@
#include "base/message_loop.h"
#include "base/string_number_conversions.h"
#include "content/browser/browser_thread_impl.h"
+#include "content/browser/download/byte_stream.h"
#include "content/browser/download/download_create_info.h"
#include "content/browser/download/download_file_impl.h"
#include "content/browser/download/download_request_handle.h"
#include "content/browser/power_save_blocker.h"
+#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_manager.h"
#include "content/public/test/mock_download_manager.h"
#include "net/base/file_stream.h"
#include "net/base/net_errors.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::BrowserThread;
@@ -21,9 +24,28 @@ using content::BrowserThreadImpl;
using content::DownloadFile;
using content::DownloadId;
using content::DownloadManager;
-using testing::_;
-using testing::AnyNumber;
-using testing::StrictMock;
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrictMock;
+
+namespace {
+
+class MockByteStreamReader : public content::ByteStreamReader {
+ public:
+ MockByteStreamReader() {}
+ ~MockByteStreamReader() {}
+
+ // ByteStream functions
+ MOCK_METHOD2(Read, content::ByteStreamReader::StreamState(
+ scoped_refptr<net::IOBuffer>*, size_t*));
+ MOCK_CONST_METHOD0(GetStatus, content::DownloadInterruptReason());
+ MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
+};
+
+} // namespace
DownloadId::Domain kValidIdDomain = "valid DownloadId::Domain";
@@ -77,45 +99,133 @@ class DownloadFileTest : public testing::Test {
ui_thread_.message_loop()->RunAllPending();
}
- virtual void CreateDownloadFile(scoped_ptr<DownloadFile>* file,
- int offset,
- bool calculate_hash) {
+ // Mock calls to this function are forwarded here.
+ void RegisterCallback(base::Closure sink_callback) {
+ sink_callback_ = sink_callback;
+ }
+
+ virtual bool CreateDownloadFile(int offset, bool calculate_hash) {
+ // There can be only one.
+ DCHECK(!download_file_.get());
+
+ input_stream_ = new StrictMock<MockByteStreamReader>();
+
+ // TODO: Need to actually create a function that'll set the variables
+ // based on the inputs from the callback.
+ EXPECT_CALL(*input_stream_, RegisterCallback(_))
+ .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
+ .RetiresOnSaturation();
+
DownloadCreateInfo info;
info.download_id = DownloadId(kValidIdDomain, kDummyDownloadId + offset);
// info.request_handle default constructed to null.
info.save_info.file_stream = file_stream_;
- file->reset(
- new DownloadFileImpl(&info, new DownloadRequestHandle(),
- download_manager_, calculate_hash,
- scoped_ptr<PowerSaveBlocker>(NULL).Pass(),
- net::BoundNetLog()));
+ download_file_.reset(
+ new DownloadFileImpl(
+ &info,
+ scoped_ptr<content::ByteStreamReader>(input_stream_).Pass(),
+ new DownloadRequestHandle(),
+ download_manager_, calculate_hash,
+ scoped_ptr<PowerSaveBlocker>(NULL).Pass(),
+ net::BoundNetLog()));
+
+ EXPECT_CALL(*input_stream_, Read(_, _))
+ .WillOnce(Return(content::ByteStreamReader::STREAM_EMPTY))
+ .RetiresOnSaturation();
+ net::Error result = download_file_->Initialize();
+ ::testing::Mock::VerifyAndClearExpectations(input_stream_);
+ return result == net::OK;
}
- virtual void DestroyDownloadFile(scoped_ptr<DownloadFile>* file, int offset) {
- EXPECT_EQ(kDummyDownloadId + offset, (*file)->Id());
- EXPECT_EQ(download_manager_, (*file)->GetDownloadManager());
- EXPECT_FALSE((*file)->InProgress());
+ virtual void DestroyDownloadFile(int offset) {
+ EXPECT_EQ(kDummyDownloadId + offset, download_file_->Id());
+ EXPECT_EQ(download_manager_, download_file_->GetDownloadManager());
+ EXPECT_FALSE(download_file_->InProgress());
EXPECT_EQ(static_cast<int64>(expected_data_.size()),
- (*file)->BytesSoFar());
+ download_file_->BytesSoFar());
// Make sure the data has been properly written to disk.
std::string disk_data;
- EXPECT_TRUE(file_util::ReadFileToString((*file)->FullPath(),
+ EXPECT_TRUE(file_util::ReadFileToString(download_file_->FullPath(),
&disk_data));
EXPECT_EQ(expected_data_, disk_data);
// Make sure the Browser and File threads outlive the DownloadFile
// to satisfy thread checks inside it.
- file->reset();
+ download_file_.reset();
}
- void AppendDataToFile(scoped_ptr<DownloadFile>* file,
- const std::string& data) {
- EXPECT_TRUE((*file)->InProgress());
- (*file)->AppendDataToFile(data.data(), data.size());
- expected_data_ += data;
- EXPECT_EQ(static_cast<int64>(expected_data_.size()),
- (*file)->BytesSoFar());
+ // Setup the stream to do be a data append; don't actually trigger
+ // the callback or do verifications.
+ void SetupDataAppend(const char **data_chunks, size_t num_chunks,
+ ::testing::Sequence s) {
+ DCHECK(input_stream_);
+ for (size_t i = 0; i < num_chunks; i++) {
+ const char *source_data = data_chunks[i];
+ size_t length = strlen(source_data);
+ scoped_refptr<net::IOBuffer> data = new net::IOBuffer(length);
+ memcpy(data->data(), source_data, length);
+ EXPECT_CALL(*input_stream_, Read(_, _))
+ .InSequence(s)
+ .WillOnce(DoAll(SetArgPointee<0>(data),
+ SetArgPointee<1>(length),
+ Return(content::ByteStreamReader::STREAM_HAS_DATA)))
+ .RetiresOnSaturation();
+ expected_data_ += source_data;
+ }
+ }
+
+ void VerifyStreamAndSize() {
+ ::testing::Mock::VerifyAndClearExpectations(input_stream_);
+ int64 size;
+ EXPECT_TRUE(file_util::GetFileSize(download_file_->FullPath(), &size));
+ EXPECT_EQ(expected_data_.size(), static_cast<size_t>(size));
+ }
+
+ // TODO(rdsmith): Manage full percentage issues properly.
+ void AppendDataToFile(const char **data_chunks, size_t num_chunks) {
+ ::testing::Sequence s1;
+ SetupDataAppend(data_chunks, num_chunks, s1);
+ EXPECT_CALL(*input_stream_, Read(_, _))
+ .InSequence(s1)
+ .WillOnce(Return(content::ByteStreamReader::STREAM_EMPTY))
+ .RetiresOnSaturation();
+ sink_callback_.Run();
+ VerifyStreamAndSize();
+ }
+
+ void SetupFinishStream(content::DownloadInterruptReason interrupt_reason,
+ ::testing::Sequence s) {
+ EXPECT_CALL(*input_stream_, Read(_, _))
+ .InSequence(s)
+ .WillOnce(Return(content::ByteStreamReader::STREAM_COMPLETE))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*input_stream_, GetStatus())
+ .InSequence(s)
+ .WillOnce(Return(interrupt_reason))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*input_stream_, RegisterCallback(_))
+ .RetiresOnSaturation();
+ }
+
+ void FinishStream(content::DownloadInterruptReason interrupt_reason,
+ bool check_download_manager) {
+ ::testing::Sequence s1;
+ SetupFinishStream(interrupt_reason, s1);
+ sink_callback_.Run();
+ VerifyStreamAndSize();
+ if (check_download_manager) {
+ EXPECT_CALL(*download_manager_, OnResponseCompleted(_, _, _));
+ loop_.RunAllPending();
+ ::testing::Mock::VerifyAndClearExpectations(download_manager_.get());
+ EXPECT_CALL(*(download_manager_.get()),
+ UpdateDownload(
+ DownloadId(kValidIdDomain, kDummyDownloadId + 0).local(),
+ _, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke(this,
+ &DownloadFileTest::SetUpdateDownloadInfo));
+ }
}
protected:
@@ -126,6 +236,13 @@ class DownloadFileTest : public testing::Test {
// DownloadFile instance we are testing.
scoped_ptr<DownloadFile> download_file_;
+ // Stream for sending data into the download file.
+ // Owned by download_file_; will be alive for lifetime of download_file_.
+ StrictMock<MockByteStreamReader>* input_stream_;
+
+ // Sink callback data for stream.
+ base::Closure sink_callback_;
+
// Latest update sent to the download manager.
int64 bytes_;
int64 bytes_per_sec_;
@@ -157,8 +274,7 @@ const int DownloadFileTest::kDummyRequestId = 67;
// Rename the file before any data is downloaded, after some has, after it all
// has, and after it's closed.
TEST_F(DownloadFileTest, RenameFileFinal) {
- CreateDownloadFile(&download_file_, 0, true);
- ASSERT_EQ(net::OK, download_file_->Initialize());
+ ASSERT_TRUE(CreateDownloadFile(0, true));
FilePath initial_path(download_file_->FullPath());
EXPECT_TRUE(file_util::PathExists(initial_path));
FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
@@ -176,8 +292,8 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
EXPECT_TRUE(file_util::PathExists(path_1));
// Download the data.
- AppendDataToFile(&download_file_, kTestData1);
- AppendDataToFile(&download_file_, kTestData2);
+ const char* chunks1[] = { kTestData1, kTestData2 };
+ AppendDataToFile(chunks1, 2);
// Rename the file after downloading some data.
EXPECT_EQ(net::OK, download_file_->Rename(path_2));
@@ -188,7 +304,8 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
EXPECT_FALSE(file_util::PathExists(path_1));
EXPECT_TRUE(file_util::PathExists(path_2));
- AppendDataToFile(&download_file_, kTestData3);
+ const char* chunks2[] = { kTestData3 };
+ AppendDataToFile(chunks2, 1);
// Rename the file after downloading all the data.
EXPECT_EQ(net::OK, download_file_->Rename(path_3));
@@ -202,8 +319,8 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
// Should not be able to get the hash until the file is closed.
std::string hash;
EXPECT_FALSE(download_file_->GetHash(&hash));
-
- download_file_->Finish();
+ FinishStream(content::DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ loop_.RunAllPending();
// Rename the file after downloading all the data and closing the file.
EXPECT_EQ(net::OK, download_file_->Rename(path_4));
@@ -218,17 +335,100 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
EXPECT_TRUE(download_file_->GetHash(&hash));
EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
- DestroyDownloadFile(&download_file_, 0);
+ DestroyDownloadFile(0);
+}
+
+// Various tests of the StreamActive method.
+TEST_F(DownloadFileTest, StreamEmptySuccess) {
+ ASSERT_TRUE(CreateDownloadFile(0, true));
+ FilePath initial_path(download_file_->FullPath());
+ EXPECT_TRUE(file_util::PathExists(initial_path));
+
+ // Test that calling the sink_callback_ on an empty stream shouldn't
+ // do anything.
+ AppendDataToFile(NULL, 0);
+ ::testing::Mock::VerifyAndClearExpectations(download_manager_.get());
+ EXPECT_CALL(*(download_manager_.get()),
+ UpdateDownload(
+ DownloadId(kValidIdDomain, kDummyDownloadId + 0).local(),
+ _, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
+
+ // Finish the download this way and make sure we see it on the
+ // DownloadManager.
+ EXPECT_CALL(*(download_manager_.get()),
+ OnResponseCompleted(DownloadId(kValidIdDomain,
+ kDummyDownloadId + 0).local(),
+ 0, _));
+ FinishStream(content::DOWNLOAD_INTERRUPT_REASON_NONE, false);
+
+ DestroyDownloadFile(0);
+}
+
+TEST_F(DownloadFileTest, StreamEmptyError) {
+ ASSERT_TRUE(CreateDownloadFile(0, true));
+ FilePath initial_path(download_file_->FullPath());
+ EXPECT_TRUE(file_util::PathExists(initial_path));
+
+ // Finish the download in error and make sure we see it on the
+ // DownloadManager.
+ EXPECT_CALL(*(download_manager_.get()),
+ OnDownloadInterrupted(
+ DownloadId(kValidIdDomain, kDummyDownloadId + 0).local(),
+ 0, _,
+ content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED));
+ FinishStream(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false);
+
+ DestroyDownloadFile(0);
+}
+
+TEST_F(DownloadFileTest, StreamNonEmptySuccess) {
+ ASSERT_TRUE(CreateDownloadFile(0, true));
+ FilePath initial_path(download_file_->FullPath());
+ EXPECT_TRUE(file_util::PathExists(initial_path));
+
+ const char* chunks1[] = { kTestData1, kTestData2 };
+ ::testing::Sequence s1;
+ SetupDataAppend(chunks1, 2, s1);
+ SetupFinishStream(content::DOWNLOAD_INTERRUPT_REASON_NONE, s1);
+ EXPECT_CALL(*(download_manager_.get()),
+ OnResponseCompleted(DownloadId(kValidIdDomain,
+ kDummyDownloadId + 0).local(),
+ strlen(kTestData1) + strlen(kTestData2),
+ _));
+ sink_callback_.Run();
+ VerifyStreamAndSize();
+ DestroyDownloadFile(0);
+}
+
+TEST_F(DownloadFileTest, StreamNonEmptyError) {
+ ASSERT_TRUE(CreateDownloadFile(0, true));
+ FilePath initial_path(download_file_->FullPath());
+ EXPECT_TRUE(file_util::PathExists(initial_path));
+
+ const char* chunks1[] = { kTestData1, kTestData2 };
+ ::testing::Sequence s1;
+ SetupDataAppend(chunks1, 2, s1);
+ SetupFinishStream(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED,
+ s1);
+ EXPECT_CALL(*(download_manager_.get()),
+ OnDownloadInterrupted(
+ DownloadId(kValidIdDomain, kDummyDownloadId + 0).local(),
+ strlen(kTestData1) + strlen(kTestData2), _,
+ content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED));
+ sink_callback_.Run();
+ VerifyStreamAndSize();
+ DestroyDownloadFile(0);
}
// Send some data, wait 3/4s of a second, run the message loop, and
// confirm the values the DownloadManager received are correct.
TEST_F(DownloadFileTest, ConfirmUpdate) {
- CreateDownloadFile(&download_file_, 0, true);
- ASSERT_EQ(net::OK, download_file_->Initialize());
+ CreateDownloadFile(0, true);
- AppendDataToFile(&download_file_, kTestData1);
- AppendDataToFile(&download_file_, kTestData2);
+ const char* chunks1[] = { kTestData1, kTestData2 };
+ AppendDataToFile(chunks1, 2);
// Run the message loops for 750ms and check for results.
loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
@@ -239,6 +439,6 @@ TEST_F(DownloadFileTest, ConfirmUpdate) {
bytes_);
EXPECT_EQ(download_file_->GetHashState(), hash_state_);
- download_file_->Finish();
- DestroyDownloadFile(&download_file_, 0);
+ FinishStream(content::DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ DestroyDownloadFile(0);
}
diff --git a/content/browser/download/download_item_impl_unittest.cc b/content/browser/download/download_item_impl_unittest.cc
index 3f223fc..abe5c57 100644
--- a/content/browser/download/download_item_impl_unittest.cc
+++ b/content/browser/download/download_item_impl_unittest.cc
@@ -5,6 +5,7 @@
#include "base/message_loop.h"
#include "base/stl_util.h"
#include "base/threading/thread.h"
+#include "content/browser/download/byte_stream.h"
#include "content/browser/download/download_create_info.h"
#include "content/browser/download/download_file_manager.h"
#include "content/browser/download/download_item_impl.h"
@@ -58,8 +59,21 @@ class MockRequestHandle : public DownloadRequestHandleInterface {
class MockDownloadFileFactory
: public DownloadFileManager::DownloadFileFactory {
public:
- MOCK_METHOD5(CreateFile,
+ content::DownloadFile* CreateFile(
+ DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream_reader,
+ const DownloadRequestHandle& request_handle,
+ DownloadManager* mgr,
+ bool calculate_hash,
+ const net::BoundNetLog& bound_net_log) {
+ return MockCreateFile(
+ info, stream_reader.get(), request_handle, mgr, calculate_hash,
+ bound_net_log);
+ }
+
+ MOCK_METHOD6(MockCreateFile,
content::DownloadFile*(DownloadCreateInfo*,
+ content::ByteStreamReader*,
const DownloadRequestHandle&,
DownloadManager*,
bool,
@@ -70,12 +84,15 @@ class MockDownloadFileManager : public DownloadFileManager {
public:
MockDownloadFileManager();
MOCK_METHOD0(Shutdown, void());
- MOCK_METHOD2(StartDownload,
- void(DownloadCreateInfo*, const DownloadRequestHandle&));
- MOCK_METHOD2(UpdateDownload, void(DownloadId, content::DownloadBuffer*));
- MOCK_METHOD3(OnResponseCompleted,
- void(DownloadId, content::DownloadInterruptReason,
- const std::string&));
+ MOCK_METHOD3(MockStartDownload,
+ void(DownloadCreateInfo*, content::ByteStreamReader*,
+ const DownloadRequestHandle&));
+ virtual void StartDownload(scoped_ptr<DownloadCreateInfo> info,
+ scoped_ptr<content::ByteStreamReader> stream,
+ const DownloadRequestHandle& request_handle) {
+ MockStartDownload(info.release(), stream.release(), request_handle);
+ }
+
MOCK_METHOD1(CancelDownload, void(DownloadId));
MOCK_METHOD1(CompleteDownload, void(DownloadId));
MOCK_METHOD1(OnDownloadManagerShutdown, void(DownloadManager*));
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index cc38b29..1be540f 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -16,7 +16,6 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
-#include "content/browser/download/download_buffer.h"
#include "content/browser/download/download_create_info.h"
#include "content/browser/download/download_file_impl.h"
#include "content/browser/download/download_file_manager.h"
@@ -66,6 +65,10 @@ using ::testing::NiceMock;
using ::testing::ReturnRef;
using ::testing::Return;
+namespace content {
+class ByteStreamReader;
+}
+
namespace {
FilePath GetTempDownloadPath(const FilePath& suggested_path) {
@@ -79,6 +82,7 @@ class MockDownloadFileFactory
virtual DownloadFile* CreateFile(
DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
DownloadManager* download_manager,
bool calculate_hash,
@@ -87,6 +91,7 @@ class MockDownloadFileFactory
DownloadFile* MockDownloadFileFactory::CreateFile(
DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
DownloadManager* download_manager,
bool calculate_hash,
@@ -261,8 +266,7 @@ class DownloadManagerTest : public testing::Test {
download_manager_(new DownloadManagerImpl(
download_manager_delegate_.get(), NULL)),
ui_thread_(BrowserThread::UI, &message_loop_),
- file_thread_(BrowserThread::FILE, &message_loop_),
- download_buffer_(new content::DownloadBuffer) {
+ file_thread_(BrowserThread::FILE, &message_loop_) {
download_manager_->Init(browser_context.get());
download_manager_delegate_->set_download_manager(download_manager_);
}
@@ -313,23 +317,6 @@ class DownloadManagerTest : public testing::Test {
download_manager_->OnTargetPathAvailable(download);
}
- void UpdateData(int32 id, const char* data, size_t length) {
- // We are passing ownership of this buffer to the download file manager.
- net::IOBuffer* io_buffer = new net::IOBuffer(length);
- // We need |AddRef()| because we do a |Release()| in |UpdateDownload()|.
- io_buffer->AddRef();
- memcpy(io_buffer->data(), data, length);
-
- download_buffer_->AddData(io_buffer, length);
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&DownloadFileManager::UpdateDownload, file_manager_.get(),
- DownloadId(kValidIdDomain, id), download_buffer_));
-
- message_loop_.RunAllPending();
- }
-
void OnDownloadInterrupted(int32 download_id, int64 size,
const std::string& hash_state,
content::DownloadInterruptReason reason) {
@@ -356,7 +343,6 @@ class DownloadManagerTest : public testing::Test {
MessageLoopForUI message_loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread file_thread_;
- scoped_refptr<content::DownloadBuffer> download_buffer_;
ScopedTempDir scoped_download_dir_;
DownloadFileManager* file_manager() {
@@ -378,6 +364,7 @@ const size_t DownloadManagerTest::kTestDataLen =
class DownloadFileWithErrors : public DownloadFileImpl {
public:
DownloadFileWithErrors(DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
DownloadManager* manager,
bool calculate_hash);
virtual ~DownloadFileWithErrors() {}
@@ -406,10 +393,13 @@ class DownloadFileWithErrors : public DownloadFileImpl {
net::Error forced_error_;
};
-DownloadFileWithErrors::DownloadFileWithErrors(DownloadCreateInfo* info,
- DownloadManager* manager,
- bool calculate_hash)
+DownloadFileWithErrors::DownloadFileWithErrors(
+ DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
+ DownloadManager* manager,
+ bool calculate_hash)
: DownloadFileImpl(info,
+ stream.Pass(),
new DownloadRequestHandle(),
manager,
calculate_hash,
@@ -575,8 +565,16 @@ TEST_F(DownloadManagerTest, MAYBE_StartDownload) {
info->mime_type = kStartDownloadCases[i].mime_type;
download_manager_->CreateDownloadItem(info.get(), DownloadRequestHandle());
+ scoped_ptr<content::ByteStreamWriter> stream_writer;
+ scoped_ptr<content::ByteStreamReader> stream_reader;
+ content::CreateByteStream(message_loop_.message_loop_proxy(),
+ message_loop_.message_loop_proxy(),
+ kTestDataLen, &stream_writer, &stream_reader);
+
DownloadFile* download_file(
- new DownloadFileImpl(info.get(), new DownloadRequestHandle(),
+ new DownloadFileImpl(info.get(),
+ stream_reader.Pass(),
+ new DownloadRequestHandle(),
download_manager_, false,
scoped_ptr<PowerSaveBlocker>(NULL).Pass(),
net::BoundNetLog()));
@@ -882,6 +880,13 @@ TEST_F(DownloadManagerTest, DownloadFilenameTest) {
}
}
+void WriteCopyToStream(const char *source,
+ size_t len, content::ByteStreamWriter* stream) {
+ scoped_refptr<net::IOBuffer> copy(new net::IOBuffer(len));
+ memcpy(copy.get()->data(), source, len);
+ stream->Write(copy, len);
+}
+
TEST_F(DownloadManagerTest, DownloadInterruptTest) {
using ::testing::_;
using ::testing::CreateFunctor;
@@ -900,16 +905,12 @@ TEST_F(DownloadManagerTest, DownloadInterruptTest) {
const FilePath cr_path(GetTempDownloadPath(new_path));
MockDownloadFile* download_file(new NiceMock<MockDownloadFile>());
- ON_CALL(*download_file, AppendDataToFile(_, _))
- .WillByDefault(Return(net::OK));
// |download_file| is owned by DownloadFileManager.
AddMockDownloadToFileManager(info->download_id.local(), download_file);
EXPECT_CALL(*download_file, Rename(cr_path))
.WillOnce(Return(net::OK));
- EXPECT_CALL(*download_file, AppendDataToFile(kTestData, kTestDataLen))
- .WillOnce(Return(net::OK));
EXPECT_CALL(*download_file, Cancel());
download_manager_->CreateDownloadItem(info.get(), DownloadRequestHandle());
@@ -919,7 +920,6 @@ TEST_F(DownloadManagerTest, DownloadInterruptTest) {
EXPECT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
scoped_ptr<ItemObserver> observer(new ItemObserver(download));
- download_file->AppendDataToFile(kTestData, kTestDataLen);
ContinueDownloadWithPath(download, new_path);
message_loop_.RunAllPending();
EXPECT_TRUE(GetActiveDownloadItem(0) != NULL);
@@ -968,6 +968,12 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadFileErrorTest) {
path,
base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE));
+ // Make sure the DFM exists; we'll need it later.
+ // TODO(rdsmith): This is ugly and should be rewritten, but a large
+ // rewrite of this test is in progress in a different CL, so doing it
+ // the hacky way for now.
+ (void) file_manager();
+
// Normally, the download system takes ownership of info, and is
// responsible for deleting it. In these unit tests, however, we
// don't call the function that deletes it, so we do so ourselves.
@@ -979,14 +985,17 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadFileErrorTest) {
info->total_bytes = static_cast<int64>(kTestDataLen * 3);
info->save_info.file_path = path;
info->save_info.file_stream.reset(stream);
+ scoped_ptr<content::ByteStreamWriter> stream_input;
+ scoped_ptr<content::ByteStreamReader> stream_output;
+ content::CreateByteStream(message_loop_.message_loop_proxy(),
+ message_loop_.message_loop_proxy(),
+ kTestDataLen, &stream_input, &stream_output);
// Create a download file that we can insert errors into.
- DownloadFileWithErrors* download_file(new DownloadFileWithErrors(
- info.get(), download_manager_, false));
+ scoped_ptr<DownloadFileWithErrors> download_file(new DownloadFileWithErrors(
+ info.get(), stream_output.Pass(), download_manager_, false));
download_file->Initialize();
- AddDownloadToFileManager(local_id, download_file);
- // |download_file| is owned by DownloadFileManager.
download_manager_->CreateDownloadItem(info.get(), DownloadRequestHandle());
DownloadItem* download = GetActiveDownloadItem(0);
@@ -996,7 +1005,7 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadFileErrorTest) {
scoped_ptr<ItemObserver> observer(new ItemObserver(download));
// Add some data before finalizing the file name.
- UpdateData(local_id, kTestData, kTestDataLen);
+ WriteCopyToStream(kTestData, kTestDataLen, stream_input.get());
// Finalize the file name.
ContinueDownloadWithPath(download, path);
@@ -1004,11 +1013,12 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadFileErrorTest) {
EXPECT_TRUE(GetActiveDownloadItem(0) != NULL);
// Add more data.
- UpdateData(local_id, kTestData, kTestDataLen);
+ WriteCopyToStream(kTestData, kTestDataLen, stream_input.get());
// Add more data, but an error occurs.
download_file->set_forced_error(net::ERR_FAILED);
- UpdateData(local_id, kTestData, kTestDataLen);
+ WriteCopyToStream(kTestData, kTestDataLen, stream_input.get());
+ message_loop_.RunAllPending();
// Check the state. The download should have been interrupted.
EXPECT_TRUE(GetActiveDownloadItem(0) == NULL);
@@ -1045,15 +1055,11 @@ TEST_F(DownloadManagerTest, DownloadCancelTest) {
const FilePath cr_path(GetTempDownloadPath(new_path));
MockDownloadFile* download_file(new NiceMock<MockDownloadFile>());
- ON_CALL(*download_file, AppendDataToFile(_, _))
- .WillByDefault(Return(net::OK));
AddMockDownloadToFileManager(info->download_id.local(), download_file);
// |download_file| is owned by DownloadFileManager.
EXPECT_CALL(*download_file, Rename(cr_path))
.WillOnce(Return(net::OK));
- EXPECT_CALL(*download_file, AppendDataToFile(kTestData, kTestDataLen))
- .WillOnce(Return(net::OK));
EXPECT_CALL(*download_file, Cancel());
download_manager_->CreateDownloadItem(info.get(), DownloadRequestHandle());
@@ -1068,8 +1074,6 @@ TEST_F(DownloadManagerTest, DownloadCancelTest) {
message_loop_.RunAllPending();
EXPECT_TRUE(GetActiveDownloadItem(0) != NULL);
- download_file->AppendDataToFile(kTestData, kTestDataLen);
-
download->Cancel(false);
message_loop_.RunAllPending();
@@ -1124,6 +1128,11 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadOverwriteTest) {
info->download_id = DownloadId(kValidIdDomain, 0);
info->prompt_user_for_save_location = true;
info->url_chain.push_back(GURL());
+ scoped_ptr<content::ByteStreamWriter> stream_input;
+ scoped_ptr<content::ByteStreamReader> stream_output;
+ content::CreateByteStream(message_loop_.message_loop_proxy(),
+ message_loop_.message_loop_proxy(),
+ kTestDataLen, &stream_input, &stream_output);
download_manager_->CreateDownloadItem(info.get(), DownloadRequestHandle());
@@ -1138,7 +1147,8 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadOverwriteTest) {
// name has been chosen, so we need to initialize the download file
// properly.
DownloadFile* download_file(
- new DownloadFileImpl(info.get(), new DownloadRequestHandle(),
+ new DownloadFileImpl(info.get(), stream_output.Pass(),
+ new DownloadRequestHandle(),
download_manager_, false,
scoped_ptr<PowerSaveBlocker>(NULL).Pass(),
net::BoundNetLog()));
@@ -1152,7 +1162,7 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadOverwriteTest) {
message_loop_.RunAllPending();
EXPECT_TRUE(GetActiveDownloadItem(0) != NULL);
- download_file->AppendDataToFile(kTestData, kTestDataLen);
+ WriteCopyToStream(kTestData, kTestDataLen, stream_input.get());
// Finish the download.
OnResponseCompleted(0, kTestDataLen, "");
@@ -1198,6 +1208,11 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadRemoveTest) {
info->download_id = DownloadId(kValidIdDomain, 0);
info->prompt_user_for_save_location = true;
info->url_chain.push_back(GURL());
+ scoped_ptr<content::ByteStreamWriter> stream_input;
+ scoped_ptr<content::ByteStreamReader> stream_output;
+ content::CreateByteStream(message_loop_.message_loop_proxy(),
+ message_loop_.message_loop_proxy(),
+ kTestDataLen, &stream_input, &stream_output);
download_manager_->CreateDownloadItem(info.get(), DownloadRequestHandle());
@@ -1212,7 +1227,8 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadRemoveTest) {
// name has been chosen, so we need to initialize the download file
// properly.
DownloadFile* download_file(
- new DownloadFileImpl(info.get(), new DownloadRequestHandle(),
+ new DownloadFileImpl(info.get(), stream_output.Pass(),
+ new DownloadRequestHandle(),
download_manager_, false,
scoped_ptr<PowerSaveBlocker>(NULL).Pass(),
net::BoundNetLog()));
@@ -1226,7 +1242,7 @@ TEST_F(DownloadManagerTest, MAYBE_DownloadRemoveTest) {
message_loop_.RunAllPending();
EXPECT_TRUE(GetActiveDownloadItem(0) != NULL);
- download_file->AppendDataToFile(kTestData, kTestDataLen);
+ WriteCopyToStream(kTestData, kTestDataLen, stream_input.get());
// Finish the download.
OnResponseCompleted(0, kTestDataLen, "");
diff --git a/content/browser/download/download_net_log_parameters.cc b/content/browser/download/download_net_log_parameters.cc
index 244a38f..60a5b82 100644
--- a/content/browser/download/download_net_log_parameters.cc
+++ b/content/browser/download/download_net_log_parameters.cc
@@ -218,6 +218,22 @@ Value* FileOpenedParameters::ToValue() const {
FileOpenedParameters::~FileOpenedParameters() {}
+FileStreamDrainedParameters::FileStreamDrainedParameters(
+ size_t stream_size, size_t num_buffers)
+ : stream_size_(stream_size), num_buffers_(num_buffers) {
+}
+
+Value* FileStreamDrainedParameters::ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+
+ dict->SetInteger("stream_size", static_cast<int>(stream_size_));
+ dict->SetInteger("num_buffers", static_cast<int>(num_buffers_));
+
+ return dict;
+}
+
+FileStreamDrainedParameters::~FileStreamDrainedParameters() { }
+
FileRenamedParameters::FileRenamedParameters(
const std::string& old_filename, const std::string& new_filename)
: old_filename_(old_filename), new_filename_(new_filename) {
diff --git a/content/browser/download/download_net_log_parameters.h b/content/browser/download/download_net_log_parameters.h
index 5e0cf30..db97083 100644
--- a/content/browser/download/download_net_log_parameters.h
+++ b/content/browser/download/download_net_log_parameters.h
@@ -181,6 +181,23 @@ class FileOpenedParameters : public net::NetLog::EventParameters {
DISALLOW_COPY_AND_ASSIGN(FileOpenedParameters);
};
+// NetLog parameters when a DownloadFile is opened.
+class FileStreamDrainedParameters : public net::NetLog::EventParameters {
+ public:
+ FileStreamDrainedParameters(size_t stream_size,
+ size_t num_buffers);
+ virtual base::Value* ToValue() const OVERRIDE;
+
+ protected:
+ virtual ~FileStreamDrainedParameters();
+
+ private:
+ const size_t stream_size_;
+ const size_t num_buffers_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileStreamDrainedParameters);
+};
+
// NetLog parameters when a DownloadFile is renamed.
class FileRenamedParameters : public net::NetLog::EventParameters {
public:
diff --git a/content/browser/download/download_resource_handler.cc b/content/browser/download/download_resource_handler.cc
index 37f5b16..c255bb8 100644
--- a/content/browser/download/download_resource_handler.cc
+++ b/content/browser/download/download_resource_handler.cc
@@ -8,15 +8,16 @@
#include "base/bind.h"
#include "base/logging.h"
+#include "base/message_loop_proxy.h"
#include "base/metrics/histogram.h"
#include "base/metrics/stats_counters.h"
#include "base/stringprintf.h"
-#include "content/browser/download/download_buffer.h"
#include "content/browser/download/download_create_info.h"
#include "content/browser/download/download_file_manager.h"
#include "content/browser/download/download_interrupt_reasons_impl.h"
#include "content/browser/download/download_manager_impl.h"
#include "content/browser/download/download_request_handle.h"
+#include "content/browser/download/byte_stream.h"
#include "content/browser/download/download_stats.h"
#include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
#include "content/browser/renderer_host/resource_request_info_impl.h"
@@ -39,6 +40,8 @@ using content::ResourceRequestInfoImpl;
namespace {
+static const int kDownloadByteStreamSize = 100 * 1024;
+
void CallStartedCBOnUIThread(
const DownloadResourceHandler::OnStartedCallback& started_cb,
DownloadId id,
@@ -50,35 +53,31 @@ void CallStartedCBOnUIThread(
started_cb.Run(id, error);
}
-void StartDownloadOnUIThread(
- const scoped_refptr<DownloadFileManager>& download_file_manager,
+// Static function in order to prevent any accidental accesses to
+// DownloadResourceHandler members from the UI thread.
+static void StartOnUIThread(
scoped_ptr<DownloadCreateInfo> info,
+ scoped_ptr<content::ByteStreamReader> stream,
+ scoped_refptr<DownloadFileManager> download_file_manager,
const DownloadRequestHandle& handle,
- const base::Callback<void(DownloadId)>& set_download_id_callback) {
- DownloadId download_id;
+ const DownloadResourceHandler::OnStartedCallback& started_cb) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DownloadManager* download_manager = handle.GetDownloadManager();
- if (download_manager) {
- // The download manager may be NULL in unittests or if the page closed
- // right after starting the download.
- download_id = download_manager->delegate()->GetNextId();
- info->download_id = download_id;
-
- // NOTE: StartDownload triggers creation of the download destination file
- // that will hold the downloaded data. The set_download_id_callback
- // unblocks the DownloadResourceHandler to begin forwarding network data to
- // the download destination file. The sequence of these two steps is
- // critical as creation of the downloaded destination file has to happen
- // before we attempt to append data to it. Both of those operations happen
- // on the FILE thread.
-
- download_file_manager->StartDownload(info.release(), handle);
+ if (!download_manager) {
+ // NULL in unittests or if the page closed right after starting the
+ // download.
+ if (!started_cb.is_null())
+ started_cb.Run(DownloadId(), net::ERR_ACCESS_DENIED);
+ return;
}
+ DownloadId download_id = download_manager->delegate()->GetNextId();
+ info->download_id = download_id;
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(set_download_id_callback, download_id));
+ download_file_manager->StartDownload(info.Pass(), stream.Pass(), handle);
+
+ if (!started_cb.is_null())
+ started_cb.Run(download_id, net::OK);
}
} // namespace
@@ -88,7 +87,7 @@ DownloadResourceHandler::DownloadResourceHandler(
int render_view_id,
int request_id,
const GURL& url,
- DownloadFileManager* download_file_manager,
+ scoped_refptr<DownloadFileManager> download_file_manager,
net::URLRequest* request,
const DownloadResourceHandler::OnStartedCallback& started_cb,
const content::DownloadSaveInfo& save_info)
@@ -99,7 +98,6 @@ DownloadResourceHandler::DownloadResourceHandler(
request_(request),
started_cb_(started_cb),
save_info_(save_info),
- buffer_(new content::DownloadBuffer),
last_buffer_size_(0),
bytes_read_(0),
pause_count_(0),
@@ -128,6 +126,7 @@ bool DownloadResourceHandler::OnResponseStarted(
int request_id,
content::ResourceResponse* response,
bool* defer) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// There can be only one (call)
DCHECK(!on_response_started_called_);
on_response_started_called_ = true;
@@ -153,6 +152,16 @@ bool DownloadResourceHandler::OnResponseStarted(
base::Time::Now(), 0, content_length_, DownloadItem::IN_PROGRESS,
request_->net_log(), request_info->has_user_gesture(),
request_info->transition_type()));
+
+ // Create the ByteStream for sending data to the download sink.
+ scoped_ptr<content::ByteStreamReader> stream_reader;
+ CreateByteStream(
+ base::MessageLoopProxy::current(),
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
+ kDownloadByteStreamSize, &stream_writer_, &stream_reader);
+ stream_writer_->RegisterCallback(
+ base::Bind(&DownloadResourceHandler::ResumeRequest, AsWeakPtr()));
+
info->url_chain = request_->url_chain();
info->referrer_url = GURL(request_->referrer());
info->start_time = base::Time::Now();
@@ -198,19 +207,24 @@ bool DownloadResourceHandler::OnResponseStarted(
info->save_info = save_info_;
BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &StartDownloadOnUIThread,
- download_file_manager_,
- base::Passed(&info),
- request_handle,
- base::Bind(&DownloadResourceHandler::SetDownloadID, AsWeakPtr())));
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&StartOnUIThread,
+ base::Passed(info.Pass()),
+ base::Passed(stream_reader.Pass()),
+ download_file_manager_,
+ request_handle,
+ // Pass to StartOnUIThread so that variable
+ // access is always on IO thread but function
+ // is called on UI thread.
+ started_cb_));
+ // Guaranteed to be called in StartOnUIThread
+ started_cb_.Reset();
return true;
}
void DownloadResourceHandler::CallStartedCB(DownloadId id, net::Error error) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (started_cb_.is_null())
return;
BrowserThread::PostTask(
@@ -229,6 +243,7 @@ bool DownloadResourceHandler::OnWillStart(int request_id,
// writing and deletion.
bool DownloadResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
int* buf_size, int min_size) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(buf && buf_size);
if (!read_buffer_) {
*buf_size = min_size < 0 ? kReadBufSize : min_size;
@@ -242,6 +257,7 @@ bool DownloadResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
// Pass the buffer to the download file writer.
bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read,
bool* defer) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!read_buffer_) {
// Ignore spurious OnReadCompleted! Deferring from OnReadCompleted tells
// the ResourceDispatcherHost that we did not consume the data.
@@ -255,14 +271,6 @@ bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read,
return true;
}
- if (!download_id_.IsValid()) {
- // We can't start saving the data before we create the file on disk and
- // have a download id. The request will be un-paused in
- // DownloadFileManager::CreateDownloadFile.
- *defer = was_deferred_ = true;
- return true;
- }
-
base::TimeTicks now(base::TimeTicks::Now());
if (!last_read_time_.is_null()) {
double seconds_since_last_read = (now - last_read_time_).InSecondsF();
@@ -281,27 +289,17 @@ bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read,
return true;
bytes_read_ += *bytes_read;
DCHECK(read_buffer_);
- // Swap the data.
- net::IOBuffer* io_buffer = NULL;
- read_buffer_.swap(&io_buffer);
- size_t vector_size = buffer_->AddData(io_buffer, *bytes_read);
- bool need_update = (vector_size == 1); // Buffer was empty.
-
- // We are passing ownership of this buffer to the download file manager.
- if (need_update) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&DownloadFileManager::UpdateDownload,
- download_file_manager_, download_id_, buffer_));
- }
- // We schedule a pause outside of the read loop if there is too much file
- // writing work to do.
- if (vector_size > kLoadsToWrite) {
+ // Take the data ship it down the stream. If the stream is full, pause the
+ // request; the stream callback will resume it.
+ if (!stream_writer_->Write(read_buffer_, *bytes_read)) {
+ PauseRequest();
*defer = was_deferred_ = true;
- CheckWriteProgressLater();
+ last_stream_pause_time_ = now;
}
+ read_buffer_ = NULL; // Drop our reference.
+
return true;
}
@@ -309,37 +307,13 @@ bool DownloadResourceHandler::OnResponseCompleted(
int request_id,
const net::URLRequestStatus& status,
const std::string& security_info) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
VLOG(20) << __FUNCTION__ << "()" << DebugString()
<< " request_id = " << request_id
<< " status.status() = " << status.status()
<< " status.error() = " << status.error();
- int response = status.is_success() ? request_->GetResponseCode() : 0;
- if (download_id_.IsValid()) {
- OnResponseCompletedInternal(request_id, status, security_info, response);
- } else {
- // We got cancelled before the task which sets the id ran on the IO thread.
- // Wait for it.
- BrowserThread::PostTaskAndReply(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&base::DoNothing),
- base::Bind(&DownloadResourceHandler::OnResponseCompletedInternal,
- AsWeakPtr(), request_id, status, security_info, response));
- }
- // Can't trust request_ being value after this point.
- request_ = NULL;
- return true;
-}
+ int response_code = status.is_success() ? request_->GetResponseCode() : 0;
-void DownloadResourceHandler::OnResponseCompletedInternal(
- int request_id,
- const net::URLRequestStatus& status,
- const std::string& security_info,
- int response_code) {
- // NOTE: |request_| may be a dangling pointer at this point.
- VLOG(20) << __FUNCTION__ << "()"
- << " request_id = " << request_id
- << " status.status() = " << status.status()
- << " status.error() = " << status.error();
net::Error error_code = net::OK;
if (status.status() == net::URLRequestStatus::FAILED)
error_code = static_cast<net::Error>(status.error()); // Normal case.
@@ -383,35 +357,29 @@ void DownloadResourceHandler::OnResponseCompletedInternal(
download_stats::RecordAcceptsRanges(accept_ranges_, bytes_read_);
- // If the callback was already run on the UI thread, this will be a noop.
- CallStartedCB(download_id_, error_code);
+ CallStartedCB(DownloadId(), error_code);
- // We transfer ownership to |DownloadFileManager| to delete |buffer_|,
- // so that any functions queued up on the FILE thread are executed
- // before deletion.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&DownloadFileManager::OnResponseCompleted,
- download_file_manager_, download_id_, reason, security_info));
- buffer_ = NULL; // The buffer is longer needed by |DownloadResourceHandler|.
- read_buffer_ = NULL;
-}
+ // Send the info down the stream. Conditional is in case we get
+ // OnResponseCompleted without OnResponseStarted.
+ if (stream_writer_.get())
+ stream_writer_->Close(reason);
-void DownloadResourceHandler::SetDownloadID(DownloadId id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ stream_writer_.reset(); // We no longer need the stream.
+ read_buffer_ = NULL;
- download_id_ = id;
- MaybeResumeRequest();
+ // Stats
+ download_stats::RecordNetworkBandwidth(
+ bytes_read_, base::TimeTicks::Now() - download_start_time_,
+ total_pause_time_);
- CallStartedCB(
- download_id_,
- download_id_.IsValid() ? net::OK : net::ERR_ACCESS_DENIED);
+ return true;
}
// If the content-length header is not present (or contains something other
// than numbers), the incoming content_length is -1 (unknown size).
// Set the content length to 0 to indicate unknown size to DownloadManager.
void DownloadResourceHandler::SetContentLength(const int64& content_length) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
content_length_ = 0;
if (content_length > 0)
content_length_ = content_length;
@@ -419,22 +387,10 @@ void DownloadResourceHandler::SetContentLength(const int64& content_length) {
void DownloadResourceHandler::SetContentDisposition(
const std::string& content_disposition) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
content_disposition_ = content_disposition;
}
-void DownloadResourceHandler::CheckWriteProgress() {
- if (!buffer_.get())
- return; // The download completed while we were waiting to run.
-
- if (buffer_->size() > kLoadsToWrite) {
- // We'll come back later and see if it's okay to unpause the request.
- CheckWriteProgressLater();
- return;
- }
-
- MaybeResumeRequest();
-}
-
void DownloadResourceHandler::PauseRequest() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -446,7 +402,20 @@ void DownloadResourceHandler::ResumeRequest() {
DCHECK_LT(0, pause_count_);
--pause_count_;
- MaybeResumeRequest();
+
+ if (!was_deferred_)
+ return;
+ if (pause_count_ > 0)
+ return;
+
+ was_deferred_ = false;
+ if (!last_stream_pause_time_.is_null()) {
+ total_pause_time_ += (base::TimeTicks::Now() - last_stream_pause_time_);
+ last_stream_pause_time_ = base::TimeTicks();
+ }
+ ResourceDispatcherHostImpl::Get()->ResumeDeferredRequest(
+ global_id_.child_id,
+ global_id_.request_id);
}
void DownloadResourceHandler::CancelRequest() {
@@ -461,7 +430,6 @@ void DownloadResourceHandler::CancelRequest() {
std::string DownloadResourceHandler::DebugString() const {
return base::StringPrintf("{"
" url_ = " "\"%s\""
- " download_id_ = " "%d"
" global_id_ = {"
" child_id = " "%d"
" request_id = " "%d"
@@ -472,7 +440,6 @@ std::string DownloadResourceHandler::DebugString() const {
request_ ?
request_->url().spec().c_str() :
"<NULL request>",
- download_id_.local(),
global_id_.child_id,
global_id_.request_id,
render_view_id_,
@@ -480,38 +447,18 @@ std::string DownloadResourceHandler::DebugString() const {
}
DownloadResourceHandler::~DownloadResourceHandler() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
// This won't do anything if the callback was called before.
// If it goes through, it will likely be because OnWillStart() returned
// false somewhere in the chain of resource handlers.
- CallStartedCB(download_id_, net::ERR_ACCESS_DENIED);
+ CallStartedCB(DownloadId(), net::ERR_ACCESS_DENIED);
+
+ // Remove output stream callback if a stream exists.
+ if (stream_writer_.get())
+ stream_writer_->RegisterCallback(base::Closure());
UMA_HISTOGRAM_TIMES("SB2.DownloadDuration",
base::TimeTicks::Now() - download_start_time_);
}
-void DownloadResourceHandler::CheckWriteProgressLater() {
- if (!check_write_progress_timer_.IsRunning()) {
- check_write_progress_timer_.Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kThrottleTimeMs),
- this,
- &DownloadResourceHandler::CheckWriteProgress);
- }
-}
-
-void DownloadResourceHandler::MaybeResumeRequest() {
- if (!was_deferred_)
- return;
-
- if (pause_count_ > 0)
- return;
- if (!download_id_.IsValid())
- return;
- if (buffer_.get() && (buffer_->size() > kLoadsToWrite))
- return;
-
- was_deferred_ = false;
- ResourceDispatcherHostImpl::Get()->ResumeDeferredRequest(
- global_id_.child_id,
- global_id_.request_id);
-}
diff --git a/content/browser/download/download_resource_handler.h b/content/browser/download/download_resource_handler.h
index e82c5838..7f99316 100644
--- a/content/browser/download/download_resource_handler.h
+++ b/content/browser/download/download_resource_handler.h
@@ -24,7 +24,8 @@ class DownloadRequestHandle;
struct DownloadCreateInfo;
namespace content {
-class DownloadBuffer;
+class ByteStreamWriter;
+class ByteStreamReader;
}
namespace net {
@@ -38,17 +39,16 @@ class DownloadResourceHandler
public:
typedef content::DownloadUrlParameters::OnStartedCallback OnStartedCallback;
- static const size_t kLoadsToWrite = 100; // number of data buffers queued
-
// started_cb will be called exactly once on the UI thread.
- DownloadResourceHandler(int render_process_host_id,
- int render_view_id,
- int request_id,
- const GURL& url,
- DownloadFileManager* download_file_manager,
- net::URLRequest* request,
- const OnStartedCallback& started_cb,
- const content::DownloadSaveInfo& save_info);
+ DownloadResourceHandler(
+ int render_process_host_id,
+ int render_view_id,
+ int request_id,
+ const GURL& url,
+ scoped_refptr<DownloadFileManager> download_file_manager,
+ net::URLRequest* request,
+ const OnStartedCallback& started_cb,
+ const content::DownloadSaveInfo& save_info);
virtual bool OnUploadProgress(int request_id,
uint64 position,
@@ -93,18 +93,11 @@ class DownloadResourceHandler
private:
virtual ~DownloadResourceHandler();
- void OnResponseCompletedInternal(int request_id,
- const net::URLRequestStatus& status,
- const std::string& security_info,
- int response_code);
-
- void CheckWriteProgressLater();
- void CheckWriteProgress();
- void MaybeResumeRequest();
+ // Arrange for started_cb_ to be called on the UI thread with the
+ // below values, nulling out started_cb_. Should only be called
+ // on the IO thread.
void CallStartedCB(content::DownloadId id, net::Error error);
- void SetDownloadID(content::DownloadId id);
-
// If the content-length header is not present (or contains something other
// than numbers), the incoming content_length is -1 (unknown size).
// Set the content length to 0 to indicate unknown size to DownloadManager.
@@ -112,23 +105,26 @@ class DownloadResourceHandler
void SetContentDisposition(const std::string& content_disposition);
- content::DownloadId download_id_;
content::GlobalRequestID global_id_;
int render_view_id_;
- scoped_refptr<net::IOBuffer> read_buffer_;
std::string content_disposition_;
int64 content_length_;
scoped_refptr<DownloadFileManager> download_file_manager_;
net::URLRequest* request_;
- // This is used only on the UI thread.
+ // This is read only on the IO thread, but may only
+ // be called on the UI thread.
OnStartedCallback started_cb_;
content::DownloadSaveInfo save_info_;
- scoped_refptr<content::DownloadBuffer> buffer_;
- base::OneShotTimer<DownloadResourceHandler> check_write_progress_timer_;
+
+ // Data flow
+ scoped_refptr<net::IOBuffer> read_buffer_; // From URLRequest.
+ scoped_ptr<content::ByteStreamWriter> stream_writer_; // To rest of system.
// The following are used to collect stats.
base::TimeTicks download_start_time_;
base::TimeTicks last_read_time_;
+ base::TimeTicks last_stream_pause_time_;
+ base::TimeDelta total_pause_time_;
size_t last_buffer_size_;
int64 bytes_read_;
std::string accept_ranges_;
diff --git a/content/browser/download/download_stats.cc b/content/browser/download/download_stats.cc
index 40ed912..6332993 100644
--- a/content/browser/download/download_stats.cc
+++ b/content/browser/download/download_stats.cc
@@ -255,8 +255,7 @@ void RecordDownloadMimeType(const std::string& mime_type_string) {
void RecordFileThreadReceiveBuffers(size_t num_buffers) {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Download.FileThreadReceiveBuffers", num_buffers, 1,
- DownloadResourceHandler::kLoadsToWrite,
- DownloadResourceHandler::kLoadsToWrite);
+ 100, 100);
}
void RecordBandwidth(double actual_bandwidth, double potential_bandwidth) {
@@ -303,6 +302,45 @@ void RecordOpensOutstanding(int size) {
64/*num_buckets*/);
}
+void RecordContiguousWriteTime(base::TimeDelta time_blocked) {
+ UMA_HISTOGRAM_TIMES("Download.FileThreadBlockedTime", time_blocked);
+}
+
+void RecordNetworkBandwidth(size_t length,
+ base::TimeDelta elapsed_time,
+ base::TimeDelta paused_time) {
+ size_t non_pause_time_ms = (elapsed_time - paused_time).InMilliseconds();
+ if (0u == non_pause_time_ms)
+ non_pause_time_ms = 1;
+
+ // Note that this will be somewhat higher than sustainable network
+ // bandwidth because of buffering in the kernel during pauses.
+ // Using Bytes/s rather than bits/s so that this value is easily
+ // comparable with BandwidthOverall and BandwidthDisk.
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Download.BandwidthNetworkBytesPerSecond",
+ (1000 * length / non_pause_time_ms),
+ 1, 100000000, 50);
+}
+
+void RecordFileBandwidth(size_t length,
+ base::TimeDelta disk_write_time,
+ base::TimeDelta elapsed_time) {
+ size_t elapsed_time_ms = elapsed_time.InMilliseconds();
+ if (0u == elapsed_time_ms)
+ elapsed_time_ms = 1;
+ size_t disk_write_time_ms = disk_write_time.InMilliseconds();
+ if (0u == disk_write_time_ms)
+ disk_write_time_ms = 1;
+
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Download.BandwidthOverallBytesPerSecond",
+ (1000 * length / elapsed_time_ms), 1, 50000000, 50);
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Download.BandwidthDiskBytesPerSecond",
+ (1000 * length / disk_write_time_ms), 1, 50000000, 50);
+}
+
void RecordSavePackageEvent(SavePackageEvent event) {
UMA_HISTOGRAM_ENUMERATION("Download.SavePackage",
event,
diff --git a/content/browser/download/download_stats.h b/content/browser/download/download_stats.h
index 94bc2e0..7633e51 100644
--- a/content/browser/download/download_stats.h
+++ b/content/browser/download/download_stats.h
@@ -16,6 +16,7 @@
namespace base {
class Time;
+class TimeDelta;
class TimeTicks;
}
@@ -137,6 +138,19 @@ void RecordClearAllSize(int size);
// Record the number of completed unopened downloads when a download is opened.
void RecordOpensOutstanding(int size);
+// Record how long we block the file thread at a time.
+void RecordContiguousWriteTime(base::TimeDelta time_blocked);
+
+// Record overall bandwidth stats at the network end.
+void RecordNetworkBandwidth(size_t length,
+ base::TimeDelta elapsed_time,
+ base::TimeDelta paused_time);
+
+// Record overall bandwidth stats at the file end.
+void RecordFileBandwidth(size_t length,
+ base::TimeDelta disk_write_time,
+ base::TimeDelta elapsed_time);
+
enum SavePackageEvent {
// The user has started to save a page as a package.
SAVE_PACKAGE_STARTED,
diff --git a/content/browser/renderer_host/resource_dispatcher_host_impl.cc b/content/browser/renderer_host/resource_dispatcher_host_impl.cc
index 532ce2e..a44e443 100644
--- a/content/browser/renderer_host/resource_dispatcher_host_impl.cc
+++ b/content/browser/renderer_host/resource_dispatcher_host_impl.cc
@@ -570,7 +570,7 @@ ResourceDispatcherHostImpl::CreateResourceHandlerForDownload(
const DownloadResourceHandler::OnStartedCallback& started_cb) {
scoped_ptr<ResourceHandler> handler(
new DownloadResourceHandler(child_id, route_id, request_id,
- request->url(), download_file_manager_.get(),
+ request->url(), download_file_manager_,
request, started_cb, save_info));
if (delegate_) {
ScopedVector<ResourceThrottle> throttles;
diff --git a/content/browser/renderer_host/resource_dispatcher_host_unittest.cc b/content/browser/renderer_host/resource_dispatcher_host_unittest.cc
index 01fc598..f3d71e5 100644
--- a/content/browser/renderer_host/resource_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/resource_dispatcher_host_unittest.cc
@@ -265,6 +265,31 @@ class URLRequestTestDelayedStartJob : public net::URLRequestTestJob {
URLRequestTestDelayedStartJob*
URLRequestTestDelayedStartJob::list_head_ = NULL;
+// This class is a variation on URLRequestTestJob in that it
+// returns IO_pending errors before every read, not just the first one.
+class URLRequestTestDelayedCompletionJob : public net::URLRequestTestJob {
+ public:
+ explicit URLRequestTestDelayedCompletionJob(net::URLRequest* request)
+ : net::URLRequestTestJob(request) {}
+ URLRequestTestDelayedCompletionJob(net::URLRequest* request,
+ bool auto_advance)
+ : net::URLRequestTestJob(request, auto_advance) {}
+ URLRequestTestDelayedCompletionJob(net::URLRequest* request,
+ const std::string& response_headers,
+ const std::string& response_data,
+ bool auto_advance)
+ : net::URLRequestTestJob(request, response_headers,
+ response_data, auto_advance) {}
+
+ protected:
+ ~URLRequestTestDelayedCompletionJob() {}
+
+ private:
+ virtual bool NextReadAsync() OVERRIDE { return true; }
+};
+
+
+
// Associated with an URLRequest to determine if the URLRequest gets deleted.
class TestUserData : public base::SupportsUserData::Data {
public:
@@ -378,6 +403,7 @@ class ResourceDispatcherHostTest : public testing::Test,
&ResourceDispatcherHostTest::Factory);
EnsureTestSchemeIsAllowed();
delay_start_ = false;
+ delay_complete_ = false;
}
virtual void TearDown() {
@@ -455,6 +481,8 @@ class ResourceDispatcherHostTest : public testing::Test,
if (test_fixture_->response_headers_.empty()) {
if (delay_start_) {
return new URLRequestTestDelayedStartJob(request);
+ } else if (delay_complete_) {
+ return new URLRequestTestDelayedCompletionJob(request);
} else {
return new net::URLRequestTestJob(request);
}
@@ -463,6 +491,10 @@ class ResourceDispatcherHostTest : public testing::Test,
return new URLRequestTestDelayedStartJob(
request, test_fixture_->response_headers_,
test_fixture_->response_data_, false);
+ } else if (delay_complete_) {
+ return new URLRequestTestDelayedCompletionJob(
+ request, test_fixture_->response_headers_,
+ test_fixture_->response_data_, false);
} else {
return new net::URLRequestTestJob(request,
test_fixture_->response_headers_,
@@ -476,6 +508,10 @@ class ResourceDispatcherHostTest : public testing::Test,
delay_start_ = delay_job_start;
}
+ void SetDelayedCompleteJobGeneration(bool delay_job_complete) {
+ delay_complete_ = delay_job_complete;
+ }
+
MessageLoopForIO message_loop_;
BrowserThreadImpl ui_thread_;
BrowserThreadImpl file_thread_;
@@ -492,10 +528,12 @@ class ResourceDispatcherHostTest : public testing::Test,
ResourceType::Type resource_type_;
static ResourceDispatcherHostTest* test_fixture_;
static bool delay_start_;
+ static bool delay_complete_;
};
// Static.
ResourceDispatcherHostTest* ResourceDispatcherHostTest::test_fixture_ = NULL;
bool ResourceDispatcherHostTest::delay_start_ = false;
+bool ResourceDispatcherHostTest::delay_complete_ = false;
void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id,
int request_id,
@@ -1245,8 +1283,16 @@ TEST_F(ResourceDispatcherHostTest, IgnoreCancelForDownloads) {
response.size()));
std::string response_data("01234567890123456789\x01foobar");
+ // Get past sniffing metrics in the BufferedResourceHandler. Note that
+ // if we don't get past the sniffing metrics, the result will be that
+ // the BufferedResourceHandler won't have figured out that it's a download,
+ // won't have constructed a DownloadResourceHandler, and and the request
+ // will be successfully canceled below, failing the test.
+ response_data.resize(1025, ' ');
+
SetResponse(raw_headers, response_data);
SetResourceType(ResourceType::MAIN_FRAME);
+ SetDelayedCompleteJobGeneration(true);
HandleScheme("http");
MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah"));
@@ -1279,9 +1325,12 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContext) {
std::string raw_headers(net::HttpUtil::AssembleRawHeaders(response.data(),
response.size()));
std::string response_data("01234567890123456789\x01foobar");
+ // Get past sniffing metrics.
+ response_data.resize(1025, ' ');
SetResponse(raw_headers, response_data);
SetResourceType(ResourceType::MAIN_FRAME);
+ SetDelayedCompleteJobGeneration(true);
HandleScheme("http");
MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah"));
diff --git a/content/browser/renderer_host/x509_user_cert_resource_handler.cc b/content/browser/renderer_host/x509_user_cert_resource_handler.cc
index 828f813d..f66fdb6 100644
--- a/content/browser/renderer_host/x509_user_cert_resource_handler.cc
+++ b/content/browser/renderer_host/x509_user_cert_resource_handler.cc
@@ -115,9 +115,26 @@ bool X509UserCertResourceHandler::OnResponseCompleted(
}
void X509UserCertResourceHandler::AssembleResource() {
- size_t assembled_bytes = 0;
- resource_buffer_ = AssembleData(buffer_, &assembled_bytes);
- DCHECK_EQ(content_length_, assembled_bytes);
+ // 0-length IOBuffers are not allowed.
+ if (content_length_ == 0) {
+ resource_buffer_ = NULL;
+ return;
+ }
+
+ // Create the new buffer.
+ resource_buffer_ = new net::IOBuffer(content_length_);
+
+ // Copy the data into it.
+ size_t bytes_copied = 0;
+ for (size_t i = 0; i < buffer_.size(); ++i) {
+ net::IOBuffer* data = buffer_[i].first;
+ size_t data_len = buffer_[i].second;
+ DCHECK(data != NULL);
+ DCHECK_LE(bytes_copied + data_len, content_length_);
+ memcpy(resource_buffer_->data() + bytes_copied, data->data(), data_len);
+ bytes_copied += data_len;
+ }
+ DCHECK_EQ(content_length_, bytes_copied);
}
} // namespace content
diff --git a/content/browser/renderer_host/x509_user_cert_resource_handler.h b/content/browser/renderer_host/x509_user_cert_resource_handler.h
index b89ce4f..240e0f8 100644
--- a/content/browser/renderer_host/x509_user_cert_resource_handler.h
+++ b/content/browser/renderer_host/x509_user_cert_resource_handler.h
@@ -7,10 +7,12 @@
#pragma once
#include <string>
+#include <utility>
+#include <vector>
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/ref_counted.h"
-#include "content/browser/download/download_buffer.h"
#include "content/browser/renderer_host/resource_handler.h"
#include "googleurl/src/gurl.h"
@@ -70,6 +72,9 @@ class X509UserCertResourceHandler : public ResourceHandler {
const std::string& sec_info) OVERRIDE;
private:
+ typedef std::vector<std::pair<scoped_refptr<net::IOBuffer>,
+ size_t> > ContentVector;
+
void AssembleResource();
GURL url_;
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index cfbcba1..010110a 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -265,8 +265,6 @@
'browser/download/base_file.h',
'browser/download/byte_stream.cc',
'browser/download/byte_stream.h',
- 'browser/download/download_buffer.cc',
- 'browser/download/download_buffer.h',
'browser/download/download_create_info.cc',
'browser/download/download_create_info.h',
'browser/download/download_file.h',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index c1d4154..b7a742c 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -220,7 +220,6 @@
'browser/device_orientation/provider_unittest.cc',
'browser/download/base_file_unittest.cc',
'browser/download/byte_stream_unittest.cc',
- 'browser/download/download_buffer_unittest.cc',
'browser/download/download_file_manager_unittest.cc',
'browser/download/download_file_unittest.cc',
'browser/download/download_id_unittest.cc',
diff --git a/content/test/test_file_error_injector.cc b/content/test/test_file_error_injector.cc
index 09d96e0..b7585df 100644
--- a/content/test/test_file_error_injector.cc
+++ b/content/test/test_file_error_injector.cc
@@ -17,6 +17,10 @@
#include "content/public/browser/download_id.h"
#include "googleurl/src/gurl.h"
+namespace content {
+class ByteStreamReader;
+}
+
namespace {
DownloadFileManager* GetDownloadFileManager() {
@@ -35,6 +39,7 @@ class DownloadFileWithErrors: public DownloadFileImpl {
DownloadFileWithErrors(
const DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
DownloadRequestHandleInterface* request_handle,
content::DownloadManager* download_manager,
bool calculate_hash,
@@ -73,6 +78,7 @@ class DownloadFileWithErrors: public DownloadFileImpl {
DownloadFileWithErrors::DownloadFileWithErrors(
const DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
DownloadRequestHandleInterface* request_handle,
content::DownloadManager* download_manager,
bool calculate_hash,
@@ -81,6 +87,7 @@ DownloadFileWithErrors::DownloadFileWithErrors(
const ConstructionCallback& ctor_callback,
const DestructionCallback& dtor_callback)
: DownloadFileImpl(info,
+ stream.Pass(),
request_handle,
download_manager,
calculate_hash,
@@ -157,6 +164,7 @@ class DownloadFileWithErrorsFactory
// DownloadFileFactory interface.
virtual content::DownloadFile* CreateFile(
DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
content::DownloadManager* download_manager,
bool calculate_hash,
@@ -188,6 +196,7 @@ DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() {
content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile(
DownloadCreateInfo* info,
+ scoped_ptr<content::ByteStreamReader> stream,
const DownloadRequestHandle& request_handle,
content::DownloadManager* download_manager,
bool calculate_hash,
@@ -206,6 +215,7 @@ content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile(
}
return new DownloadFileWithErrors(info,
+ stream.Pass(),
new DownloadRequestHandle(request_handle),
download_manager,
calculate_hash,