Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 22 additions & 21 deletions lib/header.js
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
'use strict';

const Hoek = require('@hapi/hoek');
const Boom = require('@hapi/boom');
import * as Hoek from '@hapi/hoek';
import * as Boom from '@hapi/boom';


const internals = {};


exports.selection = function (header, preferences, options) {
const selection = function (header, preferences, options) {

const selections = exports.selections(header, preferences, options);
return selections.length ? selections[0] : '';
const results = selections(header, preferences, options);
return results.length ? results[0] : '';
};


exports.selections = function (header, preferences, options) {
const selections = function (header, preferences, options) {

Hoek.assert(!preferences || Array.isArray(preferences), 'Preferences must be an array');

Expand DownExpand Up@@ -101,7 +99,7 @@ internals.parse = function (raw, preferences, options) {
// Parse selections

const parts = header.split(',');
const selections = [];
const results = [];
const map = new Set();

for (let i = 0; i < parts.length; ++i) {
Expand All@@ -126,7 +124,7 @@ internals.parse = function (raw, preferences, options) {
token = options.equivalents.get(token);
}

const selection = {
const item = {
token,
pos: i,
q: 1
Expand All@@ -135,10 +133,10 @@ internals.parse = function (raw, preferences, options) {
if (preferences &&
lowers.has(token)) {

selection.pref = lowers.get(token).pos;
item.pref = lowers.get(token).pos;
}

map.add(selection.token);
map.add(item.token);

// Parse q=value

Expand All@@ -161,20 +159,20 @@ internals.parse = function (raw, preferences, options) {
score <= 1 &&
score >= 0.001) {

selection.q = score;
item.q = score;
}
}

selections.push(selection); // Only add allowed selections (q !== 0)
results.push(item); // Only add allowed selections (q !== 0)
}

// Sort selection based on q and then position in header

selections.sort(internals.sort);
results.sort(internals.sort);

// Extract tokens

const values = selections.map((selection) => selection.token);
const values = results.map((item) => item.token);

if (options.default &&
!map.has(options.default)) {
Expand All@@ -187,16 +185,16 @@ internals.parse = function (raw, preferences, options) {
}

const preferred = [];
for (const selection of values) {
if (selection === '*') {
for (const [preference, value] of lowers) {
for (const value of values) {
if (value === '*') {
for (const [preference, prefValue] of lowers) {
if (!map.has(preference)) {
preferred.push(value.orig);
preferred.push(prefValue.orig);
}
}
}
else {
const lower = selection.toLowerCase();
const lower = value.toLowerCase();
if (lowers.has(lower)) {
preferred.push(lowers.get(lower).orig);
}
Expand DownExpand Up@@ -230,3 +228,6 @@ internals.sort = function (a, b) {

return a.pos - b.pos;
};


export { selection, selections };
36 changes: 21 additions & 15 deletions lib/index.js
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
'use strict';

const Header = require('./header');
const Media = require('./media');
import * as Header from './header.js';
import * as Media from './media.js';


const internals = {
Expand All@@ -25,24 +23,32 @@ const internals = {
};


for (const type in internals.options) {
exports[type] = (header, preferences) => Header.selection(header, preferences, internals.options[type]);
const charset = (header, preferences) => Header.selection(header, preferences, internals.options.charset);

const charsets = (header, preferences) => Header.selections(header, preferences, internals.options.charset);

const encoding = (header, preferences) => Header.selection(header, preferences, internals.options.encoding);

exports[`${type}s`] = (header, preferences) => Header.selections(header, preferences, internals.options[type]);
}
const encodings = (header, preferences) => Header.selections(header, preferences, internals.options.encoding);

const language = (header, preferences) => Header.selection(header, preferences, internals.options.language);

exports.mediaType = (header, preferences) => Media.selection(header, preferences);
const languages = (header, preferences) => Header.selections(header, preferences, internals.options.language);

exports.mediaTypes = (header, preferences) => Media.selections(header, preferences);
const mediaType = (header, preferences) => Media.selection(header, preferences);

const mediaTypes = (header, preferences) => Media.selections(header, preferences);

exports.parseAll = function (requestHeaders) {

const parseAll = function (requestHeaders) {

return {
charsets: exports.charsets(requestHeaders['accept-charset']),
encodings: exports.encodings(requestHeaders['accept-encoding']),
languages: exports.languages(requestHeaders['accept-language']),
mediaTypes: exports.mediaTypes(requestHeaders.accept)
charsets: charsets(requestHeaders['accept-charset']),
encodings: encodings(requestHeaders['accept-encoding']),
languages: languages(requestHeaders['accept-language']),
mediaTypes: mediaTypes(requestHeaders.accept)
};
};


export { charset, charsets, encoding, encodings, language, languages, mediaType, mediaTypes, parseAll };
63 changes: 32 additions & 31 deletions lib/media.js
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
'use strict';

const Hoek = require('@hapi/hoek');
const Boom = require('@hapi/boom');
import * as Hoek from '@hapi/hoek';
import * as Boom from '@hapi/boom';


const internals = {};


exports.selection = function (header, preferences) {
const selection = function (header, preferences) {

const selections = exports.selections(header, preferences);
return selections.length ? selections[0] : '';
const results = selections(header, preferences);
return results.length ? results[0] : '';
};


exports.selections = function (header, preferences) {
const selections = function (header, preferences) {

Hoek.assert(!preferences || Array.isArray(preferences), 'Preferences must be an array');

Expand DownExpand Up@@ -73,7 +71,7 @@ internals.parse = function (raw, preferences) {
// Parse selections

const parts = header.split(',');
const selections = [];
const results = [];
const map = {};

for (let i = 0; i < parts.length; ++i) {
Expand All@@ -91,7 +89,7 @@ internals.parse = function (raw, preferences) {
continue;
}

const selection = {
const item = {
token,
params: {},
exts: {},
Expand DownExpand Up@@ -125,41 +123,41 @@ internals.parse = function (raw, preferences) {
value = 1;
}

selection.q = value;
item.q = value;
}
else {
if (value[0] === '"') {
value = `"${quoted[value]}"`;
}

selection[target][kv[0]] = value;
item[target][kv[0]] = value;
}
}

const params = Object.keys(selection.params);
selection.original = [''].concat(params.map((key) => `${key}=${selection.params[key]}`)).join(';');
selection.specificity = params.length;
const params = Object.keys(item.params);
item.original = [''].concat(params.map((key) => `${key}=${item.params[key]}`)).join(';');
item.specificity = params.length;

if (selection.q === undefined) { // Default no preference to q=1 (top preference)
selection.q = 1;
if (item.q === undefined) { // Default no preference to q=1 (top preference)
item.q = 1;
}

const tparts = selection.token.split('/');
selection.type = tparts[0];
selection.subtype = tparts[1];
const tparts = item.token.split('/');
item.type = tparts[0];
item.subtype = tparts[1];

map[selection.token] = selection;
map[item.token] = item;

if (selection.q) { // Skip denied selections (q=0)
selections.push(selection);
if (item.q) { // Skip denied selections (q=0)
results.push(item);
}
}

// Sort selection based on q and then position in header

selections.sort(internals.sort);
results.sort(internals.sort);

return internals.preferences(map, selections, preferences);
return internals.preferences(map, results, preferences);
};


Expand DownExpand Up@@ -234,12 +232,12 @@ internals.innerSort = function (a, b, key) {
};


internals.preferences = function (map, selections, preferences) {
internals.preferences = function (map, results, preferences) {

// Return selections if no preferences

if (!preferences?.length) {
return selections.map((selection) => selection.token + selection.original);
return results.map((item) => item.token + item.original);
}

// Map wildcards and filter selections to preferences
Expand All@@ -266,8 +264,8 @@ internals.preferences = function (map, selections, preferences) {
}

const preferred = [];
for (const selection of selections) {
const token = selection.token;
for (const item of results) {
const token = item.token;
const { type, subtype } = map[token];
const subtypes = lowers[type];

Expand All@@ -290,7 +288,7 @@ internals.preferences = function (map, selections, preferences) {
// any

if (any) {
preferred.push((flat[token] || token) + selection.original);
preferred.push((flat[token] || token) + item.original);
continue;
}

Expand All@@ -301,7 +299,7 @@ internals.preferences = function (map, selections, preferences) {
if (pref ||
(subtypes && subtypes['*'])) {

preferred.push((pref || token) + selection.original);
preferred.push((pref || token) + item.original);
}

continue;
Expand All@@ -320,3 +318,6 @@ internals.preferences = function (map, selections, preferences) {

return preferred;
};


export { selection, selections };
7 changes: 4 additions & 3 deletions package.json
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
{
"name": "@hapi/accept",
"description": "HTTP Accept-* headers parsing",
"version": "6.0.3",
"version": "7.0.0",
"type": "module",
"repository": "git://github.com/hapijs/accept",
"main": "lib/index.js",
"exports": "./lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib"
Expand DownExpand Up@@ -31,7 +32,7 @@
"typescript": "~4.6.4"
},
"scripts": {
"test": "lab -a @hapi/code -t 100 -L -Y",
"test": "lab -a @hapi/code -Y",
"test-cov-html": "lab -a @hapi/code -r html -o coverage.html"
},
"license": "BSD-3-Clause"
Expand Down
12 changes: 6 additions & 6 deletions test/charset.js
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
'use strict';

const Accept = require('..');
const Code = require('@hapi/code');
const Lab = require('@hapi/lab');
import * as Accept from '../lib/index.js';
import * as Code from '@hapi/code';
import * as Lab from '@hapi/lab';


const internals = {};


const { describe, it } = exports.lab = Lab.script();
const lab = Lab.script();
const { describe, it } = lab;
const expect = Code.expect;
export { lab };


describe('charset()', () => {
Expand Down
12 changes: 6 additions & 6 deletions test/encoding.js
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
'use strict';

const Accept = require('..');
const Code = require('@hapi/code');
const Lab = require('@hapi/lab');
import * as Accept from '../lib/index.js';
import * as Code from '@hapi/code';
import * as Lab from '@hapi/lab';


const internals = {};


const { describe, it } = exports.lab = Lab.script();
const lab = Lab.script();
const { describe, it } = lab;
const expect = Code.expect;
export { lab };

/*
Accept-Encoding: compress, gzip
Expand Down
Loading
Loading