aboutsummaryrefslogtreecommitdiff
path: root/lib/http
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2018-12-18 01:39:13 +0700
committerShulhan <ms@kilabit.info>2018-12-18 01:43:17 +0700
commitf4d2a279cf7b6639b1228fa55c26f3b9f4a24c0d (patch)
treebf1d1a2d9dfbb6734f800356fcbb4d847c3ec26c /lib/http
parent6a3a65ec455aeb4b1b072f8f3a760f6593509a5d (diff)
downloadpakakeh.go-f4d2a279cf7b6639b1228fa55c26f3b9f4a24c0d.tar.xz
lib/http: add evaluator, a middleware between request and handler
Diffstat (limited to 'lib/http')
-rw-r--r--lib/http/evaluator.go21
-rw-r--r--lib/http/handler.go12
-rw-r--r--lib/http/server.go13
-rw-r--r--lib/http/server_test.go64
4 files changed, 107 insertions, 3 deletions
diff --git a/lib/http/evaluator.go b/lib/http/evaluator.go
new file mode 100644
index 00000000..16fcd477
--- /dev/null
+++ b/lib/http/evaluator.go
@@ -0,0 +1,21 @@
+// Copyright 2018, Shulhan <ms@kilabit.info>. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "net/http"
+)
+
+//
+// Evaluator is an interface for middleware between actual request and handler.
+//
+type Evaluator interface {
+ //
+ // Evaluate the request. If request is invalid, the error will tell
+ // the response code and the error message to be written back to
+ // client.
+ //
+ Evaluate(req *http.Request, reqBody []byte) error
+}
diff --git a/lib/http/handler.go b/lib/http/handler.go
index 0328f6fc..f35a968c 100644
--- a/lib/http/handler.go
+++ b/lib/http/handler.go
@@ -21,7 +21,9 @@ type handler struct {
cb Callback
}
-func (h *handler) call(res http.ResponseWriter, req *http.Request) {
+func (h *handler) call(res http.ResponseWriter, req *http.Request,
+ evaluators []Evaluator,
+) {
var (
e error
reqBody []byte
@@ -56,6 +58,14 @@ func (h *handler) call(res http.ResponseWriter, req *http.Request) {
log.Printf("> request body: %s\n", reqBody)
}
+ for _, eval := range evaluators {
+ e := eval.Evaluate(req, reqBody)
+ if e != nil {
+ h.error(res, e)
+ return
+ }
+ }
+
rspb, e := h.cb(req, reqBody)
if e != nil {
log.Printf("handler.call: %d %s %s %s\n",
diff --git a/lib/http/server.go b/lib/http/server.go
index 5ae5808d..6f72b630 100644
--- a/lib/http/server.go
+++ b/lib/http/server.go
@@ -23,6 +23,7 @@ import (
//
type Server struct {
mfs *memfs.MemFS
+ evals []Evaluator
conn *http.Server
regDelete map[string]*handler
regGet map[string]*handler
@@ -80,6 +81,14 @@ func (srv *Server) RegisterDelete(
}
//
+// RegisterEvaluator register HTTP middleware that will be called before
+// handler callback is called.
+//
+func (srv *Server) RegisterEvaluator(eval Evaluator) {
+ srv.evals = append(srv.evals, eval)
+}
+
+//
// RegisterGet register HTTP method GET with callback to handle it.
//
func (srv *Server) RegisterGet(
@@ -167,7 +176,7 @@ func (srv *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) {
return
}
- h.call(res, req)
+ h.call(res, req, srv.evals)
}
//
@@ -238,7 +247,7 @@ func (srv *Server) handleFS(
func (srv *Server) handleGet(res http.ResponseWriter, req *http.Request) {
h, ok := srv.regGet[req.URL.Path]
if ok {
- h.call(res, req)
+ h.call(res, req, srv.evals)
return
}
diff --git a/lib/http/server_test.go b/lib/http/server_test.go
index beefad40..e40276e4 100644
--- a/lib/http/server_test.go
+++ b/lib/http/server_test.go
@@ -180,6 +180,70 @@ func TestRegisterDelete(t *testing.T) {
}
}
+type testEvaluator struct{}
+
+func (te *testEvaluator) Evaluate(req *http.Request, reqBody []byte) error {
+ k := req.Form.Get("k")
+
+ if len(k) == 0 {
+ return &errors.E{
+ Code: http.StatusBadRequest,
+ Message: "Missing input value for k",
+ }
+ }
+
+ return nil
+}
+
+func TestRegisterEvaluator(t *testing.T) {
+ te := new(testEvaluator)
+
+ testServer.RegisterDelete("/evaluate", ResponseTypeJSON, cbPlain)
+
+ testServer.RegisterEvaluator(te)
+
+ cases := []struct {
+ desc string
+ reqURL string
+ expStatusCode int
+ }{{
+ desc: "With invalid evaluate",
+ reqURL: "http://127.0.0.1:8080/evaluate",
+ expStatusCode: http.StatusBadRequest,
+ }, {
+ desc: "With valid evaluate",
+ reqURL: "http://127.0.0.1:8080/evaluate?k=v",
+ expStatusCode: http.StatusOK,
+ }}
+
+ for _, c := range cases {
+ t.Log(c.desc)
+
+ req, e := http.NewRequest(http.MethodDelete, c.reqURL, nil)
+ if e != nil {
+ t.Fatal(e)
+ }
+
+ res, e := client.Do(req)
+ if e != nil {
+ t.Fatal(e)
+ }
+
+ _, e = ioutil.ReadAll(res.Body)
+ if e != nil {
+ t.Fatal(e)
+ }
+
+ e = res.Body.Close()
+ if e != nil {
+ t.Fatal(e)
+ }
+
+ test.Assert(t, "StatusCode", c.expStatusCode, res.StatusCode,
+ true)
+ }
+}
+
func TestRegisterGet(t *testing.T) {
testServer.RegisterGet("/get", ResponseTypePlain, cbPlain)