Recognize asar archive with unpacked files

This commit is contained in:
Cheng Zhao 2015-03-20 20:34:58 +08:00
parent dc82553fc3
commit b5a8cfb704
9 changed files with 84 additions and 55 deletions

View file

@ -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(),
real_job_ = asar::CreateJobFromPath(
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_->Start();
}

View file

@ -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<base::TaskRunner> 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> 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<base::TaskRunner>& 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,
return CreateJobFromPath(full_path, request, network_delegate,
file_task_runner_);
std::shared_ptr<Archive> 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_);
}
bool AsarProtocolHandler::IsSafeRedirectTarget(const GURL& location) const {

View file

@ -19,10 +19,12 @@ URLRequestAsarJob::URLRequestAsarJob(
net::NetworkDelegate* network_delegate,
std::shared_ptr<Archive> archive,
const base::FilePath& file_path,
const Archive::FileInfo& file_info,
const scoped_refptr<base::TaskRunner>& 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<int64>(file_info_.size);
int flags = base::File::FLAG_OPEN |

View file

@ -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<base::TaskRunner> file_task_runner);
class URLRequestAsarJob : public net::URLRequestJob {
public:
URLRequestAsarJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate,
std::shared_ptr<Archive> archive,
const base::FilePath& file_path,
const Archive::FileInfo& file_info,
const scoped_refptr<base::TaskRunner>& file_task_runner);
// net::URLRequestJob:
@ -55,8 +63,8 @@ class URLRequestAsarJob : public net::URLRequestJob {
void DidRead(scoped_refptr<net::IOBuffer> buf, int result);
std::shared_ptr<Archive> archive_;
Archive::FileInfo file_info_;
base::FilePath file_path_;
Archive::FileInfo file_info_;
scoped_ptr<net::FileStream> stream_;
int64 remaining_bytes_;

View file

@ -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();
}

View file

@ -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<uint32>(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<uint32>(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<ScopedTemporaryFile> temp_file(new ScopedTemporaryFile);
if (!temp_file->InitFromFile(path_, info.offset, info.size))
return false;

View file

@ -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_; }

View file

@ -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;

View file

@ -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