Skip to content
Snippets Groups Projects
Commit af89c09d authored by Will McCutchen's avatar Will McCutchen
Browse files

Add /cookies/delete handler; simplify cookie handling

Stop handling multiple cookies with the same name, and revisit in the future
if it turns out to be useful/necessary.
parent d6e94c95
No related branches found
No related tags found
No related merge requests found
......@@ -6,6 +6,7 @@ import (
"net/http"
"strconv"
"strings"
"time"
)
var acceptedMediaTypes = []string{
......@@ -246,10 +247,7 @@ func (h *HTTPBin) AbsoluteRedirect(w http.ResponseWriter, r *http.Request) {
func (h *HTTPBin) Cookies(w http.ResponseWriter, r *http.Request) {
resp := cookiesResponse{}
for _, c := range r.Cookies() {
if _, found := resp[c.Name]; !found {
resp[c.Name] = []string{}
}
resp[c.Name] = append(resp[c.Name], c.Value)
resp[c.Name] = c.Value
}
body, _ := json.Marshal(resp)
writeJSON(w, body, http.StatusOK)
......@@ -259,15 +257,29 @@ func (h *HTTPBin) Cookies(w http.ResponseWriter, r *http.Request) {
// Cookies endpoint
func (h *HTTPBin) SetCookies(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
for k, vs := range params {
for _, v := range vs {
fmt.Printf("setting cookie %#v = %#v\n", k, v)
for k := range params {
http.SetCookie(w, &http.Cookie{
Name: k,
Value: v,
Value: params.Get(k),
HttpOnly: true,
})
}
w.Header().Set("Location", "/cookies")
w.WriteHeader(http.StatusFound)
}
// DeleteCookies deletes cookies specified in query params and redirects to
// Cookies endpoint
func (h *HTTPBin) DeleteCookies(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
for k := range params {
http.SetCookie(w, &http.Cookie{
Name: k,
Value: params.Get(k),
HttpOnly: true,
MaxAge: -1,
Expires: time.Now().Add(-1 * 24 * 365 * time.Hour),
})
}
w.Header().Set("Location", "/cookies")
w.WriteHeader(http.StatusFound)
......
......@@ -11,6 +11,7 @@ import (
"reflect"
"strings"
"testing"
"time"
)
const maxMemory = 1024 * 1024
......@@ -812,14 +813,12 @@ func TestRedirects(t *testing.T) {
func TestCookies(t *testing.T) {
testCookies := func(t *testing.T, cookies cookiesResponse) {
r, _ := http.NewRequest("GET", "/cookies", nil)
for k, vs := range cookies {
for _, v := range vs {
for k, v := range cookies {
r.AddCookie(&http.Cookie{
Name: k,
Value: v,
})
}
}
w := httptest.NewRecorder()
handler.ServeHTTP(w, r)
......@@ -841,28 +840,24 @@ func TestCookies(t *testing.T) {
testCookies(t, cookiesResponse{})
})
t.Run("ok/single cookies", func(t *testing.T) {
t.Run("ok/cookies", func(t *testing.T) {
testCookies(t, cookiesResponse{
"k1": {"v1"},
"k2": {"v2"},
})
})
t.Run("ok/duplicate cookies", func(t *testing.T) {
testCookies(t, cookiesResponse{
"k1": {"v1"},
"k2": {"v2a", "v2b"},
"k1": "v1",
"k2": "v2",
})
})
}
func TestSetCookies(t *testing.T) {
cookies := cookiesResponse{
"k1": {"v1"},
"k2": {"v2a", "v2b"},
"k1": "v1",
"k2": "v2",
}
params := url.Values(cookies)
params := &url.Values{}
for k, v := range cookies {
params.Set(k, v)
}
r, _ := http.NewRequest("GET", fmt.Sprintf("/cookies/set?%s", params.Encode()), nil)
w := httptest.NewRecorder()
......@@ -872,18 +867,44 @@ func TestSetCookies(t *testing.T) {
assertHeader(t, w, "Location", "/cookies")
for _, c := range w.Result().Cookies() {
values, ok := cookies[c.Name]
v, ok := cookies[c.Name]
if !ok {
t.Fatalf("got unexpected cookie %s=%s", c.Name, c.Value)
}
found := false
for _, v := range values {
if v == c.Value {
found = true
if v != c.Value {
t.Fatalf("got cookie %s=%s, expected value in %#v", c.Name, c.Value, v)
}
}
}
func TestDeleteCookies(t *testing.T) {
cookies := cookiesResponse{
"k1": "v1",
"k2": "v2",
}
toDelete := "k2"
params := &url.Values{}
params.Set(toDelete, "")
r, _ := http.NewRequest("GET", fmt.Sprintf("/cookies/delete?%s", params.Encode()), nil)
for k, v := range cookies {
r.AddCookie(&http.Cookie{
Name: k,
Value: v,
})
}
w := httptest.NewRecorder()
handler.ServeHTTP(w, r)
assertStatusCode(t, w, http.StatusFound)
assertHeader(t, w, "Location", "/cookies")
for _, c := range w.Result().Cookies() {
if c.Name == toDelete {
if time.Now().Sub(c.Expires) < (24*365-1)*time.Hour {
t.Fatalf("expected cookie %s to be deleted; got %#v", toDelete, c)
}
if !found {
t.Fatalf("got cookie %s=%s, expected value in %#v", c.Name, c.Value, values)
}
}
}
......@@ -39,7 +39,7 @@ type bodyResponse struct {
JSON interface{} `json:"json"`
}
type cookiesResponse map[string][]string
type cookiesResponse map[string]string
// Options are used to configure HTTPBin
type Options struct {
......@@ -77,6 +77,7 @@ func (h *HTTPBin) Handler() http.Handler {
mux.HandleFunc("/cookies", h.Cookies)
mux.HandleFunc("/cookies/set", h.SetCookies)
mux.HandleFunc("/cookies/delete", h.DeleteCookies)
// Make sure our ServeMux doesn't "helpfully" redirect these invalid
// endpoints by adding a trailing slash. See the ServeMux docs for more
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment