mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-02-03 23:09:17 -05:00
e4573c7e15
* fix: avoid setting body for GET requests When making a GET request to certain uplinks, such as https://registry.npmmirror.com, setting the body field can result in a 413 error. Previously, the code was setting the body field for all requests, including GET requests. This commit fixes the issue by checking the request method and avoiding setting the body field for GET requests. This ensures that GET requests are not affected by the issue and can be made without error. Fixes #3601 * add missing deps for run test locally * test(up-storage): add unit test about uplink is npmmirror Cause thers is a bug in `isObject` function from `@verdaccio/core`, when `options.json` is `true` GET request body will be string 'true', some uplinks might return 413 status code such as https://registry.npmmirror.com fix #3601 * chore(deps): update @verdaccio/core --------- Co-authored-by: Juan Picado <juanpicado19@gmail.com> Co-authored-by: botao <botao@tal.com>
264 lines
9.1 KiB
TypeScript
264 lines
9.1 KiB
TypeScript
import _ from 'lodash';
|
|
|
|
import { Config, UpLinkConf } from '@verdaccio/types';
|
|
|
|
import AppConfig from '../../../../src/lib/config';
|
|
import { API_ERROR, HTTP_STATUS } from '../../../../src/lib/constants';
|
|
import { setup } from '../../../../src/lib/logger';
|
|
import ProxyStorage from '../../../../src/lib/up-storage';
|
|
import { DOMAIN_SERVERS } from '../../../functional/config.functional';
|
|
import { mockServer } from '../../__helper/mock';
|
|
import configExample from '../../partials/config';
|
|
|
|
setup({});
|
|
|
|
describe('UpStorage', () => {
|
|
const mockServerPort = 55547;
|
|
let mockRegistry;
|
|
const uplinkDefault = {
|
|
url: `http://localhost:${mockServerPort}`,
|
|
};
|
|
const generateProxy = (config: UpLinkConf = uplinkDefault) => {
|
|
const appConfig: Config = new AppConfig(configExample());
|
|
|
|
return new ProxyStorage(config, appConfig);
|
|
};
|
|
|
|
beforeAll(async () => {
|
|
mockRegistry = await mockServer(mockServerPort).init();
|
|
});
|
|
|
|
afterAll(function (done) {
|
|
mockRegistry[0].stop();
|
|
done();
|
|
});
|
|
|
|
test('should be defined', () => {
|
|
const proxy = generateProxy();
|
|
|
|
expect(proxy).toBeDefined();
|
|
});
|
|
|
|
describe('UpStorage::getRemoteMetadata', () => {
|
|
test('should be get remote metadata', (done) => {
|
|
const proxy = generateProxy();
|
|
|
|
proxy.getRemoteMetadata('jquery', {}, (err, data, etag) => {
|
|
expect(err).toBeNull();
|
|
expect(_.isString(etag)).toBeTruthy();
|
|
expect(data.name).toBe('jquery');
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('should be get remote metadata with etag', (done) => {
|
|
const proxy = generateProxy();
|
|
|
|
proxy.getRemoteMetadata('jquery', { etag: '123456' }, (err, data, etag) => {
|
|
expect(err).toBeNull();
|
|
expect(_.isString(etag)).toBeTruthy();
|
|
expect(data.name).toBe('jquery');
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('should be get remote metadata package does not exist', (done) => {
|
|
const proxy = generateProxy();
|
|
|
|
proxy.getRemoteMetadata('@verdaccio/fake-package', { etag: '123456' }, (err) => {
|
|
expect(err).not.toBeNull();
|
|
expect(err.statusCode).toBe(HTTP_STATUS.NOT_FOUND);
|
|
expect(err.message).toMatch(API_ERROR.NOT_PACKAGE_UPLINK);
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('should be get remote metadata with json when uplink is npmmirror', (done) => {
|
|
const proxy = generateProxy({ url: 'https://registry.npmmirror.com' });
|
|
|
|
proxy.getRemoteMetadata('jquery', { json: true }, (err, data) => {
|
|
expect(err).toBeNull();
|
|
expect(data.name).toBe('jquery');
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('UpStorage::fetchTarball', () => {
|
|
test('should fetch a tarball from uplink', (done) => {
|
|
const proxy = generateProxy();
|
|
const tarball = `http://${DOMAIN_SERVERS}:${mockServerPort}/jquery/-/jquery-1.5.1.tgz`;
|
|
const stream = proxy.fetchTarball(tarball);
|
|
|
|
stream.on('error', function (err) {
|
|
expect(err).toBeNull();
|
|
done();
|
|
});
|
|
|
|
stream.on('content-length', function (contentLength) {
|
|
expect(contentLength).toBeDefined();
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('should throw a 404 on fetch a tarball from uplink', (done) => {
|
|
const proxy = generateProxy();
|
|
const tarball = `http://${DOMAIN_SERVERS}:${mockServerPort}/jquery/-/no-exist-1.5.1.tgz`;
|
|
const stream = proxy.fetchTarball(tarball);
|
|
|
|
stream.on('error', function (err: any) {
|
|
expect(err).not.toBeNull();
|
|
expect(err.statusCode).toBe(HTTP_STATUS.NOT_FOUND);
|
|
expect(err.message).toMatch(API_ERROR.NOT_FILE_UPLINK);
|
|
|
|
done();
|
|
});
|
|
|
|
stream.on('content-length', function (contentLength) {
|
|
expect(contentLength).toBeDefined();
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('should be offline uplink', (done) => {
|
|
const proxy = generateProxy();
|
|
const tarball = 'http://404.verdaccioo.com';
|
|
const stream = proxy.fetchTarball(tarball);
|
|
expect(proxy.failed_requests).toBe(0);
|
|
|
|
// to test a uplink is offline we have to be try 3 times
|
|
// the default failed request are set to 2
|
|
process.nextTick(function () {
|
|
stream.on('error', function (err) {
|
|
expect(err).not.toBeNull();
|
|
// expect(err.statusCode).toBe(404);
|
|
expect(proxy.failed_requests).toBe(1);
|
|
|
|
const streamSecondTry = proxy.fetchTarball(tarball);
|
|
streamSecondTry.on('error', function (err) {
|
|
expect(err).not.toBeNull();
|
|
/*
|
|
code: 'ENOTFOUND',
|
|
errno: 'ENOTFOUND',
|
|
*/
|
|
// expect(err.statusCode).toBe(404);
|
|
expect(proxy.failed_requests).toBe(2);
|
|
const streamThirdTry = proxy.fetchTarball(tarball);
|
|
streamThirdTry.on('error', function (err: any) {
|
|
expect(err).not.toBeNull();
|
|
expect(err.statusCode).toBe(HTTP_STATUS.INTERNAL_ERROR);
|
|
expect(proxy.failed_requests).toBe(2);
|
|
expect(err.message).toMatch(API_ERROR.UPLINK_OFFLINE);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}, 10000);
|
|
});
|
|
|
|
describe('UpStorage::isUplinkValid', () => {
|
|
describe('valid use cases', () => {
|
|
const validateUpLink = (
|
|
url: string,
|
|
tarBallUrl = `${url}/artifactory/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz`
|
|
) => {
|
|
const uplinkConf = { url };
|
|
const proxy: any = generateProxy(uplinkConf);
|
|
|
|
return proxy.isUplinkValid(tarBallUrl);
|
|
};
|
|
|
|
test('should validate tarball path against uplink', () => {
|
|
expect(validateUpLink('https://artifactory.mydomain.com')).toBe(true);
|
|
});
|
|
|
|
test('should validate tarball path against uplink case#2', () => {
|
|
expect(validateUpLink('https://artifactory.mydomain.com:443')).toBe(true);
|
|
});
|
|
|
|
test('should validate tarball path against uplink case#3', () => {
|
|
expect(validateUpLink('http://localhost')).toBe(true);
|
|
});
|
|
|
|
test('should validate tarball path against uplink case#4', () => {
|
|
expect(validateUpLink('http://my.domain.test')).toBe(true);
|
|
});
|
|
|
|
test('should validate tarball path against uplink case#5', () => {
|
|
expect(validateUpLink('http://my.domain.test:3000')).toBe(true);
|
|
});
|
|
|
|
// corner case https://github.com/verdaccio/verdaccio/issues/571
|
|
test('should validate tarball path against uplink case#6', () => {
|
|
// same protocol, same domain, port === 443 which is also the standard for https
|
|
expect(
|
|
validateUpLink(
|
|
'https://my.domain.test',
|
|
`https://my.domain.test:443/artifactory/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz`
|
|
)
|
|
).toBe(true);
|
|
});
|
|
|
|
test('should validate tarball path against uplink case#7', () => {
|
|
expect(validateUpLink('https://artifactory.mydomain.com:5569')).toBe(true);
|
|
});
|
|
|
|
test('should validate tarball path against uplink case#8', () => {
|
|
expect(validateUpLink('https://localhost:5539')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('invalid use cases', () => {
|
|
test('should fails on validate tarball path against uplink', () => {
|
|
const url = 'https://artifactory.mydomain.com';
|
|
const tarBallUrl = 'https://localhost/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
|
|
const uplinkConf = { url };
|
|
const proxy: any = generateProxy(uplinkConf);
|
|
|
|
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
|
|
});
|
|
|
|
test('should fails on validate tarball path against uplink case#2', () => {
|
|
// different domain same, same port, same protocol
|
|
const url = 'https://domain';
|
|
const tarBallUrl = 'https://localhost/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
|
|
const uplinkConf = { url };
|
|
const proxy: any = generateProxy(uplinkConf);
|
|
|
|
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
|
|
});
|
|
|
|
test('should fails on validate tarball path against uplink case#3', () => {
|
|
// same domain, different protocol, different port
|
|
const url = 'http://localhost:5001';
|
|
const tarBallUrl = 'https://localhost:4000/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
|
|
const uplinkConf = { url };
|
|
const proxy: any = generateProxy(uplinkConf);
|
|
|
|
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
|
|
});
|
|
|
|
test('should fails on validate tarball path against uplink case#4', () => {
|
|
// same domain, same protocol, different port
|
|
const url = 'https://subdomain.domain:5001';
|
|
const tarBallUrl =
|
|
'https://subdomain.domain:4000/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
|
|
const uplinkConf = { url };
|
|
const proxy: any = generateProxy(uplinkConf);
|
|
|
|
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
|
|
});
|
|
|
|
test('should fails on validate tarball path against uplink case#5', () => {
|
|
// different protocol, different domain, different port
|
|
const url = 'https://subdomain.my:5001';
|
|
const tarBallUrl = 'http://subdomain.domain:4000/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
|
|
const uplinkConf = { url };
|
|
const proxy: any = generateProxy(uplinkConf);
|
|
|
|
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
});
|