From 5a4a7d074c308a4bf6a103acd738647c6ae94b0a Mon Sep 17 00:00:00 2001 From: Lance Ball Date: Wed, 24 Mar 2021 15:56:32 -0400 Subject: [PATCH] fix: ensure loose validation for isEvent and toEvent 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 --- src/message/http/index.ts | 30 +++++++++--------------------- test/integration/message_test.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/message/http/index.ts b/src/message/http/index.ts index bd90eb56..f1626607 100644 --- a/src/message/http/index.ts +++ b/src/message/http/index.ts @@ -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 } = {}; - const parserMap: Record = version === Version.V1 ? v1binaryParsers : v1binaryParsers; + const parserMap: Record = 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); diff --git a/test/integration/message_test.ts b/test/integration/message_test.ts index 837854ee..127f6f6d 100644 --- a/test/integration/message_test.ts +++ b/test/integration/message_test.ts @@ -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", () => {