From 8486766a604ec0550abea030c2c39f31a74bf5d4 Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Wed, 6 Apr 2016 13:06:31 +0200 Subject: [PATCH] Add multiple rules Signed-off-by: Emile Vauge --- middlewares/stripPrefix.go | 17 ++++---- rules.go | 82 +++++++++++++++++++++++++++++--------- server.go | 10 ++--- 3 files changed, 78 insertions(+), 31 deletions(-) diff --git a/middlewares/stripPrefix.go b/middlewares/stripPrefix.go index 92eb7a5f1..175e29502 100644 --- a/middlewares/stripPrefix.go +++ b/middlewares/stripPrefix.go @@ -7,18 +7,19 @@ import ( // StripPrefix is a middleware used to strip prefix from an URL request type StripPrefix struct { - Handler http.Handler - Prefix string + Handler http.Handler + Prefixes []string } func (s *StripPrefix) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if p := strings.TrimPrefix(r.URL.Path, s.Prefix); len(p) < len(r.URL.Path) { - r.URL.Path = p - r.RequestURI = r.URL.RequestURI() - s.Handler.ServeHTTP(w, r) - } else { - http.NotFound(w, r) + for _, prefix := range s.Prefixes { + if p := strings.TrimPrefix(r.URL.Path, strings.TrimSpace(prefix)); len(p) < len(r.URL.Path) { + r.URL.Path = p + r.RequestURI = r.URL.RequestURI() + s.Handler.ServeHTTP(w, r) + } } + http.NotFound(w, r) } // SetHandler sets handler diff --git a/rules.go b/rules.go index 8d43a884c..29152008a 100644 --- a/rules.go +++ b/rules.go @@ -3,7 +3,9 @@ package main import ( "errors" "github.com/gorilla/mux" + "net/http" "reflect" + "sort" "strings" ) @@ -12,26 +14,65 @@ type Rules struct { route *serverRoute } -func (r *Rules) host(host string) *mux.Route { - return r.route.route.Host(host) +func (r *Rules) host(hosts ...string) *mux.Route { + return r.route.route.MatcherFunc(func(req *http.Request, route *mux.RouteMatch) bool { + for _, host := range hosts { + if strings.EqualFold(req.Host, strings.TrimSpace(host)) { + return true + } + } + return false + }) } -func (r *Rules) path(path string) *mux.Route { - return r.route.route.Path(path) +func (r *Rules) hostRegexp(hosts ...string) *mux.Route { + router := r.route.route.Subrouter() + for _, host := range hosts { + router.Host(strings.TrimSpace(host)) + } + return r.route.route } -func (r *Rules) pathPrefix(path string) *mux.Route { - return r.route.route.PathPrefix(path) +func (r *Rules) path(paths ...string) *mux.Route { + router := r.route.route.Subrouter() + for _, path := range paths { + router.Path(strings.TrimSpace(path)) + } + return r.route.route } -func (r *Rules) pathStrip(path string) *mux.Route { - r.route.stripPrefix = path - return r.route.route.Path(path) +func (r *Rules) pathPrefix(paths ...string) *mux.Route { + router := r.route.route.Subrouter() + for _, path := range paths { + router.PathPrefix(strings.TrimSpace(path)) + } + return r.route.route } -func (r *Rules) pathPrefixStrip(path string) *mux.Route { - r.route.stripPrefix = path - return r.route.route.PathPrefix(path) +type bySize []string + +func (a bySize) Len() int { return len(a) } +func (a bySize) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a bySize) Less(i, j int) bool { return len(a[i]) > len(a[j]) } + +func (r *Rules) pathStrip(paths ...string) *mux.Route { + sort.Sort(bySize(paths)) + r.route.stripPrefixes = paths + router := r.route.route.Subrouter() + for _, path := range paths { + router.Path(strings.TrimSpace(path)) + } + return r.route.route +} + +func (r *Rules) pathPrefixStrip(paths ...string) *mux.Route { + sort.Sort(bySize(paths)) + r.route.stripPrefixes = paths + router := r.route.route.Subrouter() + for _, path := range paths { + router.PathPrefix(strings.TrimSpace(path)) + } + return r.route.route } func (r *Rules) methods(methods ...string) *mux.Route { @@ -50,32 +91,33 @@ func (r *Rules) headersRegexp(headers ...string) *mux.Route { func (r *Rules) Parse(expression string) (*mux.Route, error) { functions := map[string]interface{}{ "Host": r.host, + "HostRegexp": r.hostRegexp, "Path": r.path, "PathStrip": r.pathStrip, "PathPrefix": r.pathPrefix, "PathPrefixStrip": r.pathPrefixStrip, - "Methods": r.methods, + "Method": r.methods, "Headers": r.headers, "HeadersRegexp": r.headersRegexp, } f := func(c rune) bool { - return c == ':' || c == '=' + return c == ':' } // get function parsedFunctions := strings.FieldsFunc(expression, f) - if len(parsedFunctions) != 2 { + if len(parsedFunctions) == 0 { return nil, errors.New("Error parsing rule: " + expression) } parsedFunction, ok := functions[parsedFunctions[0]] if !ok { return nil, errors.New("Error parsing rule: " + expression + ". Unknow function: " + parsedFunctions[0]) } - + parsedFunctions = append(parsedFunctions[:0], parsedFunctions[1:]...) fargs := func(c rune) bool { return c == ',' || c == ';' } // get function - parsedArgs := strings.FieldsFunc(parsedFunctions[1], fargs) + parsedArgs := strings.FieldsFunc(strings.Join(parsedFunctions, ":"), fargs) if len(parsedArgs) == 0 { return nil, errors.New("Error parsing args from rule: " + expression) } @@ -86,7 +128,11 @@ func (r *Rules) Parse(expression string) (*mux.Route, error) { } method := reflect.ValueOf(parsedFunction) if method.IsValid() { - return method.Call(inputs)[0].Interface().(*mux.Route), nil + resultRoute := method.Call(inputs)[0].Interface().(*mux.Route) + if resultRoute.GetError() != nil { + return nil, resultRoute.GetError() + } + return resultRoute, nil } return nil, errors.New("Method not found: " + parsedFunctions[0]) } diff --git a/server.go b/server.go index 820968ff3..f2e9e50ab 100644 --- a/server.go +++ b/server.go @@ -57,8 +57,8 @@ type serverEntryPoint struct { } type serverRoute struct { - route *mux.Route - stripPrefix string + route *mux.Route + stripPrefixes []string } // NewServer returns an initialized Server. @@ -471,10 +471,10 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo func (server *Server) wireFrontendBackend(serverRoute *serverRoute, handler http.Handler) { // strip prefix - if len(serverRoute.stripPrefix) > 0 { + if len(serverRoute.stripPrefixes) > 0 { serverRoute.route.Handler(&middlewares.StripPrefix{ - Prefix: serverRoute.stripPrefix, - Handler: handler, + Prefixes: serverRoute.stripPrefixes, + Handler: handler, }) } else { serverRoute.route.Handler(handler)