Skip to content

Commit

Permalink
Merge pull request #18 for v0.12.1 Release
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm authored Jul 28, 2018
2 parents 2e5e6f7 + cc9e079 commit 419205d
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 82 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
<h2 align="center">Router by aah framework</h2>
</p>
<p align="center">
<p align="center"><a href="https://travis-ci.org/go-aah/router"><img src="https://travis-ci.org/go-aah/router.svg?branch=master" alt="Build Status"></a> <a href="https://codecov.io/gh/go-aah/router/branch/master"><img src="https://codecov.io/gh/go-aah/router/branch/master/graph/badge.svg" alt="Code Coverage"></a> <a href="https://goreportcard.com/report/aahframework.org/router.v0"><img src="https://goreportcard.com/badge/aahframework.org/router.v0" alt="Go Report Card"></a> <a href="https://github.com/go-aah/router/releases/latest"><img src="https://img.shields.io/badge/version-0.12.0-blue.svg" alt="Release Version"></a> <a href="https://godoc.org/aahframework.org/router.v0"><img src="https://godoc.org/aahframework.org/router.v0?status.svg" alt="Godoc"></a> <a href="https://twitter.com/aahframework"><img src="https://img.shields.io/badge/twitter-@aahframework-55acee.svg" alt="Twitter @aahframework"></a></p>
<p align="center"><a href="https://travis-ci.org/go-aah/router"><img src="https://travis-ci.org/go-aah/router.svg?branch=master" alt="Build Status"></a> <a href="https://codecov.io/gh/go-aah/router/branch/master"><img src="https://codecov.io/gh/go-aah/router/branch/master/graph/badge.svg" alt="Code Coverage"></a> <a href="https://goreportcard.com/report/aahframework.org/router.v0"><img src="https://goreportcard.com/badge/aahframework.org/router.v0" alt="Go Report Card"></a> <a href="https://github.com/go-aah/router/releases/latest"><img src="https://img.shields.io/badge/version-0.12.1-blue.svg" alt="Release Version"></a> <a href="https://godoc.org/aahframework.org/router.v0"><img src="https://godoc.org/aahframework.org/router.v0?status.svg" alt="Godoc"></a> <a href="https://twitter.com/aahframework"><img src="https://img.shields.io/badge/twitter-@aahframework-55acee.svg" alt="Twitter @aahframework"></a></p>
</p>

