diff --git a/atom/browser/net/asar/url_request_asar_job.cc b/atom/browser/net/asar/url_request_asar_job.cc index a2ebd04c87..a4875a145f 100644 --- a/atom/browser/net/asar/url_request_asar_job.cc +++ b/atom/browser/net/asar/url_request_asar_job.cc @@ -4,6 +4,10 @@ #include "atom/browser/net/asar/url_request_asar_job.h" +#include + +#include "net/base/file_stream.h" +#include "net/base/io_buffer.h" #include "net/base/mime_util.h" #include "net/base/net_errors.h" #include "net/url_request/url_request_status.h" @@ -19,20 +23,30 @@ URLRequestAsarJob::URLRequestAsarJob( : net::URLRequestJob(request, network_delegate), archive_(asar_path), file_path_(file_path), + stream_(new net::FileStream(file_task_runner)), + remaining_bytes_(0), file_task_runner_(file_task_runner), weak_ptr_factory_(this) {} URLRequestAsarJob::~URLRequestAsarJob() {} void URLRequestAsarJob::Start() { - Archive::FileInfo info; - if (!archive_.Init() || !archive_.GetFileInfo(file_path_, &info)) { + if (!archive_.Init() || !archive_.GetFileInfo(file_path_, &file_info_)) { NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FILE_NOT_FOUND)); return; } - NotifyHeadersComplete(); + remaining_bytes_ = static_cast(file_info_.size); + + int flags = base::File::FLAG_OPEN | + base::File::FLAG_READ | + base::File::FLAG_ASYNC; + int rv = stream_->Open(archive_.path(), flags, + base::Bind(&URLRequestAsarJob::DidOpen, + weak_ptr_factory_.GetWeakPtr())); + if (rv != net::ERR_IO_PENDING) + DidOpen(rv); } void URLRequestAsarJob::Kill() { @@ -40,15 +54,89 @@ void URLRequestAsarJob::Kill() { URLRequestJob::Kill(); } -bool URLRequestAsarJob::ReadRawData(net::IOBuffer* buf, - int buf_size, +bool URLRequestAsarJob::ReadRawData(net::IOBuffer* dest, + int dest_size, int* bytes_read) { - *bytes_read = 0; - return true; + if (remaining_bytes_ < dest_size) + dest_size = static_cast(remaining_bytes_); + + // If we should copy zero bytes because |remaining_bytes_| is zero, short + // circuit here. + if (!dest_size) { + *bytes_read = 0; + return true; + } + + int rv = stream_->Read(dest, + dest_size, + base::Bind(&URLRequestAsarJob::DidRead, + weak_ptr_factory_.GetWeakPtr(), + make_scoped_refptr(dest))); + if (rv >= 0) { + // Data is immediately available. + *bytes_read = rv; + remaining_bytes_ -= rv; + DCHECK_GE(remaining_bytes_, 0); + return true; + } + + // Otherwise, a read error occured. We may just need to wait... + if (rv == net::ERR_IO_PENDING) { + SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); + } else { + NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, rv)); + } + return false; } bool URLRequestAsarJob::GetMimeType(std::string* mime_type) const { return net::GetMimeTypeFromFile(file_path_, mime_type); } +void URLRequestAsarJob::DidOpen(int result) { + if (result != net::OK) { + NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); + return; + } + + int rv = stream_->Seek(net::FROM_BEGIN, + file_info_.offset, + base::Bind(&URLRequestAsarJob::DidSeek, + weak_ptr_factory_.GetWeakPtr())); + if (rv != net::ERR_IO_PENDING) { + // stream_->Seek() failed, so pass an intentionally erroneous value + // into DidSeek(). + DidSeek(-1); + } +} + +void URLRequestAsarJob::DidSeek(int64 result) { + if (result != static_cast(file_info_.offset)) { + NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, + net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); + return; + } + + set_expected_content_size(remaining_bytes_); + NotifyHeadersComplete(); +} + +void URLRequestAsarJob::DidRead(scoped_refptr buf, int result) { + if (result > 0) { + SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status + remaining_bytes_ -= result; + DCHECK_GE(remaining_bytes_, 0); + } + + buf = NULL; + + if (result == 0) { + NotifyDone(net::URLRequestStatus()); + } else if (result < 0) { + NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); + } + + NotifyReadComplete(result); +} + } // namespace asar diff --git a/atom/browser/net/asar/url_request_asar_job.h b/atom/browser/net/asar/url_request_asar_job.h index 75653f282f..b85aa3c6f4 100644 --- a/atom/browser/net/asar/url_request_asar_job.h +++ b/atom/browser/net/asar/url_request_asar_job.h @@ -5,6 +5,8 @@ #ifndef ATOM_BROWSER_NET_ASAR_URL_REQUEST_ASAR_JOB_H_ #define ATOM_BROWSER_NET_ASAR_URL_REQUEST_ASAR_JOB_H_ +#include + #include "atom/common/asar/archive.h" #include "base/files/file_path.h" #include "base/memory/ref_counted.h" @@ -15,6 +17,10 @@ namespace base { class TaskRunner; } +namespace net { +class FileStream; +} + namespace asar { class URLRequestAsarJob : public net::URLRequestJob { @@ -37,8 +43,22 @@ class URLRequestAsarJob : public net::URLRequestJob { virtual ~URLRequestAsarJob(); private: + // Callback after opening file on a background thread. + void DidOpen(int result); + + // Callback after seeking to the beginning of |byte_range_| in the file + // on a background thread. + void DidSeek(int64 result); + + // Callback after data is asynchronously read from the file into |buf|. + void DidRead(scoped_refptr buf, int result); + Archive archive_; + Archive::FileInfo file_info_; base::FilePath file_path_; + + scoped_ptr stream_; + int64 remaining_bytes_; const scoped_refptr file_task_runner_; base::WeakPtrFactory weak_ptr_factory_; diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc index 28116d6990..a518230461 100644 --- a/atom/common/asar/archive.cc +++ b/atom/common/asar/archive.cc @@ -44,7 +44,9 @@ bool GetNodeFromPath(std::string path, } // namespace -Archive::Archive(const base::FilePath& path) : path_(path) { +Archive::Archive(const base::FilePath& path) + : path_(path), + header_size_(0) { } Archive::~Archive() { @@ -94,6 +96,7 @@ bool Archive::Init() { return false; } + header_size_ = 8 + size; header_.reset(static_cast(value)); return true; } @@ -119,8 +122,9 @@ bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) { int size; if (!node->GetInteger("size", &size)) return false; - info->size = static_cast(size); + info->offset += header_size_; + info->size = static_cast(size); return true; } diff --git a/atom/common/asar/archive.h b/atom/common/asar/archive.h index ef11eadf40..c4cde803bf 100644 --- a/atom/common/asar/archive.h +++ b/atom/common/asar/archive.h @@ -34,6 +34,7 @@ class Archive { private: base::FilePath path_; + uint32 header_size_; scoped_ptr header_; DISALLOW_COPY_AND_ASSIGN(Archive);