tsoa
This commit is contained in:
232
node_modules/@hapi/accept/lib/header.js
generated
vendored
Executable file
232
node_modules/@hapi/accept/lib/header.js
generated
vendored
Executable file
@@ -0,0 +1,232 @@
|
||||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
const Boom = require('@hapi/boom');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports.selection = function (header, preferences, options) {
|
||||
|
||||
const selections = exports.selections(header, preferences, options);
|
||||
return selections.length ? selections[0] : '';
|
||||
};
|
||||
|
||||
|
||||
exports.selections = function (header, preferences, options) {
|
||||
|
||||
Hoek.assert(!preferences || Array.isArray(preferences), 'Preferences must be an array');
|
||||
|
||||
return internals.parse(header || '', preferences, options);
|
||||
};
|
||||
|
||||
|
||||
// RFC 7231 Section 5.3.3 (https://tools.ietf.org/html/rfc7231#section-5.3.3)
|
||||
//
|
||||
// Accept-Charset = *( "," OWS ) ( ( charset / "*" ) [ weight ] ) *( OWS "," [ OWS ( ( charset / "*" ) [ weight ] ) ] )
|
||||
// charset = token
|
||||
//
|
||||
// Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
|
||||
|
||||
|
||||
// RFC 7231 Section 5.3.4 (https://tools.ietf.org/html/rfc7231#section-5.3.4)
|
||||
//
|
||||
// Accept-Encoding = [ ( "," / ( codings [ weight ] ) ) *( OWS "," [ OWS ( codings [ weight ] ) ] ) ]
|
||||
// codings = content-coding / "identity" / "*"
|
||||
// content-coding = token
|
||||
//
|
||||
// Accept-Encoding: compress, gzip
|
||||
// Accept-Encoding:
|
||||
// Accept-Encoding: *
|
||||
// Accept-Encoding: compress;q=0.5, gzip;q=1.0
|
||||
// Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
|
||||
|
||||
|
||||
// RFC 7231 Section 5.3.5 (https://tools.ietf.org/html/rfc7231#section-5.3.5)
|
||||
//
|
||||
// Accept-Language = *( "," OWS ) ( language-range [ weight ] ) *( OWS "," [ OWS ( language-range [ weight ] ) ] )
|
||||
// language-range = ( 1*8ALPHA *( "-" 1*8alphanum ) ) / "*" ; [RFC4647], Section 2.1
|
||||
// alphanum = ALPHA / DIGIT
|
||||
//
|
||||
// Accept-Language: da, en-gb;q=0.8, en;q=0.7
|
||||
|
||||
|
||||
// token = 1*tchar
|
||||
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
|
||||
// / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
|
||||
// / DIGIT / ALPHA
|
||||
// ; any VCHAR, except delimiters
|
||||
// OWS = *( SP / HTAB )
|
||||
|
||||
|
||||
// RFC 7231 Section 5.3.1 (https://tools.ietf.org/html/rfc7231#section-5.3.1)
|
||||
//
|
||||
// The weight is normalized to a real number in the range 0 through 1,
|
||||
// where 0.001 is the least preferred and 1 is the most preferred; a
|
||||
// value of 0 means "not acceptable". If no "q" parameter is present,
|
||||
// the default weight is 1.
|
||||
//
|
||||
// weight = OWS ";" OWS "q=" qvalue
|
||||
// qvalue = ( "0" [ "." 0*3DIGIT ] ) / ( "1" [ "." 0*3("0") ] )
|
||||
|
||||
|
||||
internals.parse = function (raw, preferences, options) {
|
||||
|
||||
// Normalize header (remove spaces and tabs)
|
||||
|
||||
const header = raw.replace(/[ \t]/g, '');
|
||||
|
||||
// Normalize preferences
|
||||
|
||||
const lowers = new Map();
|
||||
if (preferences) {
|
||||
let pos = 0;
|
||||
for (const preference of preferences) {
|
||||
const lower = preference.toLowerCase();
|
||||
lowers.set(lower, { orig: preference, pos: pos++ });
|
||||
|
||||
if (options.prefixMatch) {
|
||||
const parts = lower.split('-');
|
||||
while (parts.pop(), parts.length > 0) {
|
||||
const joined = parts.join('-');
|
||||
if (!lowers.has(joined)) {
|
||||
lowers.set(joined, { orig: preference, pos: pos++ });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse selections
|
||||
|
||||
const parts = header.split(',');
|
||||
const selections = [];
|
||||
const map = new Set();
|
||||
|
||||
for (let i = 0; i < parts.length; ++i) {
|
||||
const part = parts[i];
|
||||
if (!part) { // Ignore empty parts or leading commas
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse parameters
|
||||
|
||||
const params = part.split(';');
|
||||
if (params.length > 2) {
|
||||
throw Boom.badRequest(`Invalid ${options.type} header`);
|
||||
}
|
||||
|
||||
let token = params[0].toLowerCase();
|
||||
if (!token) {
|
||||
throw Boom.badRequest(`Invalid ${options.type} header`);
|
||||
}
|
||||
|
||||
if (options.equivalents?.has(token)) {
|
||||
token = options.equivalents.get(token);
|
||||
}
|
||||
|
||||
const selection = {
|
||||
token,
|
||||
pos: i,
|
||||
q: 1
|
||||
};
|
||||
|
||||
if (preferences &&
|
||||
lowers.has(token)) {
|
||||
|
||||
selection.pref = lowers.get(token).pos;
|
||||
}
|
||||
|
||||
map.add(selection.token);
|
||||
|
||||
// Parse q=value
|
||||
|
||||
if (params.length === 2) {
|
||||
const q = params[1];
|
||||
const [key, value] = q.split('=');
|
||||
|
||||
if (!value ||
|
||||
key !== 'q' && key !== 'Q') {
|
||||
|
||||
throw Boom.badRequest(`Invalid ${options.type} header`);
|
||||
}
|
||||
|
||||
const score = parseFloat(value);
|
||||
if (score === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Number.isFinite(score) &&
|
||||
score <= 1 &&
|
||||
score >= 0.001) {
|
||||
|
||||
selection.q = score;
|
||||
}
|
||||
}
|
||||
|
||||
selections.push(selection); // Only add allowed selections (q !== 0)
|
||||
}
|
||||
|
||||
// Sort selection based on q and then position in header
|
||||
|
||||
selections.sort(internals.sort);
|
||||
|
||||
// Extract tokens
|
||||
|
||||
const values = selections.map((selection) => selection.token);
|
||||
|
||||
if (options.default &&
|
||||
!map.has(options.default)) {
|
||||
|
||||
values.push(options.default);
|
||||
}
|
||||
|
||||
if (!preferences?.length) {
|
||||
return values;
|
||||
}
|
||||
|
||||
const preferred = [];
|
||||
for (const selection of values) {
|
||||
if (selection === '*') {
|
||||
for (const [preference, value] of lowers) {
|
||||
if (!map.has(preference)) {
|
||||
preferred.push(value.orig);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const lower = selection.toLowerCase();
|
||||
if (lowers.has(lower)) {
|
||||
preferred.push(lowers.get(lower).orig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return preferred;
|
||||
};
|
||||
|
||||
|
||||
internals.sort = function (a, b) {
|
||||
|
||||
const aFirst = -1;
|
||||
const bFirst = 1;
|
||||
|
||||
if (b.q !== a.q) {
|
||||
return b.q - a.q;
|
||||
}
|
||||
|
||||
if (b.pref !== a.pref) {
|
||||
if (a.pref === undefined) {
|
||||
return bFirst;
|
||||
}
|
||||
|
||||
if (b.pref === undefined) {
|
||||
return aFirst;
|
||||
}
|
||||
|
||||
return a.pref - b.pref;
|
||||
}
|
||||
|
||||
return a.pos - b.pos;
|
||||
};
|
||||
Reference in New Issue
Block a user