diff --git a/packages/core/src/handlers/cors.ts b/packages/core/src/handlers/cors.ts index 8305f49a..5ca3268b 100644 --- a/packages/core/src/handlers/cors.ts +++ b/packages/core/src/handlers/cors.ts @@ -21,7 +21,7 @@ export class Cors { this.allowedMethods.toString() || accessControlRequestMethod ); const allowedHeaders = - this.allowedHeaders.toString() || getHeader(req, 'access-control-request-headers'); + this.allowedHeaders.toString() || getHeader(req, 'access-control-request-headers', true); allowedHeaders && res.setHeader('Access-Control-Allow-Headers', allowedHeaders); res.setHeader('Access-Control-Max-Age', this.maxAge); return; diff --git a/packages/core/src/handlers/tus.ts b/packages/core/src/handlers/tus.ts index 7170e84e..54d7dd6e 100644 --- a/packages/core/src/handlers/tus.ts +++ b/packages/core/src/handlers/tus.ts @@ -48,7 +48,7 @@ export class Tus extends BaseHandler { * Create a file and send url to client */ async post(req: http.IncomingMessage, res: http.ServerResponse): Promise { - const metadataHeader = getHeader(req, 'upload-metadata'); + const metadataHeader = getHeader(req, 'upload-metadata', true); const metadata = parseMetadata(metadataHeader); const config: FileInit = { metadata }; config.userId = this.getUserId(req, res); @@ -73,7 +73,7 @@ export class Tus extends BaseHandler { */ async patch(req: http.IncomingMessage, res: http.ServerResponse): Promise { const id = await this.getAndVerifyId(req, res); - const metadataHeader = getHeader(req, 'upload-metadata'); + const metadataHeader = getHeader(req, 'upload-metadata', true); const metadata = metadataHeader && parseMetadata(metadataHeader); metadata && (await this.storage.update({ id }, { metadata, id })); const start = Number(getHeader(req, 'upload-offset')); diff --git a/packages/core/src/utils/http.ts b/packages/core/src/utils/http.ts index a099aa07..c629f079 100644 --- a/packages/core/src/utils/http.ts +++ b/packages/core/src/utils/http.ts @@ -1,4 +1,5 @@ import * as http from 'http'; +import { getLastEntry } from './primitives'; export interface IncomingMessageWithBody extends http.IncomingMessage { body?: T; @@ -57,9 +58,18 @@ export async function getMetadata( return { ...JSON.parse(raw) } as Record; } -export function getHeader(req: http.IncomingMessage, name: string): string { +/** + Retrieve the value of a specific header of an HTTP request. + @param req - The request object. + @param name - The name of the header. + @param all - If true, returns all values of the header, comma-separated, otherwise returns the last value. + */ +export function getHeader(req: http.IncomingMessage, name: string, all = false): string { const raw = req.headers?.[name.toLowerCase()]; - return Array.isArray(raw) ? raw[0] : raw || ''; + if (!raw) return ''; + return all + ? raw.toString().trim() + : getLastEntry(Array.isArray(raw) ? raw : raw.split(',')).trim(); } export function appendHeader( diff --git a/packages/core/src/utils/primitives.ts b/packages/core/src/utils/primitives.ts index a6a0b3e6..2878e7cd 100644 --- a/packages/core/src/utils/primitives.ts +++ b/packages/core/src/utils/primitives.ts @@ -67,10 +67,14 @@ export function toMilliseconds(value: string | number | undefined): number | nul return duration(value); } -export function first(val: T | T[]): T { +export function getFirstEntry(val: T | T[]): T { return Array.isArray(val) ? val[0] : val; } +export function getLastEntry(val: T | T[]): T { + return Array.isArray(val) ? val[val.length - 1] : val; +} + export const memoize = (fn: (val: T) => K): ((val: T) => K) => { const cache = new Cache(1000, 0); const cached = (val: T): K => { diff --git a/test/util.spec.ts b/test/util.spec.ts index e97c9532..ce5beb6c 100644 --- a/test/util.spec.ts +++ b/test/util.spec.ts @@ -131,9 +131,19 @@ describe('utils', () => { expect(utils.getHeader(req, 'head')).toBe('value'); }); + it('getHeader(array)', () => { + req.headers = { head: ['value1', 'value2 '] }; + expect(utils.getHeader(req, 'head')).toBe('value2'); + }); + it('getHeader(multiple)', () => { - req.headers = { head: ['value1', 'value2'] }; - expect(utils.getHeader(req, 'head')).toBe('value1'); + req.headers = { head: 'value1 ,value2' }; + expect(utils.getHeader(req, 'head')).toBe('value2'); + }); + + it('getHeader(multiple, all)', () => { + req.headers = { head: 'value1,value2 ' }; + expect(utils.getHeader(req, 'head', true)).toBe('value1,value2'); }); it('getBaseUrl(no-host)', () => {