Skip to content

Commit

Permalink
Fix payload normalization in http.request events. Closes #434 (#459)
Browse files Browse the repository at this point in the history
  • Loading branch information
mthenw committed Jun 8, 2018
1 parent 1c89d5c commit 83d3405
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 19 deletions.
34 changes: 20 additions & 14 deletions event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func New(eventType TypeName, mimeType string, payload interface{}) *Event {
},
}

event.enhanceEventData()
event.Data = normalizePayload(event.Data, event.ContentType)
return event
}

Expand Down Expand Up @@ -101,7 +101,7 @@ func FromRequest(r *http.Request) (*Event, error) {
return New(TypeName(r.Header.Get("event")), mimeType, body), nil
}

return New(TypeHTTPRequest, mimeCloudEventsJSON, NewHTTPRequestData(r, body)), nil
return New(TypeHTTPRequest, mimeJSON, NewHTTPRequestData(r, body)), nil
}

// Validate Event struct
Expand Down Expand Up @@ -199,7 +199,7 @@ func parseAsCloudEventBinary(headers http.Header, payload interface{}) (*Event,
}
}

event.enhanceEventData()
event.Data = normalizePayload(event.Data, event.ContentType)
return event, nil
}

Expand All @@ -217,7 +217,7 @@ func parseAsCloudEvent(mime string, payload interface{}) (*Event, error) {
return nil, err
}

event.enhanceEventData()
event.Data = normalizePayload(event.Data, event.ContentType)
return event, nil
}

Expand All @@ -231,17 +231,23 @@ const (
mimeCloudEventsJSON = "application/cloudevents+json"
)

// Because event.Data is []byte, it will be base64 encoded by default when being sent to remote function,
// which is why we change the event.Data type to "string" for forms or to map[string]interface{} for JSON
// so that, it is left intact.
func (e *Event) enhanceEventData() {
contentType := e.ContentType
if eventBody, ok := e.Data.([]byte); ok && len(eventBody) > 0 {
// normalizePayload takes anything, checks if it's []byte array and depending on provided mime
// type converts it to either string or map[string]interface to avoid having base64 string after
// JSON marshaling.
func normalizePayload(payload interface{}, mime string) interface{} {
if bytePayload, ok := payload.([]byte); ok && len(bytePayload) > 0 {
switch {
case contentType == mimeJSON || strings.HasSuffix(contentType, "+json"):
json.Unmarshal(eventBody, &e.Data)
case strings.HasPrefix(contentType, mimeFormMultipart), contentType == mimeFormURLEncoded:
e.Data = string(eventBody)
case mime == mimeJSON || strings.HasSuffix(mime, "+json"):
var result map[string]interface{}
err := json.Unmarshal(bytePayload, &result)
if err != nil {
return payload
}
return result
case strings.HasPrefix(mime, mimeFormMultipart), mime == mimeFormURLEncoded:
return string(bytePayload)
}
}

return payload
}
10 changes: 6 additions & 4 deletions event/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,22 +268,24 @@ var fromRequestTests = []struct {
},
},
{
name: "regular HTTP request",
name: "regular HTTP JSON request",
requestHeaders: http.Header{
"Content-Type": []string{"application/json"},
},
requestBody: []byte("hey there"),
requestBody: []byte(`{"key": "value"}`),
expectedEvent: &eventpkg.Event{
EventType: eventpkg.TypeHTTPRequest,
CloudEventsVersion: "0.1",
Source: "https://serverless.com/event-gateway/#transformationVersion=0.1",
ContentType: "application/cloudevents+json",
ContentType: "application/json",
Data: &eventpkg.HTTPRequestData{
Headers: map[string]string{
"Content-Type": "application/json",
},
Query: map[string][]string{},
Body: []byte("hey there"),
Body: map[string]interface{}{
"key": "value",
},
},
Extensions: map[string]interface{}{
"eventgateway": map[string]interface{}{"transformed": "true", "transformation-version": "0.1"}},
Expand Down
5 changes: 4 additions & 1 deletion event/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ type HTTPRequestData struct {

// NewHTTPRequestData returns a new instance of HTTPRequestData
func NewHTTPRequestData(r *http.Request, eventData interface{}) *HTTPRequestData {
return &HTTPRequestData{
req := &HTTPRequestData{
Headers: ihttp.FlattenHeader(r.Header),
Query: r.URL.Query(),
Body: eventData,
Host: r.Host,
Path: r.URL.Path,
Method: r.Method,
}

req.Body = normalizePayload(req.Body, r.Header.Get("content-type"))
return req
}

0 comments on commit 83d3405

Please sign in to comment.