mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Make internal/quads unacceptable output
This commit is contained in:
parent
69ed2e069f
commit
715ba126f9
@ -1,5 +1,6 @@
|
|||||||
import type { RepresentationPreference } from '../../ldp/representation/RepresentationPreference';
|
import type { RepresentationPreference } from '../../ldp/representation/RepresentationPreference';
|
||||||
import type { RepresentationPreferences } from '../../ldp/representation/RepresentationPreferences';
|
import type { RepresentationPreferences } from '../../ldp/representation/RepresentationPreferences';
|
||||||
|
import { INTERNAL_ALL } from '../../util/ContentTypes';
|
||||||
import { InternalServerError } from '../../util/errors/InternalServerError';
|
import { InternalServerError } from '../../util/errors/InternalServerError';
|
||||||
import { UnsupportedHttpError } from '../../util/errors/UnsupportedHttpError';
|
import { UnsupportedHttpError } from '../../util/errors/UnsupportedHttpError';
|
||||||
import { matchingMediaType } from '../../util/Util';
|
import { matchingMediaType } from '../../util/Util';
|
||||||
@ -8,6 +9,9 @@ import type { RepresentationConverterArgs } from './RepresentationConverter';
|
|||||||
/**
|
/**
|
||||||
* Filters media types based on the given preferences.
|
* Filters media types based on the given preferences.
|
||||||
* Based on RFC 7231 - Content negotiation.
|
* Based on RFC 7231 - Content negotiation.
|
||||||
|
* Will add a default `internal/*;q=0` to the preferences to prevent accidental use of internal types.
|
||||||
|
* Since more specific media ranges override less specific ones,
|
||||||
|
* this will be ignored if there is a specific internal type preference.
|
||||||
*
|
*
|
||||||
* @param preferences - Preferences for output type.
|
* @param preferences - Preferences for output type.
|
||||||
* @param types - Media types to compare to the preferences.
|
* @param types - Media types to compare to the preferences.
|
||||||
@ -31,6 +35,11 @@ RepresentationPreference[] => {
|
|||||||
return map;
|
return map;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
// Prevent accidental use of internal types
|
||||||
|
if (!prefMap[INTERNAL_ALL]) {
|
||||||
|
prefMap[INTERNAL_ALL] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// RFC 7231
|
// RFC 7231
|
||||||
// Media ranges can be overridden by more specific media ranges or
|
// Media ranges can be overridden by more specific media ranges or
|
||||||
// specific media types. If more than one media range applies to a
|
// specific media types. If more than one media range applies to a
|
||||||
|
@ -4,4 +4,5 @@ export const APPLICATION_OCTET_STREAM = 'application/octet-stream';
|
|||||||
export const APPLICATION_SPARQL_UPDATE = 'application/sparql-update';
|
export const APPLICATION_SPARQL_UPDATE = 'application/sparql-update';
|
||||||
|
|
||||||
// Internal (non-exposed) content types
|
// Internal (non-exposed) content types
|
||||||
|
export const INTERNAL_ALL = 'internal/*';
|
||||||
export const INTERNAL_QUADS = 'internal/quads';
|
export const INTERNAL_QUADS = 'internal/quads';
|
||||||
|
@ -19,22 +19,22 @@ describe('A ConversionUtil', (): void => {
|
|||||||
describe('#checkRequest', (): void => {
|
describe('#checkRequest', (): void => {
|
||||||
it('requires an input type.', async(): Promise<void> => {
|
it('requires an input type.', async(): Promise<void> => {
|
||||||
const preferences: RepresentationPreferences = {};
|
const preferences: RepresentationPreferences = {};
|
||||||
expect((): any => checkRequest({ identifier, representation, preferences }, [ '*/*' ], [ '*/*' ]))
|
expect((): any => checkRequest({ identifier, representation, preferences }, [ 'a/x' ], [ 'a/x' ]))
|
||||||
.toThrow('Input type required for conversion.');
|
.toThrow('Input type required for conversion.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('requires a matching input type.', async(): Promise<void> => {
|
it('requires a matching input type.', async(): Promise<void> => {
|
||||||
metadata.contentType = 'a/x';
|
metadata.contentType = 'a/x';
|
||||||
const preferences: RepresentationPreferences = { type: [{ value: 'b/x', weight: 1 }]};
|
const preferences: RepresentationPreferences = { type: [{ value: 'b/x', weight: 1 }]};
|
||||||
expect((): any => checkRequest({ identifier, representation, preferences }, [ 'c/x' ], [ '*/*' ]))
|
expect((): any => checkRequest({ identifier, representation, preferences }, [ 'c/x' ], [ 'a/x' ]))
|
||||||
.toThrow('Can only convert from c/x to */*.');
|
.toThrow('Can only convert from c/x to a/x.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('requires a matching output type.', async(): Promise<void> => {
|
it('requires a matching output type.', async(): Promise<void> => {
|
||||||
metadata.contentType = 'a/x';
|
metadata.contentType = 'a/x';
|
||||||
const preferences: RepresentationPreferences = { type: [{ value: 'b/x', weight: 1 }]};
|
const preferences: RepresentationPreferences = { type: [{ value: 'b/x', weight: 1 }]};
|
||||||
expect((): any => checkRequest({ identifier, representation, preferences }, [ '*/*' ], [ 'c/x' ]))
|
expect((): any => checkRequest({ identifier, representation, preferences }, [ 'a/x' ], [ 'c/x' ]))
|
||||||
.toThrow('Can only convert from */* to c/x.');
|
.toThrow('Can only convert from a/x to c/x.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('succeeds with a valid input and output type.', async(): Promise<void> => {
|
it('succeeds with a valid input and output type.', async(): Promise<void> => {
|
||||||
@ -48,7 +48,7 @@ describe('A ConversionUtil', (): void => {
|
|||||||
describe('#matchingTypes', (): void => {
|
describe('#matchingTypes', (): void => {
|
||||||
it('requires type preferences.', async(): Promise<void> => {
|
it('requires type preferences.', async(): Promise<void> => {
|
||||||
const preferences: RepresentationPreferences = {};
|
const preferences: RepresentationPreferences = {};
|
||||||
expect((): any => matchingTypes(preferences, [ '*/*' ]))
|
expect((): any => matchingTypes(preferences, [ 'a/b' ]))
|
||||||
.toThrow('Output type required for conversion.');
|
.toThrow('Output type required for conversion.');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -71,5 +71,24 @@ describe('A ConversionUtil', (): void => {
|
|||||||
expect((): any => matchingTypes(preferences, [ 'noType' ]))
|
expect((): any => matchingTypes(preferences, [ 'noType' ]))
|
||||||
.toThrow(new InternalServerError(`Unexpected type preference: noType`));
|
.toThrow(new InternalServerError(`Unexpected type preference: noType`));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('filters out internal types.', async(): Promise<void> => {
|
||||||
|
const preferences: RepresentationPreferences = { type: [{ value: '*/*', weight: 1 }]};
|
||||||
|
expect(matchingTypes(preferences, [ 'a/x', 'internal/quads' ])).toEqual([{ value: 'a/x', weight: 1 }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps internal types that are specifically requested.', async(): Promise<void> => {
|
||||||
|
const preferences: RepresentationPreferences =
|
||||||
|
{ type: [{ value: '*/*', weight: 1 }, { value: 'internal/*', weight: 0.5 }]};
|
||||||
|
expect(matchingTypes(preferences, [ 'a/x', 'internal/quads' ]))
|
||||||
|
.toEqual([{ value: 'a/x', weight: 1 }, { value: 'internal/quads', weight: 0.5 }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('takes the most relevant weight for a type.', async(): Promise<void> => {
|
||||||
|
const preferences: RepresentationPreferences =
|
||||||
|
{ type: [{ value: '*/*', weight: 1 }, { value: 'internal/quads', weight: 0.5 }]};
|
||||||
|
expect(matchingTypes(preferences, [ 'a/x', 'internal/quads' ]))
|
||||||
|
.toEqual([{ value: 'a/x', weight: 1 }, { value: 'internal/quads', weight: 0.5 }]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user