Wildcard subdomain full support | v3.0.0-beta.2

Update to v3.0.0-beta.2.
Wildcard subdomain e-book section:
https://kataras.gitbooks.io/iris/content/subdomains.html
This commit is contained in:
Makis Maropoulos 2016-06-04 16:20:32 +03:00
parent b4612dcfe0
commit 1a433e34d5
9 changed files with 93 additions and 24 deletions

View File

@ -6,7 +6,7 @@
[Travis]: http://travis-ci.org/kataras/iris
[License Widget]: https://img.shields.io/badge/license-Apache%20License%202.0-E91E63.svg?style=flat-square
[License]: https://github.com/kataras/iris/blob/master/LICENSE
[Release Widget]: https://img.shields.io/badge/release-v3.0.0--beta-blue.svg?style=flat-square
[Release Widget]: https://img.shields.io/badge/release-v3.0.0--beta.2-blue.svg?style=flat-square
[Release]: https://github.com/kataras/iris/releases
[Gitter Widget]: https://img.shields.io/badge/chat-on%20gitter-00BCD4.svg?style=flat-square
[Gitter]: https://gitter.im/kataras/iris
@ -116,7 +116,7 @@ Iris suggests you to use [this](https://github.com/gavv/httpexpect) new suite t
Versioning
------------
Current: **v3.0.0-beta.1**
Current: **v3.0.0-beta.2**
> Iris is an active project
@ -131,11 +131,13 @@ Todo
------------
> for the next release 'v3'
- [x] [Dynamic/Wildcard subdomains](https://kataras.gitbooks.io/iris/content/subdomains.html).
- [x] Create server & client side (js) library for .on('event', func action(...)) / .emit('event')... (like socket.io but supports only websocket).
- [x] Find and provide support for the most stable template engine and be able to change it via the configuration, keep html/templates support.
- [x] Extend, test and publish to the public the [Iris' cmd](https://github.com/kataras/iris/tree/master/iris).
- [x] Route naming and html url func, requested [here](https://github.com/kataras/iris/issues/165).
If you're willing to donate click [here](DONATIONS.md)
People

View File

@ -55,6 +55,8 @@ type (
sessionStore store.IStore
// pos is the position number of the Context, look .Next to understand
pos uint8
// subdomain the subdomain (taken from the host), this is empty until GetSubdomain called
subdomain string
}
)

View File

@ -91,6 +91,7 @@ type (
RemoteAddr() string
RequestHeader(k string) string
PostFormValue(string) string
GetSubdomain() string
}
// IContextResponse is part of the IContext

View File

@ -95,6 +95,20 @@ func (ctx *Context) PostFormValue(name string) string {
return string(ctx.RequestCtx.PostArgs().Peek(name))
}
// GetSubdomain returns the subdomain if any, else empty string
func (ctx *Context) GetSubdomain() string {
if ctx.subdomain == "" {
host := ctx.HostString()
if index := strings.IndexByte(host, '.'); index > 0 {
subdomain := host[0:index]
ctx.subdomain = subdomain
}
}
return ctx.subdomain
}
// URLEncode returns the path encoded as url
// useful when you want to pass something to a database and be valid to retrieve it via context.Param
// use it only for special cases, when the default behavior doesn't suits you.

View File

@ -1,4 +1,4 @@
// Package iris v3.0.0-beta.1
// Package iris v3.0.0-beta.2
//
// Note: When 'Station', we mean the Iris type.
package iris
@ -31,7 +31,7 @@ import (
const (
// Version of the iris
Version = "v3.0.0-beta.1"
Version = "v3.0.0-beta.2"
banner = ` _____ _
|_ _| (_)
| | ____ _ ___

View File

@ -81,6 +81,18 @@ func HandleFunc(method string, path string, handlersFn ...HandlerFunc) IRoute {
return DefaultIris.HandleFunc(method, path, handlersFn...)
}
// Wildcard same as .Party("*.")
// registers a route for Dynamic subdomain
// receives three parameters
// the first is the http method
// the second is the request path, can be a dynamic path also like others
// the third are the handlerfuncs
//
// example: subdomains_2
func Wildcard(method string, registedPath string, handlersFn ...HandlerFunc) {
DefaultIris.Wildcard(method, registedPath, handlersFn...)
}
// API converts & registers a custom struct to the router
// receives two parameters
// first is the request path (string)

View File

@ -21,6 +21,7 @@ type (
IParty interface {
Handle(string, string, ...Handler) IRoute
HandleFunc(string, string, ...HandlerFunc) IRoute
Wildcard(string, string, ...HandlerFunc)
API(path string, controller HandlerAPI, middlewares ...HandlerFunc) error
Get(string, ...HandlerFunc) RouteNameFunc
Post(string, ...HandlerFunc) RouteNameFunc
@ -88,6 +89,20 @@ func (p *GardenParty) HandleFunc(method string, registedPath string, handlersFn
return p.Handle(method, registedPath, ConvertToHandlers(handlersFn)...)
}
// Wildcard same as .Party("*.")
// registers a route for Dynamic subdomain
// receives three parameters
// the first is the http method
// the second is the request path, can be a dynamic path also like others
// the third are the handlerfuncs
//
// Note that this is just a global route, no party's route.
// example: subdomains_2
func (p *GardenParty) Wildcard(method string, registedPath string, handlersFn ...HandlerFunc) {
path := PrefixDynamicSubdomain + registedPath
p.station.router.HandleFunc(method, path, handlersFn...)
}
// API converts & registers a custom struct to the router
// receives two parameters
// first is the request path (string)
@ -589,7 +604,10 @@ func (p *GardenParty) StaticContent(reqPath string, contentType string, content
func (p *GardenParty) Party(path string, handlersFn ...HandlerFunc) IParty {
middleware := ConvertToHandlers(handlersFn)
if path[0] != SlashByte && strings.Contains(path, ".") {
//it's domain so no handlers share (even the global ) or path, nothing.
//it's a domain so no handlers share (even the global ) or path, nothing.
if path[0] == MatchEverythingByte { // it's a dynamic subdomain
path = PrefixDynamicSubdomain
}
} else {
// set path to parent+child
path = absPath(p.relativePath, path)

View File

@ -240,6 +240,7 @@ func (r *Route) GetURI(args ...interface{}) (uri string) {
}
host := r.host
if parsedPath, ok := r.Parse(args...); ok {
uri = scheme + host + parsedPath
}

View File

@ -19,6 +19,8 @@ const (
Slash = "/"
// MatchEverythingByte is just a byte of '*" rune/char
MatchEverythingByte = byte('*')
// PrefixDynamicSubdomain is the prefix which dynamic subdomains are registed to, as virtual. Used internaly by Iris but good to know.
PrefixDynamicSubdomain = "www.iris_subd0mAin.iris"
// HTTP Methods(1)
@ -43,6 +45,9 @@ const (
)
var (
// PrefixDynamicSubdomainBytes is the prefix (as []byte) which dynamic subdomains are registed to, as virtual. Used internaly by Iris but good to know.
PrefixDynamicSubdomainBytes = []byte(PrefixDynamicSubdomain)
// HTTP Methods(2)
// MethodConnectBytes []byte("CONNECT")
@ -217,19 +222,22 @@ func (r *router) optimize() {
// optimizeLookups runs AFTER server's listen
func (r *router) optimizeLookups() {
// set the isTLS on all routes and the listening full host
listeningHost := r.station.server.Listener().Addr().String()
for idx := range r.lookups {
theR := r.lookups[idx]
theR.setTLS(r.station.server.IsSecure())
if theR.GetDomain() == "" { // means local, no subdomain
theR.setHost(listeningHost)
} else {
// it's a subdomain route
theR.setHost(theR.GetDomain() + "." + listeningHost)
}
if r.station.server != nil && r.station.server.IsListening() {
// set the isTLS on all routes and the listening full host
listeningHost := r.station.server.Listener().Addr().String()
for idx := range r.lookups {
theR := r.lookups[idx]
theR.setTLS(r.station.server.IsSecure())
if theR.GetDomain() == "" { // means local, no subdomain
theR.setHost(listeningHost)
} else {
// it's a subdomain route
theR.setHost(theR.GetDomain() + "." + listeningHost)
}
}
}
}
// notFound internal method, it justs takes the context from pool ( in order to have the custom errors available) and procedure a Not Found 404 error
@ -271,18 +279,29 @@ func (r *router) serveFunc(reqCtx *fasthttp.RequestCtx) {
// If no route found, it sends an http status 404
func (r *router) serveDomainFunc(reqCtx *fasthttp.RequestCtx) {
method := utils.BytesToString(reqCtx.Method())
domain := utils.BytesToString(reqCtx.Host())
path := r.getRequestPath(reqCtx)
host := utils.BytesToString(reqCtx.Host())
fulldomain := ""
if strings.Count(host, ".") >= 2 {
if portIdx := strings.Index(host, ":"); portIdx != -1 {
fulldomain = host[0:portIdx]
} else {
fulldomain = host
}
}
path := utils.BytesToString(r.getRequestPath(reqCtx))
tree := r.garden.first
for tree != nil {
if tree.hosts && tree.domain == domain {
// here we have an issue, at fasthttp/uri.go 273-274 line normalize path it adds a '/' slash at the beginning, it doesn't checks for subdomains
// I could fix it but i leave it as it is, I just create a new function inside tree named 'serveReturn' which accepts a path too. ->
//-> reqCtx.Request.URI().SetPathBytes(append(reqCtx.Host(), reqCtx.Path()...)) <-
path = append(reqCtx.Host(), path...)
if tree.hosts && tree.domain != "" && fulldomain != "" {
if tree.domain == fulldomain { // it's a static subdomain
path = fulldomain + path
} else if strings.Index(tree.domain, PrefixDynamicSubdomain) != -1 { // it's a dynamic virtual subdomain
path = PrefixDynamicSubdomain + path
}
}
if r.methodMatch(tree.method, method) {
if tree.serve(reqCtx, utils.BytesToString(path)) {
if tree.serve(reqCtx, path) {
return
}
}