diff options
Diffstat (limited to 'vendor/github.com/go-zoo/bone/route.go')
-rw-r--r-- | vendor/github.com/go-zoo/bone/route.go | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/vendor/github.com/go-zoo/bone/route.go b/vendor/github.com/go-zoo/bone/route.go new file mode 100644 index 000000000..7f6c1b1d0 --- /dev/null +++ b/vendor/github.com/go-zoo/bone/route.go @@ -0,0 +1,245 @@ +/******************************** +*** Multiplexer for Go *** +*** Bone is under MIT license *** +*** Code by CodingFerret *** +*** github.com/go-zoo *** +*********************************/ + +package bone + +import ( + "net/http" + "regexp" + "strings" +) + +const ( + //PARAM value store in Atts if the route have parameters + PARAM = 2 + //SUB value store in Atts if the route is a sub router + SUB = 4 + //WC value store in Atts if the route have wildcard + WC = 8 + //REGEX value store in Atts if the route contains regex + REGEX = 16 +) + +// Route content the required information for a valid route +// Path: is the Route URL +// Size: is the length of the path +// Token: is the value of each part of the path, split by / +// Pattern: is content information about the route, if it's have a route variable +// handler: is the handler who handle this route +// Method: define HTTP method on the route +type Route struct { + Path string + Method string + Size int + Atts int + wildPos int + Token Token + Pattern map[int]string + Compile map[int]*regexp.Regexp + Tag map[int]string + Handler http.Handler +} + +// Token content all value of a spliting route path +// Tokens: string value of each token +// size: number of token +type Token struct { + raw []int + Tokens []string + Size int +} + +// NewRoute return a pointer to a Route instance and call save() on it +func NewRoute(url string, h http.Handler) *Route { + r := &Route{Path: url, Handler: h} + r.save() + return r +} + +// Save, set automatically the the Route.Size and Route.Pattern value +func (r *Route) save() { + r.Size = len(r.Path) + r.Token.Tokens = strings.Split(r.Path, "/") + for i, s := range r.Token.Tokens { + if len(s) >= 1 { + switch s[:1] { + case ":": + if r.Pattern == nil { + r.Pattern = make(map[int]string) + } + r.Pattern[i] = s[1:] + r.Atts |= PARAM + case "#": + if r.Compile == nil { + r.Compile = make(map[int]*regexp.Regexp) + r.Tag = make(map[int]string) + } + tmp := strings.Split(s, "^") + r.Tag[i] = tmp[0][1:] + r.Compile[i] = regexp.MustCompile("^" + tmp[1][:len(tmp[1])-1]) + r.Atts |= REGEX + case "*": + r.wildPos = i + r.Atts |= WC + default: + r.Token.raw = append(r.Token.raw, i) + } + } + r.Token.Size++ + } +} + +// Match check if the request match the route Pattern +func (r *Route) Match(req *http.Request) bool { + ok, _ := r.matchAndParse(req) + return ok +} + +// matchAndParse check if the request matches the route Pattern and returns a map of the parsed +// variables if it matches +func (r *Route) matchAndParse(req *http.Request) (bool, map[string]string) { + ss := strings.Split(req.URL.EscapedPath(), "/") + if r.matchRawTokens(&ss) { + if len(ss) == r.Token.Size || r.Atts&WC != 0 { + totalSize := len(r.Pattern) + if r.Atts®EX != 0 { + totalSize += len(r.Compile) + } + + vars := make(map[string]string, totalSize) + for k, v := range r.Pattern { + vars[v] = ss[k] + } + + if r.Atts®EX != 0 { + for k, v := range r.Compile { + if !v.MatchString(ss[k]) { + return false, nil + } + vars[r.Tag[k]] = ss[k] + } + } + + return true, vars + } + } + + return false, nil +} + +func (r *Route) parse(rw http.ResponseWriter, req *http.Request) bool { + if r.Atts != 0 { + if r.Atts&SUB != 0 { + if len(req.URL.Path) >= r.Size { + if req.URL.Path[:r.Size] == r.Path { + req.URL.Path = req.URL.Path[r.Size:] + r.Handler.ServeHTTP(rw, req) + return true + } + } + } + + if ok, vars := r.matchAndParse(req); ok { + r.serveMatchedRequest(rw, req, vars) + return true + } + } + if req.URL.Path == r.Path { + r.Handler.ServeHTTP(rw, req) + return true + } + return false +} + +func (r *Route) matchRawTokens(ss *[]string) bool { + if len(*ss) >= r.Token.Size { + for i, v := range r.Token.raw { + if (*ss)[v] != r.Token.Tokens[v] { + if r.Atts&WC != 0 && r.wildPos == i { + return true + } + return false + } + } + return true + } + return false +} + +func (r *Route) exists(rw http.ResponseWriter, req *http.Request) bool { + if r.Atts != 0 { + if r.Atts&SUB != 0 { + if len(req.URL.Path) >= r.Size { + if req.URL.Path[:r.Size] == r.Path { + return true + } + } + } + + if ok, _ := r.matchAndParse(req); ok { + return true + } + } + if req.URL.Path == r.Path { + return true + } + return false +} + +// Get set the route method to Get +func (r *Route) Get() *Route { + r.Method = "GET" + return r +} + +// Post set the route method to Post +func (r *Route) Post() *Route { + r.Method = "POST" + return r +} + +// Put set the route method to Put +func (r *Route) Put() *Route { + r.Method = "PUT" + return r +} + +// Delete set the route method to Delete +func (r *Route) Delete() *Route { + r.Method = "DELETE" + return r +} + +// Head set the route method to Head +func (r *Route) Head() *Route { + r.Method = "HEAD" + return r +} + +// Patch set the route method to Patch +func (r *Route) Patch() *Route { + r.Method = "PATCH" + return r +} + +// Options set the route method to Options +func (r *Route) Options() *Route { + r.Method = "OPTIONS" + return r +} + +func (r *Route) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if r.Method != "" { + if req.Method == r.Method { + r.Handler.ServeHTTP(rw, req) + return + } + http.NotFound(rw, req) + return + } + r.Handler.ServeHTTP(rw, req) +} |