diff --git a/docs/source/concepts/resource_tree.rst b/docs/source/concepts/resource_tree.rst index 423bc6e5..b02bc58d 100644 --- a/docs/source/concepts/resource_tree.rst +++ b/docs/source/concepts/resource_tree.rst @@ -12,6 +12,11 @@ to compose the response. We access the resource tree easily with the ``kapow set`` and ``kapow get`` subcommands. +.. // DOING #85: /request/remote + +.. // DOING #10: /route/id + +.. // DOING #113: /request/ssl/client/i/dn Overview -------- @@ -23,6 +28,7 @@ Overview ├─ request │ ├──── method HTTP Method used (GET, POST) │ ├──── host Host part of the URL + │ ├──── version HTTP version of the request │ ├──── path Complete URL path (URL-unquoted) │ ├──── matches │ │ └──── Previously matched URL path parts diff --git a/internal/server/data/resource.go b/internal/server/data/resource.go index 48ce0e85..53982fd7 100644 --- a/internal/server/data/resource.go +++ b/internal/server/data/resource.go @@ -57,6 +57,11 @@ func getRequestHost(w http.ResponseWriter, r *http.Request, h *model.Handler) { _, _ = w.Write([]byte(h.Request.Host)) } +func getRequestVersion(w http.ResponseWriter, r *http.Request, h *model.Handler) { + w.Header().Add("Content-Type", "application/octet-stream") + _, _ = w.Write([]byte(r.Proto)) +} + func getRequestPath(w http.ResponseWriter, r *http.Request, h *model.Handler) { w.Header().Add("Content-Type", "application/octet-stream") // TODO: Discuss a how to obtain URL.EscapedPath() instead diff --git a/internal/server/data/resource_test.go b/internal/server/data/resource_test.go index 6951d8ee..2303ee27 100644 --- a/internal/server/data/resource_test.go +++ b/internal/server/data/resource_test.go @@ -206,6 +206,22 @@ func TestGetRequestHost200sOnHappyPath(t *testing.T) { } } +func TestGetRequestHostSetsOctectStreamContentType(t *testing.T) { + h := model.Handler{ + Request: httptest.NewRequest("POST", "/", nil), + Writer: httptest.NewRecorder(), + } + r := httptest.NewRequest("GET", "/not-important-here", nil) + w := httptest.NewRecorder() + + getRequestHost(w, r, &h) + + res := w.Result() + if res.Header.Get("Content-Type") != "application/octet-stream" { + t.Error("Content Type mismatch") + } +} + func TestGetRequestHostReturnsTheCorrectHostname(t *testing.T) { h := model.Handler{ Request: httptest.NewRequest("POST", "http://www.foo.bar:8080/", nil), @@ -222,7 +238,7 @@ func TestGetRequestHostReturnsTheCorrectHostname(t *testing.T) { } } -func TestGetRequestHostSetsOctectStreamContentType(t *testing.T) { +func TestGetRequestVersion200sOnHappyPath(t *testing.T) { h := model.Handler{ Request: httptest.NewRequest("POST", "/", nil), Writer: httptest.NewRecorder(), @@ -230,14 +246,48 @@ func TestGetRequestHostSetsOctectStreamContentType(t *testing.T) { r := httptest.NewRequest("GET", "/not-important-here", nil) w := httptest.NewRecorder() - getRequestHost(w, r, &h) + getRequestVersion(w, r, &h) res := w.Result() - if res.Header.Get("Content-Type") != "application/octet-stream" { - t.Error("Content Type mismatch") + if res.StatusCode != http.StatusOK { + t.Errorf("Status code mismatch. Expected: %d, got: %d", http.StatusOK, res.StatusCode) } } +func TestGetRequestVersionSetsOctectStreamContentType(t *testing.T) { + h := model.Handler{ + Request: httptest.NewRequest("POST", "/", nil), + Writer: httptest.NewRecorder(), + } + r := httptest.NewRequest("GET", "/not-important-here", nil) + w := httptest.NewRecorder() + + getRequestVersion(w, r, &h) + + res := w.Result() + if ct := res.Header.Get("Content-Type"); ct != "application/octet-stream" { + t.Errorf("Content Type mismatch. Expected: %v, got: %v", "application/octet-stream", ct) + } +} + +func TestGetRequestVersionReturnsTheCorrectHttpVersion(t *testing.T) { + h := model.Handler{ + Request: httptest.NewRequest("POST", "http://www.foo.bar:8080/", nil), + Writer: httptest.NewRecorder(), + } + r := httptest.NewRequest("GET", "/not-important-here", nil) + w := httptest.NewRecorder() + + getRequestVersion(w, r, &h) + + res := w.Result() + if body, _ := ioutil.ReadAll(res.Body); string(body) != "HTTP/1.1" { + t.Errorf("Version mismatch. Expected %v, got %v", "HTTP/1.1", string(body)) + } +} + +// DOING #85: /request/remote + func TestGetRequestPath200sOnHappyPath(t *testing.T) { h := model.Handler{ Request: httptest.NewRequest("POST", "/", nil), @@ -302,6 +352,8 @@ func TestGetRequestPathDoesntReturnQueryStringParams(t *testing.T) { } } +// DOING #113: /request/ssl/client/i/dn + func createMuxRequest(pattern, url, method string, content io.Reader) (req *http.Request) { m := mux.NewRouter() m.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { req = r }) @@ -589,6 +641,8 @@ func TestGetRequestHeadersReturnsTheFirstCorrectMatchValue(t *testing.T) { } } +// DOING #78: /request/headers/Host /request/headers/host + func TestGetRequestCookies200sOnHappyPath(t *testing.T) { h := model.Handler{ Request: httptest.NewRequest("GET", "/", nil), @@ -1005,6 +1059,8 @@ func TestGetRequestFileContent500sWhenHandlerRequestErrors(t *testing.T) { } } +// DOING #10: /route/id + func TestSetResponseStatus200sOnHappyPath(t *testing.T) { h := model.Handler{ Request: httptest.NewRequest("POST", "/", nil),