mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-01-06 22:40:26 -05:00
chore(flow): update flow definitions for proxy
This commit is contained in:
parent
7e06ccc8ac
commit
f7414e9bb2
6 changed files with 82 additions and 40 deletions
|
@ -51,7 +51,7 @@
|
|||
"@commitlint/cli": "^6.1.0",
|
||||
"@commitlint/config-conventional": "^6.1.0",
|
||||
"@commitlint/travis-cli": "^6.1.0",
|
||||
"@verdaccio/types": "0.3.0",
|
||||
"@verdaccio/types": "0.3.1",
|
||||
"axios": "0.17.1",
|
||||
"babel-cli": "6.26.0",
|
||||
"babel-core": "6.26.0",
|
||||
|
|
|
@ -570,7 +570,8 @@ class Storage implements IStorageHandler {
|
|||
}
|
||||
|
||||
if (err || !upLinkResponse) {
|
||||
return cb(null, [err || Error(500, 'no data')]);
|
||||
// $FlowFixMe
|
||||
return cb(null, [err || Error('no data')]);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -597,6 +598,7 @@ class Storage implements IStorageHandler {
|
|||
|
||||
try {
|
||||
Storage._mergeVersions(packageInfo, upLinkResponse, self.config);
|
||||
|
||||
} catch(err) {
|
||||
self.logger.error({
|
||||
sub: 'out',
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import zlib from 'zlib';
|
||||
import JSONStream from 'JSONStream';
|
||||
import createError from 'http-errors';
|
||||
|
@ -8,7 +10,17 @@ import URL from 'url';
|
|||
import {parseInterval, is_object, ErrorCode} from './utils';
|
||||
import {ReadTarball} from '@verdaccio/streams';
|
||||
|
||||
const Logger = require('./logger');
|
||||
import type {
|
||||
IProxy,
|
||||
Config,
|
||||
Callback,
|
||||
Logger,
|
||||
} from '@verdaccio/types';
|
||||
|
||||
import type {IUploadTarball} from '@verdaccio/streams';
|
||||
|
||||
|
||||
const LoggerApi = require('./logger');
|
||||
|
||||
const encode = function(thing) {
|
||||
return encodeURIComponent(thing).replace(/^%40/, '@');
|
||||
|
@ -33,23 +45,37 @@ const setConfig = (config, key, def) => {
|
|||
* Implements Storage interface
|
||||
* (same for storage.js, local-storage.js, up-storage.js)
|
||||
*/
|
||||
class ProxyStorage {
|
||||
class ProxyStorage implements IProxy {
|
||||
config: Config;
|
||||
failed_requests: number;
|
||||
userAgent: string;
|
||||
ca: string | void;
|
||||
logger: Logger;
|
||||
server_id: string;
|
||||
url: any;
|
||||
maxage: string;
|
||||
timeout: string;
|
||||
max_fails: number;
|
||||
fail_timeout: number;
|
||||
upname: string;
|
||||
proxy: string;
|
||||
last_request_time: number;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param {*} config
|
||||
* @param {*} mainConfig
|
||||
*/
|
||||
constructor(config, mainConfig) {
|
||||
constructor(config: UpLinkConf, mainConfig: Config) {
|
||||
this.config = config;
|
||||
this.failed_requests = 0;
|
||||
this.userAgent = mainConfig.user_agent;
|
||||
this.ca = config.ca;
|
||||
this.logger = Logger.logger.child({sub: 'out'});
|
||||
this.logger = LoggerApi.logger.child({sub: 'out'});
|
||||
this.server_id = mainConfig.server_id;
|
||||
|
||||
this.url = URL.parse(this.config.url);
|
||||
|
||||
// $FlowFixMe
|
||||
this._setupProxy(this.url.hostname, config, mainConfig, this.url.protocol === 'https:');
|
||||
|
||||
this.config.url = this.config.url.replace(/\/$/, '');
|
||||
|
@ -74,7 +100,7 @@ class ProxyStorage {
|
|||
* @param {*} cb
|
||||
* @return {Request}
|
||||
*/
|
||||
request(options, cb) {
|
||||
request(options: any, cb: Callback) {
|
||||
let json;
|
||||
|
||||
if (this._statusCheck() === false) {
|
||||
|
@ -84,9 +110,10 @@ class ProxyStorage {
|
|||
if (_.isFunction(cb)) {
|
||||
cb(ErrorCode.get500('uplink is offline'));
|
||||
}
|
||||
// $FlowFixMe
|
||||
streamRead.emit('error', createError('uplink is offline'));
|
||||
});
|
||||
|
||||
// $FlowFixMe
|
||||
streamRead._read = function() {};
|
||||
// preventing 'Uncaught, unspecified "error" event'
|
||||
streamRead.on('error', function() {});
|
||||
|
@ -116,7 +143,7 @@ class ProxyStorage {
|
|||
let requestCallback = cb ? (function(err, res, body) {
|
||||
let error;
|
||||
const responseLength = err ? 0 : body.length;
|
||||
|
||||
// $FlowFixMe
|
||||
processBody(err, body);
|
||||
logActivity();
|
||||
cb(err, res, body);
|
||||
|
@ -132,6 +159,7 @@ class ProxyStorage {
|
|||
|
||||
if (options.json && res.statusCode < 300) {
|
||||
try {
|
||||
// $FlowFixMe
|
||||
body = JSON.parse(body.toString('utf8'));
|
||||
} catch(_err) {
|
||||
body = {};
|
||||
|
@ -216,7 +244,7 @@ class ProxyStorage {
|
|||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
_setHeaders(options) {
|
||||
_setHeaders(options: any) {
|
||||
const headers = options.headers || {};
|
||||
const accept = 'Accept';
|
||||
const acceptEncoding = 'Accept-Encoding';
|
||||
|
@ -236,7 +264,7 @@ class ProxyStorage {
|
|||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
_setAuth(headers) {
|
||||
_setAuth(headers: any) {
|
||||
|
||||
if (_.isNil(this.config.auth) || headers['authorization']) {
|
||||
return headers;
|
||||
|
@ -248,7 +276,7 @@ class ProxyStorage {
|
|||
|
||||
// get NPM_TOKEN http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules
|
||||
// or get other variable export in env
|
||||
let token = process.env.NPM_TOKEN;
|
||||
let token: any = process.env.NPM_TOKEN;
|
||||
if (this.config.auth.token) {
|
||||
token = this.config.auth.token;
|
||||
} else if (this.config.auth.token_env) {
|
||||
|
@ -270,7 +298,7 @@ class ProxyStorage {
|
|||
* @throws {Error}
|
||||
* @private
|
||||
*/
|
||||
_throwErrorAuth(message) {
|
||||
_throwErrorAuth(message: string) {
|
||||
this.logger.error(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
@ -282,7 +310,7 @@ class ProxyStorage {
|
|||
* @param {string} token
|
||||
* @private
|
||||
*/
|
||||
_setHeaderAuthorization(headers, type, token) {
|
||||
_setHeaderAuthorization(headers: any, type: string, token: string) {
|
||||
if (type !== 'bearer' && type !== 'basic') {
|
||||
this._throwErrorAuth(`Auth type '${type}' not allowed`);
|
||||
}
|
||||
|
@ -310,7 +338,7 @@ class ProxyStorage {
|
|||
* @param {Object} headers
|
||||
* @private
|
||||
*/
|
||||
_overrideWithUplinkConfigHeaders(headers) {
|
||||
_overrideWithUplinkConfigHeaders(headers: any) {
|
||||
// add/override headers specified in the config
|
||||
for (let key in this.config.headers) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.config.headers, key)) {
|
||||
|
@ -320,13 +348,15 @@ class ProxyStorage {
|
|||
}
|
||||
|
||||
/**
|
||||
* Determine whether can fetch from the provided URL.
|
||||
* Determine whether can fetch from the provided URL
|
||||
* @param {*} url
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isUplinkValid(url) {
|
||||
url = URL.parse(url);
|
||||
return url.protocol === this.url.protocol && url.host === this.url.host && url.path.indexOf(this.url.path) === 0;
|
||||
isUplinkValid(url: string) {
|
||||
// $FlowFixMe
|
||||
url = URL.parse(url);
|
||||
// $FlowFixMe
|
||||
return url.protocol === this.url.protocol && url.host === this.url.host && url.path.indexOf(this.url.path) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -335,7 +365,7 @@ class ProxyStorage {
|
|||
* @param {*} options request options, eg: eTag.
|
||||
* @param {*} callback
|
||||
*/
|
||||
getRemoteMetadata(name, options, callback) {
|
||||
getRemoteMetadata(name: string, options: any, callback: Callback) {
|
||||
const headers = {};
|
||||
if (_.isNil(options.etag) === false) {
|
||||
headers['If-None-Match'] = options.etag;
|
||||
|
@ -355,7 +385,9 @@ class ProxyStorage {
|
|||
return callback( ErrorCode.get404('package doesn\'t exist on uplink'));
|
||||
}
|
||||
if (!(res.statusCode >= 200 && res.statusCode < 300)) {
|
||||
// $FlowFixMe
|
||||
const error = createError(`bad status code: ${res.statusCode}`);
|
||||
// $FlowFixMe
|
||||
error.remoteStatus = res.statusCode;
|
||||
return callback(error);
|
||||
}
|
||||
|
@ -368,7 +400,7 @@ class ProxyStorage {
|
|||
* @param {String} url
|
||||
* @return {Stream}
|
||||
*/
|
||||
fetchTarball(url) {
|
||||
fetchTarball(url: string) {
|
||||
const stream = new ReadTarball({});
|
||||
let current_length = 0;
|
||||
let expected_length;
|
||||
|
@ -382,11 +414,12 @@ class ProxyStorage {
|
|||
},
|
||||
});
|
||||
|
||||
readStream.on('response', function(res) {
|
||||
readStream.on('response', function(res: any) {
|
||||
if (res.statusCode === 404) {
|
||||
return stream.emit('error', ErrorCode.get404('file doesn\'t exist on uplink'));
|
||||
}
|
||||
if (!(res.statusCode >= 200 && res.statusCode < 300)) {
|
||||
// $FlowFixMe
|
||||
return stream.emit('error', createError('bad uplink status code: ' + res.statusCode));
|
||||
}
|
||||
if (res.headers['content-length']) {
|
||||
|
@ -408,6 +441,7 @@ class ProxyStorage {
|
|||
current_length += data.length;
|
||||
}
|
||||
if (expected_length && current_length != expected_length) {
|
||||
// $FlowFixMe
|
||||
stream.emit('error', createError('content length mismatch'));
|
||||
}
|
||||
});
|
||||
|
@ -419,9 +453,9 @@ class ProxyStorage {
|
|||
* @param {*} options request options
|
||||
* @return {Stream}
|
||||
*/
|
||||
search(options) {
|
||||
const transformStream = new Stream.PassThrough({objectMode: true});
|
||||
const requestStream = this.request({
|
||||
search(options: any) {
|
||||
const transformStream: IUploadTarball = new Stream.PassThrough({objectMode: true});
|
||||
const requestStream: IUploadTarball = this.request({
|
||||
uri: options.req.url,
|
||||
req: options.req,
|
||||
headers: {
|
||||
|
@ -437,6 +471,7 @@ class ProxyStorage {
|
|||
|
||||
requestStream.on('response', (res) => {
|
||||
if (!String(res.statusCode).match(/^2\d\d$/)) {
|
||||
// $FlowFixMe
|
||||
return transformStream.emit('error', createError(`bad status code ${res.statusCode} from uplink`));
|
||||
}
|
||||
|
||||
|
@ -471,7 +506,7 @@ class ProxyStorage {
|
|||
* @param {*} req the http request
|
||||
* @param {*} headers the request headers
|
||||
*/
|
||||
_addProxyHeaders(req, headers) {
|
||||
_addProxyHeaders(req: any, headers: any) {
|
||||
if (req) {
|
||||
// Only submit X-Forwarded-For field if we don't have a proxy selected
|
||||
// in the config file.
|
||||
|
@ -502,7 +537,7 @@ class ProxyStorage {
|
|||
* @param {*} alive
|
||||
* @return {Boolean}
|
||||
*/
|
||||
_statusCheck(alive) {
|
||||
_statusCheck(alive?: boolean) {
|
||||
if (arguments.length === 0) {
|
||||
return this._ifRequestFailure() === false;
|
||||
} else {
|
||||
|
@ -541,9 +576,9 @@ class ProxyStorage {
|
|||
* @param {*} mainconfig
|
||||
* @param {*} isHTTPS
|
||||
*/
|
||||
_setupProxy(hostname, config, mainconfig, isHTTPS) {
|
||||
_setupProxy(hostname: string, config: UpLinkConf, mainconfig: Config, isHTTPS: boolean) {
|
||||
let noProxyList;
|
||||
let proxy_key = isHTTPS ? 'https_proxy' : 'http_proxy';
|
||||
let proxy_key: string = isHTTPS ? 'https_proxy' : 'http_proxy';
|
||||
|
||||
// get http_proxy and no_proxy configs
|
||||
if (proxy_key in config) {
|
||||
|
@ -552,6 +587,7 @@ class ProxyStorage {
|
|||
this.proxy = mainconfig[proxy_key];
|
||||
}
|
||||
if ('no_proxy' in config) {
|
||||
// $FlowFixMe
|
||||
noProxyList = config.no_proxy;
|
||||
} else if ('no_proxy' in mainconfig) {
|
||||
noProxyList = mainconfig.no_proxy;
|
||||
|
@ -561,17 +597,22 @@ class ProxyStorage {
|
|||
if (hostname[0] !== '.') {
|
||||
hostname = '.' + hostname;
|
||||
}
|
||||
// $FlowFixMe
|
||||
if (_.isString(noProxyList) && noProxyList.length) {
|
||||
// $FlowFixMe
|
||||
noProxyList = noProxyList.split(',');
|
||||
}
|
||||
if (_.isArray(noProxyList)) {
|
||||
// $FlowFixMe
|
||||
for (let i = 0; i < noProxyList.length; i++) {
|
||||
// $FlowFixMe
|
||||
let noProxyItem = noProxyList[i];
|
||||
if (noProxyItem[0] !== '.') noProxyItem = '.' + noProxyItem;
|
||||
if (hostname.lastIndexOf(noProxyItem) === hostname.length - noProxyItem.length) {
|
||||
if (this.proxy) {
|
||||
this.logger.debug({url: this.url.href, rule: noProxyItem},
|
||||
'not using proxy for @{url}, excluded by @{rule} rule');
|
||||
// $FlowFixMe
|
||||
this.proxy = false;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import assert from 'assert';
|
||||
|
||||
export default function(server, express) {
|
||||
|
||||
describe('test for unexpected client hangs', () => {
|
||||
let on_tarball;
|
||||
let handleResponseTarball;
|
||||
|
||||
beforeAll(function() {
|
||||
express.get('/testexp-racycrash', function(request, response) {
|
||||
|
@ -23,16 +21,17 @@ export default function(server, express) {
|
|||
});
|
||||
|
||||
express.get('/testexp-racycrash/-/test.tar.gz', function(request, response) {
|
||||
on_tarball(response);
|
||||
handleResponseTarball(response);
|
||||
});
|
||||
});
|
||||
|
||||
test('should not crash on error if client disconnects', callback => {
|
||||
on_tarball = function(res) {
|
||||
handleResponseTarball = function(res) {
|
||||
res.header('content-length', 1e6);
|
||||
res.write('test test test\n');
|
||||
res.write('test test test');
|
||||
setTimeout(function() {
|
||||
res.write('test test test\n');
|
||||
res.write('-');
|
||||
// destroy the connection
|
||||
res.socket.destroy();
|
||||
cb();
|
||||
}, 200);
|
||||
|
@ -40,7 +39,7 @@ export default function(server, express) {
|
|||
|
||||
server.request({uri: '/testexp-racycrash/-/test.tar.gz'})
|
||||
.then(function(body) {
|
||||
assert.equal(body, 'test test test\n');
|
||||
expect(body).toEqual('test test test');
|
||||
});
|
||||
|
||||
function cb() {
|
||||
|
@ -54,7 +53,7 @@ export default function(server, express) {
|
|||
});
|
||||
|
||||
test('should not store tarball', () => {
|
||||
on_tarball = function(res) {
|
||||
handleResponseTarball = function(res) {
|
||||
res.socket.destroy();
|
||||
};
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('UpStorge', () => {
|
|||
const uplinkDefault = {
|
||||
url: 'https://registry.npmjs.org/'
|
||||
};
|
||||
let generateProxy = (config = uplinkDefault) => {
|
||||
let generateProxy = (config: UpLinkConf = uplinkDefault) => {
|
||||
const appConfig: Config = new AppConfig(configExample);
|
||||
|
||||
return new ProxyStorage(config, appConfig);
|
||||
|
|
BIN
yarn.lock
BIN
yarn.lock
Binary file not shown.
Loading…
Reference in a new issue