diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-11 17:28:40 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-11 17:28:40 +0000 |
commit | 5b47ac32b7c1a6b0fd95b0622163fc4546eee3c1 (patch) | |
tree | 04c69466437d9954cca0a07b249560af4647e2bd /webkit | |
parent | 08b274f76c1474ece6128e55a30e1eba49fe37cf (diff) | |
download | chromium_src-5b47ac32b7c1a6b0fd95b0622163fc4546eee3c1.zip chromium_src-5b47ac32b7c1a6b0fd95b0622163fc4546eee3c1.tar.gz chromium_src-5b47ac32b7c1a6b0fd95b0622163fc4546eee3c1.tar.bz2 |
2nd try: separate FileStream related code out of BlobURLRequest
The original change I had tried to submit was:
http://codereview.chromium.org/9651032
The change was reverted because FileStream cannot be created on other
threads than on IO thread on Windows, and therefore broke
the ExtensionPageCaptureApiTest.SaveAsMHTML browser test.
BUG=114999
TEST=test_shell_tests:BlobURLRequestJobTest.*, browser_tests:ExtensionPageCaptureApiTest.SaveAsMHTML
Review URL: http://codereview.chromium.org/10029008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@131791 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/blob/blob_url_request_job.cc | 166 | ||||
-rw-r--r-- | webkit/blob/blob_url_request_job.h | 25 | ||||
-rw-r--r-- | webkit/blob/blob_url_request_job_unittest.cc | 10 | ||||
-rw-r--r-- | webkit/blob/local_file_reader.cc | 216 | ||||
-rw-r--r-- | webkit/blob/local_file_reader.h | 83 | ||||
-rw-r--r-- | webkit/blob/webkit_blob.gypi | 4 |
6 files changed, 381 insertions, 123 deletions
diff --git a/webkit/blob/blob_url_request_job.cc b/webkit/blob/blob_url_request_job.cc index d6be8a5..1a360f1 100644 --- a/webkit/blob/blob_url_request_job.cc +++ b/webkit/blob/blob_url_request_job.cc @@ -6,14 +6,11 @@ #include "base/bind.h" #include "base/compiler_specific.h" -#include "base/file_path.h" -#include "base/file_util.h" #include "base/file_util_proxy.h" #include "base/message_loop.h" #include "base/message_loop_proxy.h" +#include "base/stl_util.h" #include "base/string_number_conversions.h" -#include "base/threading/thread_restrictions.h" -#include "net/base/file_stream.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/http/http_request_headers.h" @@ -23,6 +20,7 @@ #include "net/url_request/url_request.h" #include "net/url_request/url_request_error_job.h" #include "net/url_request/url_request_status.h" +#include "webkit/blob/local_file_reader.h" namespace webkit_blob { @@ -71,9 +69,7 @@ BlobURLRequestJob::BlobURLRequestJob( } BlobURLRequestJob::~BlobURLRequestJob() { - // FileStream's destructor won't close it for us because we passed in our own - // file handle. - CloseFileStream(); + STLDeleteValues(&index_to_reader_); } void BlobURLRequestJob::Start() { @@ -84,7 +80,7 @@ void BlobURLRequestJob::Start() { } void BlobURLRequestJob::Kill() { - CloseFileStream(); + DeleteCurrentFileReader(); net::URLRequestJob::Kill(); weak_factory_.InvalidateWeakPtrs(); @@ -185,9 +181,8 @@ void BlobURLRequestJob::CountSize() { const BlobData::Item& item = blob_data_->items().at(i); if (item.type == BlobData::TYPE_FILE) { ++pending_get_file_info_count_; - base::FileUtilProxy::GetFileInfo( - file_thread_proxy_, item.file_path, - base::Bind(&BlobURLRequestJob::DidGetFileItemInfo, + GetFileReader(i)->GetLength( + base::Bind(&BlobURLRequestJob::DidGetFileItemLength, weak_factory_.GetWeakPtr(), i)); continue; } @@ -227,41 +222,28 @@ void BlobURLRequestJob::DidCountSize(int error) { NotifySuccess(); } -void BlobURLRequestJob::DidGetFileItemInfo( - size_t index, - base::PlatformFileError rv, - const base::PlatformFileInfo& file_info) { +void BlobURLRequestJob::DidGetFileItemLength(size_t index, int result) { // Do nothing if we have encountered an error. if (error_) return; - if (rv == base::PLATFORM_FILE_ERROR_NOT_FOUND) { + if (result == net::ERR_UPLOAD_FILE_CHANGED) { NotifyFailure(net::ERR_FILE_NOT_FOUND); return; - } else if (rv != base::PLATFORM_FILE_OK) { - NotifyFailure(net::ERR_FAILED); + } else if (result < 0) { + NotifyFailure(result); return; } - // Validate the expected modification time. - // Note that the expected modification time from WebKit is based on - // time_t precision. So we have to convert both to time_t to compare. DCHECK_LT(index, blob_data_->items().size()); const BlobData::Item& item = blob_data_->items().at(index); DCHECK(item.type == BlobData::TYPE_FILE); - if (!item.expected_modification_time.is_null() && - item.expected_modification_time.ToTimeT() != - file_info.last_modified.ToTimeT()) { - NotifyFailure(net::ERR_FILE_NOT_FOUND); - return; - } - // If item length is -1, we need to use the file size being resolved // in the real time. int64 item_length = static_cast<int64>(item.length); if (item_length == -1) - item_length = file_info.size; + item_length = result; // Cache the size and add it to the total size. DCHECK_LT(index, item_length_list_.size()); @@ -283,6 +265,20 @@ void BlobURLRequestJob::Seek(int64 offset) { // Set the offset that need to jump to for the first item in the range. current_item_offset_ = offset; + + if (offset == 0) + return; + + // Adjust the offset of the first stream if it is of file type. + const BlobData::Item& item = blob_data_->items().at(current_item_index_); + if (item.type == BlobData::TYPE_FILE) { + DeleteCurrentFileReader(); + index_to_reader_[current_item_index_] = new LocalFileReader( + file_thread_proxy_, + item.file_path, + item.offset + offset, + item.expected_modification_time); + } } bool BlobURLRequestJob::ReadItem() { @@ -312,7 +308,7 @@ bool BlobURLRequestJob::ReadItem() { case BlobData::TYPE_DATA: return ReadBytesItem(item, bytes_to_read); case BlobData::TYPE_FILE: - return ReadFileItem(item, bytes_to_read); + return ReadFileItem(GetFileReader(current_item_index_), bytes_to_read); default: DCHECK(false); return false; @@ -320,8 +316,8 @@ bool BlobURLRequestJob::ReadItem() { } void BlobURLRequestJob::AdvanceItem() { - // Close the stream if the current item is a file. - CloseFileStream(); + // Close the file if the current item is a file. + DeleteCurrentFileReader(); // Advance to the next item. current_item_index_++; @@ -357,79 +353,24 @@ bool BlobURLRequestJob::ReadBytesItem(const BlobData::Item& item, return true; } -bool BlobURLRequestJob::ReadFileItem(const BlobData::Item& item, +bool BlobURLRequestJob::ReadFileItem(LocalFileReader* reader, int bytes_to_read) { - // If the stream already exists, keep reading from it. - if (stream_ != NULL) - return ReadFileStream(bytes_to_read); - - base::FileUtilProxy::CreateOrOpen( - file_thread_proxy_, item.file_path, kFileOpenFlags, - base::Bind(&BlobURLRequestJob::DidOpenFile, - weak_factory_.GetWeakPtr(), bytes_to_read)); - SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); - return false; -} - -void BlobURLRequestJob::DidOpenFile(int bytes_to_read, - base::PlatformFileError rv, - base::PassPlatformFile file, - bool created) { - if (rv != base::PLATFORM_FILE_OK) { - NotifyFailure(net::ERR_FAILED); - return; - } - - DCHECK(!stream_.get()); - stream_.reset(new net::FileStream(file.ReleaseValue(), kFileOpenFlags, NULL)); - - const BlobData::Item& item = blob_data_->items().at(current_item_index_); - { - // stream_.SeekSync() blocks the IO thread, see http://crbug.com/75548. - base::ThreadRestrictions::ScopedAllowIO allow_io; - int64 offset = current_item_offset_ + static_cast<int64>(item.offset); - if (offset > 0 && offset != stream_->SeekSync(net::FROM_BEGIN, offset)) { - NotifyFailure(net::ERR_FAILED); - return; - } - } - - ReadFileStream(bytes_to_read); -} - -bool BlobURLRequestJob::ReadFileStream(int bytes_to_read) { - DCHECK(stream_.get()); - DCHECK(stream_->IsOpen()); DCHECK_GE(read_buf_->BytesRemaining(), bytes_to_read); - - // Start the asynchronous reading. - int rv = stream_->Read(read_buf_, - bytes_to_read, - base::Bind(&BlobURLRequestJob::DidReadFileStream, - base::Unretained(this))); - - // If I/O pending error is returned, we just need to wait. - if (rv == net::ERR_IO_PENDING) { - SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); - return false; - } - - // For all other errors (and for unexpected EOF case), bail out. - if (rv <= 0) { - NotifyFailure(net::ERR_FAILED); + DCHECK(reader); + const int result = reader->Read( + read_buf_, bytes_to_read, + base::Bind(&BlobURLRequestJob::DidReadFile, + base::Unretained(this))); + if (result != net::ERR_IO_PENDING) { + DCHECK(result != net::OK); + NotifyFailure(result); return false; } - - // Otherwise, data is immediately available. - if (GetStatus().is_io_pending()) - DidReadFileStream(rv); - else - AdvanceBytesRead(rv); - - return true; + SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); + return false; } -void BlobURLRequestJob::DidReadFileStream(int result) { +void BlobURLRequestJob::DidReadFile(int result) { if (result <= 0) { NotifyFailure(net::ERR_FAILED); return; @@ -451,12 +392,11 @@ void BlobURLRequestJob::DidReadFileStream(int result) { NotifyReadComplete(bytes_read); } -void BlobURLRequestJob::CloseFileStream() { - if (stream_ != NULL) { - // stream_.Close() blocks the IO thread, see http://crbug.com/75548. - base::ThreadRestrictions::ScopedAllowIO allow_io; - stream_->CloseSync(); - stream_.reset(NULL); +void BlobURLRequestJob::DeleteCurrentFileReader() { + IndexToReaderMap::iterator found = index_to_reader_.find(current_item_index_); + if (found != index_to_reader_.end() && found->second) { + delete found->second; + index_to_reader_.erase(found); } } @@ -578,4 +518,20 @@ void BlobURLRequestJob::HeadersCompleted(int status_code, NotifyHeadersComplete(); } +LocalFileReader* BlobURLRequestJob::GetFileReader(size_t index) { + DCHECK_LT(index, blob_data_->items().size()); + const BlobData::Item& item = blob_data_->items().at(index); + if (item.type != BlobData::TYPE_FILE) + return NULL; + if (index_to_reader_.find(index) == index_to_reader_.end()) { + index_to_reader_[index] = new LocalFileReader( + file_thread_proxy_, + item.file_path, + item.offset, + item.expected_modification_time); + } + DCHECK(index_to_reader_[index]); + return index_to_reader_[index]; +} + } // namespace webkit_blob diff --git a/webkit/blob/blob_url_request_job.h b/webkit/blob/blob_url_request_job.h index e242aff..86a5f31 100644 --- a/webkit/blob/blob_url_request_job.h +++ b/webkit/blob/blob_url_request_job.h @@ -26,6 +26,8 @@ class IOBuffer; namespace webkit_blob { +class LocalFileReader; + // A request job that handles reading blob URLs. class BLOB_EXPORT BlobURLRequestJob : public net::URLRequestJob { public: @@ -47,13 +49,13 @@ class BLOB_EXPORT BlobURLRequestJob : public net::URLRequestJob { const net::HttpRequestHeaders& headers) OVERRIDE; private: + typedef std::map<size_t, LocalFileReader*> IndexToReaderMap; + // For preparing for read: get the size, apply the range and perform seek. void DidStart(); void CountSize(); void DidCountSize(int error); - void DidGetFileItemInfo(size_t index, - base::PlatformFileError error, - const base::PlatformFileInfo& file_info); + void DidGetFileItemLength(size_t index, int result); void Seek(int64 offset); // For reading the blob. @@ -62,15 +64,10 @@ class BLOB_EXPORT BlobURLRequestJob : public net::URLRequestJob { void AdvanceItem(); void AdvanceBytesRead(int result); bool ReadBytesItem(const BlobData::Item& item, int bytes_to_read); - bool ReadFileItem(const BlobData::Item& item, int bytes_to_read); + bool ReadFileItem(LocalFileReader* reader, int bytes_to_read); - void DidOpenFile(int bytes_to_read, - base::PlatformFileError rv, - base::PassPlatformFile file, - bool created); - bool ReadFileStream(int bytes_to_read); - void DidReadFileStream(int result); - void CloseFileStream(); + void DidReadFile(int result); + void DeleteCurrentFileReader(); int ComputeBytesToRead() const; int BytesReadCompleted(); @@ -79,6 +76,10 @@ class BLOB_EXPORT BlobURLRequestJob : public net::URLRequestJob { void NotifyFailure(int); void HeadersCompleted(int status_code, const std::string& status_txt); + // Returns a LocalFileReader for a blob item at |index|. + // If the item at |index| is not of TYPE_FILE this returns NULL. + LocalFileReader* GetFileReader(size_t index); + base::WeakPtrFactory<BlobURLRequestJob> weak_factory_; scoped_refptr<BlobData> blob_data_; scoped_refptr<base::MessageLoopProxy> file_thread_proxy_; @@ -86,7 +87,7 @@ class BLOB_EXPORT BlobURLRequestJob : public net::URLRequestJob { int64 total_size_; int64 remaining_bytes_; int pending_get_file_info_count_; - scoped_ptr<net::FileStream> stream_; + IndexToReaderMap index_to_reader_; size_t current_item_index_; int64 current_item_offset_; scoped_refptr<net::DrainableIOBuffer> read_buf_; diff --git a/webkit/blob/blob_url_request_job_unittest.cc b/webkit/blob/blob_url_request_job_unittest.cc index 12a0cb7..515574a 100644 --- a/webkit/blob/blob_url_request_job_unittest.cc +++ b/webkit/blob/blob_url_request_job_unittest.cc @@ -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. @@ -259,10 +259,10 @@ class BlobURLRequestJobTest : public testing::Test { void VerifyResponse() { EXPECT_TRUE(request_->status().is_success()); - EXPECT_EQ(request_->response_headers()->response_code(), - expected_status_code_); - EXPECT_STREQ(url_request_delegate_->response_data().c_str(), - expected_response_.c_str()); + EXPECT_EQ(expected_status_code_, + request_->response_headers()->response_code()); + EXPECT_STREQ(expected_response_.c_str(), + url_request_delegate_->response_data().c_str()); TestFinished(); } diff --git a/webkit/blob/local_file_reader.cc b/webkit/blob/local_file_reader.cc new file mode 100644 index 0000000..54493c1 --- /dev/null +++ b/webkit/blob/local_file_reader.cc @@ -0,0 +1,216 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/blob/local_file_reader.h" + +#include "base/file_util.h" +#include "base/file_util_proxy.h" +#include "base/logging.h" +#include "base/message_loop_proxy.h" +#include "base/platform_file.h" +#include "net/base/file_stream.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" + +namespace webkit_blob { + +namespace { + +const int kOpenFlagsForRead = base::PLATFORM_FILE_OPEN | + base::PLATFORM_FILE_READ | + base::PLATFORM_FILE_ASYNC; + +int PlatformFileErrorToNetError(base::PlatformFileError file_error) { + switch (file_error) { + case base::PLATFORM_FILE_OK: + return net::OK; + case base::PLATFORM_FILE_ERROR_NOT_FOUND: + return net::ERR_FILE_NOT_FOUND; + case base::PLATFORM_FILE_ERROR_ACCESS_DENIED: + return net::ERR_ACCESS_DENIED; + default: + return net::ERR_FAILED; + } +} + +// Verify if the underlying file has not been modified. +bool VerifySnapshotTime(const base::Time& expected_modification_time, + const base::PlatformFileInfo& file_info) { + return expected_modification_time.is_null() || + expected_modification_time.ToTimeT() == + file_info.last_modified.ToTimeT(); +} + +void DidGetFileInfoForGetLength(const net::CompletionCallback& callback, + const base::Time& expected_modification_time, + int64 initial_offset, + base::PlatformFileError error, + const base::PlatformFileInfo& file_info) { + if (file_info.is_directory) { + callback.Run(net::ERR_FILE_NOT_FOUND); + return; + } + if (error != base::PLATFORM_FILE_OK) { + callback.Run(PlatformFileErrorToNetError(error)); + return; + } + if (!VerifySnapshotTime(expected_modification_time, file_info)) { + callback.Run(net::ERR_UPLOAD_FILE_CHANGED); + return; + } + callback.Run(file_info.size - initial_offset); +} + +void DidSeekFile(const LocalFileReader::OpenFileStreamCallback& callback, + scoped_ptr<net::FileStream> stream_impl, + int64 initial_offset, + int64 new_offset) { + int result = net::OK; + if (new_offset < 0) + result = static_cast<int>(new_offset); + else if (new_offset != initial_offset) + result = net::ERR_FAILED; + callback.Run(result, stream_impl.Pass()); +} + +void EmptyCompletionCallback(int) {} + +} // namespace + +// A helper class to open, verify and seek a file stream for a given path. +class LocalFileReader::OpenFileStreamHelper { + public: + OpenFileStreamHelper(base::MessageLoopProxy* file_thread_proxy) + : file_thread_proxy_(file_thread_proxy), + file_handle_(base::kInvalidPlatformFileValue), + result_(net::OK) {} + ~OpenFileStreamHelper() { + if (file_handle_ != base::kInvalidPlatformFileValue) { + file_thread_proxy_->PostTask( + FROM_HERE, + base::Bind(base::IgnoreResult(&base::ClosePlatformFile), + file_handle_)); + } + } + + void OpenAndVerifyOnFileThread(const FilePath& file_path, + const base::Time& expected_modification_time) { + base::PlatformFileError file_error = base::PLATFORM_FILE_OK; + file_handle_ = base::CreatePlatformFile( + file_path, kOpenFlagsForRead, NULL, &file_error); + if (file_error != base::PLATFORM_FILE_OK) { + result_ = PlatformFileErrorToNetError(file_error); + return; + } + DCHECK_NE(base::kInvalidPlatformFileValue, file_handle_); + base::PlatformFileInfo file_info; + if (!base::GetPlatformFileInfo(file_handle_, &file_info)) { + result_ = net::ERR_FAILED; + return; + } + if (!VerifySnapshotTime(expected_modification_time, file_info)) { + result_ = net::ERR_UPLOAD_FILE_CHANGED; + return; + } + result_ = net::OK; + } + + void OpenStreamOnCallingThread(int64 initial_offset, + const OpenFileStreamCallback& callback) { + DCHECK(!callback.is_null()); + scoped_ptr<net::FileStream> stream_impl; + if (result_ != net::OK) { + callback.Run(result_, stream_impl.Pass()); + return; + } + stream_impl.reset( + new net::FileStream(file_handle_, kOpenFlagsForRead, NULL)); + file_handle_ = base::kInvalidPlatformFileValue; + result_ = stream_impl->Seek(net::FROM_BEGIN, initial_offset, + base::Bind(&DidSeekFile, callback, + base::Passed(&stream_impl), + initial_offset)); + if (result_ != net::ERR_IO_PENDING) + callback.Run(result_, stream_impl.Pass()); + } + + private: + scoped_refptr<base::MessageLoopProxy> file_thread_proxy_; + base::PlatformFile file_handle_; + int result_; + DISALLOW_COPY_AND_ASSIGN(OpenFileStreamHelper); +}; + +LocalFileReader::LocalFileReader( + base::MessageLoopProxy* file_thread_proxy, + const FilePath& file_path, + int64 initial_offset, + const base::Time& expected_modification_time) + : file_thread_proxy_(file_thread_proxy), + file_path_(file_path), + initial_offset_(initial_offset), + expected_modification_time_(expected_modification_time), + has_pending_open_(false), + weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} + +LocalFileReader::~LocalFileReader() { + if (!stream_impl_.get()) + return; + stream_impl_->Close(base::Bind(&EmptyCompletionCallback)); +} + +int LocalFileReader::Read(net::IOBuffer* buf, int buf_len, + const net::CompletionCallback& callback) { + DCHECK(!has_pending_open_); + if (stream_impl_.get()) + return stream_impl_->Read(buf, buf_len, callback); + return Open(base::Bind(&LocalFileReader::DidOpen, weak_factory_.GetWeakPtr(), + make_scoped_refptr(buf), buf_len, callback)); +} + +int LocalFileReader::GetLength(const net::CompletionCallback& callback) { + const bool posted = base::FileUtilProxy::GetFileInfo( + file_thread_proxy_, file_path_, + base::Bind(&DidGetFileInfoForGetLength, callback, + expected_modification_time_, initial_offset_)); + DCHECK(posted); + return net::ERR_IO_PENDING; +} + +int LocalFileReader::Open(const OpenFileStreamCallback& callback) { + DCHECK(!has_pending_open_); + DCHECK(!stream_impl_.get()); + has_pending_open_ = true; + OpenFileStreamHelper* helper = new OpenFileStreamHelper(file_thread_proxy_); + const bool posted = file_thread_proxy_->PostTaskAndReply( + FROM_HERE, + base::Bind(&OpenFileStreamHelper::OpenAndVerifyOnFileThread, + base::Unretained(helper), file_path_, + expected_modification_time_), + base::Bind(&OpenFileStreamHelper::OpenStreamOnCallingThread, + base::Owned(helper), initial_offset_, callback)); + DCHECK(posted); + return net::ERR_IO_PENDING; +} + +void LocalFileReader::DidOpen(net::IOBuffer* buf, + int buf_len, + const net::CompletionCallback& callback, + int open_error, + scoped_ptr<net::FileStream> stream_impl) { + DCHECK(has_pending_open_); + DCHECK(!stream_impl_.get()); + has_pending_open_ = false; + if (open_error != net::OK) { + callback.Run(open_error); + return; + } + DCHECK(stream_impl.get()); + stream_impl_ = stream_impl.Pass(); + const int read_error = stream_impl_->Read(buf, buf_len, callback); + if (read_error != net::ERR_IO_PENDING) + callback.Run(read_error); +} + +} // namespace webkit_blob diff --git a/webkit/blob/local_file_reader.h b/webkit/blob/local_file_reader.h new file mode 100644 index 0000000..fd87dd4 --- /dev/null +++ b/webkit/blob/local_file_reader.h @@ -0,0 +1,83 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_BLOB_LOCAL_FILE_READER_H_ +#define WEBKIT_BLOB_LOCAL_FILE_READER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/file_path.h" +#include "base/memory/weak_ptr.h" +#include "base/time.h" +#include "net/base/completion_callback.h" +#include "webkit/blob/blob_export.h" + +namespace base { +class MessageLoopProxy; +} + +namespace net { +class FileStream; +class IOBuffer; +} + +namespace webkit_blob { + +// A thin wrapper of net::FileStream with range support for sliced file +// handling. +class BLOB_EXPORT LocalFileReader { + public: + typedef base::Callback<void(int error, scoped_ptr<net::FileStream> stream)> + OpenFileStreamCallback; + + // Creates a new FileReader for a local file |file_path|. + // |initial_offset| specifies the offset in the file where the first read + // should start. + // |expected_modification_time| specifies the expected last modification + // If the value is non-null, the reader will check the underlying file's + // actual modification time to see if the file has been modified, and if + // it does any succeeding read operations should fail with + // ERR_UPLOAD_FILE_CHANGED error. + LocalFileReader(base::MessageLoopProxy* file_thread_proxy, + const FilePath& file_path, + int64 initial_offset, + const base::Time& expected_modification_time); + + ~LocalFileReader(); + + // Reads from the current cursor position asynchronously. + // This works mostly same as how net::FileStream::Read() works except that + // it internally opens (and seeks) the file if it is not opened yet. + // It is invalid to call Read while there is an in-flight Read operation. + int Read(net::IOBuffer* buf, int buf_len, + const net::CompletionCallback& callback); + + // Returns the number of bytes available to read from the beginning of + // the file (or initial_offset) until the end of the file (rv >= 0 cases). + // Otherwise, a negative error code is returned (rv < 0 cases). + int GetLength(const net::CompletionCallback& callback); + + private: + class OpenFileStreamHelper; + + int Open(const OpenFileStreamCallback& callback); + void DidOpen(net::IOBuffer* buf, + int buf_len, + const net::CompletionCallback& callback, + int open_error, + scoped_ptr<net::FileStream> stream); + + scoped_refptr<base::MessageLoopProxy> file_thread_proxy_; + scoped_ptr<net::FileStream> stream_impl_; + const FilePath file_path_; + const int64 initial_offset_; + const base::Time expected_modification_time_; + bool has_pending_open_; + base::WeakPtrFactory<LocalFileReader> weak_factory_; +}; + +} // namespace webkit_blob + +#endif // WEBKIT_BLOB_LOCAL_FILE_READER_H_ diff --git a/webkit/blob/webkit_blob.gypi b/webkit/blob/webkit_blob.gypi index bb07019..196c3fb 100644 --- a/webkit/blob/webkit_blob.gypi +++ b/webkit/blob/webkit_blob.gypi @@ -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. @@ -37,6 +37,8 @@ 'blob_url_request_job.h', 'blob_url_request_job_factory.cc', 'blob_url_request_job_factory.h', + 'local_file_reader.cc', + 'local_file_reader.h', 'shareable_file_reference.cc', 'shareable_file_reference.h', 'view_blob_internals_job.cc', |