mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
add internal subdomain redirect handler
TODO more things
This commit is contained in:
parent
f8ac760f69
commit
a61f743fa8
|
@ -551,7 +551,9 @@ New Context Methods:
|
|||
- `Context.CompressReader(enable bool)` method and `iris.CompressReader` middleware to enable future request read body calls to decompress data, [example](_examples/compression/main.go).
|
||||
- `Context.RegisterDependency(v interface{})` and `Context.UnregisterDependency(typ reflect.Type)` to register/remove struct dependencies on serve-time through a middleware.
|
||||
- `Context.SetID(id interface{})` and `Context.GetID() interface{}` added to register a custom unique indetifier to the Context, if necessary.
|
||||
- `Context.GetDomain() string` returns the domain.
|
||||
- `Context.Scheme() string` returns the full scheme of the request URL.
|
||||
- `Context.SubdomainFull() string` returns the full subdomain(s) part of the host (`host[0:rootLevelDomain]`).
|
||||
- `Context.Domain() string` returns the root level domain.
|
||||
- `Context.AddCookieOptions(...CookieOption)` adds options for `SetCookie`, `SetCookieKV, UpsertCookie` and `RemoveCookie` methods for the current request.
|
||||
- `Context.ClearCookieOptions()` clears any cookie options registered through `AddCookieOptions`.
|
||||
- `Context.SetLanguage(langCode string)` force-sets a language code from inside a middleare, similar to the `app.I18n.ExtractFunc`
|
||||
|
|
|
@ -26,5 +26,5 @@
|
|||
127.0.0.1 username3.mydomain.com
|
||||
127.0.0.1 username4.mydomain.com
|
||||
127.0.0.1 username5.mydomain.com
|
||||
|
||||
127.0.0.1 en-us.test.mydomain.com
|
||||
#-END iris-
|
||||
|
|
|
@ -54,6 +54,7 @@ func main() {
|
|||
// http://username1.mydomain.com:8080
|
||||
// http://username2.mydomain.com:8080/something
|
||||
// http://username3.mydomain.com:8080/something/yourname
|
||||
// http://en-us.test.mydomain.com:8080/something/42
|
||||
app.Listen("mydomain.com:8080") // for beginners: look ../hosts file
|
||||
}
|
||||
|
||||
|
@ -66,6 +67,6 @@ func dynamicSubdomainHandler(ctx iris.Context) {
|
|||
|
||||
func dynamicSubdomainHandlerWithParam(ctx iris.Context) {
|
||||
username := ctx.Subdomain()
|
||||
ctx.Writef("Hello from dynamic subdomain path: %s, here you can handle the route for dynamic subdomains, handle the user: %s", ctx.Path(), username)
|
||||
ctx.Writef("Hello from dynamic (full) subdomain: %s and path: %s, here you can handle the route for dynamic subdomains, handle the user: %s", ctx.SubdomainFull(), ctx.Path(), username)
|
||||
ctx.Writef("The paramfirst is: %s", ctx.Params().Get("paramfirst"))
|
||||
}
|
||||
|
|
|
@ -810,6 +810,28 @@ func (ctx *Context) RequestPath(escape bool) string {
|
|||
return ctx.request.URL.Path // RawPath returns empty, requesturi can be used instead also.
|
||||
}
|
||||
|
||||
const sufscheme = "://"
|
||||
|
||||
// GetScheme returns the full scheme of the request URL (https://, http:// or ws:// and e.t.c.``).
|
||||
func GetScheme(r *http.Request) string {
|
||||
scheme := r.URL.Scheme
|
||||
|
||||
if scheme == "" {
|
||||
if r.TLS != nil {
|
||||
scheme = netutil.SchemeHTTPS
|
||||
} else {
|
||||
scheme = netutil.SchemeHTTP
|
||||
}
|
||||
}
|
||||
|
||||
return scheme + sufscheme
|
||||
}
|
||||
|
||||
// Scheme returns the full scheme of the request (including :// suffix).
|
||||
func (ctx *Context) Scheme() string {
|
||||
return GetScheme(ctx.Request())
|
||||
}
|
||||
|
||||
// PathPrefixMap accepts a map of string and a handler.
|
||||
// The key of "m" is the key, which is the prefix, regular expressions are not valid.
|
||||
// The value of "m" is the handler that will be executed if HasPrefix(context.Path).
|
||||
|
@ -824,6 +846,15 @@ func (ctx *Context) RequestPath(escape bool) string {
|
|||
// return false
|
||||
// } no, it will not work because map is a random peek data structure.
|
||||
|
||||
// GetHost returns the host part of the current URI.
|
||||
func GetHost(r *http.Request) string {
|
||||
// contains subdomain.
|
||||
if host := r.URL.Host; host != "" {
|
||||
return host
|
||||
}
|
||||
return r.Host
|
||||
}
|
||||
|
||||
// Host returns the host:port part of the request URI, calls the `Request().Host`.
|
||||
// To get the subdomain part as well use the `Request().URL.Host` method instead.
|
||||
// To get the subdomain only use the `Subdomain` method instead.
|
||||
|
@ -842,17 +873,47 @@ func (ctx *Context) Host() string {
|
|||
return GetHost(ctx.request)
|
||||
}
|
||||
|
||||
// GetHost returns the host part of the current URI.
|
||||
func GetHost(r *http.Request) string {
|
||||
// contains subdomain.
|
||||
if host := r.URL.Host; host != "" {
|
||||
// GetDomain resolves and returns the server's domain.
|
||||
func GetDomain(hostport string) string {
|
||||
host := hostport
|
||||
if tmp, _, err := net.SplitHostPort(hostport); err == nil {
|
||||
host = tmp
|
||||
}
|
||||
|
||||
switch host {
|
||||
case "127.0.0.1", "0.0.0.0", "::1", "[::1]", "0:0:0:0:0:0:0:0", "0:0:0:0:0:0:0:1":
|
||||
// loopback.
|
||||
return "localhost"
|
||||
default:
|
||||
if domain, err := publicsuffix.EffectiveTLDPlusOne(host); err == nil {
|
||||
host = domain
|
||||
}
|
||||
|
||||
return host
|
||||
}
|
||||
return r.Host
|
||||
}
|
||||
|
||||
// Subdomain returns the subdomain of this request, if any.
|
||||
// Note that this is a fast method which does not cover all cases.
|
||||
// Domain returns the root level domain.
|
||||
func (ctx *Context) Domain() string {
|
||||
return GetDomain(ctx.Host())
|
||||
}
|
||||
|
||||
// SubdomainFull returnst he full subdomain level, e.g.
|
||||
// [test.user.]mydomain.com.
|
||||
func (ctx *Context) SubdomainFull() string {
|
||||
host := ctx.Host() // host:port
|
||||
rootDomain := GetDomain(host) // mydomain.com
|
||||
rootDomainIdx := strings.Index(host, rootDomain)
|
||||
if rootDomainIdx == -1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return host[0:rootDomainIdx]
|
||||
}
|
||||
|
||||
// Subdomain returns the first subdomain of this request,
|
||||
// e.g. [user.]mydomain.com.
|
||||
// See `SubdomainFull` too.
|
||||
func (ctx *Context) Subdomain() (subdomain string) {
|
||||
host := ctx.Host()
|
||||
if index := strings.IndexByte(host, '.'); index > 0 {
|
||||
|
@ -962,31 +1023,6 @@ func (ctx *Context) GetHeader(name string) string {
|
|||
return ctx.request.Header.Get(name)
|
||||
}
|
||||
|
||||
// GetDomain resolves and returns the server's domain.
|
||||
func GetDomain(hostport string) string {
|
||||
host := hostport
|
||||
if tmp, _, err := net.SplitHostPort(hostport); err == nil {
|
||||
host = tmp
|
||||
}
|
||||
|
||||
switch host {
|
||||
case "127.0.0.1", "0.0.0.0", "::1", "[::1]", "0:0:0:0:0:0:0:0", "0:0:0:0:0:0:0:1":
|
||||
// loopback.
|
||||
return "localhost"
|
||||
default:
|
||||
if domain, err := publicsuffix.EffectiveTLDPlusOne(host); err == nil {
|
||||
host = domain
|
||||
}
|
||||
|
||||
return host
|
||||
}
|
||||
}
|
||||
|
||||
// GetDomain resolves and returns the server's domain.
|
||||
func (ctx *Context) GetDomain() string {
|
||||
return GetDomain(ctx.Host())
|
||||
}
|
||||
|
||||
// IsAjax returns true if this request is an 'ajax request'( XMLHttpRequest)
|
||||
//
|
||||
// There is no a 100% way of knowing that a request was made via Ajax.
|
||||
|
@ -4072,7 +4108,7 @@ func CookieAllowSubdomains(cookieNames ...string) CookieOption {
|
|||
return
|
||||
}
|
||||
|
||||
c.Domain = ctx.GetDomain()
|
||||
c.Domain = ctx.Domain()
|
||||
c.SameSite = http.SameSiteLaxMode // allow subdomain sharing.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,16 +92,6 @@ func NewSubdomainRedirectWrapper(rootDomainGetter func() string, from, to string
|
|||
return sd.Wrapper
|
||||
}
|
||||
|
||||
const sufscheme = "://"
|
||||
|
||||
func getFullScheme(r *http.Request) string {
|
||||
if !r.URL.IsAbs() {
|
||||
// url scheme is empty.
|
||||
return netutil.SchemeHTTP + sufscheme
|
||||
}
|
||||
return r.URL.Scheme + sufscheme
|
||||
}
|
||||
|
||||
// Wrapper is the function that is being used to wrap the router with a redirect
|
||||
// service that is able to redirect between (sub)domains as fast as possible.
|
||||
// Please take a look at the `NewSubdomainRedirectWrapper` function for more.
|
||||
|
@ -142,11 +132,11 @@ func (s *subdomainRedirectWrapper) Wrapper(w http.ResponseWriter, r *http.Reques
|
|||
resturi := r.URL.RequestURI()
|
||||
if s.isToRoot {
|
||||
// from a specific subdomain or any subdomain to the root domain.
|
||||
redirectAbsolute(w, r, getFullScheme(r)+root+resturi, http.StatusMovedPermanently)
|
||||
redirectAbsolute(w, r, context.GetScheme(r)+root+resturi, http.StatusMovedPermanently)
|
||||
return
|
||||
}
|
||||
// from a specific subdomain or any subdomain to a specific subdomain.
|
||||
redirectAbsolute(w, r, getFullScheme(r)+s.to+root+resturi, http.StatusMovedPermanently)
|
||||
redirectAbsolute(w, r, context.GetScheme(r)+s.to+root+resturi, http.StatusMovedPermanently)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -172,7 +162,7 @@ func (s *subdomainRedirectWrapper) Wrapper(w http.ResponseWriter, r *http.Reques
|
|||
resturi := r.URL.RequestURI()
|
||||
// we are not inside a subdomain, so we are in the root domain
|
||||
// and the redirect is configured to be used from root domain to a subdomain.
|
||||
redirectAbsolute(w, r, getFullScheme(r)+s.to+root+resturi, http.StatusMovedPermanently)
|
||||
redirectAbsolute(w, r, context.GetScheme(r)+s.to+root+resturi, http.StatusMovedPermanently)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -199,3 +189,30 @@ func redirectAbsolute(w http.ResponseWriter, r *http.Request, url string, code i
|
|||
fmt.Fprintln(w, body)
|
||||
}
|
||||
}
|
||||
|
||||
// NewSubdomainPartyRedirectHandler returns a handler which can be registered
|
||||
// through `UseRouter` or `Use` to redirect from the current request's
|
||||
// subdomain to the one which the given `to` Party can handle.
|
||||
func NewSubdomainPartyRedirectHandler(to Party) context.Handler {
|
||||
return NewSubdomainRedirectHandler(to.GetRelPath())
|
||||
}
|
||||
|
||||
// NewSubdomainRedirectHandler returns a handler which can be registered
|
||||
// through `UseRouter` or `Use` to redirect from the current request's
|
||||
// subdomain to the given "toSubdomain".
|
||||
func NewSubdomainRedirectHandler(toSubdomain string) context.Handler {
|
||||
toSubdomain, _ = splitSubdomainAndPath(toSubdomain) // let it here so users can just pass the GetRelPath of a Party.
|
||||
if pathIsWildcard(toSubdomain) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(ctx *context.Context) {
|
||||
// en-us.test.mydomain.com
|
||||
host := ctx.Host()
|
||||
fullSubdomain := ctx.SubdomainFull()
|
||||
newHost := strings.Replace(host, fullSubdomain, toSubdomain, 1)
|
||||
resturi := ctx.Request().URL.RequestURI()
|
||||
urlToRedirect := ctx.Scheme() + newHost + resturi
|
||||
redirectAbsolute(ctx.ResponseWriter(), ctx.Request(), urlToRedirect, http.StatusMovedPermanently)
|
||||
}
|
||||
}
|
|
@ -159,3 +159,40 @@ func TestRouterWrapperOrder(t *testing.T) {
|
|||
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedOrderStr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewSubdomainPartyRedirectHandler(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString("root index")
|
||||
})
|
||||
|
||||
test := app.Subdomain("test")
|
||||
test.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) {
|
||||
ctx.WriteString("test 404")
|
||||
})
|
||||
test.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString("test index")
|
||||
})
|
||||
|
||||
testold := app.Subdomain("testold")
|
||||
// redirects testold.mydomain.com to test.mydomain.com .
|
||||
testold.UseRouter(router.NewSubdomainPartyRedirectHandler(test))
|
||||
testold.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString("test old index (should never be fired)")
|
||||
})
|
||||
testoldLeveled := testold.Subdomain("leveled")
|
||||
testoldLeveled.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteString("leveled.testold this can be fired")
|
||||
})
|
||||
|
||||
if redirectHandler := router.NewSubdomainPartyRedirectHandler(app.WildcardSubdomain()); redirectHandler != nil {
|
||||
t.Fatal("redirect handler should be nil, we cannot redirect to a wildcard")
|
||||
}
|
||||
|
||||
e := httptest.New(t, app)
|
||||
e.GET("/").WithURL("http://mydomain.com").Expect().Status(iris.StatusOK).Body().Equal("root index")
|
||||
e.GET("/").WithURL("http://test.mydomain.com").Expect().Status(iris.StatusOK).Body().Equal("test index")
|
||||
e.GET("/").WithURL("http://testold.mydomain.com").Expect().Status(iris.StatusOK).Body().Equal("test index")
|
||||
e.GET("/").WithURL("http://testold.mydomain.com/notfound").Expect().Status(iris.StatusNotFound).Body().Equal("test 404")
|
||||
e.GET("/").WithURL("http://leveled.testold.mydomain.com").Expect().Status(iris.StatusOK).Body().Equal("leveled.testold this can be fired")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user