diff --git a/docs/source/concepts/resource_tree.rst b/docs/source/concepts/resource_tree.rst index 2ae044f..62c50ac 100644 --- a/docs/source/concepts/resource_tree.rst +++ b/docs/source/concepts/resource_tree.rst @@ -12,8 +12,6 @@ to compose the response. We access the resource tree easily with the ``kapow set`` and ``kapow get`` subcommands. -.. // DOING #10: /route/id - .. // DOING #113: /request/ssl/client/i/dn Overview @@ -45,6 +43,9 @@ Overview │ │ └──── content The contents of the file uploaded in the form field │ └──── body HTTP request body │ + │─ route + │ └──── id Id of the route that matched this request. + │ └─ response ├──── status HTTP status code ├──── headers @@ -382,6 +383,28 @@ then, when handling the request: foobar +``/route/id`` Resource +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ID of the original route that matched this request.. + +Sample Usage +^^^^^^^^^^^^ + +If the user runs: + +.. code-block:: console + + $ curl http://kapow.example:8080/ + +then, when handling the request: + +.. code-block:: console + + $ kapow get /route/id + ecd5d63f-f28b-11ea-ac55-ec21e5089c1f + + ``/response/status`` Resource ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/internal/server/data/resource.go b/internal/server/data/resource.go index e21c40f..fb1ff8c 100644 --- a/internal/server/data/resource.go +++ b/internal/server/data/resource.go @@ -156,6 +156,12 @@ func getRequestFileContent(w http.ResponseWriter, r *http.Request, h *model.Hand } } +func getRequestId(w http.ResponseWriter, r *http.Request, h *model.Handler) { + w.Header().Add("Content-Type", "application/octet-stream") + _, _ = w.Write([]byte(h.Route.ID)) + +} + // FIXME: Allow any HTTP status code. Now we are limited by WriteHeader // capabilities func setResponseStatus(w http.ResponseWriter, r *http.Request, h *model.Handler) { diff --git a/internal/server/data/resource_test.go b/internal/server/data/resource_test.go index 5a7032b..51ee2a4 100644 --- a/internal/server/data/resource_test.go +++ b/internal/server/data/resource_test.go @@ -266,8 +266,8 @@ func TestGetRequestVersionSetsOctectStreamContentType(t *testing.T) { 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) + if v := res.Header.Get("Content-Type"); v != "application/octet-stream" { + t.Errorf("Content Type mismatch. Expected: %q, got: %q", "application/octet-stream", v) } } @@ -378,8 +378,8 @@ func TestGetRequestRemoteSetsOctectStreamContentType(t *testing.T) { getRequestRemote(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) + if v := res.Header.Get("Content-Type"); v != "application/octet-stream" { + t.Errorf("Content Type mismatch. Expected: %q, got: %q", "application/octet-stream", v) } } @@ -586,7 +586,7 @@ func TestGetRequestHeadersSetsOctectStreamContentType(t *testing.T) { res := w.Result() if v := res.Header.Get("Content-Type"); v != "application/octet-stream" { - t.Errorf("Content Type mismatch. Expected: application/octet-stream. Got: %q", v) + t.Errorf("Content Type mismatch. Expected: %q. Got: %q", "application/octet-stream", v) } } @@ -1109,7 +1109,54 @@ func TestGetRequestFileContent500sWhenHandlerRequestErrors(t *testing.T) { } } -// DOING #10: /route/id +func TestGetRouteId200sOnHappyPath(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() + + getRequestId(w, r, &h) + + res := w.Result() + if res.StatusCode != http.StatusOK { + t.Error("Status code mismatch") + } +} + +func TestGetRouteIdSetsOctectStreamContentType(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() + + getRequestId(w, r, &h) + + res := w.Result() + if v := res.Header.Get("Content-Type"); v != "application/octet-stream" { + t.Errorf("Content Type mismatch. Expected: %q, got: %q", "application/octet-stream", v) + } +} + +func TestGetRouteIdReturnsTheCorrectMethod(t *testing.T) { + h := model.Handler{ + Request: httptest.NewRequest("FOO", "/", nil), + Writer: httptest.NewRecorder(), + Route: model.Route{ID: "Expected_ID"}, + } + r := httptest.NewRequest("GET", "/not-important-here", nil) + w := httptest.NewRecorder() + + getRequestId(w, r, &h) + + res := w.Result() + if body, _ := ioutil.ReadAll(res.Body); string(body) != "Expected_ID" { + t.Errorf("Body mismatch. Expected: %q, got: %q", "Expected_ID", string(body)) + } +} func TestSetResponseStatus200sOnHappyPath(t *testing.T) { h := model.Handler{ diff --git a/internal/server/data/server.go b/internal/server/data/server.go index f5f131e..791cdc0 100644 --- a/internal/server/data/server.go +++ b/internal/server/data/server.go @@ -71,6 +71,9 @@ func Run(bindAddr string, wg *sync.WaitGroup) { {"/handlers/{handlerID}/request/files/{name}/content", "GET", getRequestFileContent}, {"/handlers/{handlerID}/request/body", "GET", getRequestBody}, + // route + //{"/handlers/{handlerID}/route/id", "GET", getRouteId}, + // response {"/handlers/{handlerID}/response/status", "PUT", lockResponseWriter(setResponseStatus)}, {"/handlers/{handlerID}/response/headers/{name}", "PUT", lockResponseWriter(setResponseHeaders)},