From b5a8cfb704ae1998cd0aa95de4bf95e7bdc59578 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 20 Mar 2015 20:34:58 +0800 Subject: [PATCH] Recognize asar archive with unpacked files --- atom/browser/net/adapter_request_job.cc | 33 +++---------- .../browser/net/asar/asar_protocol_handler.cc | 47 +++++++++++++------ atom/browser/net/asar/url_request_asar_job.cc | 8 +--- atom/browser/net/asar/url_request_asar_job.h | 10 +++- atom/common/api/atom_api_asar.cc | 1 + atom/common/asar/archive.cc | 21 ++++++--- atom/common/asar/archive.h | 2 + atom/common/asar/asar_util.cc | 7 +++ atom/common/lib/asar.coffee | 10 +++- 9 files changed, 84 insertions(+), 55 deletions(-) diff --git a/atom/browser/net/adapter_request_job.cc b/atom/browser/net/adapter_request_job.cc index 0d873d4a7da4..86c82d7836ce 100644 --- a/atom/browser/net/adapter_request_job.cc +++ b/atom/browser/net/adapter_request_job.cc @@ -100,32 +100,13 @@ void AdapterRequestJob::CreateBufferJobAndStart(const std::string& mime_type, void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - - base::FilePath asar_path, relative_path; - if (!asar::GetAsarArchivePath(path, &asar_path, &relative_path)) { - real_job_ = new net::URLRequestFileJob( - request(), - network_delegate(), - path, - content::BrowserThread::GetBlockingPool()-> - GetTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); - } else { - auto archive = asar::GetOrCreateAsarArchive(asar_path); - if (archive) - real_job_ = new asar::URLRequestAsarJob( - request(), - network_delegate(), - archive, - relative_path, - content::BrowserThread::GetBlockingPool()-> - GetTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); - else - real_job_ = new net::URLRequestErrorJob( - request(), network_delegate(), net::ERR_FILE_NOT_FOUND); - } - + real_job_ = asar::CreateJobFromPath( + path, + request(), + network_delegate(), + content::BrowserThread::GetBlockingPool()-> + GetTaskRunnerWithShutdownBehavior( + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); real_job_->Start(); } diff --git a/atom/browser/net/asar/asar_protocol_handler.cc b/atom/browser/net/asar/asar_protocol_handler.cc index 0daa6f427e8f..6d2a2cd5bf0a 100644 --- a/atom/browser/net/asar/asar_protocol_handler.cc +++ b/atom/browser/net/asar/asar_protocol_handler.cc @@ -14,6 +14,36 @@ namespace asar { +// static +net::URLRequestJob* CreateJobFromPath( + const base::FilePath& full_path, + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const scoped_refptr file_task_runner) { + // Create asar:// job when the path contains "xxx.asar/", otherwise treat the + // URL request as file://. + base::FilePath asar_path, relative_path; + if (!GetAsarArchivePath(full_path, &asar_path, &relative_path)) + return new net::URLRequestFileJob(request, network_delegate, full_path, + file_task_runner); + + std::shared_ptr archive = GetOrCreateAsarArchive(asar_path); + Archive::FileInfo file_info; + if (!archive || !archive->GetFileInfo(relative_path, &file_info)) + return new net::URLRequestErrorJob(request, network_delegate, + net::ERR_FILE_NOT_FOUND); + + if (file_info.unpacked) { + base::FilePath real_path; + archive->CopyFileOut(relative_path, &real_path); + return new net::URLRequestFileJob(request, network_delegate, real_path, + file_task_runner); + } + + return new URLRequestAsarJob(request, network_delegate, archive, + relative_path, file_info, file_task_runner); +} + AsarProtocolHandler::AsarProtocolHandler( const scoped_refptr& file_task_runner) : file_task_runner_(file_task_runner) {} @@ -26,21 +56,8 @@ net::URLRequestJob* AsarProtocolHandler::MaybeCreateJob( net::NetworkDelegate* network_delegate) const { base::FilePath full_path; net::FileURLToFilePath(request->url(), &full_path); - - // Create asar:// job when the path contains "xxx.asar/", otherwise treat the - // URL request as file://. - base::FilePath asar_path, relative_path; - if (!GetAsarArchivePath(full_path, &asar_path, &relative_path)) - return new net::URLRequestFileJob(request, network_delegate, full_path, - file_task_runner_); - - std::shared_ptr archive = GetOrCreateAsarArchive(asar_path); - if (!archive) - return new net::URLRequestErrorJob(request, network_delegate, - net::ERR_FILE_NOT_FOUND); - - return new URLRequestAsarJob(request, network_delegate, archive, - relative_path, file_task_runner_); + return CreateJobFromPath(full_path, request, network_delegate, + file_task_runner_); } bool AsarProtocolHandler::IsSafeRedirectTarget(const GURL& location) const { diff --git a/atom/browser/net/asar/url_request_asar_job.cc b/atom/browser/net/asar/url_request_asar_job.cc index 82cade53c6f7..477c6610b1b1 100644 --- a/atom/browser/net/asar/url_request_asar_job.cc +++ b/atom/browser/net/asar/url_request_asar_job.cc @@ -19,10 +19,12 @@ URLRequestAsarJob::URLRequestAsarJob( net::NetworkDelegate* network_delegate, std::shared_ptr archive, const base::FilePath& file_path, + const Archive::FileInfo& file_info, const scoped_refptr& file_task_runner) : net::URLRequestJob(request, network_delegate), archive_(archive), file_path_(file_path), + file_info_(file_info), stream_(new net::FileStream(file_task_runner)), remaining_bytes_(0), file_task_runner_(file_task_runner), @@ -31,12 +33,6 @@ URLRequestAsarJob::URLRequestAsarJob( URLRequestAsarJob::~URLRequestAsarJob() {} void URLRequestAsarJob::Start() { - if (!archive_ || !archive_->GetFileInfo(file_path_, &file_info_)) { - NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, - net::ERR_FILE_NOT_FOUND)); - return; - } - remaining_bytes_ = static_cast(file_info_.size); int flags = base::File::FLAG_OPEN | diff --git a/atom/browser/net/asar/url_request_asar_job.h b/atom/browser/net/asar/url_request_asar_job.h index dc23e327cdff..adcac85b37d7 100644 --- a/atom/browser/net/asar/url_request_asar_job.h +++ b/atom/browser/net/asar/url_request_asar_job.h @@ -24,12 +24,20 @@ class FileStream; namespace asar { +// Createa a request job according to the file path. +net::URLRequestJob* CreateJobFromPath( + const base::FilePath& full_path, + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const scoped_refptr file_task_runner); + class URLRequestAsarJob : public net::URLRequestJob { public: URLRequestAsarJob(net::URLRequest* request, net::NetworkDelegate* network_delegate, std::shared_ptr archive, const base::FilePath& file_path, + const Archive::FileInfo& file_info, const scoped_refptr& file_task_runner); // net::URLRequestJob: @@ -55,8 +63,8 @@ class URLRequestAsarJob : public net::URLRequestJob { void DidRead(scoped_refptr buf, int result); std::shared_ptr archive_; - Archive::FileInfo file_info_; base::FilePath file_path_; + Archive::FileInfo file_info_; scoped_ptr stream_; int64 remaining_bytes_; diff --git a/atom/common/api/atom_api_asar.cc b/atom/common/api/atom_api_asar.cc index 11a208ac2508..d035159380a4 100644 --- a/atom/common/api/atom_api_asar.cc +++ b/atom/common/api/atom_api_asar.cc @@ -41,6 +41,7 @@ class Archive : public mate::Wrappable { return v8::False(isolate); mate::Dictionary dict(isolate, v8::Object::New(isolate)); dict.Set("size", info.size); + dict.Set("unpacked", info.unpacked); dict.Set("offset", info.offset); return dict.GetHandle(); } diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc index ba885b8f49e1..4ad8c1817a90 100644 --- a/atom/common/asar/archive.cc +++ b/atom/common/asar/archive.cc @@ -81,18 +81,22 @@ bool GetNodeFromPath(std::string path, bool FillFileInfoWithNode(Archive::FileInfo* info, uint32 header_size, const base::DictionaryValue* node) { + int size; + if (!node->GetInteger("size", &size)) + return false; + info->size = static_cast(size); + + info->unpacked = false; + if (node->GetBoolean("unpacked", &info->unpacked) && info->unpacked) + return true; + std::string offset; if (!node->GetString("offset", &offset)) return false; if (!base::StringToUint64(offset, &info->offset)) return false; - - int size; - if (!node->GetInteger("size", &size)) - return false; - info->offset += header_size; - info->size = static_cast(size); + return true; } @@ -240,6 +244,11 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) { if (!GetFileInfo(path, &info)) return false; + if (info.unpacked) { + *out = path_.AddExtension(FILE_PATH_LITERAL("unpacked")).Append(path); + return true; + } + scoped_ptr temp_file(new ScopedTemporaryFile); if (!temp_file->InitFromFile(path_, info.offset, info.size)) return false; diff --git a/atom/common/asar/archive.h b/atom/common/asar/archive.h index 7a27e3f4d460..53adbfc13c41 100644 --- a/atom/common/asar/archive.h +++ b/atom/common/asar/archive.h @@ -25,6 +25,7 @@ class Archive { public: struct FileInfo { FileInfo() : size(0), offset(0) {} + bool unpacked; uint32 size; uint64 offset; }; @@ -55,6 +56,7 @@ class Archive { bool Realpath(const base::FilePath& path, base::FilePath* realpath); // Copy the file into a temporary file, and return the new path. + // For unpacked file, this method will return its real path. bool CopyFileOut(const base::FilePath& path, base::FilePath* out); base::FilePath path() const { return path_; } diff --git a/atom/common/asar/asar_util.cc b/atom/common/asar/asar_util.cc index 43e2601ac456..1eee09949aff 100644 --- a/atom/common/asar/asar_util.cc +++ b/atom/common/asar/asar_util.cc @@ -71,6 +71,13 @@ bool ReadFileToString(const base::FilePath& path, std::string* contents) { if (!archive->GetFileInfo(relative_path, &info)) return false; + if (info.unpacked) { + base::FilePath real_path; + // For unpacked file it will return the real path instead of doing the copy. + archive->CopyFileOut(relative_path, &real_path); + return base::ReadFileToString(real_path, contents); + } + base::File src(asar_path, base::File::FLAG_OPEN | base::File::FLAG_READ); if (!src.IsValid()) return false; diff --git a/atom/common/lib/asar.coffee b/atom/common/lib/asar.coffee index e3e0f6f29899..daac5f6a2e32 100644 --- a/atom/common/lib/asar.coffee +++ b/atom/common/lib/asar.coffee @@ -90,7 +90,7 @@ overrideAPI = (module, name, arg = 0) -> return callback new Error("Invalid package #{asarPath}") unless archive newPath = archive.copyFileOut filePath - return callback createNotFoundError(asarPath, filePath) unless newPath + return callback createNotFoundError(asarPath, filePath) unless newPath arguments[arg] = newPath old.apply this, arguments @@ -218,6 +218,10 @@ exports.wrapFsWithAsar = (fs) -> info = archive.getFileInfo filePath return callback createNotFoundError(asarPath, filePath) unless info + if info.unpacked + realPath = archive.copyFileOut filePath + return fs.readFile realPath, options, callback + if not options options = encoding: null, flag: 'r' else if util.isString options @@ -247,6 +251,10 @@ exports.wrapFsWithAsar = (fs) -> info = archive.getFileInfo filePath throw createNotFoundError(asarPath, filePath) unless info + if info.unpacked + realPath = archive.copyFileOut filePath + return fs.readFileSync realPath, options + if not options options = encoding: null, flag: 'r' else if util.isString options