fix: ensure loose validation for isEvent and toEvent (#394)

The `HTTP.isEvent()` and `HTTP.toEvent()` functions both had some validation
code that violated the principle of loose validation when receiving an
event over HTTP. As discussed, the validation should be managed by the
receiver in this case with `event.validate()`

Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
Lance Ball 2021-03-25 12:37:05 -04:00 committed by GitHub
parent 93f02130f6
commit efe466ac7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 21 deletions

View File

@ -1,7 +1,14 @@
import { CloudEvent, CloudEventV03, CloudEventV1, CONSTANTS, Mode, Version } from "../..";
import { Message, Headers } from "..";
import { headersFor, sanitize, v03structuredParsers, v1binaryParsers, v1structuredParsers } from "./headers";
import {
headersFor,
sanitize,
v03binaryParsers,
v03structuredParsers,
v1binaryParsers,
v1structuredParsers,
} from "./headers";
import { isStringOrObjectOrThrow, ValidationError } from "../../event/validation";
import { JSONParser, MappedParser, Parser, parserByContentType } from "../../parsers";
@ -122,23 +129,12 @@ function parseBinary(message: Message, version: Version): CloudEvent {
let body = message.body;
if (!headers) throw new ValidationError("headers is null or undefined");
if (body) {
isStringOrObjectOrThrow(body, new ValidationError("payload must be an object or a string"));
}
if (
headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] &&
headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] !== Version.V03 &&
headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] !== Version.V1
) {
throw new ValidationError(`invalid spec version ${headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]}`);
}
// Clone and low case all headers names
const sanitizedHeaders = sanitize(headers);
const eventObj: { [key: string]: unknown | string | Record<string, unknown> } = {};
const parserMap: Record<string, MappedParser> = version === Version.V1 ? v1binaryParsers : v1binaryParsers;
const parserMap: Record<string, MappedParser> = version === Version.V1 ? v1binaryParsers : v03binaryParsers;
for (const header in parserMap) {
if (sanitizedHeaders[header]) {
@ -186,14 +182,6 @@ function parseStructured(message: Message, version: Version): CloudEvent {
if (!headers) throw new ValidationError("headers is null or undefined");
isStringOrObjectOrThrow(payload, new ValidationError("payload must be an object or a string"));
if (
headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] &&
headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] != Version.V03 &&
headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] != Version.V1
) {
throw new ValidationError(`invalid spec version ${headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]}`);
}
// Clone and low case all headers names
const sanitizedHeaders = sanitize(headers);

View File

@ -59,6 +59,32 @@ describe("HTTP transport", () => {
expect(HTTP.isEvent(message)).to.be.true;
});
it("Can detect CloudEvent binary Messages with weird versions", () => {
// 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]: "11.8",
},
};
expect(HTTP.isEvent(message)).to.be.true;
expect(HTTP.toEvent(message)).not.to.throw;
});
it("Can detect CloudEvent structured Messages with weird versions", () => {
// Now create a message that is an event
const message = {
body: `{ "source": "test", "type": "test.event", "specversion": "11.8"}`,
headers: {
[CONSTANTS.CE_HEADERS.ID]: "1234",
},
};
expect(HTTP.isEvent(message)).to.be.true;
expect(HTTP.toEvent(message)).not.to.throw;
});
// Allow for external systems to send bad events - do what we can
// to accept them
it("Does not throw an exception when converting an invalid Message to a CloudEvent", () => {