| Index: webkit/blob/blob_url_request_job.cc
|
| diff --git a/webkit/blob/blob_url_request_job.cc b/webkit/blob/blob_url_request_job.cc
|
| index 58e96c6bb9be48dbab5c32b1d0532acbdb712ae1..0de56ac15bb83779279f4ed8ec62b590a1130419 100644
|
| --- a/webkit/blob/blob_url_request_job.cc
|
| +++ b/webkit/blob/blob_url_request_job.cc
|
| @@ -12,6 +12,7 @@
|
| #include "base/message_loop_proxy.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"
|
| @@ -41,6 +42,10 @@ static const char kHTTPRequestedRangeNotSatisfiableText[] =
|
| "Requested Range Not Satisfiable";
|
| static const char kHTTPInternalErrorText[] = "Internal Server Error";
|
|
|
| +static const int kFileOpenFlags = base::PLATFORM_FILE_OPEN |
|
| + base::PLATFORM_FILE_READ |
|
| + base::PLATFORM_FILE_ASYNC;
|
| +
|
| BlobURLRequestJob::BlobURLRequestJob(
|
| net::URLRequest* request,
|
| BlobData* blob_data,
|
| @@ -58,13 +63,18 @@ BlobURLRequestJob::BlobURLRequestJob(
|
| read_buf_offset_(0),
|
| read_buf_size_(0),
|
| read_buf_remaining_bytes_(0),
|
| + bytes_to_read_(0),
|
| error_(false),
|
| headers_set_(false),
|
| byte_range_set_(false),
|
| ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
|
| + DCHECK(file_thread_proxy_);
|
| }
|
|
|
| BlobURLRequestJob::~BlobURLRequestJob() {
|
| + // FileStream's destructor won't close it for us because we passed in our own
|
| + // file handle.
|
| + CloseStream();
|
| }
|
|
|
| void BlobURLRequestJob::Start() {
|
| @@ -90,8 +100,15 @@ void BlobURLRequestJob::DidStart() {
|
| CountSize();
|
| }
|
|
|
| +void BlobURLRequestJob::CloseStream() {
|
| + if (stream_ != NULL) {
|
| + stream_->Close();
|
| + stream_.reset(NULL);
|
| + }
|
| +}
|
| +
|
| void BlobURLRequestJob::Kill() {
|
| - stream_.Close();
|
| + CloseStream();
|
|
|
| net::URLRequestJob::Kill();
|
| callback_factory_.RevokeAll();
|
| @@ -99,28 +116,10 @@ void BlobURLRequestJob::Kill() {
|
| }
|
|
|
| void BlobURLRequestJob::ResolveFile(const FilePath& file_path) {
|
| - // If the file thread proxy is provided, we can use it get the file info.
|
| - if (file_thread_proxy_) {
|
| - base::FileUtilProxy::GetFileInfo(
|
| - file_thread_proxy_,
|
| - file_path,
|
| - callback_factory_.NewCallback(&BlobURLRequestJob::DidResolve));
|
| - return;
|
| - }
|
| -
|
| - // Otherwise, we use current thread, i.e. IO thread, as this is the case when
|
| - // we run the unittest or test shell.
|
| - // TODO(jianli): Consider using the proxy of current thread.
|
| - base::PlatformFileInfo file_info;
|
| - bool exists = file_util::GetFileInfo(file_path, &file_info);
|
| -
|
| - // Continue asynchronously.
|
| - MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - method_factory_.NewRunnableMethod(
|
| - &BlobURLRequestJob::DidResolve,
|
| - exists ? base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_NOT_FOUND,
|
| - file_info));
|
| + base::FileUtilProxy::GetFileInfo(
|
| + file_thread_proxy_,
|
| + file_path,
|
| + callback_factory_.NewCallback(&BlobURLRequestJob::DidResolve));
|
| }
|
|
|
| void BlobURLRequestJob::DidResolve(base::PlatformFileError rv,
|
| @@ -255,6 +254,17 @@ bool BlobURLRequestJob::ReadLoop(int* bytes_read) {
|
| return true;
|
| }
|
|
|
| +int BlobURLRequestJob::ComputeBytesToRead() const {
|
| + int64 current_item_remaining_bytes =
|
| + item_length_list_[item_index_] - current_item_offset_;
|
| + int bytes_to_read = (read_buf_remaining_bytes_ > current_item_remaining_bytes)
|
| + ? static_cast<int>(current_item_remaining_bytes)
|
| + : read_buf_remaining_bytes_;
|
| + if (bytes_to_read > remaining_bytes_)
|
| + bytes_to_read = static_cast<int>(remaining_bytes_);
|
| + return bytes_to_read;
|
| +}
|
| +
|
| bool BlobURLRequestJob::ReadItem() {
|
| // Are we done with reading all the blob data?
|
| if (remaining_bytes_ == 0)
|
| @@ -267,77 +277,85 @@ bool BlobURLRequestJob::ReadItem() {
|
| return false;
|
| }
|
|
|
| - const BlobData::Item& item = blob_data_->items().at(item_index_);
|
| -
|
| // Compute the bytes to read for current item.
|
| - int64 current_item_remaining_bytes =
|
| - item_length_list_[item_index_] - current_item_offset_;
|
| - int bytes_to_read = (read_buf_remaining_bytes_ > current_item_remaining_bytes)
|
| - ? static_cast<int>(current_item_remaining_bytes)
|
| - : read_buf_remaining_bytes_;
|
| - if (bytes_to_read > remaining_bytes_)
|
| - bytes_to_read = static_cast<int>(remaining_bytes_);
|
| + bytes_to_read_ = ComputeBytesToRead();
|
|
|
| // If nothing to read for current item, advance to next item.
|
| - if (bytes_to_read == 0) {
|
| + if (bytes_to_read_ == 0) {
|
| AdvanceItem();
|
| return ReadItem();
|
| }
|
|
|
| // Do the reading.
|
| + const BlobData::Item& item = blob_data_->items().at(item_index_);
|
| switch (item.type()) {
|
| case BlobData::TYPE_DATA:
|
| - return ReadBytes(item, bytes_to_read);
|
| + return ReadBytes(item);
|
| case BlobData::TYPE_FILE:
|
| - return ReadFile(item, bytes_to_read);
|
| + return DispatchReadFile(item);
|
| default:
|
| DCHECK(false);
|
| return false;
|
| }
|
| }
|
|
|
| -bool BlobURLRequestJob::ReadBytes(const BlobData::Item& item,
|
| - int bytes_to_read) {
|
| - DCHECK(read_buf_remaining_bytes_ >= bytes_to_read);
|
| +bool BlobURLRequestJob::ReadBytes(const BlobData::Item& item) {
|
| + DCHECK(read_buf_remaining_bytes_ >= bytes_to_read_);
|
|
|
| memcpy(read_buf_->data() + read_buf_offset_,
|
| &item.data().at(0) + item.offset() + current_item_offset_,
|
| - bytes_to_read);
|
| + bytes_to_read_);
|
|
|
| - AdvanceBytesRead(bytes_to_read);
|
| + AdvanceBytesRead(bytes_to_read_);
|
| return true;
|
| }
|
|
|
| -bool BlobURLRequestJob::ReadFile(const BlobData::Item& item,
|
| - int bytes_to_read) {
|
| - DCHECK(read_buf_remaining_bytes_ >= bytes_to_read);
|
| +bool BlobURLRequestJob::DispatchReadFile(const BlobData::Item& item) {
|
| + // If the stream already exists, keep reading from it.
|
| + if (stream_ != NULL)
|
| + return ReadFile(item);
|
|
|
| - // Open the file if not yet.
|
| - if (!stream_.IsOpen()) {
|
| - // stream_.Open() and stream_.Seek() block the IO thread.
|
| - // See http://crbug.com/75548.
|
| - base::ThreadRestrictions::ScopedAllowIO allow_io;
|
| - int rv = stream_.Open(item.file_path(), base::PLATFORM_FILE_OPEN |
|
| - base::PLATFORM_FILE_READ | base::PLATFORM_FILE_ASYNC);
|
| - if (rv != net::OK) {
|
| - NotifyFailure(net::ERR_FAILED);
|
| - return false;
|
| - }
|
| + base::FileUtilProxy::CreateOrOpen(
|
| + file_thread_proxy_, item.file_path(), kFileOpenFlags,
|
| + callback_factory_.NewCallback(&BlobURLRequestJob::DidOpen));
|
| + SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
|
| + return false;
|
| +}
|
| +
|
| +void BlobURLRequestJob::DidOpen(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));
|
|
|
| - // Seek the file if needed.
|
| + const BlobData::Item& item = blob_data_->items().at(item_index_);
|
| + {
|
| + // stream_.Seek() 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) {
|
| - if (offset != stream_.Seek(net::FROM_BEGIN, offset)) {
|
| - NotifyFailure(net::ERR_FAILED);
|
| - return false;
|
| - }
|
| + if (offset > 0 && offset != stream_->Seek(net::FROM_BEGIN, offset)) {
|
| + NotifyFailure(net::ERR_FAILED);
|
| + return;
|
| }
|
| }
|
|
|
| + ReadFile(item);
|
| +}
|
| +
|
| +bool BlobURLRequestJob::ReadFile(const BlobData::Item& item) {
|
| + DCHECK(stream_.get());
|
| + DCHECK(stream_->IsOpen());
|
| + DCHECK(read_buf_remaining_bytes_ >= bytes_to_read_);
|
| +
|
| // Start the asynchronous reading.
|
| - int rv = stream_.Read(read_buf_->data() + read_buf_offset_,
|
| - bytes_to_read,
|
| - &io_callback_);
|
| + int rv = stream_->Read(read_buf_->data() + read_buf_offset_,
|
| + bytes_to_read_,
|
| + &io_callback_);
|
|
|
| // If I/O pending error is returned, we just need to wait.
|
| if (rv == net::ERR_IO_PENDING) {
|
| @@ -352,7 +370,11 @@ bool BlobURLRequestJob::ReadFile(const BlobData::Item& item,
|
| }
|
|
|
| // Otherwise, data is immediately available.
|
| - AdvanceBytesRead(rv);
|
| + if (GetStatus().is_io_pending())
|
| + DidRead(rv);
|
| + else
|
| + AdvanceBytesRead(rv);
|
| +
|
| return true;
|
| }
|
|
|
| @@ -380,8 +402,7 @@ void BlobURLRequestJob::DidRead(int result) {
|
|
|
| void BlobURLRequestJob::AdvanceItem() {
|
| // Close the stream if the current item is a file.
|
| - if (stream_.IsOpen())
|
| - stream_.Close();
|
| + CloseStream();
|
|
|
| // Advance to the next item.
|
| item_index_++;
|
|
|