Browse Source

allow skipping specified hosts from Host matcher

introduce SkipHosts(hosts ...string) at the router
level which can be used to allow certain hosts to be
ignored by the Host() matcher, this is some times
necessary for an application which registers handlers
for one domain to be at a completely different style
of operation

One example is S3 APIs when servicing them as path style
v/s bucket as part of the DNS style.
pull/589/head
Harshavardhana 5 years ago
parent
commit
75fbc3e904
  1. 18
      mux.go
  2. 20
      mux_test.go
  3. 6
      regexp.go
  4. 1
      route.go

18
mux.go

@ -82,6 +82,9 @@ type routeConf struct {
// will not redirect // will not redirect
skipClean bool skipClean bool
// If set to a host skips the this host from r.Host() matcher.
skipHosts map[string]struct{}
// Manager for the variables from host and path. // Manager for the variables from host and path.
regexp routeRegexpGroup regexp routeRegexpGroup
@ -269,6 +272,21 @@ func (r *Router) UseEncodedPath() *Router {
return r return r
} }
// SkipHosts tells the router to skip the these list of hosts from
// r.Host() rules.
// For eg: "r.Host("{subdomain}.domain.com") will match "test.subdomain.com"
// and you would want to skip the matcher for `test.subdomain.com`.
//
// Go regexes do not support PCRE style lookahead/lookbehind like
// features, this function is a way to provide this functionality.
func (r *Router) SkipHosts(hosts ...string) *Router {
r.skipHosts = map[string]struct{}{}
for _, host := range hosts {
r.skipHosts[host] = struct{}{}
}
return r
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Route factories // Route factories
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

20
mux_test.go

@ -51,6 +51,16 @@ type routeTest struct {
shouldRedirect bool // whether the request should result in a redirect shouldRedirect bool // whether the request should result in a redirect
} }
func skipRoute(tpl string, skipHosts ...string) *Route {
skipRoute := &Route{}
skipRoute.skipHosts = map[string]struct{}{}
for _, host := range skipHosts {
skipRoute.skipHosts[host] = struct{}{}
}
skipRoute.Host(tpl)
return skipRoute
}
func TestHost(t *testing.T) { func TestHost(t *testing.T) {
tests := []routeTest{ tests := []routeTest{
@ -216,6 +226,16 @@ func TestHost(t *testing.T) {
hostTemplate: `{v-1:[a-z]{3}}.{v-2:[a-z]{3}}.{v-3:[a-z]{3}}`, hostTemplate: `{v-1:[a-z]{3}}.{v-2:[a-z]{3}}.{v-3:[a-z]{3}}`,
shouldMatch: true, shouldMatch: true,
}, },
{
title: "Host route match should skip specific hosts when specified",
route: skipRoute("{subdomain}.domain.com", "test.domain.com"), // skip matching 'test.domain.com'
request: newRequest("GET", "http://test.domain.com"),
vars: map[string]string{},
host: "test.domain.com",
path: "",
hostTemplate: `{subdomain}.domain.com`,
shouldMatch: false,
},
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.title, func(t *testing.T) { t.Run(test.title, func(t *testing.T) {

6
regexp.go

@ -17,6 +17,7 @@ import (
type routeRegexpOptions struct { type routeRegexpOptions struct {
strictSlash bool strictSlash bool
useEncodedPath bool useEncodedPath bool
skipHosts map[string]struct{}
} }
type regexpType int type regexpType int
@ -180,6 +181,11 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
host = host[:i] host = host[:i]
} }
} }
if len(r.options.skipHosts) > 0 {
if _, ok := r.options.skipHosts[host]; ok {
return false
}
}
return r.regexp.MatchString(host) return r.regexp.MatchString(host)
} }

1
route.go

@ -186,6 +186,7 @@ func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error {
rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{ rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{
strictSlash: r.strictSlash, strictSlash: r.strictSlash,
useEncodedPath: r.useEncodedPath, useEncodedPath: r.useEncodedPath,
skipHosts: r.skipHosts,
}) })
if err != nil { if err != nil {
return err return err

Loading…
Cancel
Save