@@ -2,16 +2,17 @@ import { CloudEvent, CloudEventV03, CloudEventV1, CONSTANTS, Mode, Version } fro
2
2
import { Message , Headers } from ".." ;
3
3
4
4
import { headersFor , sanitize , v03structuredParsers , v1binaryParsers , v1structuredParsers } from "./headers" ;
5
- import { asData , isBase64 , isString , isStringOrObjectOrThrow , ValidationError } from "../../event/validation" ;
6
- import { Base64Parser , JSONParser , MappedParser , Parser , parserByContentType } from "../../parsers" ;
5
+ import { isStringOrObjectOrThrow , ValidationError } from "../../event/validation" ;
6
+ import { JSONParser , MappedParser , Parser , parserByContentType } from "../../parsers" ;
7
7
8
8
// implements Serializer
9
9
export function binary ( event : CloudEvent ) : Message {
10
10
const contentType : Headers = { [ CONSTANTS . HEADER_CONTENT_TYPE ] : CONSTANTS . DEFAULT_CONTENT_TYPE } ;
11
11
const headers : Headers = { ...contentType , ...headersFor ( event ) } ;
12
- let body = asData ( event . data , event . datacontenttype as string ) ;
13
- if ( typeof body === "object" ) {
14
- body = JSON . stringify ( body ) ;
12
+ let body = event . data ;
13
+ if ( typeof event . data === "object" && ! ( event . data instanceof Uint32Array ) ) {
14
+ // we'll stringify objects, but not binary data
15
+ body = JSON . stringify ( event . data ) ;
15
16
}
16
17
return {
17
18
headers,
@@ -21,6 +22,10 @@ export function binary(event: CloudEvent): Message {
21
22
22
23
// implements Serializer
23
24
export function structured ( event : CloudEvent ) : Message {
25
+ if ( event . data_base64 ) {
26
+ // The event's data is binary - delete it
27
+ event = event . cloneWith ( { data : undefined } ) ;
28
+ }
24
29
return {
25
30
headers : {
26
31
[ CONSTANTS . HEADER_CONTENT_TYPE ] : CONSTANTS . DEFAULT_CE_CONTENT_TYPE ,
@@ -89,7 +94,7 @@ function getMode(headers: Headers): Mode {
89
94
* @param {Record<string, unknown> } body the HTTP request body
90
95
* @returns {Version } the CloudEvent specification version
91
96
*/
92
- function getVersion ( mode : Mode , headers : Headers , body : string | Record < string , string > ) {
97
+ function getVersion ( mode : Mode , headers : Headers , body : string | Record < string , string > | unknown ) {
93
98
if ( mode === Mode . BINARY ) {
94
99
// Check the headers for the version
95
100
const versionHeader = headers [ CONSTANTS . CE_HEADERS . SPEC_VERSION ] ;
@@ -129,8 +134,6 @@ function parseBinary(message: Message, version: Version): CloudEvent {
129
134
throw new ValidationError ( `invalid spec version ${ headers [ CONSTANTS . CE_HEADERS . SPEC_VERSION ] } ` ) ;
130
135
}
131
136
132
- body = isString ( body ) && isBase64 ( body ) ? Buffer . from ( body as string , "base64" ) . toString ( ) : body ;
133
-
134
137
// Clone and low case all headers names
135
138
const sanitizedHeaders = sanitize ( headers ) ;
136
139
@@ -145,30 +148,26 @@ function parseBinary(message: Message, version: Version): CloudEvent {
145
148
}
146
149
}
147
150
148
- let parsedPayload ;
149
-
150
- if ( body ) {
151
- const parser = parserByContentType [ eventObj . datacontenttype as string ] ;
152
- if ( ! parser ) {
153
- throw new ValidationError ( `no parser found for content type ${ eventObj . datacontenttype } ` ) ;
154
- }
155
- parsedPayload = parser . parse ( body ) ;
156
- }
157
-
158
151
// Every unprocessed header can be an extension
159
152
for ( const header in sanitizedHeaders ) {
160
153
if ( header . startsWith ( CONSTANTS . EXTENSIONS_PREFIX ) ) {
161
154
eventObj [ header . substring ( CONSTANTS . EXTENSIONS_PREFIX . length ) ] = headers [ header ] ;
162
155
}
163
156
}
157
+
158
+ const parser = parserByContentType [ eventObj . datacontenttype as string ] ;
159
+ if ( parser && body ) {
160
+ body = parser . parse ( body as string ) ;
161
+ }
162
+
164
163
// At this point, if the datacontenttype is application/json and the datacontentencoding is base64
165
164
// then the data has already been decoded as a string, then parsed as JSON. We don't need to have
166
165
// the datacontentencoding property set - in fact, it's incorrect to do so.
167
166
if ( eventObj . datacontenttype === CONSTANTS . MIME_JSON && eventObj . datacontentencoding === CONSTANTS . ENCODING_BASE64 ) {
168
167
delete eventObj . datacontentencoding ;
169
168
}
170
169
171
- return new CloudEvent ( { ...eventObj , data : parsedPayload } as CloudEventV1 | CloudEventV03 , false ) ;
170
+ return new CloudEvent ( { ...eventObj , data : body } as CloudEventV1 | CloudEventV03 , false ) ;
172
171
}
173
172
174
173
/**
@@ -201,7 +200,7 @@ function parseStructured(message: Message, version: Version): CloudEvent {
201
200
const contentType = sanitizedHeaders [ CONSTANTS . HEADER_CONTENT_TYPE ] ;
202
201
const parser : Parser = contentType ? parserByContentType [ contentType ] : new JSONParser ( ) ;
203
202
if ( ! parser ) throw new ValidationError ( `invalid content type ${ sanitizedHeaders [ CONSTANTS . HEADER_CONTENT_TYPE ] } ` ) ;
204
- const incoming = { ...( parser . parse ( payload ) as Record < string , unknown > ) } ;
203
+ const incoming = { ...( parser . parse ( payload as string ) as Record < string , unknown > ) } ;
205
204
206
205
const eventObj : { [ key : string ] : unknown } = { } ;
207
206
const parserMap : Record < string , MappedParser > = version === Version . V1 ? v1structuredParsers : v03structuredParsers ;
@@ -220,10 +219,12 @@ function parseStructured(message: Message, version: Version): CloudEvent {
220
219
eventObj [ key ] = incoming [ key ] ;
221
220
}
222
221
223
- // ensure data content is correctly decoded
224
- if ( eventObj . data_base64 ) {
225
- const parser = new Base64Parser ( ) ;
226
- eventObj . data = JSON . parse ( parser . parse ( eventObj . data_base64 as string ) ) ;
222
+ // data_base64 is a property that only exists on V1 events. For V03 events,
223
+ // there will be a .datacontentencoding property, and the .data property
224
+ // itself will be encoded as base64
225
+ if ( eventObj . data_base64 || eventObj . datacontentencoding === CONSTANTS . ENCODING_BASE64 ) {
226
+ const data = eventObj . data_base64 || eventObj . data ;
227
+ eventObj . data = new Uint32Array ( Buffer . from ( data as string , "base64" ) ) ;
227
228
delete eventObj . data_base64 ;
228
229
delete eventObj . datacontentencoding ;
229
230
}
0 commit comments