fix: throw on validation if extensions are improperly named (#420)
Also fixes the case where UPPERCASED extension names were silently changed to lowercase and then set as undefined. Even though uppercased extension names are invalid, we should still accept them in incoming messsages and only throw when validating the event. Fixes: https://github.com/cloudevents/sdk-javascript/issues/380 Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
parent
80d987c1f6
commit
7f6b658858
|
@ -28,14 +28,21 @@ export function validateCloudEvent(event: CloudEventV03 | CloudEventV1): boolean
|
|||
if (!isValidAgainstSchemaV1(event)) {
|
||||
throw new ValidationError("invalid payload", isValidAgainstSchemaV1.errors);
|
||||
}
|
||||
return true;
|
||||
} else if (event.specversion === Version.V03) {
|
||||
if (!isValidAgainstSchemaV03(event)) {
|
||||
throw new ValidationError("invalid payload", isValidAgainstSchemaV03.errors);
|
||||
}
|
||||
return checkDataContentEncoding(event);
|
||||
checkDataContentEncoding(event);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
// attribute names must all be lowercase
|
||||
for (const key in event) {
|
||||
if (key !== key.toLowerCase()) {
|
||||
throw new ValidationError(`invalid attribute name: ${key}`);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkDataContentEncoding(event: CloudEventV03): boolean {
|
||||
|
|
|
@ -19,7 +19,7 @@ export class ValidationError extends TypeError {
|
|||
// @ts-ignore
|
||||
errors?.reduce(
|
||||
(accum: string, err: Record<string, string>) =>
|
||||
(accum as string).concat(`
|
||||
accum.concat(`
|
||||
${err instanceof Object ? JSON.stringify(err) : err}`),
|
||||
message,
|
||||
)
|
||||
|
|
|
@ -151,7 +151,7 @@ function getVersion(mode: Mode, headers: Headers, body: string | Record<string,
|
|||
* @throws {ValidationError} of the event does not conform to the spec
|
||||
*/
|
||||
function parseBinary(message: Message, version: Version): CloudEvent {
|
||||
const headers = message.headers;
|
||||
const headers = { ...message.headers };
|
||||
let body = message.body;
|
||||
|
||||
if (!headers) throw new ValidationError("headers is null or undefined");
|
||||
|
@ -167,11 +167,12 @@ function parseBinary(message: Message, version: Version): CloudEvent {
|
|||
const mappedParser: MappedParser = parserMap[header];
|
||||
eventObj[mappedParser.name] = mappedParser.parser.parse(sanitizedHeaders[header]);
|
||||
delete sanitizedHeaders[header];
|
||||
delete headers[header];
|
||||
}
|
||||
}
|
||||
|
||||
// Every unprocessed header can be an extension
|
||||
for (const header in sanitizedHeaders) {
|
||||
for (const header in headers) {
|
||||
if (header.startsWith(CONSTANTS.EXTENSIONS_PREFIX)) {
|
||||
eventObj[header.substring(CONSTANTS.EXTENSIONS_PREFIX.length)] = headers[header];
|
||||
}
|
||||
|
|
|
@ -64,6 +64,26 @@ describe("HTTP transport", () => {
|
|||
expect(HTTP.isEvent(message)).to.be.true;
|
||||
});
|
||||
|
||||
it("Respects extension attribute casing (even if against spec)", () => {
|
||||
// Now create a message that is an event
|
||||
const message = {
|
||||
body: `{ "greeting": "hello" }`,
|
||||
headers: {
|
||||
[CONSTANTS.CE_HEADERS.ID]: "1234",
|
||||
[CONSTANTS.CE_HEADERS.SOURCE]: "test",
|
||||
[CONSTANTS.CE_HEADERS.TYPE]: "test.event",
|
||||
[CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1,
|
||||
"ce-LUNCH": "tacos",
|
||||
},
|
||||
};
|
||||
expect(HTTP.isEvent(message)).to.be.true;
|
||||
const event: CloudEvent = HTTP.toEvent(message);
|
||||
expect(event.LUNCH).to.equal("tacos");
|
||||
expect(function () {
|
||||
event.validate();
|
||||
}).to.throw("invalid attribute name: LUNCH");
|
||||
});
|
||||
|
||||
it("Can detect CloudEvent binary Messages with weird versions", () => {
|
||||
// Now create a message that is an event
|
||||
const message = {
|
||||
|
|
Loading…
Reference in New Issue