[HTTP Router](http://docs.aahframework.org/routing.html) brings domain and sub-domains routing, it internally uses customized version of radix tree implementation from `github.com/julienschmidt/httprouter` developer by `@julienschmidt`.

### News

* `v0.12.0` [released](https://github.com/go-aah/router/releases/latest) and tagged on Jul 06, 2018.
* `v0.12.1` [released](https://github.com/go-aah/router/releases/latest) and tagged on Jul 27, 2018.

## Installation

Expand Down
2 changes: 1 addition & 1 deletion cors.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (c *CORS) SetAllowCredentials(b bool) *CORS {

// IsOriginAllowed method check given origin is allowed or not.
func (c *CORS) IsOriginAllowed(origin string) bool {
if ess.IsStrEmpty(origin) {
if len(origin) == 0 {
return false
}

Expand Down
8 changes: 4 additions & 4 deletions cors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ func TestRouterCORS1(t *testing.T) {
router, err := createRouter("routes-cors-1.conf")
assert.FailNowOnError(t, err, "")

domain := router.Domains["localhost:8080"]
domain := router.Lookup("localhost:8080")
assert.True(t, domain.CORS.IsOriginAllowed("*"))
assert.True(t, domain.CORS.IsHeadersAllowed("Accept, Origin"))
assert.True(t, domain.CORS.IsMethodAllowed("HEAD"))
assert.False(t, domain.CORS.AllowCredentials)
assert.False(t, domain.CORS.IsOriginAllowed(""))

routes := router.Domains["localhost:8080"].routes
routes := router.Lookup("localhost:8080").routes
assert.NotNil(t, routes)
assert.Equal(t, 8, len(routes))

Expand All @@ -53,15 +53,15 @@ func TestRouterCORS2(t *testing.T) {
router, err := createRouter("routes-cors-2.conf")
assert.FailNowOnError(t, err, "")

domain := router.Domains["localhost:8080"]
domain := router.Lookup("localhost:8080")
assert.True(t, domain.CORS.IsOriginAllowed("https://www.basemydomain.com"))
assert.True(t, domain.CORS.IsHeadersAllowed("X-Base-Test2"))
assert.True(t, domain.CORS.IsMethodAllowed("DELETE"))
assert.True(t, ess.IsSliceContainsString(domain.CORS.ExposeHeaders, "X-Base-Test2"))
assert.True(t, domain.CORS.AllowCredentials)
assert.Equal(t, "172800", domain.CORS.MaxAge)

routes := router.Domains["localhost:8080"].routes
routes := router.Lookup("localhost:8080").routes
assert.NotNil(t, routes)
assert.Equal(t, 8, len(routes))

Expand Down
43 changes: 18 additions & 25 deletions domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type Domain struct {
AutoOptions bool
AntiCSRFEnabled bool
CORSEnabled bool
Key string
Name string
Host string
Port string
Expand All @@ -45,14 +46,21 @@ type Domain struct {
func (d *Domain) Lookup(req *http.Request) (*Route, ahttp.PathParams, bool) {
// HTTP method override support
overrideMethod := req.Header.Get(ahttp.HeaderXHTTPMethodOverride)
if !ess.IsStrEmpty(overrideMethod) && req.Method == ahttp.MethodPost {
if len(overrideMethod) > 0 && req.Method == ahttp.MethodPost {
req.Method = overrideMethod
}

// get route tree for request method
tree, found := d.lookupRouteTree(req)
tree, found := d.trees[req.Method]
if !found {
return nil, nil, false
// get route tree for CORS access control method
if req.Method == ahttp.MethodOptions && d.CORSEnabled {
tree, found = d.trees[req.Header.Get(ahttp.HeaderAccessControlRequestMethod)]
}

if !found {
return nil, nil, false
}
}

route, pathParams, rts, err := tree.find(req.URL.Path)
Expand Down Expand Up @@ -147,7 +155,7 @@ func (d *Domain) RouteURLNamedArgs(routeName string, args map[string]interface{}
// compose URL with values
reverseURL := "/"
for _, segment := range strings.Split(route.Path, "/")[1:] {
if ess.IsStrEmpty(segment) {
if len(segment) == 0 {
continue
}

Expand Down Expand Up @@ -219,7 +227,7 @@ func (d *Domain) RouteURL(routeName string, args ...interface{}) string {
reverseURL := "/"
idx := 0
for _, segment := range strings.Split(route.Path, "/") {
if ess.IsStrEmpty(segment) {
if len(segment) == 0 {
continue
}

Expand All @@ -239,27 +247,12 @@ func (d *Domain) RouteURL(routeName string, args ...interface{}) string {
// Domain unexpoted methods
//___________________________________

func (d *Domain) key() string {
if d.Port == "" {
return strings.ToLower(d.Host)
func (d *Domain) inferKey() {
if len(d.Port) == 0 {
d.Key = strings.ToLower(d.Host)
} else {
d.Key = strings.ToLower(d.Host + ":" + d.Port)
}
return strings.ToLower(d.Host + ":" + d.Port)
}

func (d *Domain) lookupRouteTree(req *http.Request) (*node, bool) {
// get route tree for request method
if tree, found := d.trees[req.Method]; found {
return tree, true
}

// get route tree for CORS access control method
if req.Method == ahttp.MethodOptions && d.CORSEnabled {
if tree, found := d.trees[req.Header.Get(ahttp.HeaderAccessControlRequestMethod)]; found {
return tree, true
}
}

return nil, false
}

func (d *Domain) isAuthConfigured(secMgr *security.Manager) ([]string, bool) {
Expand Down
12 changes: 5 additions & 7 deletions path.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@
// https://raw.githubusercontent.com/julienschmidt/httprouter/master/LICENSE &
// https://raw.githubusercontent.com/golang/go/master/LICENSE
//
// From upstream updated as of last commit date Jun 08, 2014 git#9866532.
// From upstream updated as of last commit date Jul 15, 2018 git#348b672cd90d8190f8240323e372ecd1e66b59dc.

package router

import "aahframework.org/essentials.v0"

// CleanPath is the URL version of path.Clean, it returns a canonical URL path
// for p, eliminating . and .. elements.
//
Expand All @@ -28,7 +26,7 @@ import "aahframework.org/essentials.v0"
// If the result of this process is an empty string, "/" is returned
func CleanPath(p string) string {
// Turn empty string into "/"
if ess.IsStrEmpty(p) {
if len(p) == 0 {
return "/"
}

Expand All @@ -49,7 +47,7 @@ func CleanPath(p string) string {
buf[0] = slashByte
}

trailing := n > 2 && p[n-1] == slashByte
trailing := n > 1 && p[n-1] == slashByte

// A bit more clunky without a 'lazybuf' like the path package, but the loop
// gets completely inlined (bufApp). So in contrast to the path package this
Expand All @@ -67,11 +65,11 @@ func CleanPath(p string) string {

case p[r] == dotByte && p[r+1] == slashByte:
// . element
r++
r += 2

case p[r] == dotByte && p[r+1] == dotByte && (r+2 == n || p[r+2] == slashByte):
// .. element: remove to last /
r += 2
r += 3

if w > 1 {
// can backtrack
Expand Down
1 change: 1 addition & 0 deletions path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var cleanTests = []struct {
}{
// Already clean
{"/", "/"},
{"a/", "/a/"},
{"/abc", "/abc"},
{"/a/b/c", "/a/b/c"},
{"/abc/", "/abc/"},
Expand Down
5 changes: 2 additions & 3 deletions route.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"strings"

"aahframework.org/config.v0"
"aahframework.org/essentials.v0"
"aahframework.org/security.v0"
"aahframework.org/security.v0/authz"
)
Expand Down Expand Up @@ -42,12 +41,12 @@ type Route struct {

// IsDir method returns true if serving directory otherwise false.
func (r *Route) IsDir() bool {
return !ess.IsStrEmpty(r.Dir) && ess.IsStrEmpty(r.File)
return len(r.Dir) > 0 && len(r.File) == 0
}

// IsFile method returns true if serving single file otherwise false.
func (r *Route) IsFile() bool {
return !ess.IsStrEmpty(r.File)
return len(r.File) > 0
}

// HasAccess method does authorization check based on configured values at route
Expand Down
61 changes: 31 additions & 30 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,13 @@ func IsDefaultAction(action string) bool {
// Router is used to register all application routes and finds the appropriate
// route information for incoming request path.
type Router struct {
Domains map[string]*Domain

configPath string
addresses []string
rootDomain *Domain
singleDomain *Domain
app application
config *config.Config
aCfg *config.Config // kept for backward purpose, to be removed in subsequent release
Domains []*Domain

configPath string
rootDomain *Domain
app application
config *config.Config
aCfg *config.Config // kept for backward purpose, to be removed in subsequent release
}

// Load method loads a configuration from given file e.g. `routes.conf` and
Expand Down Expand Up @@ -151,25 +149,21 @@ func (r *Router) FindDomain(req *ahttp.Request) *Domain {

// Lookup method returns domain for given host otherwise nil.
func (r *Router) Lookup(host string) *Domain {
if r.singleDomain != nil {
// only one domain scenario
return r.singleDomain
if len(r.Domains) == 1 {
return r.Domains[0] // only one domain scenario
}
host = strings.ToLower(host)

// Extact match of host value
// for e.g.: sample.com:8080, www.sample.com:8080, admin.sample.com:8080
if domain, found := r.Domains[host]; found {
if domain := r.findDomain(host); domain != nil {
return domain
}

// Wildcard match of host value
// for e.g.: router.conf value is `*.sample.com:8080` it matches
// {subdomain}.sample.com
if idx := strings.IndexByte(host, '.'); idx > 0 {
if domain, found := r.Domains[wildcardSubdomainPrefix+host[idx+1:]]; found {
return domain
}
return r.findDomain(wildcardSubdomainPrefix + host[idx+1:])
}

return nil
Expand All @@ -185,7 +179,11 @@ func (r *Router) RootDomain() *Domain {
// DomainAddresses method returns domain addresses (host:port) from
// routes configuration.
func (r *Router) DomainAddresses() []string {
return r.addresses
var addresses []string
for _, d := range r.Domains {
addresses = append(addresses, d.Key)
}
return addresses
}

// RegisteredActions method returns all the controller name and it's actions
Expand Down Expand Up @@ -222,6 +220,16 @@ func (r *Router) RegisteredWSActions() map[string]map[string]uint8 {
// Router unexpoted methods
//______________________________________________________________________________

func (r *Router) findDomain(key string) *Domain {
key = strings.ToLower(key)
for _, d := range r.Domains {
if d.Key == key {
return d
}
}
return nil
}

func (r *Router) isExists(name string) bool {
if r.app == nil {
return vfs.IsExists(nil, name)
Expand All @@ -245,10 +253,10 @@ func (r *Router) processRoutesConfig() (err error) {
_ = r.config.SetProfile("domains")

// allocate for no. of domains
r.Domains = make(map[string]*Domain)
r.Domains = make([]*Domain, len(domains))
log.Debugf("Domain count: %d", len(domains))

for _, key := range domains {
for idx, key := range domains {
domainCfg, _ := r.config.GetSubConfig(key)

// domain host name
Expand Down Expand Up @@ -304,8 +312,8 @@ func (r *Router) processRoutesConfig() (err error) {
}

// add domain routes
key := domain.key()
log.Debugf("Domain: %s, routes found: %d", key, len(domain.routes))
domain.inferKey()
log.Debugf("Domain: %s, routes found: %d", domain.Key, len(domain.routes))
if log.IsLevelTrace() { // process only if log level is trace
// Static Files routes
log.Trace("Routes: Static")
Expand All @@ -324,16 +332,9 @@ func (r *Router) processRoutesConfig() (err error) {
}
}

r.Domains[key] = domain
r.addresses = append(r.addresses, key)

r.Domains[idx] = domain
} // End of domains

// Only one domain scenario
if len(r.Domains) == 1 {
r.singleDomain = r.Domains[r.addresses[0]]
}

// find out root domain
// Note: Assuming of one domain and multiple sub-domains configured
// otherwise it will have first non-subdomain reference.
Expand Down
Loading

0 comments on commit 419205d

Please sign in to comment.