@@ -2,6 +2,7 @@ package http
2
2
3
3
import (
4
4
"context"
5
+ "encoding/base64"
5
6
"encoding/json"
6
7
"fmt"
7
8
"io/ioutil"
@@ -29,6 +30,34 @@ const (
29
30
PubSubHandlerDropStatusCode int = http .StatusSeeOther
30
31
)
31
32
33
+ // topicEventJSON is identical to `common.TopicEvent`
34
+ // except for it treats `data` as a json.RawMessage so it can
35
+ // be used as bytes or interface{}.
36
+ type topicEventJSON struct {
37
+ // ID identifies the event.
38
+ ID string `json:"id"`
39
+ // The version of the CloudEvents specification.
40
+ SpecVersion string `json:"specversion"`
41
+ // The type of event related to the originating occurrence.
42
+ Type string `json:"type"`
43
+ // Source identifies the context in which an event happened.
44
+ Source string `json:"source"`
45
+ // The content type of data value.
46
+ DataContentType string `json:"datacontenttype"`
47
+ // The content of the event.
48
+ // Note, this is why the gRPC and HTTP implementations need separate structs for cloud events.
49
+ Data json.RawMessage `json:"data"`
50
+ // The base64 encoding content of the event.
51
+ // Note, this is processing rawPayload and binary content types.
52
+ DataBase64 string `json:"data_base64,omitempty"`
53
+ // Cloud event subject
54
+ Subject string `json:"subject"`
55
+ // The pubsub topic which publisher sent to.
56
+ Topic string `json:"topic"`
57
+ // PubsubName is name of the pub/sub this message came from
58
+ PubsubName string `json:"pubsubname"`
59
+ }
60
+
32
61
func (s * Server ) registerBaseHandler () {
33
62
// register subscribe handler
34
63
f := func (w http.ResponseWriter , r * http.Request ) {
@@ -168,21 +197,78 @@ func (s *Server) AddTopicEventHandler(sub *common.Subscription, fn func(ctx cont
168
197
}
169
198
170
199
// deserialize the event
171
- var in common. TopicEvent
200
+ var in topicEventJSON
172
201
if err := json .NewDecoder (r .Body ).Decode (& in ); err != nil {
173
202
http .Error (w , err .Error (), PubSubHandlerDropStatusCode )
174
203
return
175
204
}
176
205
206
+ if in .PubsubName == "" {
207
+ in .Topic = sub .PubsubName
208
+ }
177
209
if in .Topic == "" {
178
210
in .Topic = sub .Topic
179
211
}
180
212
213
+ var data interface {}
214
+ var rawData []byte
215
+ if len (in .Data ) > 0 {
216
+ rawData = []byte (in .Data )
217
+ data = rawData
218
+ var v interface {}
219
+ // We can assume that rawData is valid JSON
220
+ // without checking in.DataContentType == "application/json".
221
+ if err := json .Unmarshal (rawData , & v ); err == nil {
222
+ data = v
223
+ // Handling of JSON base64 encoded or escaped in a string.
224
+ if str , ok := v .(string ); ok {
225
+ // This is the path that will most likely succeed.
226
+ var vString interface {}
227
+ if err := json .Unmarshal ([]byte (str ), & vString ); err == nil {
228
+ data = vString
229
+ } else if decoded , err := base64 .StdEncoding .DecodeString (str ); err == nil {
230
+ // Decoded Base64 encoded JSON does not seem to be in the spec
231
+ // but it is in existing unit tests so this handles that case.
232
+ var vBase64 interface {}
233
+ if err := json .Unmarshal (decoded , & vBase64 ); err == nil {
234
+ data = vBase64
235
+ }
236
+ }
237
+ }
238
+ }
239
+ } else if in .DataBase64 != "" {
240
+ var err error
241
+ rawData , err = base64 .StdEncoding .DecodeString (in .DataBase64 )
242
+ if err == nil {
243
+ data = rawData
244
+ if in .DataContentType == "application/json" {
245
+ var v interface {}
246
+ if err := json .Unmarshal (rawData , & v ); err == nil {
247
+ data = v
248
+ }
249
+ }
250
+ }
251
+ }
252
+
253
+ te := common.TopicEvent {
254
+ ID : in .ID ,
255
+ SpecVersion : in .SpecVersion ,
256
+ Type : in .Type ,
257
+ Source : in .Source ,
258
+ DataContentType : in .DataContentType ,
259
+ Data : data ,
260
+ RawData : rawData ,
261
+ DataBase64 : in .DataBase64 ,
262
+ Subject : in .Subject ,
263
+ PubsubName : in .PubsubName ,
264
+ Topic : in .Topic ,
265
+ }
266
+
181
267
w .Header ().Add ("Content-Type" , "application/json" )
182
268
w .WriteHeader (http .StatusOK )
183
269
184
270
// execute user handler
185
- retry , err := fn (r .Context (), & in )
271
+ retry , err := fn (r .Context (), & te )
186
272
if err == nil {
187
273
writeStatus (w , common .SubscriptionResponseStatusSuccess )
188
274
return
0 commit comments