Skip to content

Commit 72a87df

Browse files
authored
fix: ensure binary events can handle no content-type header (#134)
* fix: ensure binary events can handle no content-type header The fix provided in #118 only included tests for `receiver.check()`, and the change in that case was to add the `application/json` content type to the cleansed headers if to type was specified. However, `receiver.parse()` did not receive the benefit of this change. It calls `this.check()` but then sanitizes the original headers again, and the missing content-type was not re-inserted into the newly sanitized headers. This commit, modifies the code so that `receiver.check()` does not insert the content-type, but does allow the validation check to pass if no content-type header exists. When `receiver.parse()` is called, and the headers are sanitized again - and this time used to look up parser implementation, the default `application/json` content-is applied if no content-type header exists. I've also removed a redundant call to `receiver.check()` in receiver_binary_1.js and simplified the usage of `Constants` in the test. Signed-off-by: Lance Ball <[email protected]> * chore: clean up header sniffing Signed-off-by: Lance Ball <[email protected]>
1 parent c1fda94 commit 72a87df

File tree

3 files changed

+70
-29
lines changed

3 files changed

+70
-29
lines changed

lib/bindings/http/receiver_binary.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
const Constants = require("./constants.js");
1+
const { HEADER_CONTENT_TYPE, MIME_JSON, DEFAULT_SPEC_VERSION_HEADER } =
2+
require("./constants.js");
23
const Commons = require("./commons.js");
34
const CloudEvent = require("../../cloudevent.js");
45

@@ -52,16 +53,13 @@ BinaryHTTPReceiver.prototype.check = function(payload, headers) {
5253
// Clone and low case all headers names
5354
const sanityHeaders = Commons.sanityAndClone(headers);
5455

55-
// If no content type is provided, default to application/json
56-
if (!sanityHeaders[Constants.HEADER_CONTENT_TYPE]) {
57-
sanityHeaders[Constants.HEADER_CONTENT_TYPE] = Constants.MIME_JSON;
58-
}
59-
60-
// Validation Level 1
61-
if (!this.allowedContentTypes
62-
.includes(sanityHeaders[Constants.HEADER_CONTENT_TYPE])) {
56+
// Validation Level 1 - if content-type exists, be sure it's
57+
// an allowed type
58+
const contentTypeHeader = sanityHeaders[HEADER_CONTENT_TYPE];
59+
const noContentType = !this.allowedContentTypes.includes(contentTypeHeader);
60+
if (contentTypeHeader && noContentType) {
6361
const err = new TypeError("invalid content type");
64-
err.errors = [sanityHeaders[Constants.HEADER_CONTENT_TYPE]];
62+
err.errors = [sanityHeaders[HEADER_CONTENT_TYPE]];
6563
throw err;
6664
}
6765

@@ -71,10 +69,10 @@ BinaryHTTPReceiver.prototype.check = function(payload, headers) {
7169
throw new TypeError(`header '${required}' not found`);
7270
});
7371

74-
if (sanityHeaders[Constants.DEFAULT_SPEC_VERSION_HEADER] !==
72+
if (sanityHeaders[DEFAULT_SPEC_VERSION_HEADER] !==
7573
this.specversion) {
7674
const err = new TypeError("invalid spec version");
77-
err.errors = [sanityHeaders[Constants.DEFAULT_SPEC_VERSION_HEADER]];
75+
err.errors = [sanityHeaders[DEFAULT_SPEC_VERSION_HEADER]];
7876
throw err;
7977
}
8078

@@ -83,14 +81,17 @@ BinaryHTTPReceiver.prototype.check = function(payload, headers) {
8381

8482
function parserFor(parsersByEncoding, cloudevent, headers) {
8583
const encoding = cloudevent.spec.payload.datacontentencoding;
86-
return parsersByEncoding[encoding][headers[Constants.HEADER_CONTENT_TYPE]];
84+
return parsersByEncoding[encoding][headers[HEADER_CONTENT_TYPE]];
8785
}
8886

8987
BinaryHTTPReceiver.prototype.parse = function(payload, headers) {
9088
this.check(payload, headers);
9189

9290
// Clone and low case all headers names
9391
const sanityHeaders = Commons.sanityAndClone(headers);
92+
if (!sanityHeaders[HEADER_CONTENT_TYPE]) {
93+
sanityHeaders[HEADER_CONTENT_TYPE] = MIME_JSON;
94+
}
9495

9596
const processedHeaders = [];
9697
const cloudevent = new CloudEvent(this.Spec);

lib/bindings/http/receiver_binary_1.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,6 @@ Receiver.prototype.check = function(payload, headers) {
101101
};
102102

103103
Receiver.prototype.parse = function(payload, headers) {
104-
// firstly specific local checks
105-
this.check(payload, headers);
106-
107104
payload = isString(payload) && isBase64(payload)
108105
? Buffer.from(payload, "base64").toString()
109106
: payload;

test/bindings/http/promiscuous_receiver_test.js

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
const { expect } = require("chai");
22
const { CloudEvent, HTTPReceiver } = require("../../../index.js");
3-
const constants = require("../../../lib/bindings/http/constants.js");
3+
const {
4+
HEADER_CONTENT_TYPE,
5+
DEFAULT_CONTENT_TYPE,
6+
MIME_CE_JSON,
7+
DEFAULT_SPEC_VERSION_HEADER,
8+
BINARY_HEADERS_03,
9+
BINARY_HEADERS_1
10+
} = require("../../../lib/bindings/http/constants.js");
411

512
const receiver = new HTTPReceiver();
613
const id = "1234";
@@ -24,7 +31,7 @@ describe("HTTP Transport Binding Receiver for CloudEvents", () => {
2431
};
2532

2633
const headers = {
27-
[constants.HEADER_CONTENT_TYPE]: constants.MIME_CE_JSON
34+
[HEADER_CONTENT_TYPE]: MIME_CE_JSON
2835
};
2936

3037
const event = receiver.accept(headers, payload);
@@ -33,11 +40,11 @@ describe("HTTP Transport Binding Receiver for CloudEvents", () => {
3340

3441
it("Binary data returns a CloudEvent", () => {
3542
const headers = {
36-
[constants.HEADER_CONTENT_TYPE]: constants.DEFAULT_CONTENT_TYPE,
37-
[constants.DEFAULT_SPEC_VERSION_HEADER]: specversion,
38-
[constants.BINARY_HEADERS_1.ID]: id,
39-
[constants.BINARY_HEADERS_1.TYPE]: type,
40-
[constants.BINARY_HEADERS_1.SOURCE]: source
43+
[HEADER_CONTENT_TYPE]: DEFAULT_CONTENT_TYPE,
44+
[DEFAULT_SPEC_VERSION_HEADER]: specversion,
45+
[BINARY_HEADERS_1.ID]: id,
46+
[BINARY_HEADERS_1.TYPE]: type,
47+
[BINARY_HEADERS_1.SOURCE]: source
4148
};
4249

4350
const event = receiver.accept(headers, data);
@@ -58,7 +65,7 @@ describe("HTTP Transport Binding Receiver for CloudEvents", () => {
5865
};
5966

6067
const headers = {
61-
[constants.HEADER_CONTENT_TYPE]: constants.MIME_CE_JSON
68+
[HEADER_CONTENT_TYPE]: MIME_CE_JSON
6269
};
6370

6471
const event = receiver.accept(headers, payload);
@@ -67,17 +74,53 @@ describe("HTTP Transport Binding Receiver for CloudEvents", () => {
6774

6875
it("Binary data returns a CloudEvent", () => {
6976
const headers = {
70-
[constants.HEADER_CONTENT_TYPE]: constants.DEFAULT_CONTENT_TYPE,
71-
[constants.DEFAULT_SPEC_VERSION_HEADER]: specversion,
72-
[constants.BINARY_HEADERS_03.ID]: id,
73-
[constants.BINARY_HEADERS_03.TYPE]: type,
74-
[constants.BINARY_HEADERS_03.SOURCE]: source
77+
[HEADER_CONTENT_TYPE]: DEFAULT_CONTENT_TYPE,
78+
[DEFAULT_SPEC_VERSION_HEADER]: specversion,
79+
[BINARY_HEADERS_03.ID]: id,
80+
[BINARY_HEADERS_03.TYPE]: type,
81+
[BINARY_HEADERS_03.SOURCE]: source
7582
};
7683

7784
const event = receiver.accept(headers, data);
7885
validateEvent(event, specversion);
7986
});
8087
});
88+
89+
describe("Kafka-Knative event source", () => {
90+
const specversion = "1.0";
91+
const id = "partition:1/offset:23";
92+
const type = "dev.knative.kafka.event";
93+
const source =
94+
"/apis/v1/namespaces/kafka/kafkasources/kafka-source#knative-demo-topic";
95+
96+
it("Should be parsable", () => {
97+
const headers = {
98+
host: "event-display.kafka.svc.cluster.local",
99+
"user-agent": "Go-http-client/1.1",
100+
"content-length": "59",
101+
"accept-encoding": "gzip",
102+
"ce-id": id,
103+
"ce-source": source,
104+
"ce-specversion": "1.0",
105+
"ce-subject": "partition:1#23",
106+
"ce-time": "2020-05-07T14:16:30.245Z",
107+
"ce-type": type,
108+
forwarded: "for=10.131.0.72;proto=http",
109+
"k-proxy-request": "activator",
110+
"x-envoy-expected-rq-timeout-ms": "600000",
111+
"x-forwarded-for": "10.131.0.72, 10.128.2.99",
112+
"x-forwarded-proto": "http",
113+
"x-request-id": "d3649c1b-a968-40bf-a9da-3e853abc0c8b"
114+
};
115+
const event = receiver.accept(headers, data);
116+
expect(event instanceof CloudEvent).to.equal(true);
117+
expect(event.getId()).to.equal(id);
118+
expect(event.getType()).to.equal(type);
119+
expect(event.getSource()).to.equal(source);
120+
expect(event.getData()).to.deep.equal(data);
121+
expect(event.getSpecversion()).to.equal(specversion);
122+
});
123+
});
81124
});
82125

83126
function validateEvent(event, specversion) {

0 commit comments

Comments
 (0)