Skip to content

Commit

Permalink
Make sure event body is a string (#393)
Browse files Browse the repository at this point in the history
* Add form to string conversion in eventFromRequest

* Reformat logic

* Change a func name

* Update the switch case logic

* Remove the function

* Add comment to explain the process

* Update comment

* Add Provider mock

* Add encoding test

* Add missing break

* Fix the test

* Remove breaks

* Rename a test func

* Add multiple scenarios in the test

* Change a key name

* Add test case for multipart/form-data
  • Loading branch information
RaeesBhatti authored Mar 26, 2018
1 parent f673e72 commit 0da4cd7
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 4 deletions.
18 changes: 14 additions & 4 deletions router/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type HTTPResponse struct {

const (
mimeJSON = "application/json"
mimeFormMultipart = "multipart/form-data"
mimeFormURLEncoded = "application/x-www-form-urlencoded"
)

func isHTTPEvent(r *http.Request) bool {
Expand Down Expand Up @@ -63,10 +65,18 @@ func (router *Router) eventFromRequest(r *http.Request) (*eventpkg.Event, string
}

event := eventpkg.New(eventType, mime, body)
if mime == mimeJSON && len(body) > 0 {
err = json.Unmarshal(body, &event.Data)
if err != nil {
return nil, "", errors.New("malformed JSON body")

// Because event.Data is []bytes here, 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, so that, it is left intact.
if len(body) > 0 {
switch {
case mime == mimeJSON:
err := json.Unmarshal(body, &event.Data)
if err != nil {
return nil, "", errors.New("malformed JSON body")
}
case strings.HasPrefix(mime, mimeFormMultipart), mime == mimeFormURLEncoded:
event.Data = string(body)
}
}

Expand Down
1 change: 1 addition & 0 deletions router/mock/mock.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:generate mockgen -package mock -destination ./targetcache.go github.com/serverless/event-gateway/router Targeter
//go:generate mockgen -package mock -destination ./provider.go github.com/serverless/event-gateway/function Provider

package mock
59 changes: 59 additions & 0 deletions router/mock/provider.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 54 additions & 0 deletions router/router_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package router_test

import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
Expand All @@ -13,6 +14,7 @@ import (
"github.com/serverless/event-gateway/function"
"github.com/serverless/event-gateway/internal/pathtree"
"github.com/serverless/event-gateway/plugin"
httpprovider "github.com/serverless/event-gateway/providers/http"
"github.com/serverless/event-gateway/router"
"github.com/serverless/event-gateway/router/mock"
"github.com/serverless/event-gateway/subscription"
Expand Down Expand Up @@ -101,6 +103,58 @@ func TestRouterServeHTTP_ErrorMalformedCustomEventJSONRequest(t *testing.T) {
assert.Equal(t, `{"errors":[{"message":"malformed JSON body"}]}`+"\n", recorder.Body.String())
}

func TestRouterServeHTTP_Encoding(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
tests := []map[string]string{
{
"body": "some=thing",
"expected": "c29tZT10aGluZw==",
"content-type": "",
},
{
"body": "some=thing",
"expected": "some=thing",
"content-type": "application/x-www-form-urlencoded",
},
{
"body": "--X-INSOMNIA-BOUNDARY\r\nContent-Disposition: form-data; name=\"some\"\r\n\r\nthing\r\n--X-INSOMNIA-BOUNDARY--\r\n",
"expected": "--X-INSOMNIA-BOUNDARY\r\nContent-Disposition: form-data; name=\"some\"\r\n\r\nthing\r\n--X-INSOMNIA-BOUNDARY--\r\n",
"content-type": "multipart/form-data; boundary=X-INSOMNIA-BOUNDARY",
},
}
for _, test := range tests {
testListServer := httptest.NewServer(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
testevent := event.Event{
Data: event.HTTPEvent{},
}
json.NewDecoder(r.Body).Decode(&testevent)

assert.Equal(t, test["expected"], testevent.Data.(map[string]interface{})["body"])
}))
defer testListServer.Close()
target := mock.NewMockTargeter(ctrl)
someFunc := function.Function{
Space: "",
ID: "somefunc",
ProviderType: httpprovider.Type,
Provider: httpprovider.HTTP{
URL: testListServer.URL,
},
}
target.EXPECT().HTTPBackingFunction(http.MethodPost, "/").Return("", &someFunc.ID, pathtree.Params{}, nil)
target.EXPECT().Function("", someFunc.ID).Return(&someFunc)
target.EXPECT().SubscribersOfEvent(gomock.Any(), gomock.Any()).Return([]router.FunctionInfo{}).MaxTimes(3)
router := testrouter(target)

req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(test["body"]))
req.Header.Set("content-type", test["content-type"])
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, req)
}
}

func TestRouterServeHTTP_ErrorOnCustomEventEmittedWithNonPostMethod(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Expand Down

0 comments on commit 0da4cd7

Please sign in to comment.