diff --git a/src/http/input/metadata/ContentTypeParser.ts b/src/http/input/metadata/ContentTypeParser.ts index 77c8ccfe8..d4cddd1fc 100644 --- a/src/http/input/metadata/ContentTypeParser.ts +++ b/src/http/input/metadata/ContentTypeParser.ts @@ -1,4 +1,5 @@ import type { HttpRequest } from '../../../server/HttpRequest'; +import { parseContentType } from '../../../util/HeaderUtil'; import type { RepresentationMetadata } from '../../representation/RepresentationMetadata'; import { MetadataParser } from './MetadataParser'; @@ -10,8 +11,7 @@ export class ContentTypeParser extends MetadataParser { public async handle(input: { request: HttpRequest; metadata: RepresentationMetadata }): Promise { const contentType = input.request.headers['content-type']; if (contentType) { - // Will need to use HeaderUtil once parameters need to be parsed - input.metadata.contentType = /^[^;]*/u.exec(contentType)![0].trim(); + input.metadata.contentType = parseContentType(contentType).type; } } } diff --git a/src/util/FetchUtil.ts b/src/util/FetchUtil.ts index 8d8a409db..9d1c317a3 100644 --- a/src/util/FetchUtil.ts +++ b/src/util/FetchUtil.ts @@ -6,6 +6,7 @@ import { getLoggerFor } from '../logging/LogUtil'; import type { RepresentationConverter } from '../storage/conversion/RepresentationConverter'; import { INTERNAL_QUADS } from './ContentTypes'; import { BadRequestHttpError } from './errors/BadRequestHttpError'; +import { parseContentType } from './HeaderUtil'; const logger = getLoggerFor('FetchUtil'); @@ -46,9 +47,10 @@ Promise { logger.warn(`Missing content-type header from ${response.url}`); throw error; } + const contentTypeValue = parseContentType(contentType).type; // Try to convert to quads - const representation = new BasicRepresentation(body, contentType); + const representation = new BasicRepresentation(body, contentTypeValue); const preferences = { type: { [INTERNAL_QUADS]: 1 }}; return converter.handleSafe({ representation, identifier: { path: response.url }, preferences }); } diff --git a/src/util/HeaderUtil.ts b/src/util/HeaderUtil.ts index 311c31baf..996ba092a 100644 --- a/src/util/HeaderUtil.ts +++ b/src/util/HeaderUtil.ts @@ -415,6 +415,18 @@ export function addHeader(response: HttpResponse, name: string, value: string | response.setHeader(name, allValues.length === 1 ? allValues[0] : allValues); } +/** + * Parses the Content-Type header. + * + * @param contentType - The media type of the content-type header + * + * @returns The parsed media type of the content-type + */ +export function parseContentType(contentType: string): { type: string } { + const contentTypeValue = /^\s*([^;\s]*)/u.exec(contentType)![1]; + return { type: contentTypeValue }; +} + /** * The Forwarded header from RFC7239 */ diff --git a/test/unit/util/HeaderUtil.test.ts b/test/unit/util/HeaderUtil.test.ts index 3610d395e..2e5c124fd 100644 --- a/test/unit/util/HeaderUtil.test.ts +++ b/test/unit/util/HeaderUtil.test.ts @@ -6,6 +6,7 @@ import { parseAcceptDateTime, parseAcceptEncoding, parseAcceptLanguage, + parseContentType, parseForwarded, } from '../../../src/util/HeaderUtil'; @@ -187,6 +188,18 @@ describe('HeaderUtil', (): void => { }); }); + describe('#parseContentType', (): void => { + const contentTypeTurtle = 'text/turtle'; + it('handles single content-type parameter (with leading and trailing whitespaces).', (): void => { + expect(parseContentType('text/turtle').type).toEqual(contentTypeTurtle); + expect(parseContentType('text/turtle ').type).toEqual(contentTypeTurtle); + expect(parseContentType(' text/turtle').type).toEqual(contentTypeTurtle); + }); + + it('handles multiple content-type parameters.', (): void => { + expect(parseContentType('text/turtle; charset=UTF-8').type).toEqual(contentTypeTurtle); + }); + }); describe('#parseForwarded', (): void => { it('handles an empty set of headers.', (): void => { expect(parseForwarded({})).toEqual({});