summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-25 18:52:53 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-25 18:52:53 +0000
commit8bf0c566acc6bb42b59daab2b814cb27ae9c4235 (patch)
tree05fd9d0cfe11949638e32202a086e04a033916e4 /net/base
parent4c0e28bc0012fef534b6f83003df98df21a3a666 (diff)
downloadchromium_src-8bf0c566acc6bb42b59daab2b814cb27ae9c4235.zip
chromium_src-8bf0c566acc6bb42b59daab2b814cb27ae9c4235.tar.gz
chromium_src-8bf0c566acc6bb42b59daab2b814cb27ae9c4235.tar.bz2
Fix net::FileStream to handle all errors correctly.
This CL adds FileStream::Context::IOResult struct that's used to pass results of IO operations inside FileStream::Context. Following bugs are fixes: 1. On POSIX net::FileStream::Read() and net::FileStream::Write() would return a positive result in case of an error. This happens because POSIX errors are positive integers and FileStream was written with assumption that they are negative. 2. On Windows Seek() and Flush() errors were not handled correctly. This is because CheckForIOError() was assuming that all error codes are negative, but RecordAndMapError() was mapping positive errors. 3. On Windows results of asynchronous ReadFile() and WriteFile() were not handled correctly - ERR_IO_PENDING would be returned even when operation completes synchronously. 4. On Windows OVERLAPPED struct wasn't set to zeros as necessary. Also added unittests to check that error codes are handled correctly now. Review URL: https://codereview.chromium.org/12321100 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@184453 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-rw-r--r--net/base/file_stream_context.cc101
-rw-r--r--net/base/file_stream_context.h50
-rw-r--r--net/base/file_stream_context_posix.cc60
-rw-r--r--net/base/file_stream_context_win.cc120
-rw-r--r--net/base/file_stream_unittest.cc38
-rw-r--r--net/base/net_errors_win.cc1
6 files changed, 219 insertions, 151 deletions
diff --git a/net/base/file_stream_context.cc b/net/base/file_stream_context.cc
index 53f3c3d..092302f 100644
--- a/net/base/file_stream_context.cc
+++ b/net/base/file_stream_context.cc
@@ -22,6 +22,32 @@ void CallInt64ToInt(const net::CompletionCallback& callback, int64 result) {
namespace net {
+FileStream::Context::IOResult::IOResult()
+ : result(OK),
+ os_error(0) {
+}
+
+FileStream::Context::IOResult::IOResult(int64 result, int os_error)
+ : result(result),
+ os_error(os_error) {
+}
+
+// static
+FileStream::Context::IOResult FileStream::Context::IOResult::FromOSError(
+ int64 os_error) {
+ return IOResult(MapSystemError(os_error), os_error);
+}
+
+FileStream::Context::OpenResult::OpenResult()
+ : file(base::kInvalidPlatformFileValue) {
+}
+
+FileStream::Context::OpenResult::OpenResult(base::PlatformFile file,
+ IOResult error_code)
+ : file(file),
+ error_code(error_code) {
+}
+
void FileStream::Context::Orphan() {
DCHECK(!orphaned_);
@@ -62,14 +88,14 @@ int FileStream::Context::OpenSync(const base::FilePath& path, int open_flags) {
OpenResult result = OpenFileImpl(path, open_flags);
file_ = result.file;
if (file_ == base::kInvalidPlatformFileValue) {
- result.error_code = ProcessOpenError(result.error_code);
+ ProcessOpenError(result.error_code);
} else {
// TODO(satorux): Remove this once all async clients are migrated to use
// Open(). crbug.com/114783
if (open_flags & base::PLATFORM_FILE_ASYNC)
OnAsyncFileOpened();
}
- return result.error_code;
+ return result.error_code.result;
}
void FileStream::Context::CloseSync() {
@@ -99,9 +125,9 @@ void FileStream::Context::SeekAsync(Whence whence,
}
int64 FileStream::Context::SeekSync(Whence whence, int64 offset) {
- int64 result = SeekFileImpl(whence, offset);
- CheckForIOError(&result, FILE_ERROR_SOURCE_SEEK);
- return result;
+ IOResult result = SeekFileImpl(whence, offset);
+ RecordError(result, FILE_ERROR_SOURCE_SEEK);
+ return result.result;
}
void FileStream::Context::FlushAsync(const CompletionCallback& callback) {
@@ -121,26 +147,32 @@ void FileStream::Context::FlushAsync(const CompletionCallback& callback) {
}
int FileStream::Context::FlushSync() {
- int64 result = FlushFileImpl();
- CheckForIOError(&result, FILE_ERROR_SOURCE_FLUSH);
- return result;
+ IOResult result = FlushFileImpl();
+ RecordError(result, FILE_ERROR_SOURCE_FLUSH);
+ return result.result;
}
-int FileStream::Context::RecordAndMapError(int error,
- FileErrorSource source) const {
+void FileStream::Context::RecordError(const IOResult& result,
+ FileErrorSource source) const {
+ if (result.result >= 0) {
+ // |result| is not an error.
+ return;
+ }
+
// The following check is against incorrect use or bug. File descriptor
// shouldn't ever be closed outside of FileStream while it still tries to do
// something with it.
- DCHECK(error != ERROR_BAD_FILE);
- Error net_error = MapSystemError(error);
+ DCHECK_NE(result.result, ERR_INVALID_HANDLE);
if (!orphaned_) {
- bound_net_log_.AddEvent(NetLog::TYPE_FILE_STREAM_ERROR,
- base::Bind(&NetLogFileStreamErrorCallback,
- source, error, net_error));
+ bound_net_log_.AddEvent(
+ NetLog::TYPE_FILE_STREAM_ERROR,
+ base::Bind(&NetLogFileStreamErrorCallback,
+ source, result.os_error,
+ static_cast<net::Error>(result.result)));
}
- RecordFileError(error, source, record_uma_);
- return net_error;
+
+ RecordFileError(result.os_error, source, record_uma_);
}
void FileStream::Context::BeginOpenEvent(const base::FilePath& path) {
@@ -156,28 +188,27 @@ FileStream::Context::OpenResult FileStream::Context::OpenFileImpl(
// delete the file right after FileStream deletion. Thus we are always
// adding SHARE_DELETE flag to accommodate such use case.
open_flags |= base::PLATFORM_FILE_SHARE_DELETE;
- OpenResult result;
- result.error_code = OK;
- result.file = base::CreatePlatformFile(path, open_flags, NULL, NULL);
- if (result.file == base::kInvalidPlatformFileValue)
- result.error_code = GetLastErrno();
+ base::PlatformFile file =
+ base::CreatePlatformFile(path, open_flags, NULL, NULL);
+ if (file == base::kInvalidPlatformFileValue)
+ return OpenResult(file, IOResult::FromOSError(GetLastErrno()));
- return result;
+ return OpenResult(file, IOResult(OK, 0));
}
-int FileStream::Context::ProcessOpenError(int error_code) {
+void FileStream::Context::ProcessOpenError(const IOResult& error_code) {
bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN);
- return RecordAndMapError(error_code, FILE_ERROR_SOURCE_OPEN);
+ RecordError(error_code, FILE_ERROR_SOURCE_OPEN);
}
void FileStream::Context::OnOpenCompleted(const CompletionCallback& callback,
- OpenResult result) {
- file_ = result.file;
+ OpenResult open_result) {
+ file_ = open_result.file;
if (file_ == base::kInvalidPlatformFileValue)
- result.error_code = ProcessOpenError(result.error_code);
+ ProcessOpenError(open_result.error_code);
else if (!orphaned_)
OnAsyncFileOpened();
- OnAsyncCompleted(IntToInt64(callback), result.error_code);
+ OnAsyncCompleted(IntToInt64(callback), open_result.error_code.result);
}
void FileStream::Context::CloseAndDelete() {
@@ -205,18 +236,12 @@ Int64CompletionCallback FileStream::Context::IntToInt64(
return base::Bind(&CallInt64ToInt, callback);
}
-void FileStream::Context::CheckForIOError(int64* result,
- FileErrorSource source) {
- if (*result < 0)
- *result = RecordAndMapError(static_cast<int>(*result), source);
-}
-
void FileStream::Context::ProcessAsyncResult(
const Int64CompletionCallback& callback,
FileErrorSource source,
- int64 result) {
- CheckForIOError(&result, source);
- OnAsyncCompleted(callback, result);
+ const IOResult& result) {
+ RecordError(result, source);
+ OnAsyncCompleted(callback, result.result);
}
void FileStream::Context::OnAsyncCompleted(
diff --git a/net/base/file_stream_context.h b/net/base/file_stream_context.h
index 42fc0eb..34effea 100644
--- a/net/base/file_stream_context.h
+++ b/net/base/file_stream_context.h
@@ -116,50 +116,46 @@ class FileStream::Context {
private:
////////////////////////////////////////////////////////////////////////////
- // Error code that is platform-dependent but is used in the platform-
- // independent code implemented in file_stream_context.cc.
- ////////////////////////////////////////////////////////////////////////////
- enum {
-#if defined(OS_WIN)
- ERROR_BAD_FILE = ERROR_INVALID_HANDLE
-#elif defined(OS_POSIX)
- ERROR_BAD_FILE = EBADF
-#endif
- };
-
- ////////////////////////////////////////////////////////////////////////////
// Platform-independent methods implemented in file_stream_context.cc.
////////////////////////////////////////////////////////////////////////////
+ struct IOResult {
+ IOResult();
+ IOResult(int64 result, int os_error);
+ static IOResult FromOSError(int64 os_error);
+
+ int64 result;
+ int os_error; // Set only when result < 0.
+ };
+
struct OpenResult {
+ OpenResult();
+ OpenResult(base::PlatformFile file, IOResult error_code);
base::PlatformFile file;
- int error_code;
+ IOResult error_code;
};
- // Map system error into network error code and log it with |bound_net_log_|.
- int RecordAndMapError(int error, FileErrorSource source) const;
+ // Log the error from |result| to |bound_net_log_|.
+ void RecordError(const IOResult& result, FileErrorSource source) const;
void BeginOpenEvent(const base::FilePath& path);
OpenResult OpenFileImpl(const base::FilePath& path, int open_flags);
- int ProcessOpenError(int error_code);
- void OnOpenCompleted(const CompletionCallback& callback, OpenResult result);
+ void ProcessOpenError(const IOResult& result);
+ void OnOpenCompleted(const CompletionCallback& callback,
+ OpenResult open_result);
void CloseAndDelete();
void OnCloseCompleted();
Int64CompletionCallback IntToInt64(const CompletionCallback& callback);
- // Checks for IO error that probably happened in async methods.
- // If there was error reports it.
- void CheckForIOError(int64* result, FileErrorSource source);
-
// Called when asynchronous Seek() is completed.
// Reports error if needed and calls callback.
void ProcessAsyncResult(const Int64CompletionCallback& callback,
FileErrorSource source,
- int64 result);
+ const IOResult& result);
// Called when asynchronous Open() or Seek()
// is completed. |result| contains the result or a network error code.
@@ -187,27 +183,27 @@ class FileStream::Context {
////////////////////////////////////////////////////////////////////////////
// Adjusts the position from where the data is read.
- int64 SeekFileImpl(Whence whence, int64 offset);
+ IOResult SeekFileImpl(Whence whence, int64 offset);
// Flushes all data written to the stream.
- int64 FlushFileImpl();
+ IOResult FlushFileImpl();
#if defined(OS_WIN)
void IOCompletionIsPending(const CompletionCallback& callback, IOBuffer* buf);
- // Implementation of MessageLoopForIO::IOHandler
+ // Implementation of MessageLoopForIO::IOHandler.
virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
DWORD bytes_read,
DWORD error) OVERRIDE;
#elif defined(OS_POSIX)
// ReadFileImpl() is a simple wrapper around read() that handles EINTR
// signals and calls RecordAndMapError() to map errno to net error codes.
- int64 ReadFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);
+ IOResult ReadFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);
// WriteFileImpl() is a simple wrapper around write() that handles EINTR
// signals and calls MapSystemError() to map errno to net error codes.
// It tries to write to completion.
- int64 WriteFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);
+ IOResult WriteFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);
#endif
base::PlatformFile file_;
diff --git a/net/base/file_stream_context_posix.cc b/net/base/file_stream_context_posix.cc
index d39b17a..87fa106 100644
--- a/net/base/file_stream_context_posix.cc
+++ b/net/base/file_stream_context_posix.cc
@@ -68,8 +68,11 @@ FileStream::Context::~Context() {
int64 FileStream::Context::GetFileSize() const {
struct stat info;
- if (fstat(file_, &info) != 0)
- return RecordAndMapError(errno, FILE_ERROR_SOURCE_GET_SIZE);
+ if (fstat(file_, &info) != 0) {
+ IOResult result = IOResult::FromOSError(errno);
+ RecordError(result, FILE_ERROR_SOURCE_GET_SIZE);
+ return result.result;
+ }
return static_cast<int64>(info.st_size);
}
@@ -96,9 +99,9 @@ int FileStream::Context::ReadAsync(IOBuffer* in_buf,
int FileStream::Context::ReadSync(char* in_buf, int buf_len) {
scoped_refptr<IOBuffer> buf = new WrappedIOBuffer(in_buf);
- int64 result = ReadFileImpl(buf, buf_len);
- CheckForIOError(&result, FILE_ERROR_SOURCE_READ);
- return result;
+ IOResult result = ReadFileImpl(buf, buf_len);
+ RecordError(result, FILE_ERROR_SOURCE_READ);
+ return result.result;
}
int FileStream::Context::WriteAsync(IOBuffer* in_buf,
@@ -123,54 +126,59 @@ int FileStream::Context::WriteAsync(IOBuffer* in_buf,
int FileStream::Context::WriteSync(const char* in_buf, int buf_len) {
scoped_refptr<IOBuffer> buf = new WrappedIOBuffer(in_buf);
- int64 result = WriteFileImpl(buf, buf_len);
- CheckForIOError(&result, FILE_ERROR_SOURCE_WRITE);
- return result;
+ IOResult result = WriteFileImpl(buf, buf_len);
+ RecordError(result, FILE_ERROR_SOURCE_WRITE);
+ return result.result;
}
int FileStream::Context::Truncate(int64 bytes) {
- int result = ftruncate(file_, bytes);
- if (result == 0)
- return bytes;
+ if (ftruncate(file_, bytes) != 0) {
+ IOResult result = IOResult::FromOSError(errno);
+ RecordError(result, FILE_ERROR_SOURCE_SET_EOF);
+ return result.result;
+ }
- return RecordAndMapError(errno, FILE_ERROR_SOURCE_SET_EOF);
+ return bytes;
}
-int64 FileStream::Context::SeekFileImpl(Whence whence, int64 offset) {
+FileStream::Context::IOResult FileStream::Context::SeekFileImpl(Whence whence,
+ int64 offset) {
off_t res = lseek(file_, static_cast<off_t>(offset),
static_cast<int>(whence));
if (res == static_cast<off_t>(-1))
- return errno;
+ return IOResult::FromOSError(errno);
- return res;
+ return IOResult(res, 0);
}
-int64 FileStream::Context::FlushFileImpl() {
+FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
ssize_t res = HANDLE_EINTR(fsync(file_));
if (res == -1)
- return errno;
+ return IOResult::FromOSError(errno);
- return res;
+ return IOResult(res, 0);
}
-int64 FileStream::Context::ReadFileImpl(scoped_refptr<IOBuffer> buf,
- int buf_len) {
+FileStream::Context::IOResult FileStream::Context::ReadFileImpl(
+ scoped_refptr<IOBuffer> buf,
+ int buf_len) {
// Loop in the case of getting interrupted by a signal.
ssize_t res = HANDLE_EINTR(read(file_, buf->data(),
static_cast<size_t>(buf_len)));
if (res == -1)
- return errno;
+ return IOResult::FromOSError(errno);
- return res;
+ return IOResult(res, 0);
}
-int64 FileStream::Context::WriteFileImpl(scoped_refptr<IOBuffer> buf,
- int buf_len) {
+FileStream::Context::IOResult FileStream::Context::WriteFileImpl(
+ scoped_refptr<IOBuffer> buf,
+ int buf_len) {
ssize_t res = HANDLE_EINTR(write(file_, buf->data(), buf_len));
if (res == -1)
- return errno;
+ return IOResult::FromOSError(errno);
- return res;
+ return IOResult(res, 0);
}
} // namespace net
diff --git a/net/base/file_stream_context_win.cc b/net/base/file_stream_context_win.cc
index f5656a3..22f26cf 100644
--- a/net/base/file_stream_context_win.cc
+++ b/net/base/file_stream_context_win.cc
@@ -47,6 +47,7 @@ FileStream::Context::Context(const BoundNetLog& bound_net_log)
bound_net_log_(bound_net_log),
error_source_(FILE_ERROR_SOURCE_COUNT) {
io_context_.handler = this;
+ memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
}
FileStream::Context::Context(base::PlatformFile file,
@@ -60,6 +61,7 @@ FileStream::Context::Context(base::PlatformFile file,
bound_net_log_(bound_net_log),
error_source_(FILE_ERROR_SOURCE_COUNT) {
io_context_.handler = this;
+ memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
if (file_ != base::kInvalidPlatformFileValue &&
(open_flags & base::PLATFORM_FILE_ASYNC)) {
OnAsyncFileOpened();
@@ -72,9 +74,10 @@ FileStream::Context::~Context() {
int64 FileStream::Context::GetFileSize() const {
LARGE_INTEGER file_size;
if (!GetFileSizeEx(file_, &file_size)) {
- DWORD error = GetLastError();
- LOG(WARNING) << "GetFileSizeEx failed: " << error;
- return RecordAndMapError(error, FILE_ERROR_SOURCE_GET_SIZE);
+ IOResult error = IOResult::FromOSError(GetLastError());
+ LOG(WARNING) << "GetFileSizeEx failed: " << error.os_error;
+ RecordError(error, FILE_ERROR_SOURCE_GET_SIZE);
+ return error.result;
}
return file_size.QuadPart;
@@ -86,44 +89,38 @@ int FileStream::Context::ReadAsync(IOBuffer* buf,
DCHECK(!async_in_progress_);
error_source_ = FILE_ERROR_SOURCE_READ;
- int rv = 0;
-
DWORD bytes_read;
if (!ReadFile(file_, buf->data(), buf_len,
&bytes_read, &io_context_.overlapped)) {
- DWORD error = GetLastError();
- if (error == ERROR_IO_PENDING) {
+ IOResult error = IOResult::FromOSError(GetLastError());
+ if (error.os_error == ERROR_IO_PENDING) {
IOCompletionIsPending(callback, buf);
- rv = ERR_IO_PENDING;
- } else if (error == ERROR_HANDLE_EOF) {
- rv = 0; // Report EOF by returning 0 bytes read.
+ } else if (error.os_error == ERROR_HANDLE_EOF) {
+ return 0; // Report EOF by returning 0 bytes read.
} else {
- LOG(WARNING) << "ReadFile failed: " << error;
- rv = RecordAndMapError(error, FILE_ERROR_SOURCE_READ);
+ LOG(WARNING) << "ReadFile failed: " << error.os_error;
+ RecordError(error, FILE_ERROR_SOURCE_READ);
}
- } else {
- IOCompletionIsPending(callback, buf);
- rv = ERR_IO_PENDING;
+ return error.result;
}
- return rv;
+
+ return bytes_read;
}
int FileStream::Context::ReadSync(char* buf, int buf_len) {
- 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.
+ IOResult error = IOResult::FromOSError(GetLastError());
+ if (error.os_error == ERROR_HANDLE_EOF) {
+ return 0; // Report EOF by returning 0 bytes read.
} else {
- LOG(WARNING) << "ReadFile failed: " << error;
- rv = RecordAndMapError(error, FILE_ERROR_SOURCE_READ);
+ LOG(WARNING) << "ReadFile failed: " << error.os_error;
+ RecordError(error, FILE_ERROR_SOURCE_READ);
}
- } else {
- rv = static_cast<int>(bytes_read);
+ return error.result;
}
- return rv;
+
+ return bytes_read;
}
int FileStream::Context::WriteAsync(IOBuffer* buf,
@@ -131,69 +128,67 @@ int FileStream::Context::WriteAsync(IOBuffer* buf,
const CompletionCallback& callback) {
error_source_ = FILE_ERROR_SOURCE_WRITE;
- int rv = 0;
DWORD bytes_written = 0;
if (!WriteFile(file_, buf->data(), buf_len,
&bytes_written, &io_context_.overlapped)) {
- DWORD error = GetLastError();
- if (error == ERROR_IO_PENDING) {
+ IOResult error = IOResult::FromOSError(GetLastError());
+ if (error.os_error == ERROR_IO_PENDING) {
IOCompletionIsPending(callback, buf);
- rv = ERR_IO_PENDING;
} else {
- LOG(WARNING) << "WriteFile failed: " << error;
- rv = RecordAndMapError(error, FILE_ERROR_SOURCE_WRITE);
+ LOG(WARNING) << "WriteFile failed: " << error.os_error;
+ RecordError(error, FILE_ERROR_SOURCE_WRITE);
}
- } else {
- IOCompletionIsPending(callback, buf);
- rv = ERR_IO_PENDING;
+ return error.result;
}
- return rv;
+
+ return bytes_written;
}
int FileStream::Context::WriteSync(const char* buf, int buf_len) {
- 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);
- } else {
- rv = static_cast<int>(bytes_written);
+ IOResult error = IOResult::FromOSError(GetLastError());
+ LOG(WARNING) << "WriteFile failed: " << error.os_error;
+ RecordError(error, FILE_ERROR_SOURCE_WRITE);
+ return error.result;
}
- return rv;
+
+ return bytes_written;
}
int FileStream::Context::Truncate(int64 bytes) {
- BOOL result = SetEndOfFile(file_);
- if (result)
- return bytes;
+ if (!SetEndOfFile(file_)) {
+ IOResult error = IOResult::FromOSError(GetLastError());
+ LOG(WARNING) << "SetEndOfFile failed: " << error.os_error;
+ RecordError(error, FILE_ERROR_SOURCE_SET_EOF);
+ return error.result;
+ }
- DWORD error = GetLastError();
- LOG(WARNING) << "SetEndOfFile failed: " << error;
- return RecordAndMapError(error, FILE_ERROR_SOURCE_SET_EOF);
+ return bytes;
}
void FileStream::Context::OnAsyncFileOpened() {
MessageLoopForIO::current()->RegisterIOHandler(file_, this);
}
-int64 FileStream::Context::SeekFileImpl(Whence whence, int64 offset) {
+FileStream::Context::IOResult FileStream::Context::SeekFileImpl(Whence whence,
+ int64 offset) {
LARGE_INTEGER distance, res;
distance.QuadPart = offset;
DWORD move_method = static_cast<DWORD>(whence);
if (SetFilePointerEx(file_, distance, &res, move_method)) {
SetOffset(&io_context_.overlapped, res);
- return res.QuadPart;
+ return IOResult(res.QuadPart, 0);
}
- return -static_cast<int>(GetLastError());
+ return IOResult::FromOSError(GetLastError());
}
-int64 FileStream::Context::FlushFileImpl() {
+FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
if (FlushFileBuffers(file_))
- return OK;
+ return IOResult(OK, 0);
- return -static_cast<int>(GetLastError());
+ return IOResult::FromOSError(GetLastError());
}
void FileStream::Context::IOCompletionIsPending(
@@ -220,12 +215,17 @@ void FileStream::Context::OnIOCompleted(MessageLoopForIO::IOContext* context,
return;
}
- int result = static_cast<int>(bytes_read);
- if (error && error != ERROR_HANDLE_EOF)
- result = RecordAndMapError(error, error_source_);
-
- if (bytes_read)
+ int result;
+ if (error == ERROR_HANDLE_EOF) {
+ result = 0;
+ } else if (error) {
+ IOResult error_result = IOResult::FromOSError(error);
+ RecordError(error_result, error_source_);
+ result = error_result.result;
+ } else {
+ result = bytes_read;
IncrementOffset(&io_context_.overlapped, bytes_read);
+ }
CompletionCallback temp_callback = callback_;
callback_.Reset();
diff --git a/net/base/file_stream_unittest.cc b/net/base/file_stream_unittest.cc
index 1757918..1f79747 100644
--- a/net/base/file_stream_unittest.cc
+++ b/net/base/file_stream_unittest.cc
@@ -1031,6 +1031,44 @@ TEST_F(FileStreamTest, AsyncOpenAndDelete) {
EXPECT_FALSE(open_callback.have_result());
}
+// Verify that async Write() errors are mapped correctly.
+TEST_F(FileStreamTest, AsyncWriteError) {
+ scoped_ptr<FileStream> stream(new FileStream(NULL));
+ int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_ASYNC;
+ int rv = stream->OpenSync(temp_file_path(), flags);
+ EXPECT_EQ(OK, rv);
+
+ TestCompletionCallback callback;
+
+ // Try passing NULL buffer to Write() and check that it fails.
+ scoped_refptr<IOBuffer> buf = new WrappedIOBuffer(NULL);
+ rv = stream->Write(buf, 1, callback.callback());
+ if (rv == ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ EXPECT_LT(rv, 0);
+}
+
+// Verify that async Read() errors are mapped correctly.
+TEST_F(FileStreamTest, AsyncReadError) {
+ scoped_ptr<FileStream> stream(new FileStream(NULL));
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_ASYNC;
+ int rv = stream->OpenSync(temp_file_path(), flags);
+ EXPECT_EQ(OK, rv);
+
+ TestCompletionCallback callback;
+
+ // Try passing NULL buffer to Read() and check that it fails.
+ scoped_refptr<IOBuffer> buf = new WrappedIOBuffer(NULL);
+ rv = stream->Read(buf, 1, callback.callback());
+ if (rv == ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ EXPECT_LT(rv, 0);
+}
+
} // namespace
} // namespace net
diff --git a/net/base/net_errors_win.cc b/net/base/net_errors_win.cc
index 74ed228..c56225f 100644
--- a/net/base/net_errors_win.cc
+++ b/net/base/net_errors_win.cc
@@ -19,6 +19,7 @@ Error MapSystemError(int os_error) {
// find interesting.
switch (os_error) {
case WSAEWOULDBLOCK:
+ case WSA_IO_PENDING:
return ERR_IO_PENDING;
case WSAEACCES:
return ERR_ACCESS_DENIED;