From efaa0ba375aa30ed3710247a68d2c48bfc01d0ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Thu, 17 Oct 2019 17:14:38 +0200 Subject: [PATCH] Implement getRequestForm. Co-authored-by: Hector Hurtado --- internal/server/data/resource.go | 20 ++++ internal/server/data/resource_test.go | 142 ++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/internal/server/data/resource.go b/internal/server/data/resource.go index 0121624..31817df 100644 --- a/internal/server/data/resource.go +++ b/internal/server/data/resource.go @@ -81,3 +81,23 @@ func getRequestCookies(w http.ResponseWriter, r *http.Request, h *model.Handler) w.WriteHeader(http.StatusNotFound) } } + +// NOTE: The current implementation doesn't allow us to decode +// form encoded data sent in a request with an arbitrary method. This is +// needed for Kapow! semantic so it MUST be changed in the future +// FIXME: Implement a ParseForm function that doesn't care about Method +// nor Content-Type +func getRequestForm(w http.ResponseWriter, r *http.Request, h *model.Handler) { + w.Header().Add("Content-Type", "application/octet-stream") + name := mux.Vars(r)["name"] + // FIXME: This SHOULD? return an error when Body is empty and IS NOT + // We tried to exercise this execution path but didn't know how. + err := h.Request.ParseForm() + if err != nil { + w.WriteHeader(http.StatusNotFound) + } else if values, ok := h.Request.Form[name]; ok { + _, _ = w.Write([]byte(values[0])) + } else { + w.WriteHeader(http.StatusNotFound) + } +} diff --git a/internal/server/data/resource_test.go b/internal/server/data/resource_test.go index b810106..05063ab 100644 --- a/internal/server/data/resource_test.go +++ b/internal/server/data/resource_test.go @@ -2,10 +2,12 @@ package data import ( "errors" + // "fmt" "io" "io/ioutil" "net/http" "net/http/httptest" + "net/url" "strings" "testing" @@ -656,3 +658,143 @@ func TestGetRequestCookiesReturnsTheFirstCorrectMatchValue(t *testing.T) { t.Errorf("Body mismatch. Expected: BAZ. Got: %v", string(body)) } } + +// NOTE: The current implementation doesn't allow us to decode +// form encoded data sent in a request with an arbitrary method. This is +// needed for Kapow! semantic so it MUST be changed in the future + +// FIXME: Test form decoding with GET method +// FIXME: Test form decoding without Content-Type: +// application/x-www-form-urlencoded header + +func TestGetRequestForm200sOnHappyPath(t *testing.T) { + form := url.Values{} + form.Add("bar", "BAZ") + h := model.Handler{ + Request: httptest.NewRequest("POST", "/", strings.NewReader(form.Encode())), + Writer: httptest.NewRecorder(), + } + h.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + r := createMuxRequest("/handlers/HANDLERID/request/form/{name}", "/handlers/HANDLERID/request/form/bar", "GET") + w := httptest.NewRecorder() + + getRequestForm(w, r, &h) + + res := w.Result() + if res.StatusCode != http.StatusOK { + t.Errorf("Status code mismatch. Expected: 200, Got: %d", res.StatusCode) + } +} + +func TestGetRequestFormSetsOctectStreamContentType(t *testing.T) { + form := url.Values{} + form.Add("bar", "BAZ") + h := model.Handler{ + Request: httptest.NewRequest("POST", "/", strings.NewReader(form.Encode())), + Writer: httptest.NewRecorder(), + } + h.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + r := createMuxRequest("/handlers/HANDLERID/request/form/{name}", "/handlers/HANDLERID/request/form/bar", "GET") + w := httptest.NewRecorder() + + getRequestForm(w, r, &h) + + res := w.Result() + if res.Header.Get("Content-Type") != "application/octet-stream" { + t.Error("Content Type mismatch") + } +} + +func TestGetRequestFormReturnsTheCorrectMatchValue(t *testing.T) { + form := url.Values{} + form.Add("bar", "BAZ") + h := model.Handler{ + Request: httptest.NewRequest("POST", "/", strings.NewReader(form.Encode())), + Writer: httptest.NewRecorder(), + } + h.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + r := createMuxRequest("/handlers/HANDLERID/request/form/{name}", "/handlers/HANDLERID/request/form/bar", "GET") + w := httptest.NewRecorder() + + getRequestForm(w, r, &h) + + res := w.Result() + if body, _ := ioutil.ReadAll(res.Body); string(body) != "BAZ" { + t.Errorf("Body mismatch. Expected: BAZ. Got: %v", string(body)) + } +} + +func TestGetRequestForm404sWhenFieldDoesntExist(t *testing.T) { + form := url.Values{} + form.Add("foo", "BAZ") + h := model.Handler{ + Request: httptest.NewRequest("POST", "/", strings.NewReader(form.Encode())), + Writer: httptest.NewRecorder(), + } + h.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + r := createMuxRequest("/handlers/HANDLERID/request/form/{name}", "/handlers/HANDLERID/request/form/bar", "GET") + w := httptest.NewRecorder() + + getRequestForm(w, r, &h) + + res := w.Result() + if res.StatusCode != http.StatusNotFound { + t.Errorf("Status code mismatch. Expected: 404, Got: %d", res.StatusCode) + } +} + +func TestGetRequestForm200sWhenFieldIsEmptyString(t *testing.T) { + form := url.Values{} + form.Add("bar", "") + h := model.Handler{ + Request: httptest.NewRequest("POST", "/", strings.NewReader(form.Encode())), + Writer: httptest.NewRecorder(), + } + h.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + r := createMuxRequest("/handlers/HANDLERID/request/form/{name}", "/handlers/HANDLERID/request/form/bar", "GET") + w := httptest.NewRecorder() + + getRequestForm(w, r, &h) + + res := w.Result() + if res.StatusCode != http.StatusOK { + t.Errorf("Status code mismatch. Expected: 200, Got: %d", res.StatusCode) + } +} + +func TestGetRequestFormReturnsEmptyBodyWhenFieldIsEmptyString(t *testing.T) { + form := url.Values{} + form.Add("bar", "") + h := model.Handler{ + Request: httptest.NewRequest("POST", "/", strings.NewReader(form.Encode())), + Writer: httptest.NewRecorder(), + } + h.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + r := createMuxRequest("/handlers/HANDLERID/request/form/{name}", "/handlers/HANDLERID/request/form/bar", "GET") + w := httptest.NewRecorder() + + getRequestForm(w, r, &h) + + res := w.Result() + if body, _ := ioutil.ReadAll(res.Body); string(body) != "" { + t.Errorf(`Body mismatch. Expected: "". Got: %q`, string(body)) + } +} + +// TODO: Discuss how to manage this use case, Not Found, Bad Request, ... +func TestGetRequestForm404sWhenFormDoesntExist(t *testing.T) { + h := model.Handler{ + Request: httptest.NewRequest("POST", "/", nil), + Writer: httptest.NewRecorder(), + } + h.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + r := createMuxRequest("/handlers/HANDLERID/request/form/{name}", "/handlers/HANDLERID/request/form/bar", "GET") + w := httptest.NewRecorder() + + getRequestForm(w, r, &h) + + res := w.Result() + if res.StatusCode != http.StatusNotFound { + t.Errorf("Status code mismatch. Expected: 404, Got: %d", res.StatusCode) + } +}