Skip to content

Commit

Permalink
simple method dispatcher middleware added
Browse files Browse the repository at this point in the history
  • Loading branch information
kpacha committed Dec 18, 2018
1 parent 55df068 commit 3e814cb
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 19 deletions.
7 changes: 0 additions & 7 deletions router/mux/endpoint.go
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"net/http"
"strings"

"github.com/devopsfaith/krakend/config"
"github.com/devopsfaith/krakend/core"
Expand Down Expand Up @@ -35,15 +34,9 @@ func CustomEndpointHandlerWithHTTPError(rb RequestBuilder, errF router.ToHTTPErr
if len(headersToSend) == 0 {
headersToSend = router.HeadersToSend
}
method := strings.ToTitle(configuration.Method)

return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(core.KrakendHeaderName, core.KrakendHeaderValue)
if r.Method != method {
w.Header().Set(router.CompleteResponseHeaderName, router.HeaderIncompleteResponseValue)
http.Error(w, "", http.StatusMethodNotAllowed)
return
}

requestCtx, cancel := context.WithTimeout(context.Background(), configuration.Timeout)

Expand Down
5 changes: 0 additions & 5 deletions router/mux/endpoint_test.go
Expand Up @@ -91,11 +91,6 @@ func TestEndpointHandler_noop(t *testing.T) {
time.Sleep(5 * time.Millisecond)
}

func TestEndpointHandler_badMethod(t *testing.T) {
testEndpointHandler(t, 10, proxy.NoopProxy, "PUT", "\n", "", "text/plain; charset=utf-8", http.StatusMethodNotAllowed, false)
time.Sleep(5 * time.Millisecond)
}

func testEndpointHandler(t *testing.T, timeout time.Duration, p proxy.Proxy, method, expectedBody, expectedCache, expectedContent string,
expectedStatusCode int, completed bool) {
endpoint := &config.EndpointConfig{
Expand Down
44 changes: 37 additions & 7 deletions router/mux/router.go
Expand Up @@ -3,6 +3,7 @@ package mux

import (
"context"
"fmt"
"net/http"
"strings"

Expand Down Expand Up @@ -95,22 +96,39 @@ func (r httpRouter) Run(cfg config.ServiceConfig) {
}

func (r httpRouter) registerKrakendEndpoints(endpoints []*config.EndpointConfig) {
uniquePaths := map[string]map[string]http.HandlerFunc{}
sortedUniquePaths := []string{}
for _, c := range endpoints {
proxyStack, err := r.cfg.ProxyFactory.New(c)
if err != nil {
r.cfg.Logger.Error("calling the ProxyFactory", err.Error())
continue
}

r.registerKrakendEndpoint(c.Method, c.Endpoint, r.cfg.HandlerFactory(c, proxyStack), len(c.Backend))
handler := r.cfg.HandlerFactory(c, proxyStack)
method := strings.ToTitle(c.Method)

if err := r.checkKrakendEndpoint(method, c.Endpoint, len(c.Backend)); err != nil {
r.cfg.Logger.Error("validating endpoint:", err.Error())
continue
}

if _, ok := uniquePaths[c.Endpoint]; !ok {
uniquePaths[c.Endpoint] = map[string]http.HandlerFunc{}
sortedUniquePaths = append(sortedUniquePaths, c.Endpoint)
}
uniquePaths[c.Endpoint][method] = handler
}

for _, path := range sortedUniquePaths {
r.cfg.Engine.Handle(path, methodDispatcher(uniquePaths[path]))
}
}

func (r httpRouter) registerKrakendEndpoint(method, path string, handler http.HandlerFunc, totBackends int) {
func (r httpRouter) checkKrakendEndpoint(method, path string, totBackends int) error {
method = strings.ToTitle(method)
if method != http.MethodGet && totBackends > 1 {
r.cfg.Logger.Error(method, "endpoints must have a single backend! Ignoring", path)
return
return fmt.Errorf("%s endpoints must have a single backend! Ignoring %s", method, path)
}

switch method {
Expand All @@ -120,11 +138,11 @@ func (r httpRouter) registerKrakendEndpoint(method, path string, handler http.Ha
case http.MethodPatch:
case http.MethodDelete:
default:
r.cfg.Logger.Error("Unsupported method", method)
return
return fmt.Errorf("Unsupported method %s", method)
}

r.cfg.Logger.Debug("registering the endpoint", method, path)
r.cfg.Engine.Handle(path, handler)
return nil
}

func (r httpRouter) handler() http.Handler {
Expand All @@ -135,3 +153,15 @@ func (r httpRouter) handler() http.Handler {
}
return handler
}

func methodDispatcher(handlers map[string]http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if handler, ok := handlers[req.Method]; ok {
handler(rw, req)
return
}

rw.Header().Set(router.CompleteResponseHeaderName, router.HeaderIncompleteResponseValue)
http.Error(rw, "", http.StatusMethodNotAllowed)
})
}
19 changes: 19 additions & 0 deletions router/mux/router_test.go
Expand Up @@ -48,6 +48,14 @@ func TestDefaultFactory_ok(t *testing.T) {
{},
},
},
{
Endpoint: "/get",
Method: "POST",
Timeout: 10,
Backend: []*config.Backend{
{},
},
},
{
Endpoint: "/post",
Method: "Post",
Expand Down Expand Up @@ -122,6 +130,17 @@ func TestDefaultFactory_ok(t *testing.T) {
t.Error(endpoint.Endpoint, "Unexpected body:", content, "expected:", expectedBody)
}
}

req, _ := http.NewRequest("PUT", "http://127.0.0.1:8062/get", nil)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Error("Making the request:", err.Error())
return
}
if resp.StatusCode != http.StatusMethodNotAllowed {
t.Errorf("Unexpected status code for unsupported method. have: %d, want: %d", resp.StatusCode, http.StatusMethodNotAllowed)
}
}

func TestDefaultFactory_ko(t *testing.T) {
Expand Down

0 comments on commit 3e814cb

Please sign in to comment.