summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/base/file_stream.h19
-rw-r--r--net/base/file_stream_posix.cc98
-rw-r--r--net/base/file_stream_unittest.cc108
-rw-r--r--net/base/file_stream_win.cc145
-rw-r--r--net/base/mock_file_stream.cc4
-rw-r--r--net/base/mock_file_stream.h6
-rw-r--r--net/url_request/url_request_file_job.cc2
7 files changed, 222 insertions, 160 deletions
diff --git a/net/base/file_stream.h b/net/base/file_stream.h
index 7017f30..b9efb25 100644
--- a/net/base/file_stream.h
+++ b/net/base/file_stream.h
@@ -21,6 +21,8 @@ class FilePath;
namespace net {
+class IOBuffer;
+
// TODO(darin): Move this to a more generic location.
// This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux.
enum Whence {
@@ -87,9 +89,6 @@ class NET_EXPORT FileStream {
// callback will be notified on the current thread (via the MessageLoop)
// when the read has completed.
//
- // The memory pointed to by |buf| must remain valid until the callback is
- // notified. TODO(satorux): Use IOBuffer instead of char*.
- //
// It is valid to destroy or close the file stream while there is an
// asynchronous read in progress. That will cancel the read and allow
// the buffer to be freed.
@@ -98,7 +97,8 @@ class NET_EXPORT FileStream {
// in-flight asynchronous operation.
//
// This method must not be called if the stream was opened WRITE_ONLY.
- virtual int Read(char* buf, int buf_len, const CompletionCallback& callback);
+ virtual int Read(IOBuffer* buf, int buf_len,
+ const CompletionCallback& callback);
// Call this method to read data from the current stream position
// synchronously. Up to buf_len bytes will be copied into buf. (In
@@ -129,9 +129,6 @@ class NET_EXPORT FileStream {
// callback will be notified on the current thread (via the MessageLoop)
// when the write has completed.
//
- // The memory pointed to by |buf| must remain valid until the callback
- // is notified. TODO(satorux): Use IOBuffer instead of char*.
- //
// It is valid to destroy or close the file stream while there is an
// asynchronous write in progress. That will cancel the write and allow
// the buffer to be freed.
@@ -140,7 +137,7 @@ class NET_EXPORT FileStream {
// in-flight asynchronous operation.
//
// This method must not be called if the stream was opened READ_ONLY.
- virtual int Write(const char* buf, int buf_len,
+ virtual int Write(IOBuffer* buf, int buf_len,
const CompletionCallback& callback);
// Call this method to write data at the current stream position
@@ -181,12 +178,6 @@ class NET_EXPORT FileStream {
void SetBoundNetLogSource(const net::BoundNetLog& owner_bound_net_log);
private:
- // Helper functions used to implement reads and writes.
- int ReadInternal(char* buf, int buf_len,
- const CompletionCallback& callback);
- int WriteInternal(const char* buf, int buf_len,
- const CompletionCallback& callback);
-
class AsyncContext;
friend class AsyncContext;
friend class FileStreamTest;
diff --git a/net/base/file_stream_posix.cc b/net/base/file_stream_posix.cc
index ded0cfc..86bf728 100644
--- a/net/base/file_stream_posix.cc
+++ b/net/base/file_stream_posix.cc
@@ -28,6 +28,7 @@
#include "base/synchronization/waitable_event.h"
#include "net/base/file_stream_metrics.h"
#include "net/base/file_stream_net_log_parameters.h"
+#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#if defined(OS_ANDROID)
@@ -167,11 +168,11 @@ class FileStream::AsyncContext {
// These methods post synchronous read() and write() calls to a WorkerThread.
void InitiateAsyncRead(
- base::PlatformFile file, char* buf, int buf_len,
+ base::PlatformFile file, IOBuffer* buf, int buf_len,
const net::BoundNetLog& bound_net_log,
const CompletionCallback& callback);
void InitiateAsyncWrite(
- base::PlatformFile file, const char* buf, int buf_len,
+ base::PlatformFile file, IOBuffer* buf, int buf_len,
const net::BoundNetLog& bound_net_log,
const CompletionCallback& callback);
@@ -197,6 +198,7 @@ class FileStream::AsyncContext {
// The MessageLoopForIO that this AsyncContext is running on.
MessageLoopForIO* const message_loop_;
CompletionCallback callback_; // The user provided callback.
+ scoped_refptr<IOBuffer> in_flight_buf_;
// This is used to synchronize between the AsyncContext destructor (which runs
// on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool
@@ -238,17 +240,19 @@ FileStream::AsyncContext::~AsyncContext() {
}
void FileStream::AsyncContext::InitiateAsyncRead(
- base::PlatformFile file, char* buf, int buf_len,
+ base::PlatformFile file, IOBuffer* buf, int buf_len,
const net::BoundNetLog& bound_net_log,
const CompletionCallback& callback) {
DCHECK(callback_.is_null());
+ DCHECK(!in_flight_buf_);
callback_ = callback;
+ in_flight_buf_ = buf; // Hold until the async operation ends.
base::WorkerPool::PostTask(
FROM_HERE,
base::Bind(&ReadFileTask,
file,
- buf,
+ buf->data(),
buf_len,
record_uma_,
bound_net_log,
@@ -258,17 +262,19 @@ void FileStream::AsyncContext::InitiateAsyncRead(
}
void FileStream::AsyncContext::InitiateAsyncWrite(
- base::PlatformFile file, const char* buf, int buf_len,
+ base::PlatformFile file, IOBuffer* buf, int buf_len,
const net::BoundNetLog& bound_net_log,
const CompletionCallback& callback) {
DCHECK(callback_.is_null());
+ DCHECK(!in_flight_buf_);
callback_ = callback;
+ in_flight_buf_ = buf; // Hold until the async operation ends.
base::WorkerPool::PostTask(
FROM_HERE,
base::Bind(&WriteFileTask,
file,
- buf,
+ buf->data(),
buf_len,
record_uma_,
bound_net_log,
@@ -301,14 +307,17 @@ void FileStream::AsyncContext::RunAsynchronousCallback() {
if (is_closing_) {
callback_.Reset();
+ in_flight_buf_ = NULL;
return;
}
DCHECK(!callback_.is_null());
- CompletionCallback temp;
- std::swap(temp, callback_);
+ CompletionCallback temp_callback = callback_;
+ callback_.Reset();
+ scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
+ in_flight_buf_ = NULL;
background_io_completed_.Reset();
- temp.Run(result_);
+ temp_callback.Run(result_);
}
// FileStream ------------------------------------------------------------
@@ -440,18 +449,29 @@ int64 FileStream::Available() {
}
int FileStream::Read(
- char* buf, int buf_len, const CompletionCallback& callback) {
+ IOBuffer* buf, int buf_len, const CompletionCallback& callback) {
DCHECK(async_context_.get());
- return ReadInternal(buf, buf_len, callback);
+
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+
+ // read(..., 0) will return 0, which indicates end-of-file.
+ DCHECK_GT(buf_len, 0);
+ DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
+
+ DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
+ // Make sure we don't have a request in flight.
+ DCHECK(async_context_->callback().is_null());
+ if (record_uma_)
+ async_context_->EnableErrorStatistics();
+ async_context_->InitiateAsyncRead(file_, buf, buf_len, bound_net_log_,
+ callback);
+ return ERR_IO_PENDING;
}
int FileStream::ReadSync(char* buf, int buf_len) {
DCHECK(!async_context_.get());
- return ReadInternal(buf, buf_len, CompletionCallback());
-}
-int FileStream::ReadInternal(
- char* buf, int buf_len, const CompletionCallback& callback) {
if (!IsOpen())
return ERR_UNEXPECTED;
@@ -459,18 +479,7 @@ int FileStream::ReadInternal(
DCHECK_GT(buf_len, 0);
DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
- if (async_context_.get()) {
- DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
- // If we're in async, make sure we don't have a request in flight.
- DCHECK(async_context_->callback().is_null());
- if (record_uma_)
- async_context_->EnableErrorStatistics();
- async_context_->InitiateAsyncRead(file_, buf, buf_len, bound_net_log_,
- callback);
- return ERR_IO_PENDING;
- } else {
- return ReadFile(file_, buf, buf_len, record_uma_, bound_net_log_);
- }
+ return ReadFile(file_, buf, buf_len, record_uma_, bound_net_log_);
}
int FileStream::ReadUntilComplete(char *buf, int buf_len) {
@@ -495,37 +504,36 @@ int FileStream::ReadUntilComplete(char *buf, int buf_len) {
}
int FileStream::Write(
- const char* buf, int buf_len, const CompletionCallback& callback) {
+ IOBuffer* buf, int buf_len, const CompletionCallback& callback) {
DCHECK(async_context_.get());
- return WriteInternal(buf, buf_len, callback);
+
+ // write(..., 0) will return 0, which indicates end-of-file.
+ DCHECK_GT(buf_len, 0);
+
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+
+ DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
+ // Make sure we don't have a request in flight.
+ DCHECK(async_context_->callback().is_null());
+ if (record_uma_)
+ async_context_->EnableErrorStatistics();
+ async_context_->InitiateAsyncWrite(file_, buf, buf_len, bound_net_log_,
+ callback);
+ return ERR_IO_PENDING;
}
int FileStream::WriteSync(
const char* buf, int buf_len) {
DCHECK(!async_context_.get());
- return WriteInternal(buf, buf_len, CompletionCallback());
-}
-int FileStream::WriteInternal(
- const char* buf, int buf_len, const CompletionCallback& callback) {
// write(..., 0) will return 0, which indicates end-of-file.
DCHECK_GT(buf_len, 0);
if (!IsOpen())
return ERR_UNEXPECTED;
- if (async_context_.get()) {
- DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
- // If we're in async, make sure we don't have a request in flight.
- DCHECK(async_context_->callback().is_null());
- if (record_uma_)
- async_context_->EnableErrorStatistics();
- async_context_->InitiateAsyncWrite(file_, buf, buf_len, bound_net_log_,
- callback);
- return ERR_IO_PENDING;
- } else {
- return WriteFile(file_, buf, buf_len, record_uma_, bound_net_log_);
- }
+ return WriteFile(file_, buf, buf_len, record_uma_, bound_net_log_);
}
int64 FileStream::Truncate(int64 bytes) {
diff --git a/net/base/file_stream_unittest.cc b/net/base/file_stream_unittest.cc
index 44044f6..537e6b1 100644
--- a/net/base/file_stream_unittest.cc
+++ b/net/base/file_stream_unittest.cc
@@ -10,6 +10,7 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/platform_file.h"
+#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,6 +23,13 @@ namespace {
const char kTestData[] = "0123456789";
const int kTestDataSize = arraysize(kTestData) - 1;
+// Creates an IOBufferWithSize that contains the kTestDataSize.
+IOBufferWithSize* CreateTestDataBuffer() {
+ IOBufferWithSize* buf = new IOBufferWithSize(kTestDataSize);
+ memcpy(buf->data(), kTestData, kTestDataSize);
+ return buf;
+}
+
} // namespace
class FileStreamTest : public PlatformTest {
@@ -197,15 +205,15 @@ TEST_F(FileStreamTest, AsyncRead) {
std::string data_read;
for (;;) {
- char buf[4];
- rv = stream.Read(buf, arraysize(buf), callback.callback());
+ scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
+ rv = stream.Read(buf, buf->size(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_LE(0, rv);
if (rv <= 0)
break;
total_bytes_read += rv;
- data_read.append(buf, rv);
+ data_read.append(buf->data(), rv);
}
EXPECT_EQ(file_size, total_bytes_read);
EXPECT_EQ(kTestData, data_read);
@@ -228,8 +236,8 @@ TEST_F(FileStreamTest, AsyncRead_EarlyClose) {
TestCompletionCallback callback;
- char buf[4];
- rv = stream.Read(buf, arraysize(buf), callback.callback());
+ scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
+ rv = stream.Read(buf, buf->size(), callback.callback());
stream.CloseSync();
if (rv < 0) {
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -237,7 +245,7 @@ TEST_F(FileStreamTest, AsyncRead_EarlyClose) {
MessageLoop::current()->RunAllPending();
EXPECT_FALSE(callback.have_result());
} else {
- EXPECT_EQ(std::string(kTestData, rv), std::string(buf, rv));
+ EXPECT_EQ(std::string(kTestData, rv), std::string(buf->data(), rv));
}
}
@@ -301,15 +309,15 @@ TEST_F(FileStreamTest, AsyncRead_FromOffset) {
std::string data_read;
for (;;) {
- char buf[4];
- rv = stream.Read(buf, arraysize(buf), callback.callback());
+ scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
+ rv = stream.Read(buf, buf->size(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_LE(0, rv);
if (rv <= 0)
break;
total_bytes_read += rv;
- data_read.append(buf, rv);
+ data_read.append(buf->data(), rv);
}
EXPECT_EQ(file_size - kOffset, total_bytes_read);
EXPECT_EQ(kTestData + kOffset, data_read);
@@ -375,15 +383,18 @@ TEST_F(FileStreamTest, AsyncWrite) {
TestCompletionCallback callback;
int total_bytes_written = 0;
+ scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
+ scoped_refptr<DrainableIOBuffer> drainable =
+ new DrainableIOBuffer(buf, buf->size());
while (total_bytes_written != kTestDataSize) {
- rv = stream.Write(kTestData + total_bytes_written,
- kTestDataSize - total_bytes_written,
+ rv = stream.Write(drainable, drainable->BytesRemaining(),
callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_LT(0, rv);
if (rv <= 0)
break;
+ drainable->DidConsume(rv);
total_bytes_written += rv;
}
ok = file_util::GetFileSize(temp_file_path(), &file_size);
@@ -405,11 +416,9 @@ TEST_F(FileStreamTest, AsyncWrite_EarlyClose) {
EXPECT_EQ(0, file_size);
TestCompletionCallback callback;
- int total_bytes_written = 0;
- rv = stream.Write(kTestData + total_bytes_written,
- kTestDataSize - total_bytes_written,
- callback.callback());
+ scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
+ rv = stream.Write(buf, buf->size(), callback.callback());
stream.CloseSync();
if (rv < 0) {
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -467,15 +476,18 @@ TEST_F(FileStreamTest, AsyncWrite_FromOffset) {
TestCompletionCallback callback;
int total_bytes_written = 0;
+ scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
+ scoped_refptr<DrainableIOBuffer> drainable =
+ new DrainableIOBuffer(buf, buf->size());
while (total_bytes_written != kTestDataSize) {
- rv = stream.Write(kTestData + total_bytes_written,
- kTestDataSize - total_bytes_written,
+ rv = stream.Write(drainable, drainable->BytesRemaining(),
callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_LT(0, rv);
if (rv <= 0)
break;
+ drainable->DidConsume(rv);
total_bytes_written += rv;
}
ok = file_util::GetFileSize(temp_file_path(), &file_size);
@@ -591,30 +603,33 @@ TEST_F(FileStreamTest, BasicAsyncReadWrite) {
std::string data_read;
for (;;) {
- char buf[4];
- rv = stream.Read(buf, arraysize(buf), callback.callback());
+ scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
+ rv = stream.Read(buf, buf->size(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_LE(0, rv);
if (rv <= 0)
break;
total_bytes_read += rv;
- data_read.append(buf, rv);
+ data_read.append(buf->data(), rv);
}
EXPECT_EQ(file_size, total_bytes_read);
EXPECT_TRUE(data_read == kTestData);
int total_bytes_written = 0;
+ scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
+ scoped_refptr<DrainableIOBuffer> drainable =
+ new DrainableIOBuffer(buf, buf->size());
while (total_bytes_written != kTestDataSize) {
- rv = stream.Write(kTestData + total_bytes_written,
- kTestDataSize - total_bytes_written,
+ rv = stream.Write(drainable, drainable->BytesRemaining(),
callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_LT(0, rv);
if (rv <= 0)
break;
+ drainable->DidConsume(rv);
total_bytes_written += rv;
}
@@ -647,15 +662,18 @@ TEST_F(FileStreamTest, BasicAsyncWriteRead) {
TestCompletionCallback callback;
int total_bytes_written = 0;
+ scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
+ scoped_refptr<DrainableIOBuffer> drainable =
+ new DrainableIOBuffer(buf, buf->size());
while (total_bytes_written != kTestDataSize) {
- rv = stream.Write(kTestData + total_bytes_written,
- kTestDataSize - total_bytes_written,
+ rv = stream.Write(drainable, drainable->BytesRemaining(),
callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_LT(0, rv);
if (rv <= 0)
break;
+ drainable->DidConsume(rv);
total_bytes_written += rv;
}
@@ -668,15 +686,15 @@ TEST_F(FileStreamTest, BasicAsyncWriteRead) {
std::string data_read;
for (;;) {
- char buf[4];
- rv = stream.Read(buf, arraysize(buf), callback.callback());
+ scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
+ rv = stream.Read(buf, buf->size(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_LE(0, rv);
if (rv <= 0)
break;
total_bytes_read += rv;
- data_read.append(buf, rv);
+ data_read.append(buf->data(), rv);
}
stream.CloseSync();
@@ -705,7 +723,10 @@ class TestWriteReadCompletionCallback {
total_bytes_read_(total_bytes_read),
data_read_(data_read),
callback_(base::Bind(&TestWriteReadCompletionCallback::OnComplete,
- base::Unretained(this))) {}
+ base::Unretained(this))),
+ test_data_(CreateTestDataBuffer()),
+ drainable_(new DrainableIOBuffer(test_data_, kTestDataSize)) {
+ }
int WaitForResult() {
DCHECK(!waiting_for_result_);
@@ -733,11 +754,11 @@ class TestWriteReadCompletionCallback {
std::string data_read;
TestWriteReadCompletionCallback callback(
stream_, &total_bytes_written, &total_bytes_read, &data_read);
- rv = stream_->Write(kTestData + *total_bytes_written_,
- kTestDataSize - *total_bytes_written_,
+ rv = stream_->Write(drainable_, drainable_->BytesRemaining(),
callback.callback());
DCHECK_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
+ drainable_->DidConsume(total_bytes_written);
*total_bytes_written_ += total_bytes_written;
*total_bytes_read_ += total_bytes_read;
*data_read_ += data_read;
@@ -746,8 +767,8 @@ class TestWriteReadCompletionCallback {
TestCompletionCallback callback;
for (;;) {
- char buf[4];
- rv = stream_->Read(buf, arraysize(buf), callback.callback());
+ scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
+ rv = stream_->Read(buf, buf->size(), callback.callback());
if (rv == ERR_IO_PENDING) {
MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
rv = callback.WaitForResult();
@@ -756,7 +777,7 @@ class TestWriteReadCompletionCallback {
if (rv <= 0)
break;
*total_bytes_read_ += rv;
- data_read_->append(buf, rv);
+ data_read_->append(buf->data(), rv);
}
}
@@ -774,6 +795,8 @@ class TestWriteReadCompletionCallback {
int* total_bytes_read_;
std::string* data_read_;
const CompletionCallback callback_;
+ scoped_refptr<IOBufferWithSize> test_data_;
+ scoped_refptr<DrainableIOBuffer> drainable_;
DISALLOW_COPY_AND_ASSIGN(TestWriteReadCompletionCallback);
};
@@ -803,9 +826,8 @@ TEST_F(FileStreamTest, AsyncWriteRead) {
TestWriteReadCompletionCallback callback(&stream, &total_bytes_written,
&total_bytes_read, &data_read);
- rv = stream.Write(kTestData + total_bytes_written,
- kTestDataSize - static_cast<int>(total_bytes_written),
- callback.callback());
+ scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
+ rv = stream.Write(buf, buf->size(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_LT(0, rv);
@@ -832,7 +854,10 @@ class TestWriteCloseCompletionCallback {
stream_(stream),
total_bytes_written_(total_bytes_written),
callback_(base::Bind(&TestWriteCloseCompletionCallback::OnComplete,
- base::Unretained(this))) {}
+ base::Unretained(this))),
+ test_data_(CreateTestDataBuffer()),
+ drainable_(new DrainableIOBuffer(test_data_, kTestDataSize)) {
+ }
int WaitForResult() {
DCHECK(!waiting_for_result_);
@@ -858,11 +883,11 @@ class TestWriteCloseCompletionCallback {
// Recurse to finish writing all data.
int total_bytes_written = 0;
TestWriteCloseCompletionCallback callback(stream_, &total_bytes_written);
- rv = stream_->Write(kTestData + *total_bytes_written_,
- kTestDataSize - *total_bytes_written_,
+ rv = stream_->Write(drainable_, drainable_->BytesRemaining(),
callback.callback());
DCHECK_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
+ drainable_->DidConsume(total_bytes_written);
*total_bytes_written_ += total_bytes_written;
} else { // We're done writing all data. Close the file.
stream_->CloseSync();
@@ -880,6 +905,8 @@ class TestWriteCloseCompletionCallback {
FileStream* stream_;
int* total_bytes_written_;
const CompletionCallback callback_;
+ scoped_refptr<IOBufferWithSize> test_data_;
+ scoped_refptr<DrainableIOBuffer> drainable_;
DISALLOW_COPY_AND_ASSIGN(TestWriteCloseCompletionCallback);
};
@@ -906,7 +933,8 @@ TEST_F(FileStreamTest, AsyncWriteClose) {
int total_bytes_written = 0;
TestWriteCloseCompletionCallback callback(&stream, &total_bytes_written);
- rv = stream.Write(kTestData, kTestDataSize, callback.callback());
+ scoped_refptr<IOBufferWithSize> buf = CreateTestDataBuffer();
+ rv = stream.Write(buf, buf->size(), callback.callback());
if (rv == ERR_IO_PENDING)
total_bytes_written = callback.WaitForResult();
EXPECT_LT(0, total_bytes_written);
diff --git a/net/base/file_stream_win.cc b/net/base/file_stream_win.cc
index e111733..aa2b045 100644
--- a/net/base/file_stream_win.cc
+++ b/net/base/file_stream_win.cc
@@ -13,6 +13,7 @@
#include "base/threading/thread_restrictions.h"
#include "net/base/file_stream_metrics.h"
#include "net/base/file_stream_net_log_parameters.h"
+#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
namespace net {
@@ -69,7 +70,8 @@ class FileStream::AsyncContext : public MessageLoopForIO::IOHandler {
}
~AsyncContext();
- void IOCompletionIsPending(const CompletionCallback& callback);
+ void IOCompletionIsPending(const CompletionCallback& callback,
+ IOBuffer* buf);
OVERLAPPED* overlapped() { return &context_.overlapped; }
const CompletionCallback& callback() const { return callback_; }
@@ -86,6 +88,7 @@ class FileStream::AsyncContext : public MessageLoopForIO::IOHandler {
MessageLoopForIO::IOContext context_;
CompletionCallback callback_;
+ scoped_refptr<IOBuffer> in_flight_buf_;
bool is_closing_;
bool record_uma_;
const net::BoundNetLog bound_net_log_;
@@ -108,9 +111,11 @@ FileStream::AsyncContext::~AsyncContext() {
}
void FileStream::AsyncContext::IOCompletionIsPending(
- const CompletionCallback& callback) {
+ const CompletionCallback& callback,
+ IOBuffer* buf) {
DCHECK(callback_.is_null());
callback_ = callback;
+ in_flight_buf_ = buf; // Hold until the async operation ends.
}
void FileStream::AsyncContext::OnIOCompleted(
@@ -120,6 +125,7 @@ void FileStream::AsyncContext::OnIOCompleted(
if (is_closing_) {
callback_.Reset();
+ in_flight_buf_ = NULL;
return;
}
@@ -132,9 +138,11 @@ void FileStream::AsyncContext::OnIOCompleted(
if (bytes_read)
IncrementOffset(&context->overlapped, bytes_read);
- CompletionCallback temp;
- std::swap(temp, callback_);
- temp.Run(result);
+ CompletionCallback temp_callback = callback_;
+ callback_.Reset();
+ scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
+ in_flight_buf_ = NULL;
+ temp_callback.Run(result);
}
// FileStream ------------------------------------------------------------
@@ -277,41 +285,27 @@ int64 FileStream::Available() {
}
int FileStream::Read(
- char* buf, int buf_len, const CompletionCallback& callback) {
+ IOBuffer* buf, int buf_len, const CompletionCallback& callback) {
DCHECK(async_context_.get());
- return ReadInternal(buf, buf_len, callback);
-}
-
-int FileStream::ReadSync(char* buf, int buf_len) {
- DCHECK(!async_context_.get());
- return ReadInternal(buf, buf_len, CompletionCallback());
-}
-int FileStream::ReadInternal(
- char* buf, int buf_len, const CompletionCallback& callback) {
if (!IsOpen())
return ERR_UNEXPECTED;
DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
OVERLAPPED* overlapped = NULL;
- if (async_context_.get()) {
- DCHECK(!callback.is_null());
- DCHECK(async_context_->callback().is_null());
- overlapped = async_context_->overlapped();
- async_context_->set_error_source(FILE_ERROR_SOURCE_READ);
- } else {
- DCHECK(callback.is_null());
- base::ThreadRestrictions::AssertIOAllowed();
- }
+ DCHECK(!callback.is_null());
+ DCHECK(async_context_->callback().is_null());
+ overlapped = async_context_->overlapped();
+ async_context_->set_error_source(FILE_ERROR_SOURCE_READ);
- int rv;
+ int rv = 0;
DWORD bytes_read;
- if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) {
+ if (!ReadFile(file_, buf->data(), buf_len, &bytes_read, overlapped)) {
DWORD error = GetLastError();
- if (async_context_.get() && error == ERROR_IO_PENDING) {
- async_context_->IOCompletionIsPending(callback);
+ if (error == ERROR_IO_PENDING) {
+ async_context_->IOCompletionIsPending(callback, buf);
rv = ERR_IO_PENDING;
} else if (error == ERROR_HANDLE_EOF) {
rv = 0; // Report EOF by returning 0 bytes read.
@@ -323,7 +317,7 @@ int FileStream::ReadInternal(
bound_net_log_);
}
} else if (overlapped) {
- async_context_->IOCompletionIsPending(callback);
+ async_context_->IOCompletionIsPending(callback, buf);
rv = ERR_IO_PENDING;
} else {
rv = static_cast<int>(bytes_read);
@@ -331,6 +325,35 @@ int FileStream::ReadInternal(
return rv;
}
+int FileStream::ReadSync(char* buf, int buf_len) {
+ DCHECK(!async_context_.get());
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+
+ DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
+
+ int rv = 0;
+
+ DWORD bytes_read;
+ if (!ReadFile(file_, buf, buf_len, &bytes_read, NULL)) {
+ DWORD error = GetLastError();
+ if (error == ERROR_HANDLE_EOF) {
+ rv = 0; // Report EOF by returning 0 bytes read.
+ } else {
+ LOG(WARNING) << "ReadFile failed: " << error;
+ rv = RecordAndMapError(error,
+ FILE_ERROR_SOURCE_READ,
+ record_uma_,
+ bound_net_log_);
+ }
+ } else {
+ rv = static_cast<int>(bytes_read);
+ }
+ return rv;
+}
+
int FileStream::ReadUntilComplete(char *buf, int buf_len) {
int to_read = buf_len;
int bytes_total = 0;
@@ -353,41 +376,26 @@ int FileStream::ReadUntilComplete(char *buf, int buf_len) {
}
int FileStream::Write(
- const char* buf, int buf_len, const CompletionCallback& callback) {
+ IOBuffer* buf, int buf_len, const CompletionCallback& callback) {
DCHECK(async_context_.get());
- return WriteInternal(buf, buf_len, callback);
-}
-
-int FileStream::WriteSync(
- const char* buf, int buf_len) {
- DCHECK(!async_context_.get());
- return WriteInternal(buf, buf_len, CompletionCallback());
-}
-int FileStream::WriteInternal(
- const char* buf, int buf_len, const CompletionCallback& callback) {
if (!IsOpen())
return ERR_UNEXPECTED;
DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
OVERLAPPED* overlapped = NULL;
- if (async_context_.get()) {
- DCHECK(!callback.is_null());
- DCHECK(async_context_->callback().is_null());
- overlapped = async_context_->overlapped();
- async_context_->set_error_source(FILE_ERROR_SOURCE_WRITE);
- } else {
- DCHECK(callback.is_null());
- base::ThreadRestrictions::AssertIOAllowed();
- }
-
- int rv;
- DWORD bytes_written;
- if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) {
+ DCHECK(!callback.is_null());
+ DCHECK(async_context_->callback().is_null());
+ overlapped = async_context_->overlapped();
+ async_context_->set_error_source(FILE_ERROR_SOURCE_WRITE);
+
+ int rv = 0;
+ DWORD bytes_written = 0;
+ if (!WriteFile(file_, buf->data(), buf_len, &bytes_written, overlapped)) {
DWORD error = GetLastError();
- if (async_context_.get() && error == ERROR_IO_PENDING) {
- async_context_->IOCompletionIsPending(callback);
+ if (error == ERROR_IO_PENDING) {
+ async_context_->IOCompletionIsPending(callback, buf);
rv = ERR_IO_PENDING;
} else {
LOG(WARNING) << "WriteFile failed: " << error;
@@ -397,7 +405,7 @@ int FileStream::WriteInternal(
bound_net_log_);
}
} else if (overlapped) {
- async_context_->IOCompletionIsPending(callback);
+ async_context_->IOCompletionIsPending(callback, buf);
rv = ERR_IO_PENDING;
} else {
rv = static_cast<int>(bytes_written);
@@ -405,6 +413,31 @@ int FileStream::WriteInternal(
return rv;
}
+int FileStream::WriteSync(
+ const char* buf, int buf_len) {
+ DCHECK(!async_context_.get());
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+
+ DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
+
+ int rv = 0;
+ DWORD bytes_written = 0;
+ if (!WriteFile(file_, buf, buf_len, &bytes_written, NULL)) {
+ DWORD error = GetLastError();
+ LOG(WARNING) << "WriteFile failed: " << error;
+ rv = RecordAndMapError(error,
+ FILE_ERROR_SOURCE_WRITE,
+ record_uma_,
+ bound_net_log_);
+ } else {
+ rv = static_cast<int>(bytes_written);
+ }
+ return rv;
+}
+
int FileStream::Flush() {
base::ThreadRestrictions::AssertIOAllowed();
diff --git a/net/base/mock_file_stream.cc b/net/base/mock_file_stream.cc
index e87491f..419f65f 100644
--- a/net/base/mock_file_stream.cc
+++ b/net/base/mock_file_stream.cc
@@ -21,7 +21,7 @@ int64 MockFileStream::Available() {
return ReturnError64(FileStream::Available());
}
-int MockFileStream::Read(char* buf,
+int MockFileStream::Read(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
return ReturnError(FileStream::Read(buf, buf_len, callback));
@@ -35,7 +35,7 @@ int MockFileStream::ReadUntilComplete(char *buf, int buf_len) {
return ReturnError(FileStream::ReadUntilComplete(buf, buf_len));
}
-int MockFileStream::Write(const char* buf,
+int MockFileStream::Write(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
return ReturnError(FileStream::Write(buf, buf_len, callback));
diff --git a/net/base/mock_file_stream.h b/net/base/mock_file_stream.h
index 8424e51..61c9db8 100644
--- a/net/base/mock_file_stream.h
+++ b/net/base/mock_file_stream.h
@@ -16,6 +16,8 @@
namespace net {
+class IOBuffer;
+
namespace testing {
class MockFileStream : public net::FileStream {
@@ -30,12 +32,12 @@ class MockFileStream : public net::FileStream {
virtual int OpenSync(const FilePath& path, int open_flags) OVERRIDE;
virtual int64 Seek(net::Whence whence, int64 offset) OVERRIDE;
virtual int64 Available() OVERRIDE;
- virtual int Read(char* buf,
+ virtual int Read(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) OVERRIDE;
virtual int ReadSync(char* buf, int buf_len) OVERRIDE;
virtual int ReadUntilComplete(char *buf, int buf_len) OVERRIDE;
- virtual int Write(const char* buf,
+ virtual int Write(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) OVERRIDE;
virtual int WriteSync(const char* buf, int buf_len) OVERRIDE;
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index fa6d6a2..70826e5 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -187,7 +187,7 @@ bool URLRequestFileJob::ReadRawData(IOBuffer* dest, int dest_size,
return true;
}
- int rv = stream_.Read(dest->data(), dest_size,
+ int rv = stream_.Read(dest, dest_size,
base::Bind(&URLRequestFileJob::DidRead,
base::Unretained(this)));
if (rv >= 0) {