server: Add an inspect endpoint for containers
Signed-off-by: Mrunal Patel <mpatel@redhat.com>
This commit is contained in:
parent
d634468da6
commit
58bc35ab40
11 changed files with 876 additions and 0 deletions
|
@ -412,6 +412,13 @@ func main() {
|
|||
service.StartExitMonitor()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
err := service.StartInspectEndpoint()
|
||||
if err != nil {
|
||||
logrus.Fatalf("Failed to start container inspect endpoint: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = s.Serve(lis)
|
||||
if graceful && strings.Contains(strings.ToLower(err.Error()), "use of closed network connection") {
|
||||
err = nil
|
||||
|
|
56
server/inspect.go
Normal file
56
server/inspect.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-zoo/bone"
|
||||
)
|
||||
|
||||
// ContainerInfo stores information about containers
|
||||
type ContainerInfo struct {
|
||||
Pid int `json:"pid"`
|
||||
Image string `json:"image"`
|
||||
CreatedTime int64 `json:"created_time"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
Annotations map[string]string `json:"annotations"`
|
||||
}
|
||||
|
||||
// StartInspectEndpoint starts a http server that
|
||||
// serves container information requests
|
||||
func (s *Server) StartInspectEndpoint() error {
|
||||
mux := bone.New()
|
||||
|
||||
mux.Get("/containers/:id", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
containerID := bone.GetValue(req, "id")
|
||||
ctr := s.GetContainer(containerID)
|
||||
if ctr == nil {
|
||||
http.Error(w, fmt.Sprintf("container with id: %s not found", containerID), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
ctrState := ctr.State()
|
||||
if ctrState == nil {
|
||||
http.Error(w, fmt.Sprintf("container %s state is nil", containerID), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
ci := ContainerInfo{
|
||||
Pid: ctrState.Pid,
|
||||
Image: ctr.Image(),
|
||||
CreatedTime: ctrState.Created.UnixNano(),
|
||||
Labels: ctr.Labels(),
|
||||
Annotations: ctr.Annotations(),
|
||||
}
|
||||
js, err := json.Marshal(ci)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}))
|
||||
|
||||
// TODO: Make this configurable
|
||||
return http.ListenAndServe("localhost:7373", mux)
|
||||
}
|
|
@ -97,3 +97,4 @@ github.com/prometheus/procfs 65c1f6f8f0fc1e2185eb9863a3bc751496404259
|
|||
github.com/matttproud/golang_protobuf_extensions fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a
|
||||
github.com/beorn7/perks 3ac7bf7a47d159a033b107610db8a1b6575507a4
|
||||
github.com/containerd/cgroups 7a5fdd8330119dc70d850260db8f3594d89d6943
|
||||
github.com/go-zoo/bone 031b4005dfe248ccba241a0c9de0f9e112fd6b7c
|
||||
|
|
22
vendor/github.com/go-zoo/bone/LICENSE
generated
vendored
Normal file
22
vendor/github.com/go-zoo/bone/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 CodingFerret
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, Subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or Substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
81
vendor/github.com/go-zoo/bone/README.md
generated
vendored
Normal file
81
vendor/github.com/go-zoo/bone/README.md
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
bone [![GoDoc](https://godoc.org/github.com/squiidz/bone?status.png)](http://godoc.org/github.com/go-zoo/bone) [![Build Status](https://travis-ci.org/go-zoo/bone.svg)](https://travis-ci.org/go-zoo/bone) [![Go Report Card](https://goreportcard.com/badge/go-zoo/bone)](https://goreportcard.com/report/go-zoo/bone) [![Sourcegraph](https://sourcegraph.com/github.com/go-zoo/bone/-/badge.svg)](https://sourcegraph.com/github.com/go-zoo/bone?badge)
|
||||
=======
|
||||
|
||||
## What is bone ?
|
||||
|
||||
Bone is a lightweight and lightning fast HTTP Multiplexer for Golang. It support :
|
||||
|
||||
- URL Parameters
|
||||
- REGEX Parameters
|
||||
- Wildcard routes
|
||||
- Router Prefix
|
||||
- Sub Router, `mux.SubRoute()`, support most standard router (bone, gorilla/mux, httpRouter etc...)
|
||||
- Http method declaration
|
||||
- Support for `http.Handler` and `http.HandlerFunc`
|
||||
- Custom NotFound handler
|
||||
- Respect the Go standard `http.Handler` interface
|
||||
|
||||
![alt tag](https://c2.staticflickr.com/2/1070/540747396_5542b42cca_z.jpg)
|
||||
|
||||
## Speed
|
||||
|
||||
```
|
||||
- BenchmarkBoneMux 10000000 118 ns/op
|
||||
- BenchmarkZeusMux 100000 144 ns/op
|
||||
- BenchmarkHttpRouterMux 10000000 134 ns/op
|
||||
- BenchmarkNetHttpMux 3000000 580 ns/op
|
||||
- BenchmarkGorillaMux 300000 3333 ns/op
|
||||
- BenchmarkGorillaPatMux 1000000 1889 ns/op
|
||||
```
|
||||
|
||||
These test are just for fun, all these router are great and really efficient.
|
||||
Bone do not pretend to be the fastest router for every job.
|
||||
|
||||
## Example
|
||||
|
||||
``` go
|
||||
|
||||
package main
|
||||
|
||||
import(
|
||||
"net/http"
|
||||
|
||||
"github.com/go-zoo/bone"
|
||||
)
|
||||
|
||||
func main () {
|
||||
mux := bone.New()
|
||||
|
||||
// mux.Get, Post, etc ... takes http.Handler
|
||||
mux.Get("/home/:id", http.HandlerFunc(HomeHandler))
|
||||
mux.Get("/profil/:id/:var", http.HandlerFunc(ProfilHandler))
|
||||
mux.Post("/data", http.HandlerFunc(DataHandler))
|
||||
|
||||
// Support REGEX Route params
|
||||
mux.Get("/index/#id^[0-9]$", http.HandlerFunc(IndexHandler))
|
||||
|
||||
// Handle take http.Handler
|
||||
mux.Handle("/", http.HandlerFunc(RootHandler))
|
||||
|
||||
// GetFunc, PostFunc etc ... takes http.HandlerFunc
|
||||
mux.GetFunc("/test", Handler)
|
||||
|
||||
http.ListenAndServe(":8080", mux)
|
||||
}
|
||||
|
||||
func Handler(rw http.ResponseWriter, req *http.Request) {
|
||||
// Get the value of the "id" parameters.
|
||||
val := bone.GetValue(req, "id")
|
||||
|
||||
rw.Write([]byte(val))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Blog Posts
|
||||
- http://www.peterbe.com/plog/my-favorite-go-multiplexer
|
||||
- https://harshladha.xyz/my-first-library-in-go-language-hasty-791b8e2b9e69
|
||||
|
||||
## Libs
|
||||
- Errors dump for Go : [Trash](https://github.com/go-zoo/trash)
|
||||
- Middleware Chaining module : [Claw](https://github.com/go-zoo/claw)
|
74
vendor/github.com/go-zoo/bone/bone.go
generated
vendored
Normal file
74
vendor/github.com/go-zoo/bone/bone.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
/********************************
|
||||
*** Multiplexer for Go ***
|
||||
*** Bone is under MIT license ***
|
||||
*** Code by CodingFerret ***
|
||||
*** github.com/go-zoo ***
|
||||
*********************************/
|
||||
|
||||
package bone
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Mux have routes and a notFound handler
|
||||
// Route: all the registred route
|
||||
// notFound: 404 handler, default http.NotFound if not provided
|
||||
type Mux struct {
|
||||
Routes map[string][]*Route
|
||||
prefix string
|
||||
notFound http.Handler
|
||||
Serve func(rw http.ResponseWriter, req *http.Request)
|
||||
CaseSensitive bool
|
||||
}
|
||||
|
||||
var (
|
||||
static = "static"
|
||||
method = []string{"GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS"}
|
||||
)
|
||||
|
||||
type adapter func(*Mux) *Mux
|
||||
|
||||
// New create a pointer to a Mux instance
|
||||
func New(adapters ...adapter) *Mux {
|
||||
m := &Mux{Routes: make(map[string][]*Route), Serve: nil, CaseSensitive: true}
|
||||
for _, adap := range adapters {
|
||||
adap(m)
|
||||
}
|
||||
if m.Serve == nil {
|
||||
m.Serve = m.DefaultServe
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Prefix set a default prefix for all routes registred on the router
|
||||
func (m *Mux) Prefix(p string) *Mux {
|
||||
m.prefix = strings.TrimSuffix(p, "/")
|
||||
return m
|
||||
}
|
||||
|
||||
// DefaultServe is the default http request handler
|
||||
func (m *Mux) DefaultServe(rw http.ResponseWriter, req *http.Request) {
|
||||
// Check if a route match
|
||||
if !m.parse(rw, req) {
|
||||
// Check if it's a static ressource
|
||||
if !m.staticRoute(rw, req) {
|
||||
// Check if the request path doesn't end with /
|
||||
if !m.validate(rw, req) {
|
||||
// Check if same route exists for another HTTP method
|
||||
if !m.otherMethods(rw, req) {
|
||||
m.HandleNotFound(rw, req)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ServeHTTP pass the request to the serve method of Mux
|
||||
func (m *Mux) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
if !m.CaseSensitive {
|
||||
req.URL.Path = strings.ToLower(req.URL.Path)
|
||||
}
|
||||
m.Serve(rw, req)
|
||||
}
|
169
vendor/github.com/go-zoo/bone/helper.go
generated
vendored
Normal file
169
vendor/github.com/go-zoo/bone/helper.go
generated
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
/********************************
|
||||
*** Multiplexer for Go ***
|
||||
*** Bone is under MIT license ***
|
||||
*** Code by CodingFerret ***
|
||||
*** github.com/go-zoo ***
|
||||
*********************************/
|
||||
|
||||
package bone
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (m *Mux) ListenAndServe(port string) error {
|
||||
return http.ListenAndServe(port, m)
|
||||
}
|
||||
|
||||
func (m *Mux) parse(rw http.ResponseWriter, req *http.Request) bool {
|
||||
for _, r := range m.Routes[req.Method] {
|
||||
ok := r.parse(rw, req)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// If no HEAD method, default to GET
|
||||
if req.Method == "HEAD" {
|
||||
for _, r := range m.Routes["GET"] {
|
||||
ok := r.parse(rw, req)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// StaticRoute check if the request path is for Static route
|
||||
func (m *Mux) staticRoute(rw http.ResponseWriter, req *http.Request) bool {
|
||||
for _, s := range m.Routes[static] {
|
||||
if len(req.URL.Path) >= s.Size {
|
||||
if req.URL.Path[:s.Size] == s.Path {
|
||||
s.Handler.ServeHTTP(rw, req)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HandleNotFound handle when a request does not match a registered handler.
|
||||
func (m *Mux) HandleNotFound(rw http.ResponseWriter, req *http.Request) {
|
||||
if m.notFound != nil {
|
||||
m.notFound.ServeHTTP(rw, req)
|
||||
} else {
|
||||
http.NotFound(rw, req)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the path don't end with a /
|
||||
func (m *Mux) validate(rw http.ResponseWriter, req *http.Request) bool {
|
||||
plen := len(req.URL.Path)
|
||||
if plen > 1 && req.URL.Path[plen-1:] == "/" {
|
||||
cleanURL(&req.URL.Path)
|
||||
rw.Header().Set("Location", req.URL.String())
|
||||
rw.WriteHeader(http.StatusFound)
|
||||
return true
|
||||
}
|
||||
// Retry to find a route that match
|
||||
return m.parse(rw, req)
|
||||
}
|
||||
|
||||
func valid(path string) bool {
|
||||
plen := len(path)
|
||||
if plen > 1 && path[plen-1:] == "/" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Clean url path
|
||||
func cleanURL(url *string) {
|
||||
ulen := len((*url))
|
||||
if ulen > 1 {
|
||||
if (*url)[ulen-1:] == "/" {
|
||||
*url = (*url)[:ulen-1]
|
||||
cleanURL(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetValue return the key value, of the current *http.Request
|
||||
func GetValue(req *http.Request, key string) string {
|
||||
return GetAllValues(req)[key]
|
||||
}
|
||||
|
||||
// GetRequestRoute returns the route of given Request
|
||||
func (m *Mux) GetRequestRoute(req *http.Request) string {
|
||||
cleanURL(&req.URL.Path)
|
||||
for _, r := range m.Routes[req.Method] {
|
||||
if r.Atts != 0 {
|
||||
if r.Atts&SUB != 0 {
|
||||
return r.Handler.(*Mux).GetRequestRoute(req)
|
||||
}
|
||||
if r.Match(req) {
|
||||
return r.Path
|
||||
}
|
||||
}
|
||||
if req.URL.Path == r.Path {
|
||||
return r.Path
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range m.Routes[static] {
|
||||
if len(req.URL.Path) >= s.Size {
|
||||
if req.URL.Path[:s.Size] == s.Path {
|
||||
return s.Path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "NotFound"
|
||||
}
|
||||
|
||||
// GetQuery return the key value, of the current *http.Request query
|
||||
func GetQuery(req *http.Request, key string) []string {
|
||||
if ok, value := extractQueries(req); ok {
|
||||
return value[key]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllQueries return all queries of the current *http.Request
|
||||
func GetAllQueries(req *http.Request) map[string][]string {
|
||||
if ok, values := extractQueries(req); ok {
|
||||
return values
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractQueries(req *http.Request) (bool, map[string][]string) {
|
||||
if q, err := url.ParseQuery(req.URL.RawQuery); err == nil {
|
||||
var queries = make(map[string][]string)
|
||||
for k, v := range q {
|
||||
for _, item := range v {
|
||||
values := strings.Split(item, ",")
|
||||
queries[k] = append(queries[k], values...)
|
||||
}
|
||||
}
|
||||
return true, queries
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (m *Mux) otherMethods(rw http.ResponseWriter, req *http.Request) bool {
|
||||
for _, met := range method {
|
||||
if met != req.Method {
|
||||
for _, r := range m.Routes[met] {
|
||||
ok := r.exists(rw, req)
|
||||
if ok {
|
||||
rw.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
45
vendor/github.com/go-zoo/bone/helper_15.go
generated
vendored
Normal file
45
vendor/github.com/go-zoo/bone/helper_15.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
// +build !go1.7
|
||||
|
||||
/********************************
|
||||
*** Multiplexer for Go ***
|
||||
*** Bone is under MIT license ***
|
||||
*** Code by CodingFerret ***
|
||||
*** github.com/go-zoo ***
|
||||
*********************************/
|
||||
|
||||
package bone
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var globalVars = struct {
|
||||
sync.RWMutex
|
||||
v map[*http.Request]map[string]string
|
||||
}{v: make(map[*http.Request]map[string]string)}
|
||||
|
||||
// GetAllValues return the req PARAMs
|
||||
func GetAllValues(req *http.Request) map[string]string {
|
||||
globalVars.RLock()
|
||||
values := globalVars.v[req]
|
||||
globalVars.RUnlock()
|
||||
return values
|
||||
}
|
||||
|
||||
// serveMatchedRequest is an extension point for Route which allows us to conditionally compile for
|
||||
// go1.7 and <go1.7
|
||||
func (r *Route) serveMatchedRequest(rw http.ResponseWriter, req *http.Request, vars map[string]string) {
|
||||
globalVars.Lock()
|
||||
globalVars.v[req] = vars
|
||||
globalVars.Unlock()
|
||||
|
||||
// Regardless if ServeHTTP panics (and potentially recovers) we can make sure to not leak
|
||||
// memory in globalVars for this request
|
||||
defer func() {
|
||||
globalVars.Lock()
|
||||
delete(globalVars.v, req)
|
||||
globalVars.Unlock()
|
||||
}()
|
||||
r.Handler.ServeHTTP(rw, req)
|
||||
}
|
39
vendor/github.com/go-zoo/bone/helper_17.go
generated
vendored
Normal file
39
vendor/github.com/go-zoo/bone/helper_17.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// +build go1.7
|
||||
|
||||
/********************************
|
||||
*** Multiplexer for Go ***
|
||||
*** Bone is under MIT license ***
|
||||
*** Code by CodingFerret ***
|
||||
*** github.com/go-zoo ***
|
||||
*********************************/
|
||||
|
||||
package bone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// contextKeyType is a private struct that is used for storing bone values in net.Context
|
||||
type contextKeyType struct{}
|
||||
|
||||
// contextKey is the key that is used to store bone values in the net.Context for each request
|
||||
var contextKey = contextKeyType{}
|
||||
|
||||
// GetAllValues return the req PARAMs
|
||||
func GetAllValues(req *http.Request) map[string]string {
|
||||
values, ok := req.Context().Value(contextKey).(map[string]string)
|
||||
if ok {
|
||||
return values
|
||||
}
|
||||
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
// serveMatchedRequest is an extension point for Route which allows us to conditionally compile for
|
||||
// go1.7 and <go1.7
|
||||
func (r *Route) serveMatchedRequest(rw http.ResponseWriter, req *http.Request, vars map[string]string) {
|
||||
ctx := context.WithValue(req.Context(), contextKey, vars)
|
||||
newReq := req.WithContext(ctx)
|
||||
r.Handler.ServeHTTP(rw, newReq)
|
||||
}
|
137
vendor/github.com/go-zoo/bone/mux.go
generated
vendored
Normal file
137
vendor/github.com/go-zoo/bone/mux.go
generated
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
/********************************
|
||||
*** Multiplexer for Go ***
|
||||
*** Bone is under MIT license ***
|
||||
*** Code by CodingFerret ***
|
||||
*** github.com/go-zoo ***
|
||||
*********************************/
|
||||
|
||||
package bone
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Router is the same as a http.Handler
|
||||
type Router interface {
|
||||
ServeHTTP(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
// Register the route in the router
|
||||
func (m *Mux) Register(method string, path string, handler http.Handler) *Route {
|
||||
return m.register(method, path, handler)
|
||||
}
|
||||
|
||||
// GetFunc add a new route to the Mux with the Get method
|
||||
func (m *Mux) GetFunc(path string, handler http.HandlerFunc) *Route {
|
||||
return m.register("GET", path, handler)
|
||||
}
|
||||
|
||||
// PostFunc add a new route to the Mux with the Post method
|
||||
func (m *Mux) PostFunc(path string, handler http.HandlerFunc) *Route {
|
||||
return m.register("POST", path, handler)
|
||||
}
|
||||
|
||||
// PutFunc add a new route to the Mux with the Put method
|
||||
func (m *Mux) PutFunc(path string, handler http.HandlerFunc) *Route {
|
||||
return m.register("PUT", path, handler)
|
||||
}
|
||||
|
||||
// DeleteFunc add a new route to the Mux with the Delete method
|
||||
func (m *Mux) DeleteFunc(path string, handler http.HandlerFunc) *Route {
|
||||
return m.register("DELETE", path, handler)
|
||||
}
|
||||
|
||||
// HeadFunc add a new route to the Mux with the Head method
|
||||
func (m *Mux) HeadFunc(path string, handler http.HandlerFunc) *Route {
|
||||
return m.register("HEAD", path, handler)
|
||||
}
|
||||
|
||||
// PatchFunc add a new route to the Mux with the Patch method
|
||||
func (m *Mux) PatchFunc(path string, handler http.HandlerFunc) *Route {
|
||||
return m.register("PATCH", path, handler)
|
||||
}
|
||||
|
||||
// OptionsFunc add a new route to the Mux with the Options method
|
||||
func (m *Mux) OptionsFunc(path string, handler http.HandlerFunc) *Route {
|
||||
return m.register("OPTIONS", path, handler)
|
||||
}
|
||||
|
||||
// NotFoundFunc the mux custom 404 handler
|
||||
func (m *Mux) NotFoundFunc(handler http.HandlerFunc) {
|
||||
m.notFound = handler
|
||||
}
|
||||
|
||||
// Handle add a new route to the Mux without a HTTP method
|
||||
func (m *Mux) Handle(path string, handler http.Handler) {
|
||||
for _, mt := range method {
|
||||
m.register(mt, path, handler)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleFunc is use to pass a func(http.ResponseWriter, *Http.Request) instead of http.Handler
|
||||
func (m *Mux) HandleFunc(path string, handler http.HandlerFunc) {
|
||||
m.Handle(path, handler)
|
||||
}
|
||||
|
||||
// Get add a new route to the Mux with the Get method
|
||||
func (m *Mux) Get(path string, handler http.Handler) *Route {
|
||||
return m.register("GET", path, handler)
|
||||
}
|
||||
|
||||
// Post add a new route to the Mux with the Post method
|
||||
func (m *Mux) Post(path string, handler http.Handler) *Route {
|
||||
return m.register("POST", path, handler)
|
||||
}
|
||||
|
||||
// Put add a new route to the Mux with the Put method
|
||||
func (m *Mux) Put(path string, handler http.Handler) *Route {
|
||||
return m.register("PUT", path, handler)
|
||||
}
|
||||
|
||||
// Delete add a new route to the Mux with the Delete method
|
||||
func (m *Mux) Delete(path string, handler http.Handler) *Route {
|
||||
return m.register("DELETE", path, handler)
|
||||
}
|
||||
|
||||
// Head add a new route to the Mux with the Head method
|
||||
func (m *Mux) Head(path string, handler http.Handler) *Route {
|
||||
return m.register("HEAD", path, handler)
|
||||
}
|
||||
|
||||
// Patch add a new route to the Mux with the Patch method
|
||||
func (m *Mux) Patch(path string, handler http.Handler) *Route {
|
||||
return m.register("PATCH", path, handler)
|
||||
}
|
||||
|
||||
// Options add a new route to the Mux with the Options method
|
||||
func (m *Mux) Options(path string, handler http.Handler) *Route {
|
||||
return m.register("OPTIONS", path, handler)
|
||||
}
|
||||
|
||||
// NotFound the mux custom 404 handler
|
||||
func (m *Mux) NotFound(handler http.Handler) {
|
||||
m.notFound = handler
|
||||
}
|
||||
|
||||
// Register the new route in the router with the provided method and handler
|
||||
func (m *Mux) register(method string, path string, handler http.Handler) *Route {
|
||||
r := NewRoute(m.prefix+path, handler)
|
||||
r.Method = method
|
||||
if valid(path) {
|
||||
m.Routes[method] = append(m.Routes[method], r)
|
||||
return r
|
||||
}
|
||||
m.Routes[static] = append(m.Routes[static], r)
|
||||
return r
|
||||
}
|
||||
|
||||
// SubRoute register a router as a SubRouter of bone
|
||||
func (m *Mux) SubRoute(path string, router Router) *Route {
|
||||
r := NewRoute(m.prefix+path, router)
|
||||
if valid(path) {
|
||||
r.Atts += SUB
|
||||
for _, mt := range method {
|
||||
m.Routes[mt] = append(m.Routes[mt], r)
|
||||
}
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
}
|
245
vendor/github.com/go-zoo/bone/route.go
generated
vendored
Normal file
245
vendor/github.com/go-zoo/bone/route.go
generated
vendored
Normal file
|
@ -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)
|
||||
}
|
Loading…
Reference in a new issue