mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: migrate src/BrowserFetcher to TypeScript (#5727)
* chore: migrate src/BrowserFetcher to TypeScript
This commit is contained in:
parent
8509f4660e
commit
1a4e260458
@ -467,8 +467,8 @@ This methods attaches Puppeteer to an existing browser instance.
|
|||||||
- `options` <[Object]>
|
- `options` <[Object]>
|
||||||
- `host` <[string]> A download host to be used. Defaults to `https://storage.googleapis.com`. If the `product` is `firefox`, this defaults to `https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central`.
|
- `host` <[string]> A download host to be used. Defaults to `https://storage.googleapis.com`. If the `product` is `firefox`, this defaults to `https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central`.
|
||||||
- `path` <[string]> A path for the downloads folder. Defaults to `<root>/.local-chromium`, where `<root>` is puppeteer's package root. If the `product` is `firefox`, this defaults to `<root>/.local-firefox`.
|
- `path` <[string]> A path for the downloads folder. Defaults to `<root>/.local-chromium`, where `<root>` is puppeteer's package root. If the `product` is `firefox`, this defaults to `<root>/.local-firefox`.
|
||||||
- `platform` <[string]> Possible values are: `mac`, `win32`, `win64`, `linux`. Defaults to the current platform.
|
- `platform` <"linux"|"win32"|"mac"|"win64"> [string] for the current platform. Possible values are: `mac`, `win32`, `win64`, `linux`. Defaults to the current platform.
|
||||||
- `product` <[string]> Possible values are: `chrome`, `firefox`. Defaults to `chrome`.
|
- `product` <"chrome"|"firefox"> [string] for the product to run. Possible values are: `chrome`, `firefox`. Defaults to `chrome`.
|
||||||
- returns: <[BrowserFetcher]>
|
- returns: <[BrowserFetcher]>
|
||||||
|
|
||||||
#### puppeteer.defaultArgs([options])
|
#### puppeteer.defaultArgs([options])
|
||||||
|
@ -14,20 +14,23 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const os = require('os');
|
import * as os from 'os';
|
||||||
const fs = require('fs');
|
import * as fs from 'fs';
|
||||||
const path = require('path');
|
import * as path from 'path';
|
||||||
const util = require('util');
|
import * as util from 'util';
|
||||||
const childProcess = require('child_process');
|
import * as childProcess from 'child_process';
|
||||||
const extract = require('extract-zip');
|
import * as https from 'https';
|
||||||
const debugFetcher = require('debug')(`puppeteer:fetcher`);
|
import * as http from 'http';
|
||||||
const URL = require('url');
|
|
||||||
const {helper, assert} = require('./helper');
|
import * as extract from 'extract-zip';
|
||||||
const removeRecursive = require('rimraf');
|
import * as debug from 'debug';
|
||||||
// @ts-ignore
|
import * as removeRecursive from 'rimraf';
|
||||||
const ProxyAgent = require('https-proxy-agent');
|
import * as URL from 'url';
|
||||||
// @ts-ignore
|
import * as ProxyAgent from 'https-proxy-agent';
|
||||||
const getProxyForUrl = require('proxy-from-env').getProxyForUrl;
|
import {getProxyForUrl} from 'proxy-from-env';
|
||||||
|
|
||||||
|
import {helper, assert} from './helper';
|
||||||
|
const debugFetcher = debug(`puppeteer:fetcher`);
|
||||||
|
|
||||||
const downloadURLs = {
|
const downloadURLs = {
|
||||||
chrome: {
|
chrome: {
|
||||||
@ -42,7 +45,7 @@ const downloadURLs = {
|
|||||||
win32: '%s/firefox-%s.0a1.en-US.%s.zip',
|
win32: '%s/firefox-%s.0a1.en-US.%s.zip',
|
||||||
win64: '%s/firefox-%s.0a1.en-US.%s.zip',
|
win64: '%s/firefox-%s.0a1.en-US.%s.zip',
|
||||||
},
|
},
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
const browserConfig = {
|
const browserConfig = {
|
||||||
chrome: {
|
chrome: {
|
||||||
@ -53,15 +56,12 @@ const browserConfig = {
|
|||||||
host: 'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central',
|
host: 'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central',
|
||||||
destination: '.local-firefox',
|
destination: '.local-firefox',
|
||||||
}
|
}
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
/**
|
type Platform = 'linux' | 'mac' | 'win32' | 'win64';
|
||||||
* @param {string} product
|
type Product = 'chrome' | 'firefox';
|
||||||
* @param {string} platform
|
|
||||||
* @param {string} revision
|
function archiveName(product: Product, platform: Platform, revision: string): string {
|
||||||
* @return {string}
|
|
||||||
*/
|
|
||||||
function archiveName(product, platform, revision) {
|
|
||||||
if (product === 'chrome') {
|
if (product === 'chrome') {
|
||||||
if (platform === 'linux')
|
if (platform === 'linux')
|
||||||
return 'chrome-linux';
|
return 'chrome-linux';
|
||||||
@ -74,7 +74,6 @@ function archiveName(product, platform, revision) {
|
|||||||
} else if (product === 'firefox') {
|
} else if (product === 'firefox') {
|
||||||
return platform;
|
return platform;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,7 +83,7 @@ function archiveName(product, platform, revision) {
|
|||||||
* @param {string} revision
|
* @param {string} revision
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
function downloadURL(product, platform, host, revision) {
|
function downloadURL(product: Product, platform: Platform, host: string, revision: string): string {
|
||||||
const url = util.format(downloadURLs[product][platform], host, revision, archiveName(product, platform, revision));
|
const url = util.format(downloadURLs[product][platform], host, revision, archiveName(product, platform, revision));
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
@ -94,74 +93,90 @@ const mkdirAsync = helper.promisify(fs.mkdir.bind(fs));
|
|||||||
const unlinkAsync = helper.promisify(fs.unlink.bind(fs));
|
const unlinkAsync = helper.promisify(fs.unlink.bind(fs));
|
||||||
const chmodAsync = helper.promisify(fs.chmod.bind(fs));
|
const chmodAsync = helper.promisify(fs.chmod.bind(fs));
|
||||||
|
|
||||||
function existsAsync(filePath) {
|
function existsAsync(filePath: string): Promise<boolean> {
|
||||||
let fulfill = null;
|
return new Promise(resolve => {
|
||||||
const promise = new Promise(x => fulfill = x);
|
fs.access(filePath, err => resolve(!err));
|
||||||
fs.access(filePath, err => fulfill(!err));
|
});
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BrowserFetcher {
|
/**
|
||||||
/**
|
* @typedef {Object} BrowserFetcher.Options
|
||||||
* @param {string} projectRoot
|
*/
|
||||||
* @param {!BrowserFetcher.Options=} options
|
|
||||||
*/
|
export interface BrowserFetcherOptions {
|
||||||
constructor(projectRoot, options = {}) {
|
platform?: Platform;
|
||||||
this._product = (options.product || 'chrome').toLowerCase();
|
product?: string;
|
||||||
|
path?: string;
|
||||||
|
host?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BrowserFetcherRevisionInfo {
|
||||||
|
folderPath: string;
|
||||||
|
executablePath: string;
|
||||||
|
url: string;
|
||||||
|
local: boolean;
|
||||||
|
revision: string;
|
||||||
|
product: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class BrowserFetcher {
|
||||||
|
private _product: Product;
|
||||||
|
private _downloadsFolder: string;
|
||||||
|
private _downloadHost: string;
|
||||||
|
private _platform: Platform;
|
||||||
|
|
||||||
|
constructor(projectRoot: string, options: BrowserFetcherOptions = {}) {
|
||||||
|
this._product = (options.product || 'chrome').toLowerCase() as Product;
|
||||||
assert(this._product === 'chrome' || this._product === 'firefox', `Unknown product: "${options.product}"`);
|
assert(this._product === 'chrome' || this._product === 'firefox', `Unknown product: "${options.product}"`);
|
||||||
|
|
||||||
this._downloadsFolder = options.path || path.join(projectRoot, browserConfig[this._product].destination);
|
this._downloadsFolder = options.path || path.join(projectRoot, browserConfig[this._product].destination);
|
||||||
this._downloadHost = options.host || browserConfig[this._product].host;
|
this._downloadHost = options.host || browserConfig[this._product].host;
|
||||||
this._platform = options.platform || '';
|
this.setPlatform(options.platform);
|
||||||
if (!this._platform) {
|
|
||||||
const platform = os.platform();
|
|
||||||
if (platform === 'darwin')
|
|
||||||
this._platform = 'mac';
|
|
||||||
else if (platform === 'linux')
|
|
||||||
this._platform = 'linux';
|
|
||||||
else if (platform === 'win32')
|
|
||||||
this._platform = os.arch() === 'x64' ? 'win64' : 'win32';
|
|
||||||
assert(this._platform, 'Unsupported platform: ' + os.platform());
|
|
||||||
}
|
|
||||||
assert(downloadURLs[this._product][this._platform], 'Unsupported platform: ' + this._platform);
|
assert(downloadURLs[this._product][this._platform], 'Unsupported platform: ' + this._platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private setPlatform(platformFromOptions?: Platform): void {
|
||||||
* @return {string}
|
if (platformFromOptions) {
|
||||||
*/
|
this._platform = platformFromOptions;
|
||||||
platform() {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const platform = os.platform();
|
||||||
|
if (platform === 'darwin')
|
||||||
|
this._platform = 'mac';
|
||||||
|
else if (platform === 'linux')
|
||||||
|
this._platform = 'linux';
|
||||||
|
else if (platform === 'win32')
|
||||||
|
this._platform = os.arch() === 'x64' ? 'win64' : 'win32';
|
||||||
|
else
|
||||||
|
assert(this._platform, 'Unsupported platform: ' + os.platform());
|
||||||
|
}
|
||||||
|
|
||||||
|
platform(): string {
|
||||||
return this._platform;
|
return this._platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
product(): string {
|
||||||
* @return {string}
|
|
||||||
*/
|
|
||||||
product() {
|
|
||||||
return this._product;
|
return this._product;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
host(): string {
|
||||||
* @return {string}
|
|
||||||
*/
|
|
||||||
host() {
|
|
||||||
return this._downloadHost;
|
return this._downloadHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
canDownload(revision: string): Promise<boolean> {
|
||||||
* @param {string} revision
|
|
||||||
* @return {!Promise<boolean>}
|
|
||||||
*/
|
|
||||||
canDownload(revision) {
|
|
||||||
const url = downloadURL(this._product, this._platform, this._downloadHost, revision);
|
const url = downloadURL(this._product, this._platform, this._downloadHost, revision);
|
||||||
let resolve;
|
return new Promise(resolve => {
|
||||||
const promise = new Promise(x => resolve = x);
|
const request = httpRequest(url, 'HEAD', response => {
|
||||||
const request = httpRequest(url, 'HEAD', response => {
|
resolve(response.statusCode === 200);
|
||||||
resolve(response.statusCode === 200);
|
});
|
||||||
|
request.on('error', error => {
|
||||||
|
console.error(error);
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
request.on('error', error => {
|
|
||||||
console.error(error);
|
|
||||||
resolve(false);
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,7 +184,7 @@ class BrowserFetcher {
|
|||||||
* @param {?function(number, number):void} progressCallback
|
* @param {?function(number, number):void} progressCallback
|
||||||
* @return {!Promise<!BrowserFetcher.RevisionInfo>}
|
* @return {!Promise<!BrowserFetcher.RevisionInfo>}
|
||||||
*/
|
*/
|
||||||
async download(revision, progressCallback) {
|
async download(revision: string, progressCallback: (x: number, y: number) => void): Promise<BrowserFetcherRevisionInfo> {
|
||||||
const url = downloadURL(this._product, this._platform, this._downloadHost, revision);
|
const url = downloadURL(this._product, this._platform, this._downloadHost, revision);
|
||||||
const fileName = url.split('/').pop();
|
const fileName = url.split('/').pop();
|
||||||
const archivePath = path.join(this._downloadsFolder, fileName);
|
const archivePath = path.join(this._downloadsFolder, fileName);
|
||||||
@ -191,30 +206,20 @@ class BrowserFetcher {
|
|||||||
return revisionInfo;
|
return revisionInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async localRevisions(): Promise<string[]> {
|
||||||
* @return {!Promise<!Array<string>>}
|
|
||||||
*/
|
|
||||||
async localRevisions() {
|
|
||||||
if (!await existsAsync(this._downloadsFolder))
|
if (!await existsAsync(this._downloadsFolder))
|
||||||
return [];
|
return [];
|
||||||
const fileNames = await readdirAsync(this._downloadsFolder);
|
const fileNames = await readdirAsync(this._downloadsFolder);
|
||||||
return fileNames.map(fileName => parseFolderPath(this._product, fileName)).filter(entry => entry && entry.platform === this._platform).map(entry => entry.revision);
|
return fileNames.map(fileName => parseFolderPath(this._product, fileName)).filter(entry => entry && entry.platform === this._platform).map(entry => entry.revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async remove(revision: string): Promise<void> {
|
||||||
* @param {string} revision
|
|
||||||
*/
|
|
||||||
async remove(revision) {
|
|
||||||
const folderPath = this._getFolderPath(revision);
|
const folderPath = this._getFolderPath(revision);
|
||||||
assert(await existsAsync(folderPath), `Failed to remove: revision ${revision} is not downloaded`);
|
assert(await existsAsync(folderPath), `Failed to remove: revision ${revision} is not downloaded`);
|
||||||
await new Promise(fulfill => removeRecursive(folderPath, fulfill));
|
await new Promise(fulfill => removeRecursive(folderPath, fulfill));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
revisionInfo(revision: string): BrowserFetcherRevisionInfo {
|
||||||
* @param {string} revision
|
|
||||||
* @return {!BrowserFetcher.RevisionInfo}
|
|
||||||
*/
|
|
||||||
revisionInfo(revision) {
|
|
||||||
const folderPath = this._getFolderPath(revision);
|
const folderPath = this._getFolderPath(revision);
|
||||||
let executablePath = '';
|
let executablePath = '';
|
||||||
if (this._product === 'chrome') {
|
if (this._product === 'chrome') {
|
||||||
@ -248,18 +253,12 @@ class BrowserFetcher {
|
|||||||
* @param {string} revision
|
* @param {string} revision
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
_getFolderPath(revision) {
|
_getFolderPath(revision: string): string {
|
||||||
return path.join(this._downloadsFolder, this._platform + '-' + revision);
|
return path.join(this._downloadsFolder, this._platform + '-' + revision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BrowserFetcher;
|
function parseFolderPath(product: Product, folderPath: string): {product: string; platform: string; revision: string} | null {
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} folderPath
|
|
||||||
* @return {?{product: string, platform: string, revision: string}}
|
|
||||||
*/
|
|
||||||
function parseFolderPath(product, folderPath) {
|
|
||||||
const name = path.basename(folderPath);
|
const name = path.basename(folderPath);
|
||||||
const splits = name.split('-');
|
const splits = name.split('-');
|
||||||
if (splits.length !== 2)
|
if (splits.length !== 2)
|
||||||
@ -276,13 +275,13 @@ function parseFolderPath(product, folderPath) {
|
|||||||
* @param {?function(number, number):void} progressCallback
|
* @param {?function(number, number):void} progressCallback
|
||||||
* @return {!Promise}
|
* @return {!Promise}
|
||||||
*/
|
*/
|
||||||
function downloadFile(url, destinationPath, progressCallback) {
|
function downloadFile(url: string, destinationPath: string, progressCallback: (x: number, y: number) => void): Promise<void> {
|
||||||
debugFetcher(`Downloading binary from ${url}`);
|
debugFetcher(`Downloading binary from ${url}`);
|
||||||
let fulfill, reject;
|
let fulfill, reject;
|
||||||
let downloadedBytes = 0;
|
let downloadedBytes = 0;
|
||||||
let totalBytes = 0;
|
let totalBytes = 0;
|
||||||
|
|
||||||
const promise = new Promise((x, y) => { fulfill = x; reject = y; });
|
const promise = new Promise<void>((x, y) => { fulfill = x; reject = y; });
|
||||||
|
|
||||||
const request = httpRequest(url, 'GET', response => {
|
const request = httpRequest(url, 'GET', response => {
|
||||||
if (response.statusCode !== 200) {
|
if (response.statusCode !== 200) {
|
||||||
@ -303,21 +302,13 @@ function downloadFile(url, destinationPath, progressCallback) {
|
|||||||
request.on('error', error => reject(error));
|
request.on('error', error => reject(error));
|
||||||
return promise;
|
return promise;
|
||||||
|
|
||||||
function onData(chunk) {
|
function onData(chunk: string): void {
|
||||||
downloadedBytes += chunk.length;
|
downloadedBytes += chunk.length;
|
||||||
progressCallback(downloadedBytes, totalBytes);
|
progressCallback(downloadedBytes, totalBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function install(archivePath: string, folderPath: string): Promise<unknown> {
|
||||||
/**
|
|
||||||
* Install from a zip, tar.bz2 or dmg file.
|
|
||||||
*
|
|
||||||
* @param {string} archivePath
|
|
||||||
* @param {string} folderPath
|
|
||||||
* @return {!Promise<?Error>}
|
|
||||||
*/
|
|
||||||
function install(archivePath, folderPath) {
|
|
||||||
debugFetcher(`Installing ${archivePath} to ${folderPath}`);
|
debugFetcher(`Installing ${archivePath} to ${folderPath}`);
|
||||||
if (archivePath.endsWith('.zip'))
|
if (archivePath.endsWith('.zip'))
|
||||||
return extractZip(archivePath, folderPath);
|
return extractZip(archivePath, folderPath);
|
||||||
@ -329,12 +320,7 @@ function install(archivePath, folderPath) {
|
|||||||
throw new Error(`Unsupported archive format: ${archivePath}`);
|
throw new Error(`Unsupported archive format: ${archivePath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function extractZip(zipPath: string, folderPath: string): Promise<void> {
|
||||||
* @param {string} zipPath
|
|
||||||
* @param {string} folderPath
|
|
||||||
* @return {!Promise<?Error>}
|
|
||||||
*/
|
|
||||||
async function extractZip(zipPath, folderPath) {
|
|
||||||
try {
|
try {
|
||||||
await extract(zipPath, {dir: folderPath});
|
await extract(zipPath, {dir: folderPath});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -347,9 +333,10 @@ async function extractZip(zipPath, folderPath) {
|
|||||||
* @param {string} folderPath
|
* @param {string} folderPath
|
||||||
* @return {!Promise<?Error>}
|
* @return {!Promise<?Error>}
|
||||||
*/
|
*/
|
||||||
function extractTar(tarPath, folderPath) {
|
function extractTar(tarPath: string, folderPath: string): Promise<unknown> {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const tar = require('tar-fs');
|
const tar = require('tar-fs');
|
||||||
// @ts-ignore
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const bzip = require('unbzip2-stream');
|
const bzip = require('unbzip2-stream');
|
||||||
return new Promise((fulfill, reject) => {
|
return new Promise((fulfill, reject) => {
|
||||||
const tarStream = tar.extract(folderPath);
|
const tarStream = tar.extract(folderPath);
|
||||||
@ -368,12 +355,12 @@ function extractTar(tarPath, folderPath) {
|
|||||||
* @param {string} folderPath
|
* @param {string} folderPath
|
||||||
* @return {!Promise<?Error>}
|
* @return {!Promise<?Error>}
|
||||||
*/
|
*/
|
||||||
function installDMG(dmgPath, folderPath) {
|
function installDMG(dmgPath: string, folderPath: string): Promise<void> {
|
||||||
let mountPath;
|
let mountPath;
|
||||||
|
|
||||||
function mountAndCopy(fulfill, reject) {
|
function mountAndCopy(fulfill: () => void, reject: (Error) => void): void {
|
||||||
const mountCommand = `hdiutil attach -nobrowse -noautoopen "${dmgPath}"`;
|
const mountCommand = `hdiutil attach -nobrowse -noautoopen "${dmgPath}"`;
|
||||||
childProcess.exec(mountCommand, (err, stdout, stderr) => {
|
childProcess.exec(mountCommand, (err, stdout) => {
|
||||||
if (err)
|
if (err)
|
||||||
return reject(err);
|
return reject(err);
|
||||||
const volumes = stdout.match(/\/Volumes\/(.*)/m);
|
const volumes = stdout.match(/\/Volumes\/(.*)/m);
|
||||||
@ -386,7 +373,7 @@ function installDMG(dmgPath, folderPath) {
|
|||||||
return reject(new Error(`Cannot find app in ${mountPath}`));
|
return reject(new Error(`Cannot find app in ${mountPath}`));
|
||||||
const copyPath = path.join(mountPath, appName);
|
const copyPath = path.join(mountPath, appName);
|
||||||
debugFetcher(`Copying ${copyPath} to ${folderPath}`);
|
debugFetcher(`Copying ${copyPath} to ${folderPath}`);
|
||||||
childProcess.exec(`cp -R "${copyPath}" "${folderPath}"`, (err, stdout) => {
|
childProcess.exec(`cp -R "${copyPath}" "${folderPath}"`, err => {
|
||||||
if (err)
|
if (err)
|
||||||
reject(err);
|
reject(err);
|
||||||
else
|
else
|
||||||
@ -396,7 +383,7 @@ function installDMG(dmgPath, folderPath) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmount() {
|
function unmount(): void {
|
||||||
if (!mountPath)
|
if (!mountPath)
|
||||||
return;
|
return;
|
||||||
const unmountCommand = `hdiutil detach "${mountPath}" -quiet`;
|
const unmountCommand = `hdiutil detach "${mountPath}" -quiet`;
|
||||||
@ -407,60 +394,55 @@ function installDMG(dmgPath, folderPath) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise(mountAndCopy).catch(err => { console.error(err); }).finally(unmount);
|
return new Promise<void>(mountAndCopy).catch(err => { console.error(err); }).finally(unmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function httpRequest(url, method, response) {
|
function httpRequest(url: string, method: string, response: (x: http.IncomingMessage) => void): http.ClientRequest {
|
||||||
/** @type {Object} */
|
const urlParsed = URL.parse(url);
|
||||||
let options = URL.parse(url);
|
|
||||||
options.method = method;
|
|
||||||
|
|
||||||
const proxyURL = getProxyForUrl(url);
|
type Options = Partial<URL.UrlWithStringQuery> & {
|
||||||
if (proxyURL) {
|
method?: string;
|
||||||
if (url.startsWith('http:')) {
|
agent?: ProxyAgent;
|
||||||
const proxy = URL.parse(proxyURL);
|
rejectUnauthorized?: boolean;
|
||||||
options = {
|
};
|
||||||
path: options.href,
|
|
||||||
host: proxy.hostname,
|
|
||||||
port: proxy.port,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
/** @type {Object} */
|
|
||||||
const parsedProxyURL = URL.parse(proxyURL);
|
|
||||||
parsedProxyURL.secureProxy = parsedProxyURL.protocol === 'https:';
|
|
||||||
|
|
||||||
options.agent = new ProxyAgent(parsedProxyURL);
|
let options: Options = {
|
||||||
options.rejectUnauthorized = false;
|
...urlParsed,
|
||||||
}
|
method,
|
||||||
}
|
};
|
||||||
|
|
||||||
const requestCallback = res => {
|
const proxyURL = getProxyForUrl(url);
|
||||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location)
|
if (proxyURL) {
|
||||||
httpRequest(res.headers.location, method, response);
|
if (url.startsWith('http:')) {
|
||||||
else
|
const proxy = URL.parse(proxyURL);
|
||||||
response(res);
|
options = {
|
||||||
};
|
path: options.href,
|
||||||
const request = options.protocol === 'https:' ?
|
host: proxy.hostname,
|
||||||
require('https').request(options, requestCallback) :
|
port: proxy.port,
|
||||||
require('http').request(options, requestCallback);
|
};
|
||||||
request.end();
|
} else {
|
||||||
return request;
|
const parsedProxyURL = URL.parse(proxyURL);
|
||||||
|
|
||||||
|
const proxyOptions = {
|
||||||
|
...parsedProxyURL,
|
||||||
|
secureProxy: parsedProxyURL.protocol === 'https:',
|
||||||
|
} as ProxyAgent.HttpsProxyAgentOptions;
|
||||||
|
|
||||||
|
options.agent = new ProxyAgent(proxyOptions);
|
||||||
|
options.rejectUnauthorized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestCallback = (res: http.IncomingMessage): void => {
|
||||||
|
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location)
|
||||||
|
httpRequest(res.headers.location, method, response);
|
||||||
|
else
|
||||||
|
response(res);
|
||||||
|
};
|
||||||
|
const request = options.protocol === 'https:' ?
|
||||||
|
https.request(options, requestCallback) :
|
||||||
|
http.request(options, requestCallback);
|
||||||
|
request.end();
|
||||||
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} BrowserFetcher.Options
|
|
||||||
* @property {string=} platform
|
|
||||||
* @property {string=} product
|
|
||||||
* @property {string=} path
|
|
||||||
* @property {string=} host
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} BrowserFetcher.RevisionInfo
|
|
||||||
* @property {string} folderPath
|
|
||||||
* @property {string} executablePath
|
|
||||||
* @property {string} url
|
|
||||||
* @property {boolean} local
|
|
||||||
* @property {string} revision
|
|
||||||
* @property {string} product
|
|
||||||
*/
|
|
@ -20,7 +20,7 @@ const https = require('https');
|
|||||||
const URL = require('url');
|
const URL = require('url');
|
||||||
const removeFolder = require('rimraf');
|
const removeFolder = require('rimraf');
|
||||||
const childProcess = require('child_process');
|
const childProcess = require('child_process');
|
||||||
const BrowserFetcher = require('./BrowserFetcher');
|
const {BrowserFetcher} = require('./BrowserFetcher');
|
||||||
const {Connection} = require('./Connection');
|
const {Connection} = require('./Connection');
|
||||||
const {Browser} = require('./Browser');
|
const {Browser} = require('./Browser');
|
||||||
const readline = require('readline');
|
const readline = require('readline');
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
const Launcher = require('./Launcher');
|
const Launcher = require('./Launcher');
|
||||||
const BrowserFetcher = require('./BrowserFetcher');
|
const {BrowserFetcher} = require('./BrowserFetcher');
|
||||||
const Errors = require('./Errors');
|
const Errors = require('./Errors');
|
||||||
const DeviceDescriptors = require('./DeviceDescriptors');
|
const DeviceDescriptors = require('./DeviceDescriptors');
|
||||||
|
|
||||||
@ -126,12 +126,22 @@ module.exports = class {
|
|||||||
return this._launcher.defaultArgs(options);
|
return this._launcher.defaultArgs(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** TODO(jacktfranklin@): Once this file is TS we can type this
|
||||||
|
* using the BrowserFectcherOptions interface.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {!BrowserFetcher.Options=} options
|
* @typedef {Object} BrowserFetcherOptions
|
||||||
|
* @property {('linux'|'mac'|'win32'|'win64')=} platform
|
||||||
|
* @property {('chrome'|'firefox')=} product
|
||||||
|
* @property {string=} path
|
||||||
|
* @property {string=} host
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @param {!BrowserFetcherOptions} options
|
||||||
* @return {!BrowserFetcher}
|
* @return {!BrowserFetcher}
|
||||||
*/
|
*/
|
||||||
createBrowserFetcher(options) {
|
createBrowserFetcher(options) {
|
||||||
return new BrowserFetcher(this._projectRoot, options);
|
return new BrowserFetcher(this._projectRoot, options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ module.exports = {
|
|||||||
Accessibility: require('./Accessibility').Accessibility,
|
Accessibility: require('./Accessibility').Accessibility,
|
||||||
Browser: require('./Browser').Browser,
|
Browser: require('./Browser').Browser,
|
||||||
BrowserContext: require('./Browser').BrowserContext,
|
BrowserContext: require('./Browser').BrowserContext,
|
||||||
BrowserFetcher: require('./BrowserFetcher'),
|
BrowserFetcher: require('./BrowserFetcher').BrowserFetcher,
|
||||||
CDPSession: require('./Connection').CDPSession,
|
CDPSession: require('./Connection').CDPSession,
|
||||||
ConsoleMessage: require('./Page').ConsoleMessage,
|
ConsoleMessage: require('./Page').ConsoleMessage,
|
||||||
Coverage: require('./Coverage').Coverage,
|
Coverage: require('./Coverage').Coverage,
|
||||||
|
Loading…
Reference in New Issue
Block a user