0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-16 21:56:25 -05:00

fix: abbreviated headers handle quality values (#3361)

This commit is contained in:
Juan Picado 2022-09-06 08:25:17 +02:00 committed by GitHub
parent 97078c9084
commit 43f32687cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 111 additions and 7 deletions

View file

@ -0,0 +1,8 @@
---
'@verdaccio/api': patch
'@verdaccio/core': patch
'@verdaccio/server-fastify': patch
'@verdaccio/store': patch
---
fix: abbreviated headers handle quality values

View file

@ -3,7 +3,14 @@
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [
["verdaccio", "@verdaccio/cli", "@verdaccio/core", "@verdaccio/config", "@verdaccio/node-api"]
[
"verdaccio",
"@verdaccio/cli",
"@verdaccio/core",
"@verdaccio/config",
"@verdaccio/node-api",
"@verdaccio/ui-theme"
]
],
"access": "public",
"baseBranch": "master",

View file

@ -2,7 +2,7 @@ import buildDebug from 'debug';
import { Router } from 'express';
import { IAuth } from '@verdaccio/auth';
import { HEADERS, HEADER_TYPE } from '@verdaccio/core';
import { HEADERS, HEADER_TYPE, stringUtils } from '@verdaccio/core';
import { allow } from '@verdaccio/middleware';
import { Storage } from '@verdaccio/store';
@ -25,7 +25,8 @@ export default function (route: Router, auth: IAuth, storage: Storage): void {
const name = req.params.package;
let version = req.params.version;
const write = req.query.write === 'true';
const abbreviated = req.get('Accept') === Storage.ABBREVIATED_HEADER;
const abbreviated =
stringUtils.getByQualityPriorityValue(req.get('Accept')) === Storage.ABBREVIATED_HEADER;
const requestOptions = {
protocol: req.protocol,
headers: req.headers as any,
@ -43,6 +44,12 @@ export default function (route: Router, auth: IAuth, storage: Storage): void {
version,
requestOptions,
});
if (abbreviated) {
_res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_INSTALL_CHARSET);
} else {
_res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);
}
next(manifest);
} catch (err) {
next(err);

View file

@ -90,7 +90,7 @@ describe('package', () => {
.get(`/${pkg}`)
.set(HEADERS.ACCEPT, HEADERS.JSON)
.set(HEADERS.ACCEPT, Storage.ABBREVIATED_HEADER)
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_INSTALL_CHARSET)
.expect(HTTP_STATUS.OK);
expect(response.body.name).toEqual(pkg);
expect(response.body.time).toBeDefined();

View file

@ -46,6 +46,7 @@ export const HEADERS = {
NONE_MATCH: 'If-None-Match',
ETAG: 'ETag',
JSON_CHARSET: 'application/json; charset=utf-8',
JSON_INSTALL_CHARSET: 'application/vnd.npm.install-v1+json; charset=utf-8',
OCTET_STREAM: 'application/octet-stream; charset=utf-8',
TEXT_CHARSET: 'text/plain; charset=utf-8',
WWW_AUTH: 'WWW-Authenticate',

View file

@ -5,6 +5,7 @@ import * as pkgUtils from './pkg-utils';
import * as pluginUtils from './plugin-utils';
import * as searchUtils from './search-utils';
import * as streamUtils from './stream-utils';
import * as stringUtils from './string-utils';
import * as validatioUtils from './validation-utils';
import * as warningUtils from './warning-utils';
@ -33,6 +34,7 @@ export {
// TODO: remove this typo
validatioUtils,
validationUtils,
stringUtils,
constants,
pluginUtils,
warningUtils,

View file

@ -0,0 +1,36 @@
/**
* Quality values, or q-values and q-factors, are used to describe the order
* of priority of values in a comma-separated list.
* It is a special syntax allowed in some HTTP headers and in HTML.
* https://developer.mozilla.org/en-US/docs/Glossary/Quality_values
* @param headerValue
*/
export function getByQualityPriorityValue(headerValue: string | undefined | null): string {
if (typeof headerValue !== 'string') {
return '';
}
const split = headerValue.split(',');
if (split.length <= 1) {
const qList = split[0].split(';');
return qList[0];
}
let [header] = split
.reduce((acc, item: string) => {
const qList = item.split(';');
if (qList.length > 1) {
const [accept, q] = qList;
const [, query] = q.split('=');
acc.push([accept.trim(), query ? query : 0]);
} else {
acc.push([qList[0], 0]);
}
return acc;
}, [] as any)
.sort(function (a, b) {
return b[1] - a[1];
});
return header[0];
}

View file

@ -0,0 +1,40 @@
import { stringUtils } from '../src';
describe('string-utils', () => {
test('getByQualityPriorityValue', () => {
expect(stringUtils.getByQualityPriorityValue('')).toEqual('');
expect(stringUtils.getByQualityPriorityValue(null)).toEqual('');
expect(stringUtils.getByQualityPriorityValue(undefined)).toEqual('');
expect(stringUtils.getByQualityPriorityValue('something')).toEqual('something');
expect(stringUtils.getByQualityPriorityValue('something,')).toEqual('something');
expect(stringUtils.getByQualityPriorityValue('0,')).toEqual('0');
expect(stringUtils.getByQualityPriorityValue('application/json')).toEqual('application/json');
expect(stringUtils.getByQualityPriorityValue('application/json; q=1')).toEqual(
'application/json'
);
expect(stringUtils.getByQualityPriorityValue('application/json; q=')).toEqual(
'application/json'
);
expect(stringUtils.getByQualityPriorityValue('application/json;')).toEqual('application/json');
expect(
stringUtils.getByQualityPriorityValue(
'application/json; q=1.0, application/vnd.npm.install-v1+json; q=0.9, */*'
)
).toEqual('application/json');
expect(
stringUtils.getByQualityPriorityValue(
'application/json; q=1.0, application/vnd.npm.install-v1+json; q=, */*'
)
).toEqual('application/json');
expect(
stringUtils.getByQualityPriorityValue(
'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.9, */*'
)
).toEqual('application/vnd.npm.install-v1+json');
expect(
stringUtils.getByQualityPriorityValue(
'application/vnd.npm.install-v1+json; q=, application/json; q=0.9, */*'
)
).toEqual('application/json');
});
});

View file

@ -1,6 +1,8 @@
import buildDebug from 'debug';
import { FastifyInstance } from 'fastify';
import { stringUtils } from '@verdaccio/core';
import { Storage } from '@verdaccio/store';
import { Package, Version } from '@verdaccio/types';
const debug = buildDebug('verdaccio:fastify:api:sidebar');
@ -17,7 +19,9 @@ async function manifestRoute(fastify: FastifyInstance) {
const storage = fastify.storage;
debug('pkg name %s ', name);
// @ts-ignore
const abbreviated = request.headers['accept'] === Storage.ABBREVIATED_HEADER;
const abbreviated =
stringUtils.getByQualityPriorityValue(request.headers['accept']) ===
Storage.ABBREVIATED_HEADER;
const data = await storage?.getPackageByOptions({
name,
// @ts-ignore

View file

@ -94,8 +94,7 @@ class Storage {
debug('uplinks available %o', Object.keys(this.uplinks));
}
static ABBREVIATED_HEADER =
'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*';
static ABBREVIATED_HEADER = 'application/vnd.npm.install-v1+json';
/**
* Change an existing package (i.e. unpublish one version)