fix: do not require an HTTP body on incoming binary event messages
This commit modifies the HTTP receivers/parsers to allow for the incoming body of an HTTP request to be empty if the event message is sent using the binary mode. In structured mode, a `ValidationError` will still be thrown, since the entire event must be encoded in the HTTP body. Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
parent
d866691e29
commit
a7c326b48c
|
@ -32,10 +32,11 @@ export class BinaryHTTPReceiver {
|
|||
* @returns {CloudEvent} an instance of CloudEvent representing the incoming request
|
||||
* @throws {ValidationError} of the event does not conform to the spec
|
||||
*/
|
||||
parse(payload: string | Record<string, unknown>, headers: Headers): CloudEvent {
|
||||
if (!payload) throw new ValidationError("payload is null or undefined");
|
||||
parse(payload: string | Record<string, unknown> | undefined | null, headers: Headers): CloudEvent {
|
||||
if (!headers) throw new ValidationError("headers is null or undefined");
|
||||
isStringOrObjectOrThrow(payload, new ValidationError("payload must be an object or a string"));
|
||||
if (payload) {
|
||||
isStringOrObjectOrThrow(payload, new ValidationError("payload must be an object or a string"));
|
||||
}
|
||||
|
||||
if (
|
||||
headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] &&
|
||||
|
@ -61,11 +62,15 @@ export class BinaryHTTPReceiver {
|
|||
}
|
||||
}
|
||||
|
||||
const parser = parserByContentType[eventObj.datacontenttype as string];
|
||||
if (!parser) {
|
||||
throw new ValidationError(`no parser found for content type ${eventObj.datacontenttype}`);
|
||||
let parsedPayload;
|
||||
|
||||
if (payload) {
|
||||
const parser = parserByContentType[eventObj.datacontenttype as string];
|
||||
if (!parser) {
|
||||
throw new ValidationError(`no parser found for content type ${eventObj.datacontenttype}`);
|
||||
}
|
||||
parsedPayload = parser.parse(payload);
|
||||
}
|
||||
const parsedPayload = parser.parse(payload);
|
||||
|
||||
// Every unprocessed header can be an extension
|
||||
for (const header in sanitizedHeaders) {
|
||||
|
|
|
@ -31,7 +31,7 @@ export class StructuredHTTPReceiver {
|
|||
* @returns {CloudEvent} a new CloudEvent instance for the provided headers and payload
|
||||
* @throws {ValidationError} if the payload and header combination do not conform to the spec
|
||||
*/
|
||||
parse(payload: Record<string, unknown> | string, headers: Headers): CloudEvent {
|
||||
parse(payload: Record<string, unknown> | string | undefined | null, headers: Headers): CloudEvent {
|
||||
if (!payload) throw new ValidationError("payload is null or undefined");
|
||||
if (!headers) throw new ValidationError("headers is null or undefined");
|
||||
isStringOrObjectOrThrow(payload, new ValidationError("payload must be an object or a string"));
|
||||
|
|
|
@ -59,7 +59,10 @@ export class Receiver {
|
|||
* @param {Object|JSON} body The body of the HTTP request
|
||||
* @return {CloudEvent} A new {CloudEvent} instance
|
||||
*/
|
||||
accept(headers: Headers, body: string | Record<string, unknown> | CloudEventV1 | CloudEventV03): CloudEvent {
|
||||
accept(
|
||||
headers: Headers,
|
||||
body: string | Record<string, unknown> | CloudEventV1 | CloudEventV03 | undefined | null,
|
||||
): CloudEvent {
|
||||
const cleanHeaders: Headers = sanitize(headers);
|
||||
const mode: Mode = getMode(cleanHeaders);
|
||||
const version = getVersion(mode, cleanHeaders, body);
|
||||
|
@ -103,7 +106,7 @@ function getMode(headers: Headers): Mode {
|
|||
function getVersion(
|
||||
mode: Mode,
|
||||
headers: Headers,
|
||||
body: string | Record<string, unknown> | CloudEventV03 | CloudEventV1,
|
||||
body: string | Record<string, unknown> | CloudEventV03 | CloudEventV1 | undefined | null,
|
||||
) {
|
||||
if (mode === Mode.BINARY) {
|
||||
// Check the headers for the version
|
||||
|
@ -113,7 +116,7 @@ function getVersion(
|
|||
}
|
||||
} else {
|
||||
// structured mode - the version is in the body
|
||||
return typeof body === "string" ? JSON.parse(body).specversion : body.specversion;
|
||||
return typeof body === "string" ? JSON.parse(body).specversion : (body as CloudEvent).specversion;
|
||||
}
|
||||
return Version.V1;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,30 @@ describe("HTTP Transport Binding Receiver for CloudEvents", () => {
|
|||
expect((event.data as Record<string, string>).lunch).to.equal("sushi");
|
||||
});
|
||||
|
||||
it("Accepts binary events when the data property is undefined", () => {
|
||||
const binaryHeaders = {
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"ce-specversion": specversion,
|
||||
"ce-id": id,
|
||||
"ce-type": type,
|
||||
"ce-source": source,
|
||||
};
|
||||
const event = receiver.accept(binaryHeaders, undefined);
|
||||
expect(event.data).to.be.undefined;
|
||||
});
|
||||
|
||||
it("Accepts binary events when the data property is null", () => {
|
||||
const binaryHeaders = {
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"ce-specversion": specversion,
|
||||
"ce-id": id,
|
||||
"ce-type": type,
|
||||
"ce-source": source,
|
||||
};
|
||||
const event = receiver.accept(binaryHeaders, null);
|
||||
expect(event.data).to.be.undefined;
|
||||
});
|
||||
|
||||
it("Converts the JSON body of a structured event to an Object", () => {
|
||||
const payload = {
|
||||
id,
|
||||
|
|
|
@ -9,18 +9,6 @@ const receiver = new BinaryHTTPReceiver(Version.V03);
|
|||
|
||||
describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
|
||||
describe("Check", () => {
|
||||
it("Throw error when payload arg is null or undefined", () => {
|
||||
// setup
|
||||
const payload = undefined;
|
||||
const attributes = {};
|
||||
|
||||
// act and assert
|
||||
expect(receiver.parse.bind(receiver, (payload as unknown) as string, attributes)).to.throw(
|
||||
ValidationError,
|
||||
"payload is null or undefined",
|
||||
);
|
||||
});
|
||||
|
||||
it("Throw error when attributes arg is null or undefined", () => {
|
||||
// setup
|
||||
const payload = {};
|
||||
|
|
|
@ -10,18 +10,6 @@ const receiver = new BinaryHTTPReceiver(Version.V1);
|
|||
|
||||
describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
|
||||
describe("Check", () => {
|
||||
it("Throw error when payload arg is null or undefined", () => {
|
||||
// setup
|
||||
const payload = null;
|
||||
const attributes = {};
|
||||
|
||||
// act and assert
|
||||
expect(receiver.parse.bind(receiver, (payload as unknown) as string, attributes)).to.throw(
|
||||
ValidationError,
|
||||
"payload is null or undefined",
|
||||
);
|
||||
});
|
||||
|
||||
it("Throw error when attributes arg is null or undefined", () => {
|
||||
// setup
|
||||
const payload = {};
|
||||
|
|
Loading…
Reference in New Issue