Skip to content

Commit

Permalink
fix Implement support for proxying pages inside ASAR archives (close
Browse files Browse the repository at this point in the history
  • Loading branch information
Farfurix committed Jun 11, 2019
1 parent 2c28fe4 commit 84fc58b
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 14 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"dependencies": {
"acorn-hammerhead": "^0.2.0",
"asar": "^2.0.1",
"bowser": "1.6.0",
"brotli": "^1.3.1",
"crypto-md5": "^1.0.0",
Expand Down
67 changes: 53 additions & 14 deletions src/request-pipeline/file-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,71 @@ import { EventEmitter } from 'events';
import { parse } from 'url';
import { MESSAGE, getText } from '../messages';
import { stat, access } from '../utils/promisified-functions';
import asar from 'asar';
import { toReadableStream } from '../utils/buffer';

const DISK_RE: RegExp = /^\/[A-Za-z]:/;
const DISK_RE: RegExp = /^\/[A-Za-z]:/;
const ASAR_ARCHIVE_PATH: RegExp = /^.*\.asar/;

const TARGET_IS_NOT_FILE = 'The target of the operation is not a file';
const TARGET_IS_NOT_FILE = 'The target of the operation is not a file';
const ASAR_ARCHIVE_TARGET_IS_NOT_FILE = 'The asar archive target of the operation is not a file';

export default class FileRequest extends EventEmitter {
url: string;
path: string;
asarArchivePath: string;

constructor (url: string) {
super();

this.url = url;
this.path = FileRequest._getPath(url);
this.url = url;
this.path = FileRequest._getPath(url);
this.asarArchivePath = FileRequest._getAsarArchivePath(this.path);

this._initEvents();
}

_initEvents () {
stat(this.path)
.then((stats: fs.Stats) => {
if (!stats.isFile())
throw new Error(TARGET_IS_NOT_FILE);

return access(this.path, fs.constants.R_OK);
})
.then(() => this._onOpen())
.catch((err: Error) => this._onError(err));
if (this.asarArchivePath) {
stat(this.asarArchivePath)
.catch(() => {
throw new Error(ASAR_ARCHIVE_TARGET_IS_NOT_FILE);
})
.then(() => access(this.asarArchivePath, fs.constants.R_OK))
.then(() => this._onOpen())
.catch((err: Error) => {

return this._onError(err);
});
}
else {
stat(this.path)
.then((stats: fs.Stats) => {
if (!stats.isFile())
throw new Error(TARGET_IS_NOT_FILE);

return access(this.path, fs.constants.R_OK);
})
.then(() => this._onOpen())
.catch((err: Error) => this._onError(err));
}
}

static _getAsarArchivePath (path: string) : string {
const match = path.match(ASAR_ARCHIVE_PATH);

return match ? match[0] : '';
}

static _getFilePathInAsarArchive (path: string) : string {
return path.replace(ASAR_ARCHIVE_PATH, '.');
}

_getAsarFileReadStream (path: string) : any {
const filePath = FileRequest._getFilePathInAsarArchive(path);
const file = asar.extractFile(this.asarArchivePath, filePath);

return toReadableStream(file);
}

static _getPath (proxiedUrl: string): string {
Expand All @@ -51,7 +88,9 @@ export default class FileRequest extends EventEmitter {
}

_onOpen () {
let stream = fs.createReadStream(this.path);
let stream = this.asarArchivePath
? this._getAsarFileReadStream(this.path)
: fs.createReadStream(this.path);

stream = Object.assign(stream, {
statusCode: 200,
Expand Down
Binary file added test/server/data/file-in-asar-archive/app.asar
Binary file not shown.
72 changes: 72 additions & 0 deletions test/server/proxy-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1633,6 +1633,78 @@ describe('Proxy', () => {

request(options);
});

it('Should pass an error to the session if target (an "asar" archive) does not exist (GH-2033)', done => {
const url = getFileProtocolUrl('./data/file-in-asar-archive/non-exist-asar-archive.asar/non-exist-file.txt');

session.id = 'sessionId';

session.handlePageError = (ctx, err) => {
expect(err).contains([
'Failed to read a file at <a href="' + url + '">' + url + '</a> because of the error:',
'',
'The asar archive target of the operation is not a file'
].join('\n'));

ctx.res.end();
done();
return true;
};

const options = {
url: proxy.openSession(url, session),
headers: {
accept: 'text/html,*/*;q=0.1'
}
};

request(options);
});

it('Should pass an error to the session if target (a file in an "asar" archive) does not exist (GH-2033)', done => {
const url = getFileProtocolUrl('./data/file-in-asar-archive/app.asar/non-exist-file.txt');

session.id = 'sessionId';

session.handlePageError = (ctx, err) => {
expect(err).contains([
'Failed to read a file at <a href="' + url + '">' + url + '</a> because of the error:',
'',
'Cannot read property \'link\' of undefined'
].join('\n'));

ctx.res.end();
done();
return true;
};

const options = {
url: proxy.openSession(url, session),
headers: {
accept: 'text/html,*/*;q=0.1'
}
};

request(options);
});

it('Should resolve an asar archive file (GH-2033)', () => {
session.id = 'sessionId';

const fileUrl = getFileProtocolUrl('./data/file-in-asar-archive/app.asar/src.txt');

const options = {
url: proxy.openSession(fileUrl, session),
headers: {
accept: '*/*'
}
};

return request(options)
.then(body => {
expect(body).eql('asar archive: src.txt');
});
});
});

describe('State switching', () => {
Expand Down

0 comments on commit 84fc58b

Please sign in to comment.