mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
fix: Allow Content-Type: 0 on GET.
Fixes https://github.com/solid/community-server/issues/498
This commit is contained in:
committed by
Joachim Van Herwegen
parent
41899ca9cd
commit
16ef86acef
@@ -14,18 +14,26 @@ export class RawBodyParser extends BodyParser {
|
||||
// Note that the only reason this is a union is in case the body is empty.
|
||||
// If this check gets moved away from the BodyParsers this union could be removed
|
||||
public async handle({ request, metadata }: BodyParserArgs): Promise<Representation | undefined> {
|
||||
const {
|
||||
'content-type': contentType,
|
||||
'content-length': contentLength,
|
||||
'transfer-encoding': transferEncoding,
|
||||
} = request.headers;
|
||||
|
||||
// RFC7230, §3.3: The presence of a message body in a request
|
||||
// is signaled by a Content-Length or Transfer-Encoding header field.
|
||||
if (!request.headers['content-length'] && !request.headers['transfer-encoding']) {
|
||||
this.logger.debug('HTTP request appears to not have a body, so nothing to parse');
|
||||
// While clients SHOULD NOT use use a Content-Length header on GET,
|
||||
// some still provide a Content-Length of 0 (but without Content-Type).
|
||||
if ((!contentLength || (/^0+$/u.test(contentLength) && !contentType)) && !transferEncoding) {
|
||||
this.logger.debug('HTTP request does not have a body, or its empty body is missing a Content-Type header');
|
||||
return;
|
||||
}
|
||||
|
||||
// While RFC7231 allows treating a body without content type as an octet stream,
|
||||
// such an omission likely signals a mistake, so force clients to make this explicit.
|
||||
if (!request.headers['content-type']) {
|
||||
this.logger.warn('A body was passed, but the content length was not specified');
|
||||
throw new BadRequestHttpError('HTTP request body was passed without Content-Type header');
|
||||
if (!contentType) {
|
||||
this.logger.warn('HTTP request has a body, but no Content-Type header');
|
||||
throw new BadRequestHttpError('HTTP request body was passed without a Content-Type header');
|
||||
}
|
||||
|
||||
return new BasicRepresentation(request, metadata);
|
||||
|
||||
@@ -86,4 +86,31 @@ describe('A server with authorization', (): void => {
|
||||
);
|
||||
expect(response.statusCode).toBe(401);
|
||||
});
|
||||
|
||||
// https://github.com/solid/community-server/issues/498
|
||||
it('accepts a GET with Content-Length: 0.', async(): Promise<void> => {
|
||||
await aclHelper.setSimpleAcl({ read: true, write: true, append: true }, 'agent');
|
||||
|
||||
// PUT
|
||||
let requestUrl = new URL('http://test.com/foo/bar');
|
||||
let response: MockResponse<any> = await performRequest(
|
||||
handler,
|
||||
requestUrl,
|
||||
'PUT',
|
||||
{ 'content-length': '0', 'content-type': 'text/turtle' },
|
||||
[],
|
||||
);
|
||||
expect(response.statusCode).toBe(205);
|
||||
|
||||
// GET
|
||||
requestUrl = new URL('http://test.com/foo/bar');
|
||||
response = await performRequest(
|
||||
handler,
|
||||
requestUrl,
|
||||
'GET',
|
||||
{ 'content-length': '0' },
|
||||
[],
|
||||
);
|
||||
expect(response.statusCode).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,27 +18,46 @@ describe('A RawBodyparser', (): void => {
|
||||
await expect(bodyParser.canHandle({} as any)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns empty output if there was no content length or transfer encoding.', async(): Promise<void> => {
|
||||
it('returns empty output if there is no content length or transfer encoding.', async(): Promise<void> => {
|
||||
input.request = streamifyArray([ '' ]) as HttpRequest;
|
||||
input.request.headers = {};
|
||||
await expect(bodyParser.handle(input)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('errors when a content length was specified without content type.', async(): Promise<void> => {
|
||||
input.request = streamifyArray([ 'abc' ]) as HttpRequest;
|
||||
// https://github.com/solid/community-server/issues/498
|
||||
it('returns empty output if the content length is 0 and there is no content type.', async(): Promise<void> => {
|
||||
input.request = streamifyArray([ '' ]) as HttpRequest;
|
||||
input.request.headers = { 'content-length': '0' };
|
||||
await expect(bodyParser.handle(input)).rejects
|
||||
.toThrow('HTTP request body was passed without Content-Type header');
|
||||
await expect(bodyParser.handle(input)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('errors when a transfer encoding was specified without content type.', async(): Promise<void> => {
|
||||
it('errors when a content length is specified without content type.', async(): Promise<void> => {
|
||||
input.request = streamifyArray([ 'abc' ]) as HttpRequest;
|
||||
input.request.headers = { 'content-length': '1' };
|
||||
await expect(bodyParser.handle(input)).rejects
|
||||
.toThrow('HTTP request body was passed without a Content-Type header');
|
||||
});
|
||||
|
||||
it('errors when a transfer encoding is specified without content type.', async(): Promise<void> => {
|
||||
input.request = streamifyArray([ 'abc' ]) as HttpRequest;
|
||||
input.request.headers = { 'transfer-encoding': 'chunked' };
|
||||
await expect(bodyParser.handle(input)).rejects
|
||||
.toThrow('HTTP request body was passed without Content-Type header');
|
||||
.toThrow('HTTP request body was passed without a Content-Type header');
|
||||
});
|
||||
|
||||
it('returns a Representation if there was data.', async(): Promise<void> => {
|
||||
it('returns a Representation if there is empty data.', async(): Promise<void> => {
|
||||
input.request = streamifyArray([]) as HttpRequest;
|
||||
input.request.headers = { 'content-length': '0', 'content-type': 'text/turtle' };
|
||||
const result = (await bodyParser.handle(input))!;
|
||||
expect(result).toEqual({
|
||||
binary: true,
|
||||
data: input.request,
|
||||
metadata: input.metadata,
|
||||
});
|
||||
await expect(arrayifyStream(result.data)).resolves.toEqual([]);
|
||||
});
|
||||
|
||||
it('returns a Representation if there is non-empty data.', async(): Promise<void> => {
|
||||
input.request = streamifyArray([ '<http://test.com/s> <http://test.com/p> <http://test.com/o>.' ]) as HttpRequest;
|
||||
input.request.headers = { 'transfer-encoding': 'chunked', 'content-type': 'text/turtle' };
|
||||
const result = (await bodyParser.handle(input))!;
|
||||
|
||||
Reference in New Issue
Block a user