From 4aed8c8b4c276011b45e3a722939ae97fb3e5d11 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 5 Jan 2021 01:17:12 +0100 Subject: [PATCH] refactor: Simplify AcceptPreferenceParser. --- src/ldp/http/AcceptPreferenceParser.ts | 59 ++++++++++---------------- src/util/HeaderUtil.ts | 19 ++++++++- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/ldp/http/AcceptPreferenceParser.ts b/src/ldp/http/AcceptPreferenceParser.ts index f1bd64c10..66330ee01 100644 --- a/src/ldp/http/AcceptPreferenceParser.ts +++ b/src/ldp/http/AcceptPreferenceParser.ts @@ -5,52 +5,37 @@ import { parseAcceptCharset, parseAcceptEncoding, parseAcceptLanguage, + parseAcceptDateTime, } from '../../util/HeaderUtil'; import type { RepresentationPreferences } from '../representation/RepresentationPreferences'; import { PreferenceParser } from './PreferenceParser'; +const parsers: { + name: keyof RepresentationPreferences; + header: string; + parse: (value: string) => AcceptHeader[]; +}[] = [ + { name: 'type', header: 'accept', parse: parseAccept }, + { name: 'charset', header: 'accept-charset', parse: parseAcceptCharset }, + { name: 'encoding', header: 'accept-encoding', parse: parseAcceptEncoding }, + { name: 'language', header: 'accept-language', parse: parseAcceptLanguage }, + { name: 'datetime', header: 'accept-datetime', parse: parseAcceptDateTime }, +]; + /** - * Extracts preferences from the accept-* headers from an incoming {@link HttpRequest}. + * Extracts preferences from the Accept-* headers from an incoming {@link HttpRequest}. * Supports Accept, Accept-Charset, Accept-Encoding, Accept-Language and Accept-DateTime. */ export class AcceptPreferenceParser extends PreferenceParser { - public constructor() { - super(); - } - - public async handle(input: HttpRequest): Promise { - const result: RepresentationPreferences = {}; - const headers: - { [T in keyof RepresentationPreferences]: { val?: string; func: (inp: string) => AcceptHeader[] }} = { - type: { val: input.headers.accept, func: parseAccept }, - charset: { val: input.headers['accept-charset'] as string, func: parseAcceptCharset }, - encoding: { val: input.headers['accept-encoding'] as string, func: parseAcceptEncoding }, - language: { val: input.headers['accept-language'], func: parseAcceptLanguage }, - }; - (Object.keys(headers) as (keyof RepresentationPreferences)[]).forEach((key): void => { - const preferences = this.parseHeader(headers[key]!.func, headers[key]!.val); - if (preferences.length > 0) { - result[key] = Object.fromEntries(preferences); + public async handle({ headers }: HttpRequest): Promise { + const preferences: RepresentationPreferences = {}; + for (const { name, header, parse } of parsers) { + const value = headers[header]; + if (typeof value === 'string') { + preferences[name] = Object.fromEntries(parse(value) + .map(({ range, weight }): [string, number] => [ range, weight ])); } - }); - - // Accept-DateTime is currently specified to simply have a datetime as value - if (input.headers['accept-datetime']) { - result.datetime = { [input.headers['accept-datetime'] as string]: 1 }; } - - return result; - } - - /** - * Converts a header string using the given parse function to {@link RepresentationPreference}[]. - * @param input - Input header string. - * @param parseFunction - Function that converts header string to {@link AcceptHeader}. - * - * @returns A list of preferences. Returns an empty list if input was not defined. - */ - private parseHeader(parseFunction: (input: string) => AcceptHeader[], input?: string): [string, number][] { - return (input ? parseFunction(input) : []) - .map(({ range, weight }): [string, number] => [ range, weight ]); + return preferences; } } diff --git a/src/util/HeaderUtil.ts b/src/util/HeaderUtil.ts index 2aac2b947..e411a36f3 100644 --- a/src/util/HeaderUtil.ts +++ b/src/util/HeaderUtil.ts @@ -93,6 +93,11 @@ export interface AcceptEncoding extends AcceptHeader { } */ export interface AcceptLanguage extends AcceptHeader { } +/** + * Contents of an HTTP Accept-Datetime header. + */ +export interface AcceptDatetime extends AcceptHeader { } + // REUSED REGEXES const token = /^[a-zA-Z0-9!#$%&'*+-.^_`|~]+$/u; @@ -248,10 +253,10 @@ const parseAcceptPart = (part: string, replacements: Record): Ac * * @returns An array of ranges and weights. */ -const parseNoParameters = (input: string): { range: string; weight: number }[] => { +const parseNoParameters = (input: string): AcceptHeader[] => { const parts = splitAndClean(input); - return parts.map((part): { range: string; weight: number } => { + return parts.map((part): AcceptHeader => { const [ range, qvalue ] = part.split(';').map((param): string => param.trim()); const result = { range, weight: 1 }; if (qvalue) { @@ -357,6 +362,16 @@ export const parseAcceptLanguage = (input: string): AcceptLanguage[] => { return results; }; +/** + * Parses an Accept-DateTime header string. + * + * @param input - The Accept-DateTime header string. + * + * @returns An array with a single {@link AcceptDatetime} object. + */ +export const parseAcceptDateTime = (input: string): AcceptDatetime[] => + [{ range: input, weight: 1 }]; + /** * Adds a header value without overriding previous values. */