diff --git a/agent/agent.go b/agent/agent.go index b4f1bf0b..316e65f0 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -14,7 +14,6 @@ import ( "time" log "github.com/Sirupsen/logrus" - "github.com/gin-gonic/gin" "github.com/Dataman-Cloud/swan/agent/ipam" "github.com/Dataman-Cloud/swan/agent/janitor" @@ -202,12 +201,7 @@ func (agent *Agent) ServeApi(l net.Listener) error { return httpd.Serve(l) } -func (agent *Agent) serveProxy(ctx *gin.Context) { - var ( - r = ctx.Request - w = ctx.Writer - ) - +func (agent *Agent) serveProxy(w http.ResponseWriter, r *http.Request) { hijacker, ok := w.(http.Hijacker) if !ok { w.WriteHeader(500) diff --git a/agent/api.go b/agent/api.go index 2b40e2bc..388ca255 100644 --- a/agent/api.go +++ b/agent/api.go @@ -1,93 +1,95 @@ package agent import ( + "encoding/json" "net/http" - "github.com/gin-gonic/gin" + "github.com/gorilla/mux" ) func (agent *Agent) NewHTTPMux() http.Handler { - mux := gin.Default() - gin.SetMode(gin.ReleaseMode) + m := mux.NewRouter() - mux.GET("/sysinfo", agent.sysinfo) - mux.GET("/configs", agent.showConfigs) + m.Path("/sysinfo").Methods("GET").HandlerFunc(agent.sysinfo) + m.Path("/configs").Methods("GET").HandlerFunc(agent.showConfigs) // /proxy/** if agent.config.Janitor.Enabled { - agent.setupProxyHandlers(mux) + agent.setupProxyHandlers(m) } // /dns/** if agent.config.DNS.Enabled { - agent.setupDNSHandlers(mux) + agent.setupDNSHandlers(m) } // /ipam/** if agent.config.IPAM.Enabled { - agent.setupIPAMHandlers(mux) + agent.setupIPAMHandlers(m) } - mux.NoRoute(agent.serveProxy) - return mux + m.NotFoundHandler = http.HandlerFunc(agent.serveProxy) + + return m } -func (agent *Agent) setupProxyHandlers(mux *gin.Engine) { +func (agent *Agent) setupProxyHandlers(mux *mux.Router) { var ( janitor = agent.janitor ) - r := mux.Group("/proxy") - r.GET("", janitor.ListUpstreams) - r.GET("/upstreams", janitor.ListUpstreams) - r.GET("/upstreams/:uid", janitor.GetUpstream) - r.PUT("/upstreams", janitor.UpsertUpstream) - r.DELETE("/upstreams", janitor.DelUpstream) - r.GET("/sessions", janitor.ListSessions) - r.GET("/configs", janitor.ShowConfigs) - r.GET("/stats", janitor.ShowStats) - r.GET("/stats/:uid", janitor.ShowUpstreamStats) - r.GET("/stats/:uid/:bid", janitor.ShowBackendStats) + r := mux.PathPrefix("/proxy").Subrouter() + r.Path("").Methods("GET").HandlerFunc(janitor.ListUpstreams) + r.Path("/upstreams").Methods("GET").HandlerFunc(janitor.ListUpstreams) + r.Path("/upstreams/{uid}").Methods("GET").HandlerFunc(janitor.GetUpstream) + r.Path("/upstreams").Methods("PUT").HandlerFunc(janitor.UpsertUpstream) + r.Path("/upstreams").Methods("DELETE").HandlerFunc(janitor.DelUpstream) + r.Path("/sessions").Methods("GET").HandlerFunc(janitor.ListSessions) + r.Path("/configs").Methods("GET").HandlerFunc(janitor.ShowConfigs) + r.Path("/stats").Methods("GET").HandlerFunc(janitor.ShowStats) + r.Path("/stats/{uid}").Methods("GET").HandlerFunc(janitor.ShowUpstreamStats) + r.Path("/stats/{uid}/{bid}").Methods("GET").HandlerFunc(janitor.ShowBackendStats) } -func (agent *Agent) setupDNSHandlers(mux *gin.Engine) { +func (agent *Agent) setupDNSHandlers(mux *mux.Router) { var ( resolver = agent.resolver ) - r := mux.Group("/dns") - r.GET("", resolver.ListRecords) - r.GET("/records", resolver.ListRecords) - r.GET("/records/:id", resolver.GetRecord) - r.PUT("/records", resolver.UpsertRecord) - r.DELETE("/records", resolver.DelRecord) - r.GET("/configs", resolver.ShowConfigs) - r.GET("/stats", resolver.ShowStats) - r.GET("/stats/:id", resolver.ShowParentStats) - + r := mux.PathPrefix("/dns").Subrouter() + r.Path("").Methods("GET").HandlerFunc(resolver.ListRecords) + r.Path("/records").Methods("GET").HandlerFunc(resolver.ListRecords) + r.Path("/records/{id}").Methods("GET").HandlerFunc(resolver.GetRecord) + r.Path("/records").Methods("PUT").HandlerFunc(resolver.UpsertRecord) + r.Path("/records").Methods("DELETE").HandlerFunc(resolver.DelRecord) + r.Path("/configs").Methods("GET").HandlerFunc(resolver.ShowConfigs) + r.Path("/stats").Methods("GET").HandlerFunc(resolver.ShowStats) + r.Path("/stats/{id}").Methods("GET").HandlerFunc(resolver.ShowParentStats) } -func (agent *Agent) setupIPAMHandlers(mux *gin.Engine) { +func (agent *Agent) setupIPAMHandlers(mux *mux.Router) { var ( ipam = agent.ipam ) - r := mux.Group("/ipam") - r.GET("", ipam.ListSubNets) - r.GET("subnets", ipam.ListSubNets) - r.PUT("subnets", ipam.SetSubNetPool) + r := mux.PathPrefix("/ipam").Subrouter() + r.Path("").Methods("GET").HandlerFunc(ipam.ListSubNets) + r.Path("/subnets").Methods("GET").HandlerFunc(ipam.ListSubNets) + r.Path("/subnets").Methods("PUT").HandlerFunc(ipam.SetSubNetPool) } -func (agent *Agent) sysinfo(ctx *gin.Context) { +func (agent *Agent) sysinfo(w http.ResponseWriter, r *http.Request) { info, err := Gather() if err != nil { - http.Error(ctx.Writer, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusInternalServerError) return } - ctx.JSON(200, info) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(info) } -func (agent *Agent) showConfigs(ctx *gin.Context) { - ctx.JSON(200, agent.config) +func (agent *Agent) showConfigs(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(agent.config) } diff --git a/agent/ipam/api.go b/agent/ipam/api.go index 3b289c32..60fa6d8c 100644 --- a/agent/ipam/api.go +++ b/agent/ipam/api.go @@ -1,15 +1,14 @@ package ipam import ( + "encoding/json" "net/http" - - "github.com/gin-gonic/gin" ) -func (m *IPAM) ListSubNets(c *gin.Context) { +func (m *IPAM) ListSubNets(w http.ResponseWriter, r *http.Request) { subnets, err := m.store.ListSubNets() if err != nil { - http.Error(c.Writer, err.Error(), 500) + http.Error(w, err.Error(), 500) return } @@ -31,23 +30,24 @@ func (m *IPAM) ListSubNets(c *gin.Context) { } } - c.JSON(200, ret) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(ret) } -func (m *IPAM) SetSubNetPool(c *gin.Context) { +func (m *IPAM) SetSubNetPool(w http.ResponseWriter, r *http.Request) { var pool *IPPoolRange - if err := c.BindJSON(&pool); err != nil { - http.Error(c.Writer, err.Error(), 400) + if err := json.NewDecoder(r.Body).Decode(&pool); err != nil { + http.Error(w, err.Error(), 400) return } if err := pool.Valid(); err != nil { - http.Error(c.Writer, err.Error(), 400) + http.Error(w, err.Error(), 400) return } if err := m.SetIPPool(pool); err != nil { - http.Error(c.Writer, err.Error(), 500) + http.Error(w, err.Error(), 500) return } } diff --git a/agent/janitor/api.go b/agent/janitor/api.go index 0474e38d..21c0e760 100644 --- a/agent/janitor/api.go +++ b/agent/janitor/api.go @@ -1,21 +1,23 @@ package janitor import ( + "encoding/json" "net/http" - "github.com/gin-gonic/gin" - "github.com/Dataman-Cloud/swan/agent/janitor/stats" "github.com/Dataman-Cloud/swan/agent/janitor/upstream" + + "github.com/gorilla/mux" ) -func (s *JanitorServer) ListUpstreams(c *gin.Context) { - c.JSON(200, upstream.AllUpstreams()) +func (s *JanitorServer) ListUpstreams(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(upstream.AllUpstreams()) } -func (s *JanitorServer) GetUpstream(c *gin.Context) { +func (s *JanitorServer) GetUpstream(w http.ResponseWriter, r *http.Request) { var ( - uid = c.Param("uid") + uid = mux.Vars(r)["uid"] m = upstream.AllUpstreams() ret = new(upstream.Upstream) ) @@ -27,74 +29,88 @@ func (s *JanitorServer) GetUpstream(c *gin.Context) { } } - c.JSON(200, ret) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(ret) } -func (s *JanitorServer) UpsertUpstream(c *gin.Context) { +func (s *JanitorServer) UpsertUpstream(w http.ResponseWriter, r *http.Request) { var cmb *upstream.BackendCombined - if err := c.BindJSON(&cmb); err != nil { - http.Error(c.Writer, err.Error(), 400) + if err := json.NewDecoder(r.Body).Decode(&cmb); err != nil { + http.Error(w, err.Error(), 400) return } if err := cmb.Valid(); err != nil { - http.Error(c.Writer, err.Error(), 400) + http.Error(w, err.Error(), 400) return } if err := s.UpsertBackend(cmb); err != nil { - http.Error(c.Writer, err.Error(), 500) + http.Error(w, err.Error(), 500) return } - c.Writer.WriteHeader(201) + w.WriteHeader(http.StatusCreated) } -func (s *JanitorServer) DelUpstream(c *gin.Context) { +func (s *JanitorServer) DelUpstream(w http.ResponseWriter, r *http.Request) { var cmb *upstream.BackendCombined - if err := c.BindJSON(&cmb); err != nil { - http.Error(c.Writer, err.Error(), 400) + if err := json.NewDecoder(r.Body).Decode(&cmb); err != nil { + http.Error(w, err.Error(), 400) return } s.removeBackend(cmb) - c.Writer.WriteHeader(204) + w.WriteHeader(http.StatusNoContent) } -func (s *JanitorServer) ListSessions(c *gin.Context) { - c.JSON(200, upstream.AllSessions()) +func (s *JanitorServer) ListSessions(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(upstream.AllSessions()) } -func (s *JanitorServer) ShowConfigs(c *gin.Context) { - c.JSON(200, s.config) +func (s *JanitorServer) ShowConfigs(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(s.config) } -func (s *JanitorServer) ShowStats(c *gin.Context) { +func (s *JanitorServer) ShowStats(w http.ResponseWriter, r *http.Request) { wrapper := map[string]interface{}{ "httpd": s.config.ListenAddr, "httpdTLS": s.config.TLSListenAddr, "counter": stats.Get(), "tcpd": s.tcpd, } - c.JSON(200, wrapper) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(wrapper) } -func (s *JanitorServer) ShowUpstreamStats(c *gin.Context) { - uid := c.Param("uid") +func (s *JanitorServer) ShowUpstreamStats(w http.ResponseWriter, r *http.Request) { + uid := mux.Vars(r)["uid"] if m, ok := stats.UpstreamStats()[uid]; ok { - c.JSON(200, m) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(m) return } - c.JSON(200, make(map[string]interface{})) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(make(map[string]interface{})) } -func (s *JanitorServer) ShowBackendStats(c *gin.Context) { - uid, bid := c.Param("uid"), c.Param("bid") +func (s *JanitorServer) ShowBackendStats(w http.ResponseWriter, r *http.Request) { + var ( + vars = mux.Vars(r) + uid = vars["uid"] + bid = vars["bid"] + ) + if ups, ok := stats.UpstreamStats()[uid]; ok { if backend, ok := ups[bid]; ok { - c.JSON(200, backend) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(backend) return } } - c.JSON(200, make(map[string]interface{})) + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(make(map[string]interface{})) } diff --git a/agent/resolver/api.go b/agent/resolver/api.go index ce5672ad..fcfa0c34 100644 --- a/agent/resolver/api.go +++ b/agent/resolver/api.go @@ -1,70 +1,78 @@ package resolver import ( + "encoding/json" "net/http" - "github.com/gin-gonic/gin" + "github.com/gorilla/mux" ) -func (s *Resolver) ListRecords(c *gin.Context) { - c.JSON(200, s.allRecords()) +func (s *Resolver) ListRecords(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(s.allRecords()) } -func (s *Resolver) GetRecord(c *gin.Context) { +func (s *Resolver) GetRecord(w http.ResponseWriter, r *http.Request) { var ( - id = c.Param("id") - m = s.allRecords() - ret = make([]*Record, 0) + vars = mux.Vars(r) + id = vars["id"] + m = s.allRecords() + ret = make([]*Record, 0) ) if val, ok := m[id]; ok { ret = val } - c.JSON(200, ret) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(ret) } -func (s *Resolver) UpsertRecord(c *gin.Context) { +func (s *Resolver) UpsertRecord(w http.ResponseWriter, r *http.Request) { var record *Record - if err := c.BindJSON(&record); err != nil { - http.Error(c.Writer, err.Error(), 400) + if err := json.NewDecoder(r.Body).Decode(&record); err != nil { + http.Error(w, err.Error(), 400) return } if err := s.Upsert(record); err != nil { - http.Error(c.Writer, err.Error(), 500) + http.Error(w, err.Error(), 500) return } - c.Writer.WriteHeader(201) + w.WriteHeader(http.StatusCreated) } -func (s *Resolver) DelRecord(c *gin.Context) { +func (s *Resolver) DelRecord(w http.ResponseWriter, r *http.Request) { var record *Record - if err := c.BindJSON(&record); err != nil { - http.Error(c.Writer, err.Error(), 400) + if err := json.NewDecoder(r.Body).Decode(&record); err != nil { + http.Error(w, err.Error(), 400) return } if s.remove(record) { s.stats.Del(record.Parent) } - c.Writer.WriteHeader(204) + w.WriteHeader(http.StatusNoContent) } -func (s *Resolver) ShowConfigs(c *gin.Context) { - c.JSON(200, s.config) +func (s *Resolver) ShowConfigs(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(s.config) } -func (s *Resolver) ShowStats(c *gin.Context) { - c.JSON(200, s.stats.Get()) +func (s *Resolver) ShowStats(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(s.stats.Get()) } -func (s *Resolver) ShowParentStats(c *gin.Context) { - pid := c.Param("id") +func (s *Resolver) ShowParentStats(w http.ResponseWriter, r *http.Request) { + pid := mux.Vars(r)["id"] m := s.stats.Get() if m, ok := m.Parents[pid]; ok { - c.JSON(200, m) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(m) return } - c.JSON(200, make(map[string]interface{})) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(make(map[string]interface{})) } diff --git a/agent/resolver/resolver.go b/agent/resolver/resolver.go index 4c528850..fc8f32e1 100644 --- a/agent/resolver/resolver.go +++ b/agent/resolver/resolver.go @@ -109,7 +109,8 @@ func (r *Resolver) handleLocal(w dns.ResponseWriter, req *dns.Msg) { MsgHdr: dns.MsgHdr{ Authoritative: true, RecursionAvailable: r.config.RecurseOn, - }} + }, + } msg.SetReply(req) var ( diff --git a/vendor.conf b/vendor.conf index 42a837a8..a6b09352 100644 --- a/vendor.conf +++ b/vendor.conf @@ -2,7 +2,6 @@ github.com/Sirupsen/logrus 3ec0642a7fb6488f65b06f9040adc67e3990296a github.com/andygrunwald/megos 01814b52c25a0ea60ab4908f723cc9ee3bbfc495 github.com/coreos/pkg 447b7ec906e523386d9c53be15b55a8ae86ea944 github.com/docker/go-connections e15c02316c12de00874640cd76311849de2aeed5 -github.com/gin-gonic/gin e2212d40c62a98b388a5eb48ecbdcf88534688ba github.com/gogo/protobuf 8d70fb3182befc465c4a1eac8ad4d38ff49778e2 github.com/golang/protobuf 98fa357170587e470c5f27d3c3ea0947b71eb455 github.com/gorilla/context 08b5f424b9271eedf6f9f0ce86cb9396ed337a42 diff --git a/vendor/github.com/docker/docker/api/types/types.go b/vendor/github.com/docker/docker/api/types/types.go new file mode 100644 index 00000000..f7ac7729 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/types.go @@ -0,0 +1,575 @@ +package types + +import ( + "errors" + "fmt" + "io" + "os" + "strings" + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/go-connections/nat" +) + +// RootFS returns Image's RootFS description including the layer IDs. +type RootFS struct { + Type string + Layers []string `json:",omitempty"` + BaseLayer string `json:",omitempty"` +} + +// ImageInspect contains response of Engine API: +// GET "/images/{name:.*}/json" +type ImageInspect struct { + ID string `json:"Id"` + RepoTags []string + RepoDigests []string + Parent string + Comment string + Created string + Container string + ContainerConfig *container.Config + DockerVersion string + Author string + Config *container.Config + Architecture string + Os string + OsVersion string `json:",omitempty"` + Size int64 + VirtualSize int64 + GraphDriver GraphDriverData + RootFS RootFS + Metadata ImageMetadata +} + +// ImageMetadata contains engine-local data about the image +type ImageMetadata struct { + LastTagTime time.Time `json:",omitempty"` +} + +// Container contains response of Engine API: +// GET "/containers/json" +type Container struct { + ID string `json:"Id"` + Names []string + Image string + ImageID string + Command string + Created int64 + Ports []Port + SizeRw int64 `json:",omitempty"` + SizeRootFs int64 `json:",omitempty"` + Labels map[string]string + State string + Status string + HostConfig struct { + NetworkMode string `json:",omitempty"` + } + NetworkSettings *SummaryNetworkSettings + Mounts []MountPoint +} + +// CopyConfig contains request body of Engine API: +// POST "/containers/"+containerID+"/copy" +type CopyConfig struct { + Resource string +} + +// ContainerPathStat is used to encode the header from +// GET "/containers/{name:.*}/archive" +// "Name" is the file or directory name. +type ContainerPathStat struct { + Name string `json:"name"` + Size int64 `json:"size"` + Mode os.FileMode `json:"mode"` + Mtime time.Time `json:"mtime"` + LinkTarget string `json:"linkTarget"` +} + +// ContainerStats contains response of Engine API: +// GET "/stats" +type ContainerStats struct { + Body io.ReadCloser `json:"body"` + OSType string `json:"ostype"` +} + +// Ping contains response of Engine API: +// GET "/_ping" +type Ping struct { + APIVersion string + OSType string + Experimental bool +} + +// Version contains response of Engine API: +// GET "/version" +type Version struct { + Version string + APIVersion string `json:"ApiVersion"` + MinAPIVersion string `json:"MinAPIVersion,omitempty"` + GitCommit string + GoVersion string + Os string + Arch string + KernelVersion string `json:",omitempty"` + Experimental bool `json:",omitempty"` + BuildTime string `json:",omitempty"` +} + +// Commit holds the Git-commit (SHA1) that a binary was built from, as reported +// in the version-string of external tools, such as containerd, or runC. +type Commit struct { + ID string // ID is the actual commit ID of external tool. + Expected string // Expected is the commit ID of external tool expected by dockerd as set at build time. +} + +// Info contains response of Engine API: +// GET "/info" +type Info struct { + ID string + Containers int + ContainersRunning int + ContainersPaused int + ContainersStopped int + Images int + Driver string + DriverStatus [][2]string + SystemStatus [][2]string + Plugins PluginsInfo + MemoryLimit bool + SwapLimit bool + KernelMemory bool + CPUCfsPeriod bool `json:"CpuCfsPeriod"` + CPUCfsQuota bool `json:"CpuCfsQuota"` + CPUShares bool + CPUSet bool + IPv4Forwarding bool + BridgeNfIptables bool + BridgeNfIP6tables bool `json:"BridgeNfIp6tables"` + Debug bool + NFd int + OomKillDisable bool + NGoroutines int + SystemTime string + LoggingDriver string + CgroupDriver string + NEventsListener int + KernelVersion string + OperatingSystem string + OSType string + Architecture string + IndexServerAddress string + RegistryConfig *registry.ServiceConfig + NCPU int + MemTotal int64 + GenericResources []swarm.GenericResource + DockerRootDir string + HTTPProxy string `json:"HttpProxy"` + HTTPSProxy string `json:"HttpsProxy"` + NoProxy string + Name string + Labels []string + ExperimentalBuild bool + ServerVersion string + ClusterStore string + ClusterAdvertise string + Runtimes map[string]Runtime + DefaultRuntime string + Swarm swarm.Info + // LiveRestoreEnabled determines whether containers should be kept + // running when the daemon is shutdown or upon daemon start if + // running containers are detected + LiveRestoreEnabled bool + Isolation container.Isolation + InitBinary string + ContainerdCommit Commit + RuncCommit Commit + InitCommit Commit + SecurityOptions []string +} + +// KeyValue holds a key/value pair +type KeyValue struct { + Key, Value string +} + +// SecurityOpt contains the name and options of a security option +type SecurityOpt struct { + Name string + Options []KeyValue +} + +// DecodeSecurityOptions decodes a security options string slice to a type safe +// SecurityOpt +func DecodeSecurityOptions(opts []string) ([]SecurityOpt, error) { + so := []SecurityOpt{} + for _, opt := range opts { + // support output from a < 1.13 docker daemon + if !strings.Contains(opt, "=") { + so = append(so, SecurityOpt{Name: opt}) + continue + } + secopt := SecurityOpt{} + split := strings.Split(opt, ",") + for _, s := range split { + kv := strings.SplitN(s, "=", 2) + if len(kv) != 2 { + return nil, fmt.Errorf("invalid security option %q", s) + } + if kv[0] == "" || kv[1] == "" { + return nil, errors.New("invalid empty security option") + } + if kv[0] == "name" { + secopt.Name = kv[1] + continue + } + secopt.Options = append(secopt.Options, KeyValue{Key: kv[0], Value: kv[1]}) + } + so = append(so, secopt) + } + return so, nil +} + +// PluginsInfo is a temp struct holding Plugins name +// registered with docker daemon. It is used by Info struct +type PluginsInfo struct { + // List of Volume plugins registered + Volume []string + // List of Network plugins registered + Network []string + // List of Authorization plugins registered + Authorization []string + // List of Log plugins registered + Log []string +} + +// ExecStartCheck is a temp struct used by execStart +// Config fields is part of ExecConfig in runconfig package +type ExecStartCheck struct { + // ExecStart will first check if it's detached + Detach bool + // Check if there's a tty + Tty bool +} + +// HealthcheckResult stores information about a single run of a healthcheck probe +type HealthcheckResult struct { + Start time.Time // Start is the time this check started + End time.Time // End is the time this check ended + ExitCode int // ExitCode meanings: 0=healthy, 1=unhealthy, 2=reserved (considered unhealthy), else=error running probe + Output string // Output from last check +} + +// Health states +const ( + NoHealthcheck = "none" // Indicates there is no healthcheck + Starting = "starting" // Starting indicates that the container is not yet ready + Healthy = "healthy" // Healthy indicates that the container is running correctly + Unhealthy = "unhealthy" // Unhealthy indicates that the container has a problem +) + +// Health stores information about the container's healthcheck results +type Health struct { + Status string // Status is one of Starting, Healthy or Unhealthy + FailingStreak int // FailingStreak is the number of consecutive failures + Log []*HealthcheckResult // Log contains the last few results (oldest first) +} + +// ContainerState stores container's running state +// it's part of ContainerJSONBase and will return by "inspect" command +type ContainerState struct { + Status string // String representation of the container state. Can be one of "created", "running", "paused", "restarting", "removing", "exited", or "dead" + Running bool + Paused bool + Restarting bool + OOMKilled bool + Dead bool + Pid int + ExitCode int + Error string + StartedAt string + FinishedAt string + Health *Health `json:",omitempty"` +} + +// ContainerNode stores information about the node that a container +// is running on. It's only available in Docker Swarm +type ContainerNode struct { + ID string + IPAddress string `json:"IP"` + Addr string + Name string + Cpus int + Memory int64 + Labels map[string]string +} + +// ContainerJSONBase contains response of Engine API: +// GET "/containers/{name:.*}/json" +type ContainerJSONBase struct { + ID string `json:"Id"` + Created string + Path string + Args []string + State *ContainerState + Image string + ResolvConfPath string + HostnamePath string + HostsPath string + LogPath string + Node *ContainerNode `json:",omitempty"` + Name string + RestartCount int + Driver string + Platform string + MountLabel string + ProcessLabel string + AppArmorProfile string + ExecIDs []string + HostConfig *container.HostConfig + GraphDriver GraphDriverData + SizeRw *int64 `json:",omitempty"` + SizeRootFs *int64 `json:",omitempty"` +} + +// ContainerJSON is newly used struct along with MountPoint +type ContainerJSON struct { + *ContainerJSONBase + Mounts []MountPoint + Config *container.Config + NetworkSettings *NetworkSettings +} + +// NetworkSettings exposes the network settings in the api +type NetworkSettings struct { + NetworkSettingsBase + DefaultNetworkSettings + Networks map[string]*network.EndpointSettings +} + +// SummaryNetworkSettings provides a summary of container's networks +// in /containers/json +type SummaryNetworkSettings struct { + Networks map[string]*network.EndpointSettings +} + +// NetworkSettingsBase holds basic information about networks +type NetworkSettingsBase struct { + Bridge string // Bridge is the Bridge name the network uses(e.g. `docker0`) + SandboxID string // SandboxID uniquely represents a container's network stack + HairpinMode bool // HairpinMode specifies if hairpin NAT should be enabled on the virtual interface + LinkLocalIPv6Address string // LinkLocalIPv6Address is an IPv6 unicast address using the link-local prefix + LinkLocalIPv6PrefixLen int // LinkLocalIPv6PrefixLen is the prefix length of an IPv6 unicast address + Ports nat.PortMap // Ports is a collection of PortBinding indexed by Port + SandboxKey string // SandboxKey identifies the sandbox + SecondaryIPAddresses []network.Address + SecondaryIPv6Addresses []network.Address +} + +// DefaultNetworkSettings holds network information +// during the 2 release deprecation period. +// It will be removed in Docker 1.11. +type DefaultNetworkSettings struct { + EndpointID string // EndpointID uniquely represents a service endpoint in a Sandbox + Gateway string // Gateway holds the gateway address for the network + GlobalIPv6Address string // GlobalIPv6Address holds network's global IPv6 address + GlobalIPv6PrefixLen int // GlobalIPv6PrefixLen represents mask length of network's global IPv6 address + IPAddress string // IPAddress holds the IPv4 address for the network + IPPrefixLen int // IPPrefixLen represents mask length of network's IPv4 address + IPv6Gateway string // IPv6Gateway holds gateway address specific for IPv6 + MacAddress string // MacAddress holds the MAC address for the network +} + +// MountPoint represents a mount point configuration inside the container. +// This is used for reporting the mountpoints in use by a container. +type MountPoint struct { + Type mount.Type `json:",omitempty"` + Name string `json:",omitempty"` + Source string + Destination string + Driver string `json:",omitempty"` + Mode string + RW bool + Propagation mount.Propagation +} + +// NetworkResource is the body of the "get network" http response message +type NetworkResource struct { + Name string // Name is the requested name of the network + ID string `json:"Id"` // ID uniquely identifies a network on a single machine + Created time.Time // Created is the time the network created + Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level) + Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`) + EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6 + IPAM network.IPAM // IPAM is the network's IP Address Management + Internal bool // Internal represents if the network is used internal only + Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. + Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. + ConfigFrom network.ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. + ConfigOnly bool // ConfigOnly networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services. + Containers map[string]EndpointResource // Containers contains endpoints belonging to the network + Options map[string]string // Options holds the network specific options to use for when creating the network + Labels map[string]string // Labels holds metadata specific to the network being created + Peers []network.PeerInfo `json:",omitempty"` // List of peer nodes for an overlay network + Services map[string]network.ServiceInfo `json:",omitempty"` +} + +// EndpointResource contains network resources allocated and used for a container in a network +type EndpointResource struct { + Name string + EndpointID string + MacAddress string + IPv4Address string + IPv6Address string +} + +// NetworkCreate is the expected body of the "create network" http request message +type NetworkCreate struct { + // Check for networks with duplicate names. + // Network is primarily keyed based on a random ID and not on the name. + // Network name is strictly a user-friendly alias to the network + // which is uniquely identified using ID. + // And there is no guaranteed way to check for duplicates. + // Option CheckDuplicate is there to provide a best effort checking of any networks + // which has the same name but it is not guaranteed to catch all name collisions. + CheckDuplicate bool + Driver string + Scope string + EnableIPv6 bool + IPAM *network.IPAM + Internal bool + Attachable bool + Ingress bool + ConfigOnly bool + ConfigFrom *network.ConfigReference + Options map[string]string + Labels map[string]string +} + +// NetworkCreateRequest is the request message sent to the server for network create call. +type NetworkCreateRequest struct { + NetworkCreate + Name string +} + +// NetworkCreateResponse is the response message sent by the server for network create call +type NetworkCreateResponse struct { + ID string `json:"Id"` + Warning string +} + +// NetworkConnect represents the data to be used to connect a container to the network +type NetworkConnect struct { + Container string + EndpointConfig *network.EndpointSettings `json:",omitempty"` +} + +// NetworkDisconnect represents the data to be used to disconnect a container from the network +type NetworkDisconnect struct { + Container string + Force bool +} + +// NetworkInspectOptions holds parameters to inspect network +type NetworkInspectOptions struct { + Scope string + Verbose bool +} + +// Checkpoint represents the details of a checkpoint +type Checkpoint struct { + Name string // Name is the name of the checkpoint +} + +// Runtime describes an OCI runtime +type Runtime struct { + Path string `json:"path"` + Args []string `json:"runtimeArgs,omitempty"` +} + +// DiskUsage contains response of Engine API: +// GET "/system/df" +type DiskUsage struct { + LayersSize int64 + Images []*ImageSummary + Containers []*Container + Volumes []*Volume + BuilderSize int64 +} + +// ContainersPruneReport contains the response for Engine API: +// POST "/containers/prune" +type ContainersPruneReport struct { + ContainersDeleted []string + SpaceReclaimed uint64 +} + +// VolumesPruneReport contains the response for Engine API: +// POST "/volumes/prune" +type VolumesPruneReport struct { + VolumesDeleted []string + SpaceReclaimed uint64 +} + +// ImagesPruneReport contains the response for Engine API: +// POST "/images/prune" +type ImagesPruneReport struct { + ImagesDeleted []ImageDeleteResponseItem + SpaceReclaimed uint64 +} + +// BuildCachePruneReport contains the response for Engine API: +// POST "/build/prune" +type BuildCachePruneReport struct { + SpaceReclaimed uint64 +} + +// NetworksPruneReport contains the response for Engine API: +// POST "/networks/prune" +type NetworksPruneReport struct { + NetworksDeleted []string +} + +// SecretCreateResponse contains the information returned to a client +// on the creation of a new secret. +type SecretCreateResponse struct { + // ID is the id of the created secret. + ID string +} + +// SecretListOptions holds parameters to list secrets +type SecretListOptions struct { + Filters filters.Args +} + +// ConfigCreateResponse contains the information returned to a client +// on the creation of a new config. +type ConfigCreateResponse struct { + // ID is the id of the created config. + ID string +} + +// ConfigListOptions holds parameters to list configs +type ConfigListOptions struct { + Filters filters.Args +} + +// PushResult contains the tag, manifest digest, and manifest size from the +// push. It's used to signal this information to the trust code in the client +// so it can sign the manifest if necessary. +type PushResult struct { + Tag string + Digest string + Size int +} + +// BuildResult contains the image id of a successful build +type BuildResult struct { + ID string +} diff --git a/vendor/github.com/gin-gonic/gin/LICENSE b/vendor/github.com/gin-gonic/gin/LICENSE deleted file mode 100644 index 1ff7f370..00000000 --- a/vendor/github.com/gin-gonic/gin/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Manuel Martínez-Almeida - -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. diff --git a/vendor/github.com/gin-gonic/gin/README.md b/vendor/github.com/gin-gonic/gin/README.md deleted file mode 100644 index 82ea6a58..00000000 --- a/vendor/github.com/gin-gonic/gin/README.md +++ /dev/null @@ -1,733 +0,0 @@ - -#Gin Web Framework - - -[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin) -[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin) -[![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin) -[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin) -[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin. - -![Gin console logger](https://gin-gonic.github.io/gin/other/console.png) - -```sh -$ cat test.go -``` -```go -package main - -import "gopkg.in/gin-gonic/gin.v1" - -func main() { - r := gin.Default() - r.GET("/ping", func(c *gin.Context) { - c.JSON(200, gin.H{ - "message": "pong", - }) - }) - r.Run() // listen and serve on 0.0.0.0:8080 -} -``` - -## Benchmarks - -Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter) - -[See all benchmarks](/BENCHMARKS.md) - - -Benchmark name | (1) | (2) | (3) | (4) ---------------------------------|----------:|----------:|----------:|------: -BenchmarkAce_GithubAll | 10000 | 109482 | 13792 | 167 -BenchmarkBear_GithubAll | 10000 | 287490 | 79952 | 943 -BenchmarkBeego_GithubAll | 3000 | 562184 | 146272 | 2092 -BenchmarkBone_GithubAll | 500 | 2578716 | 648016 | 8119 -BenchmarkDenco_GithubAll | 20000 | 94955 | 20224 | 167 -BenchmarkEcho_GithubAll | 30000 | 58705 | 0 | 0 -**BenchmarkGin_GithubAll** | **30000** | **50991** | **0** | **0** -BenchmarkGocraftWeb_GithubAll | 5000 | 449648 | 133280 | 1889 -BenchmarkGoji_GithubAll | 2000 | 689748 | 56113 | 334 -BenchmarkGoJsonRest_GithubAll | 5000 | 537769 | 135995 | 2940 -BenchmarkGoRestful_GithubAll | 100 | 18410628 | 797236 | 7725 -BenchmarkGorillaMux_GithubAll | 200 | 8036360 | 153137 | 1791 -BenchmarkHttpRouter_GithubAll | 20000 | 63506 | 13792 | 167 -BenchmarkHttpTreeMux_GithubAll | 10000 | 165927 | 56112 | 334 -BenchmarkKocha_GithubAll | 10000 | 171362 | 23304 | 843 -BenchmarkMacaron_GithubAll | 2000 | 817008 | 224960 | 2315 -BenchmarkMartini_GithubAll | 100 | 12609209 | 237952 | 2686 -BenchmarkPat_GithubAll | 300 | 4830398 | 1504101 | 32222 -BenchmarkPossum_GithubAll | 10000 | 301716 | 97440 | 812 -BenchmarkR2router_GithubAll | 10000 | 270691 | 77328 | 1182 -BenchmarkRevel_GithubAll | 1000 | 1491919 | 345553 | 5918 -BenchmarkRivet_GithubAll | 10000 | 283860 | 84272 | 1079 -BenchmarkTango_GithubAll | 5000 | 473821 | 87078 | 2470 -BenchmarkTigerTonic_GithubAll | 2000 | 1120131 | 241088 | 6052 -BenchmarkTraffic_GithubAll | 200 | 8708979 | 2664762 | 22390 -BenchmarkVulcan_GithubAll | 5000 | 353392 | 19894 | 609 -BenchmarkZeus_GithubAll | 2000 | 944234 | 300688 | 2648 - -(1): Total Repetitions -(2): Single Repetition Duration (ns/op) -(3): Heap Memory (B/op) -(4): Average Allocations per Repetition (allocs/op) - -## Gin v1. stable - -- [x] Zero allocation router. -- [x] Still the fastest http router and framework. From routing to writing. -- [x] Complete suite of unit tests -- [x] Battle tested -- [x] API frozen, new releases will not break your code. - - -## Start using it - -1. Download and install it: - - ```sh - $ go get gopkg.in/gin-gonic/gin.v1 - ``` - -2. Import it in your code: - - ```go - import "gopkg.in/gin-gonic/gin.v1" - ``` - -3. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`. - - ```go - import "net/http" - ``` - -## API Examples - -#### Using GET, POST, PUT, PATCH, DELETE and OPTIONS - -```go -func main() { - // Creates a gin router with default middleware: - // logger and recovery (crash-free) middleware - router := gin.Default() - - router.GET("/someGet", getting) - router.POST("/somePost", posting) - router.PUT("/somePut", putting) - router.DELETE("/someDelete", deleting) - router.PATCH("/somePatch", patching) - router.HEAD("/someHead", head) - router.OPTIONS("/someOptions", options) - - // By default it serves on :8080 unless a - // PORT environment variable was defined. - router.Run() - // router.Run(":3000") for a hard coded port -} -``` - -#### Parameters in path - -```go -func main() { - router := gin.Default() - - // This handler will match /user/john but will not match neither /user/ or /user - router.GET("/user/:name", func(c *gin.Context) { - name := c.Param("name") - c.String(http.StatusOK, "Hello %s", name) - }) - - // However, this one will match /user/john/ and also /user/john/send - // If no other routers match /user/john, it will redirect to /user/john/ - router.GET("/user/:name/*action", func(c *gin.Context) { - name := c.Param("name") - action := c.Param("action") - message := name + " is " + action - c.String(http.StatusOK, message) - }) - - router.Run(":8080") -} -``` - -#### Querystring parameters -```go -func main() { - router := gin.Default() - - // Query string parameters are parsed using the existing underlying request object. - // The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe - router.GET("/welcome", func(c *gin.Context) { - firstname := c.DefaultQuery("firstname", "Guest") - lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname") - - c.String(http.StatusOK, "Hello %s %s", firstname, lastname) - }) - router.Run(":8080") -} -``` - -### Multipart/Urlencoded Form - -```go -func main() { - router := gin.Default() - - router.POST("/form_post", func(c *gin.Context) { - message := c.PostForm("message") - nick := c.DefaultPostForm("nick", "anonymous") - - c.JSON(200, gin.H{ - "status": "posted", - "message": message, - "nick": nick, - }) - }) - router.Run(":8080") -} -``` - -### Another example: query + post form - -``` -POST /post?id=1234&page=1 HTTP/1.1 -Content-Type: application/x-www-form-urlencoded - -name=manu&message=this_is_great -``` - -```go -func main() { - router := gin.Default() - - router.POST("/post", func(c *gin.Context) { - - id := c.Query("id") - page := c.DefaultQuery("page", "0") - name := c.PostForm("name") - message := c.PostForm("message") - - fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message) - }) - router.Run(":8080") -} -``` - -``` -id: 1234; page: 1; name: manu; message: this_is_great -``` - -### Another example: upload file - -References issue [#548](https://github.com/gin-gonic/gin/issues/548). - -```go -func main() { - router := gin.Default() - - router.POST("/upload", func(c *gin.Context) { - - file, header , err := c.Request.FormFile("upload") - filename := header.Filename - fmt.Println(header.Filename) - out, err := os.Create("./tmp/"+filename+".png") - if err != nil { - log.Fatal(err) - } - defer out.Close() - _, err = io.Copy(out, file) - if err != nil { - log.Fatal(err) - } - }) - router.Run(":8080") -} -``` - -#### Grouping routes -```go -func main() { - router := gin.Default() - - // Simple group: v1 - v1 := router.Group("/v1") - { - v1.POST("/login", loginEndpoint) - v1.POST("/submit", submitEndpoint) - v1.POST("/read", readEndpoint) - } - - // Simple group: v2 - v2 := router.Group("/v2") - { - v2.POST("/login", loginEndpoint) - v2.POST("/submit", submitEndpoint) - v2.POST("/read", readEndpoint) - } - - router.Run(":8080") -} -``` - - -#### Blank Gin without middleware by default - -Use - -```go -r := gin.New() -``` -instead of - -```go -r := gin.Default() -``` - - -#### Using middleware -```go -func main() { - // Creates a router without any middleware by default - r := gin.New() - - // Global middleware - r.Use(gin.Logger()) - r.Use(gin.Recovery()) - - // Per route middleware, you can add as many as you desire. - r.GET("/benchmark", MyBenchLogger(), benchEndpoint) - - // Authorization group - // authorized := r.Group("/", AuthRequired()) - // exactly the same as: - authorized := r.Group("/") - // per group middleware! in this case we use the custom created - // AuthRequired() middleware just in the "authorized" group. - authorized.Use(AuthRequired()) - { - authorized.POST("/login", loginEndpoint) - authorized.POST("/submit", submitEndpoint) - authorized.POST("/read", readEndpoint) - - // nested group - testing := authorized.Group("testing") - testing.GET("/analytics", analyticsEndpoint) - } - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -#### Model binding and validation - -To bind a request body into a type, use model binding. We currently support binding of JSON, XML and standard form values (foo=bar&boo=baz). - -Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`. - -When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use BindWith. - -You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has a empty value when binding, the current request will fail with an error. - -```go -// Binding from JSON -type Login struct { - User string `form:"user" json:"user" binding:"required"` - Password string `form:"password" json:"password" binding:"required"` -} - -func main() { - router := gin.Default() - - // Example for binding JSON ({"user": "manu", "password": "123"}) - router.POST("/loginJSON", func(c *gin.Context) { - var json Login - if c.BindJSON(&json) == nil { - if json.User == "manu" && json.Password == "123" { - c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) - } else { - c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) - } - } - }) - - // Example for binding a HTML form (user=manu&password=123) - router.POST("/loginForm", func(c *gin.Context) { - var form Login - // This will infer what binder to use depending on the content-type header. - if c.Bind(&form) == nil { - if form.User == "manu" && form.Password == "123" { - c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) - } else { - c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) - } - } - }) - - // Listen and serve on 0.0.0.0:8080 - router.Run(":8080") -} -``` - - -###Multipart/Urlencoded binding -```go -package main - -import ( - "gopkg.in/gin-gonic/gin.v1" -) - -type LoginForm struct { - User string `form:"user" binding:"required"` - Password string `form:"password" binding:"required"` -} - -func main() { - router := gin.Default() - router.POST("/login", func(c *gin.Context) { - // you can bind multipart form with explicit binding declaration: - // c.BindWith(&form, binding.Form) - // or you can simply use autobinding with Bind method: - var form LoginForm - // in this case proper binding will be automatically selected - if c.Bind(&form) == nil { - if form.User == "user" && form.Password == "password" { - c.JSON(200, gin.H{"status": "you are logged in"}) - } else { - c.JSON(401, gin.H{"status": "unauthorized"}) - } - } - }) - router.Run(":8080") -} -``` - -Test it with: -```sh -$ curl -v --form user=user --form password=password http://localhost:8080/login -``` - - -#### XML, JSON and YAML rendering - -```go -func main() { - r := gin.Default() - - // gin.H is a shortcut for map[string]interface{} - r.GET("/someJSON", func(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) - }) - - r.GET("/moreJSON", func(c *gin.Context) { - // You also can use a struct - var msg struct { - Name string `json:"user"` - Message string - Number int - } - msg.Name = "Lena" - msg.Message = "hey" - msg.Number = 123 - // Note that msg.Name becomes "user" in the JSON - // Will output : {"user": "Lena", "Message": "hey", "Number": 123} - c.JSON(http.StatusOK, msg) - }) - - r.GET("/someXML", func(c *gin.Context) { - c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) - }) - - r.GET("/someYAML", func(c *gin.Context) { - c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -####Serving static files - -```go -func main() { - router := gin.Default() - router.Static("/assets", "./assets") - router.StaticFS("/more_static", http.Dir("my_file_system")) - router.StaticFile("/favicon.ico", "./resources/favicon.ico") - - // Listen and serve on 0.0.0.0:8080 - router.Run(":8080") -} -``` - -####HTML rendering - -Using LoadHTMLTemplates() - -```go -func main() { - router := gin.Default() - router.LoadHTMLGlob("templates/*") - //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html") - router.GET("/index", func(c *gin.Context) { - c.HTML(http.StatusOK, "index.tmpl", gin.H{ - "title": "Main website", - }) - }) - router.Run(":8080") -} -``` -templates/index.tmpl -```html - -
Using posts/index.tmpl
- -{{ end }} -``` -templates/users/index.tmpl -```html -{{ define "users/index.tmpl" }} -Using users/index.tmpl
- -{{ end }} -``` - -You can also use your own html template render - -```go -import "html/template" - -func main() { - router := gin.Default() - html := template.Must(template.ParseFiles("file1", "file2")) - router.SetHTMLTemplate(html) - router.Run(":8080") -} -``` - - -#### Redirects - -Issuing a HTTP redirect is easy: - -```go -r.GET("/test", func(c *gin.Context) { - c.Redirect(http.StatusMovedPermanently, "http://www.google.com/") -}) -``` -Both internal and external locations are supported. - - -#### Custom Middleware - -```go -func Logger() gin.HandlerFunc { - return func(c *gin.Context) { - t := time.Now() - - // Set example variable - c.Set("example", "12345") - - // before request - - c.Next() - - // after request - latency := time.Since(t) - log.Print(latency) - - // access the status we are sending - status := c.Writer.Status() - log.Println(status) - } -} - -func main() { - r := gin.New() - r.Use(Logger()) - - r.GET("/test", func(c *gin.Context) { - example := c.MustGet("example").(string) - - // it would print: "12345" - log.Println(example) - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -#### Using BasicAuth() middleware -```go -// simulate some private data -var secrets = gin.H{ - "foo": gin.H{"email": "foo@bar.com", "phone": "123433"}, - "austin": gin.H{"email": "austin@example.com", "phone": "666"}, - "lena": gin.H{"email": "lena@guapa.com", "phone": "523443"}, -} - -func main() { - r := gin.Default() - - // Group using gin.BasicAuth() middleware - // gin.Accounts is a shortcut for map[string]string - authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{ - "foo": "bar", - "austin": "1234", - "lena": "hello2", - "manu": "4321", - })) - - // /admin/secrets endpoint - // hit "localhost:8080/admin/secrets - authorized.GET("/secrets", func(c *gin.Context) { - // get user, it was set by the BasicAuth middleware - user := c.MustGet(gin.AuthUserKey).(string) - if secret, ok := secrets[user]; ok { - c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret}) - } else { - c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("}) - } - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - - -#### Goroutines inside a middleware -When starting inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy. - -```go -func main() { - r := gin.Default() - - r.GET("/long_async", func(c *gin.Context) { - // create copy to be used inside the goroutine - cCp := c.Copy() - go func() { - // simulate a long task with time.Sleep(). 5 seconds - time.Sleep(5 * time.Second) - - // note that you are using the copied context "cCp", IMPORTANT - log.Println("Done! in path " + cCp.Request.URL.Path) - }() - }) - - r.GET("/long_sync", func(c *gin.Context) { - // simulate a long task with time.Sleep(). 5 seconds - time.Sleep(5 * time.Second) - - // since we are NOT using a goroutine, we do not have to copy the context - log.Println("Done! in path " + c.Request.URL.Path) - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - -#### Custom HTTP configuration - -Use `http.ListenAndServe()` directly, like this: - -```go -func main() { - router := gin.Default() - http.ListenAndServe(":8080", router) -} -``` -or - -```go -func main() { - router := gin.Default() - - s := &http.Server{ - Addr: ":8080", - Handler: router, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - MaxHeaderBytes: 1 << 20, - } - s.ListenAndServe() -} -``` - -#### Graceful restart or stop - -Do you want to graceful restart or stop your web server? -There are some ways this can be done. - -We can use [fvbock/endless](https://github.com/fvbock/endless) to replace the default `ListenAndServe`. Refer issue [#296](https://github.com/gin-gonic/gin/issues/296) for more details. - -```go -router := gin.Default() -router.GET("/", handler) -// [...] -endless.ListenAndServe(":4242", router) -``` - -An alternative to endless: - -* [manners](https://github.com/braintree/manners): A polite Go HTTP server that shuts down gracefully. - -## Contributing - -- With issues: - - Use the search tool before opening a new issue. - - Please provide source code and commit sha if you found a bug. - - Review existing issues and provide feedback or react to them. -- With pull requests: - - Open your pull request against develop - - Your pull request should have no more than two commits, if not you should squash them. - - It should pass all tests in the available continuous integrations systems such as TravisCI. - - You should add/modify tests to cover your proposed code changes. - - If your pull request contains a new feature, please document it on the README. - -## Example - -Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework. - -* [drone](https://github.com/drone/drone): Drone is a Continuous Delivery platform built on Docker, written in Go -* [gorush](https://github.com/appleboy/gorush): A push notification server written in Go. diff --git a/vendor/github.com/gin-gonic/gin/auth.go b/vendor/github.com/gin-gonic/gin/auth.go deleted file mode 100644 index 125e659f..00000000 --- a/vendor/github.com/gin-gonic/gin/auth.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "crypto/subtle" - "encoding/base64" - "strconv" -) - -const AuthUserKey = "user" - -type ( - Accounts map[string]string - authPair struct { - Value string - User string - } - authPairs []authPair -) - -func (a authPairs) searchCredential(authValue string) (string, bool) { - if len(authValue) == 0 { - return "", false - } - for _, pair := range a { - if pair.Value == authValue { - return pair.User, true - } - } - return "", false -} - -// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where -// the key is the user name and the value is the password, as well as the name of the Realm. -// If the realm is empty, "Authorization Required" will be used by default. -// (see http://tools.ietf.org/html/rfc2617#section-1.2) -func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc { - if realm == "" { - realm = "Authorization Required" - } - realm = "Basic realm=" + strconv.Quote(realm) - pairs := processAccounts(accounts) - return func(c *Context) { - // Search user in the slice of allowed credentials - user, found := pairs.searchCredential(c.Request.Header.Get("Authorization")) - if !found { - // Credentials doesn't match, we return 401 and abort handlers chain. - c.Header("WWW-Authenticate", realm) - c.AbortWithStatus(401) - } else { - // The user credentials was found, set user's id to key AuthUserKey in this context, the userId can be read later using - // c.MustGet(gin.AuthUserKey) - c.Set(AuthUserKey, user) - } - } -} - -// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where -// the key is the user name and the value is the password. -func BasicAuth(accounts Accounts) HandlerFunc { - return BasicAuthForRealm(accounts, "") -} - -func processAccounts(accounts Accounts) authPairs { - assert1(len(accounts) > 0, "Empty list of authorized credentials") - pairs := make(authPairs, 0, len(accounts)) - for user, password := range accounts { - assert1(len(user) > 0, "User can not be empty") - value := authorizationHeader(user, password) - pairs = append(pairs, authPair{ - Value: value, - User: user, - }) - } - return pairs -} - -func authorizationHeader(user, password string) string { - base := user + ":" + password - return "Basic " + base64.StdEncoding.EncodeToString([]byte(base)) -} - -func secureCompare(given, actual string) bool { - if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 { - return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1 - } - /* Securely compare actual to itself to keep constant time, but always return false */ - return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false -} diff --git a/vendor/github.com/gin-gonic/gin/binding/binding.go b/vendor/github.com/gin-gonic/gin/binding/binding.go deleted file mode 100644 index dc7397f1..00000000 --- a/vendor/github.com/gin-gonic/gin/binding/binding.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import "net/http" - -const ( - MIMEJSON = "application/json" - MIMEHTML = "text/html" - MIMEXML = "application/xml" - MIMEXML2 = "text/xml" - MIMEPlain = "text/plain" - MIMEPOSTForm = "application/x-www-form-urlencoded" - MIMEMultipartPOSTForm = "multipart/form-data" - MIMEPROTOBUF = "application/x-protobuf" -) - -type Binding interface { - Name() string - Bind(*http.Request, interface{}) error -} - -type StructValidator interface { - // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. - // If the received type is not a struct, any validation should be skipped and nil must be returned. - // If the received type is a struct or pointer to a struct, the validation should be performed. - // If the struct is not valid or the validation itself fails, a descriptive error should be returned. - // Otherwise nil must be returned. - ValidateStruct(interface{}) error -} - -var Validator StructValidator = &defaultValidator{} - -var ( - JSON = jsonBinding{} - XML = xmlBinding{} - Form = formBinding{} - FormPost = formPostBinding{} - FormMultipart = formMultipartBinding{} - ProtoBuf = protobufBinding{} -) - -func Default(method, contentType string) Binding { - if method == "GET" { - return Form - } else { - switch contentType { - case MIMEJSON: - return JSON - case MIMEXML, MIMEXML2: - return XML - case MIMEPROTOBUF: - return ProtoBuf - default: //case MIMEPOSTForm, MIMEMultipartPOSTForm: - return Form - } - } -} - -func validate(obj interface{}) error { - if Validator == nil { - return nil - } - return Validator.ValidateStruct(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/default_validator.go b/vendor/github.com/gin-gonic/gin/binding/default_validator.go deleted file mode 100644 index 760728bb..00000000 --- a/vendor/github.com/gin-gonic/gin/binding/default_validator.go +++ /dev/null @@ -1,41 +0,0 @@ -package binding - -import ( - "reflect" - "sync" - - "gopkg.in/go-playground/validator.v8" -) - -type defaultValidator struct { - once sync.Once - validate *validator.Validate -} - -var _ StructValidator = &defaultValidator{} - -func (v *defaultValidator) ValidateStruct(obj interface{}) error { - if kindOfData(obj) == reflect.Struct { - v.lazyinit() - if err := v.validate.Struct(obj); err != nil { - return error(err) - } - } - return nil -} - -func (v *defaultValidator) lazyinit() { - v.once.Do(func() { - config := &validator.Config{TagName: "binding"} - v.validate = validator.New(config) - }) -} - -func kindOfData(data interface{}) reflect.Kind { - value := reflect.ValueOf(data) - valueType := value.Kind() - if valueType == reflect.Ptr { - valueType = value.Elem().Kind() - } - return valueType -} diff --git a/vendor/github.com/gin-gonic/gin/binding/form.go b/vendor/github.com/gin-gonic/gin/binding/form.go deleted file mode 100644 index 557333e6..00000000 --- a/vendor/github.com/gin-gonic/gin/binding/form.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import "net/http" - -type formBinding struct{} -type formPostBinding struct{} -type formMultipartBinding struct{} - -func (formBinding) Name() string { - return "form" -} - -func (formBinding) Bind(req *http.Request, obj interface{}) error { - if err := req.ParseForm(); err != nil { - return err - } - req.ParseMultipartForm(32 << 10) // 32 MB - if err := mapForm(obj, req.Form); err != nil { - return err - } - return validate(obj) -} - -func (formPostBinding) Name() string { - return "form-urlencoded" -} - -func (formPostBinding) Bind(req *http.Request, obj interface{}) error { - if err := req.ParseForm(); err != nil { - return err - } - if err := mapForm(obj, req.PostForm); err != nil { - return err - } - return validate(obj) -} - -func (formMultipartBinding) Name() string { - return "multipart/form-data" -} - -func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error { - if err := req.ParseMultipartForm(32 << 10); err != nil { - return err - } - if err := mapForm(obj, req.MultipartForm.Value); err != nil { - return err - } - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/form_mapping.go b/vendor/github.com/gin-gonic/gin/binding/form_mapping.go deleted file mode 100644 index 07c83751..00000000 --- a/vendor/github.com/gin-gonic/gin/binding/form_mapping.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "errors" - "reflect" - "strconv" -) - -func mapForm(ptr interface{}, form map[string][]string) error { - typ := reflect.TypeOf(ptr).Elem() - val := reflect.ValueOf(ptr).Elem() - for i := 0; i < typ.NumField(); i++ { - typeField := typ.Field(i) - structField := val.Field(i) - if !structField.CanSet() { - continue - } - - structFieldKind := structField.Kind() - inputFieldName := typeField.Tag.Get("form") - if inputFieldName == "" { - inputFieldName = typeField.Name - - // if "form" tag is nil, we inspect if the field is a struct. - // this would not make sense for JSON parsing but it does for a form - // since data is flatten - if structFieldKind == reflect.Struct { - err := mapForm(structField.Addr().Interface(), form) - if err != nil { - return err - } - continue - } - } - inputValue, exists := form[inputFieldName] - if !exists { - continue - } - - numElems := len(inputValue) - if structFieldKind == reflect.Slice && numElems > 0 { - sliceOf := structField.Type().Elem().Kind() - slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for i := 0; i < numElems; i++ { - if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil { - return err - } - } - val.Field(i).Set(slice) - } else { - if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil { - return err - } - } - } - return nil -} - -func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error { - switch valueKind { - case reflect.Int: - return setIntField(val, 0, structField) - case reflect.Int8: - return setIntField(val, 8, structField) - case reflect.Int16: - return setIntField(val, 16, structField) - case reflect.Int32: - return setIntField(val, 32, structField) - case reflect.Int64: - return setIntField(val, 64, structField) - case reflect.Uint: - return setUintField(val, 0, structField) - case reflect.Uint8: - return setUintField(val, 8, structField) - case reflect.Uint16: - return setUintField(val, 16, structField) - case reflect.Uint32: - return setUintField(val, 32, structField) - case reflect.Uint64: - return setUintField(val, 64, structField) - case reflect.Bool: - return setBoolField(val, structField) - case reflect.Float32: - return setFloatField(val, 32, structField) - case reflect.Float64: - return setFloatField(val, 64, structField) - case reflect.String: - structField.SetString(val) - default: - return errors.New("Unknown type") - } - return nil -} - -func setIntField(val string, bitSize int, field reflect.Value) error { - if val == "" { - val = "0" - } - intVal, err := strconv.ParseInt(val, 10, bitSize) - if err == nil { - field.SetInt(intVal) - } - return err -} - -func setUintField(val string, bitSize int, field reflect.Value) error { - if val == "" { - val = "0" - } - uintVal, err := strconv.ParseUint(val, 10, bitSize) - if err == nil { - field.SetUint(uintVal) - } - return err -} - -func setBoolField(val string, field reflect.Value) error { - if val == "" { - val = "false" - } - boolVal, err := strconv.ParseBool(val) - if err == nil { - field.SetBool(boolVal) - } - return nil -} - -func setFloatField(val string, bitSize int, field reflect.Value) error { - if val == "" { - val = "0.0" - } - floatVal, err := strconv.ParseFloat(val, bitSize) - if err == nil { - field.SetFloat(floatVal) - } - return err -} - -// Don't pass in pointers to bind to. Can lead to bugs. See: -// https://github.com/codegangsta/martini-contrib/issues/40 -// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659 -func ensureNotPointer(obj interface{}) { - if reflect.TypeOf(obj).Kind() == reflect.Ptr { - panic("Pointers are not accepted as binding models") - } -} diff --git a/vendor/github.com/gin-gonic/gin/binding/json.go b/vendor/github.com/gin-gonic/gin/binding/json.go deleted file mode 100644 index 6e532443..00000000 --- a/vendor/github.com/gin-gonic/gin/binding/json.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "encoding/json" - - "net/http" -) - -type jsonBinding struct{} - -func (jsonBinding) Name() string { - return "json" -} - -func (jsonBinding) Bind(req *http.Request, obj interface{}) error { - decoder := json.NewDecoder(req.Body) - if err := decoder.Decode(obj); err != nil { - return err - } - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/protobuf.go b/vendor/github.com/gin-gonic/gin/binding/protobuf.go deleted file mode 100644 index 9f956228..00000000 --- a/vendor/github.com/gin-gonic/gin/binding/protobuf.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "github.com/golang/protobuf/proto" - - "io/ioutil" - "net/http" -) - -type protobufBinding struct{} - -func (protobufBinding) Name() string { - return "protobuf" -} - -func (protobufBinding) Bind(req *http.Request, obj interface{}) error { - - buf, err := ioutil.ReadAll(req.Body) - if err != nil { - return err - } - - if err = proto.Unmarshal(buf, obj.(proto.Message)); err != nil { - return err - } - - //Here it's same to return validate(obj), but util now we cann't add `binding:""` to the struct - //which automatically generate by gen-proto - return nil - //return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/binding/xml.go b/vendor/github.com/gin-gonic/gin/binding/xml.go deleted file mode 100644 index f84a6b7f..00000000 --- a/vendor/github.com/gin-gonic/gin/binding/xml.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "encoding/xml" - "net/http" -) - -type xmlBinding struct{} - -func (xmlBinding) Name() string { - return "xml" -} - -func (xmlBinding) Bind(req *http.Request, obj interface{}) error { - decoder := xml.NewDecoder(req.Body) - if err := decoder.Decode(obj); err != nil { - return err - } - return validate(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/context.go b/vendor/github.com/gin-gonic/gin/context.go deleted file mode 100644 index df001a40..00000000 --- a/vendor/github.com/gin-gonic/gin/context.go +++ /dev/null @@ -1,601 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "errors" - "io" - "math" - "net" - "net/http" - "net/url" - "strings" - "time" - - "github.com/gin-gonic/gin/binding" - "github.com/gin-gonic/gin/render" - "github.com/manucorporat/sse" - "golang.org/x/net/context" -) - -// Content-Type MIME of the most common data formats -const ( - MIMEJSON = binding.MIMEJSON - MIMEHTML = binding.MIMEHTML - MIMEXML = binding.MIMEXML - MIMEXML2 = binding.MIMEXML2 - MIMEPlain = binding.MIMEPlain - MIMEPOSTForm = binding.MIMEPOSTForm - MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm -) - -const abortIndex int8 = math.MaxInt8 / 2 - -// Context is the most important part of gin. It allows us to pass variables between middleware, -// manage the flow, validate the JSON of a request and render a JSON response for example. -type Context struct { - writermem responseWriter - Request *http.Request - Writer ResponseWriter - - Params Params - handlers HandlersChain - index int8 - - engine *Engine - Keys map[string]interface{} - Errors errorMsgs - Accepted []string -} - -var _ context.Context = &Context{} - -/************************************/ -/********** CONTEXT CREATION ********/ -/************************************/ - -func (c *Context) reset() { - c.Writer = &c.writermem - c.Params = c.Params[0:0] - c.handlers = nil - c.index = -1 - c.Keys = nil - c.Errors = c.Errors[0:0] - c.Accepted = nil -} - -// Copy returns a copy of the current context that can be safely used outside the request's scope. -// This have to be used then the context has to be passed to a goroutine. -func (c *Context) Copy() *Context { - var cp = *c - cp.writermem.ResponseWriter = nil - cp.Writer = &cp.writermem - cp.index = abortIndex - cp.handlers = nil - return &cp -} - -// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", this -// function will return "main.handleGetUsers" -func (c *Context) HandlerName() string { - return nameOfFunction(c.handlers.Last()) -} - -/************************************/ -/*********** FLOW CONTROL ***********/ -/************************************/ - -// Next should be used only inside middleware. -// It executes the pending handlers in the chain inside the calling handler. -// See example in github. -func (c *Context) Next() { - c.index++ - s := int8(len(c.handlers)) - for ; c.index < s; c.index++ { - c.handlers[c.index](c) - } -} - -// IsAborted returns true if the current context was aborted. -func (c *Context) IsAborted() bool { - return c.index >= abortIndex -} - -// Abort prevents pending handlers from being called. Note that this will not stop the current handler. -// Let's say you have an authorization middleware that validates that the current request is authorized. If the -// authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers -// for this request are not called. -func (c *Context) Abort() { - c.index = abortIndex -} - -// AbortWithStatus calls `Abort()` and writes the headers with the specified status code. -// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401). -func (c *Context) AbortWithStatus(code int) { - c.Status(code) - c.Writer.WriteHeaderNow() - c.Abort() -} - -// AbortWithError calls `AbortWithStatus()` and `Error()` internally. This method stops the chain, writes the status code and -// pushes the specified error to `c.Errors`. -// See Context.Error() for more details. -func (c *Context) AbortWithError(code int, err error) *Error { - c.AbortWithStatus(code) - return c.Error(err) -} - -/************************************/ -/********* ERROR MANAGEMENT *********/ -/************************************/ - -// Attaches an error to the current context. The error is pushed to a list of errors. -// It's a good idea to call Error for each error that occurred during the resolution of a request. -// A middleware can be used to collect all the errors -// and push them to a database together, print a log, or append it in the HTTP response. -func (c *Context) Error(err error) *Error { - var parsedError *Error - switch err.(type) { - case *Error: - parsedError = err.(*Error) - default: - parsedError = &Error{ - Err: err, - Type: ErrorTypePrivate, - } - } - c.Errors = append(c.Errors, parsedError) - return parsedError -} - -/************************************/ -/******** METADATA MANAGEMENT********/ -/************************************/ - -// Set is used to store a new key/value pair exclusivelly for this context. -// It also lazy initializes c.Keys if it was not used previously. -func (c *Context) Set(key string, value interface{}) { - if c.Keys == nil { - c.Keys = make(map[string]interface{}) - } - c.Keys[key] = value -} - -// Get returns the value for the given key, ie: (value, true). -// If the value does not exists it returns (nil, false) -func (c *Context) Get(key string) (value interface{}, exists bool) { - if c.Keys != nil { - value, exists = c.Keys[key] - } - return -} - -// MustGet returns the value for the given key if it exists, otherwise it panics. -func (c *Context) MustGet(key string) interface{} { - if value, exists := c.Get(key); exists { - return value - } - panic("Key \"" + key + "\" does not exist") -} - -/************************************/ -/************ INPUT DATA ************/ -/************************************/ - -// Param returns the value of the URL param. -// It is a shortcut for c.Params.ByName(key) -// router.GET("/user/:id", func(c *gin.Context) { -// // a GET request to /user/john -// id := c.Param("id") // id == "john" -// }) -func (c *Context) Param(key string) string { - return c.Params.ByName(key) -} - -// Query returns the keyed url query value if it exists, -// othewise it returns an empty string `("")`. -// It is shortcut for `c.Request.URL.Query().Get(key)` -// GET /path?id=1234&name=Manu&value= -// c.Query("id") == "1234" -// c.Query("name") == "Manu" -// c.Query("value") == "" -// c.Query("wtf") == "" -func (c *Context) Query(key string) string { - value, _ := c.GetQuery(key) - return value -} - -// DefaultQuery returns the keyed url query value if it exists, -// othewise it returns the specified defaultValue string. -// See: Query() and GetQuery() for further information. -// GET /?name=Manu&lastname= -// c.DefaultQuery("name", "unknown") == "Manu" -// c.DefaultQuery("id", "none") == "none" -// c.DefaultQuery("lastname", "none") == "" -func (c *Context) DefaultQuery(key, defaultValue string) string { - if value, ok := c.GetQuery(key); ok { - return value - } - return defaultValue -} - -// GetQuery is like Query(), it returns the keyed url query value -// if it exists `(value, true)` (even when the value is an empty string), -// othewise it returns `("", false)`. -// It is shortcut for `c.Request.URL.Query().Get(key)` -// GET /?name=Manu&lastname= -// ("Manu", true) == c.GetQuery("name") -// ("", false) == c.GetQuery("id") -// ("", true) == c.GetQuery("lastname") -func (c *Context) GetQuery(key string) (string, bool) { - if values, ok := c.GetQueryArray(key); ok { - return values[0], ok - } - return "", false -} - -// QueryArray returns a slice of strings for a given query key. -// The length of the slice depends on the number of params with the given key. -func (c *Context) QueryArray(key string) []string { - values, _ := c.GetQueryArray(key) - return values -} - -// GetQueryArray returns a slice of strings for a given query key, plus -// a boolean value whether at least one value exists for the given key. -func (c *Context) GetQueryArray(key string) ([]string, bool) { - req := c.Request - if values, ok := req.URL.Query()[key]; ok && len(values) > 0 { - return values, true - } - return []string{}, false -} - -// PostForm returns the specified key from a POST urlencoded form or multipart form -// when it exists, otherwise it returns an empty string `("")`. -func (c *Context) PostForm(key string) string { - value, _ := c.GetPostForm(key) - return value -} - -// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form -// when it exists, otherwise it returns the specified defaultValue string. -// See: PostForm() and GetPostForm() for further information. -func (c *Context) DefaultPostForm(key, defaultValue string) string { - if value, ok := c.GetPostForm(key); ok { - return value - } - return defaultValue -} - -// GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded -// form or multipart form when it exists `(value, true)` (even when the value is an empty string), -// otherwise it returns ("", false). -// For example, during a PATCH request to update the user's email: -// email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com" -// email= --> ("", true) := GetPostForm("email") // set email to "" -// --> ("", false) := GetPostForm("email") // do nothing with email -func (c *Context) GetPostForm(key string) (string, bool) { - if values, ok := c.GetPostFormArray(key); ok { - return values[0], ok - } - return "", false -} - -// PostFormArray returns a slice of strings for a given form key. -// The length of the slice depends on the number of params with the given key. -func (c *Context) PostFormArray(key string) []string { - values, _ := c.GetPostFormArray(key) - return values -} - -// GetPostFormArray returns a slice of strings for a given form key, plus -// a boolean value whether at least one value exists for the given key. -func (c *Context) GetPostFormArray(key string) ([]string, bool) { - req := c.Request - req.ParseForm() - req.ParseMultipartForm(32 << 20) // 32 MB - if values := req.PostForm[key]; len(values) > 0 { - return values, true - } - if req.MultipartForm != nil && req.MultipartForm.File != nil { - if values := req.MultipartForm.Value[key]; len(values) > 0 { - return values, true - } - } - return []string{}, false -} - -// Bind checks the Content-Type to select a binding engine automatically, -// Depending the "Content-Type" header different bindings are used: -// "application/json" --> JSON binding -// "application/xml" --> XML binding -// otherwise --> returns an error -// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. -// It decodes the json payload into the struct specified as a pointer. -// Like ParseBody() but this method also writes a 400 error if the json is not valid. -func (c *Context) Bind(obj interface{}) error { - b := binding.Default(c.Request.Method, c.ContentType()) - return c.BindWith(obj, b) -} - -// BindJSON is a shortcut for c.BindWith(obj, binding.JSON) -func (c *Context) BindJSON(obj interface{}) error { - return c.BindWith(obj, binding.JSON) -} - -// BindWith binds the passed struct pointer using the specified binding engine. -// See the binding package. -func (c *Context) BindWith(obj interface{}, b binding.Binding) error { - if err := b.Bind(c.Request, obj); err != nil { - c.AbortWithError(400, err).SetType(ErrorTypeBind) - return err - } - return nil -} - -// ClientIP implements a best effort algorithm to return the real client IP, it parses -// X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy. -func (c *Context) ClientIP() string { - if c.engine.ForwardedByClientIP { - clientIP := strings.TrimSpace(c.requestHeader("X-Real-Ip")) - if len(clientIP) > 0 { - return clientIP - } - clientIP = c.requestHeader("X-Forwarded-For") - if index := strings.IndexByte(clientIP, ','); index >= 0 { - clientIP = clientIP[0:index] - } - clientIP = strings.TrimSpace(clientIP) - if len(clientIP) > 0 { - return clientIP - } - } - if ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)); err == nil { - return ip - } - return "" -} - -// ContentType returns the Content-Type header of the request. -func (c *Context) ContentType() string { - return filterFlags(c.requestHeader("Content-Type")) -} - -func (c *Context) requestHeader(key string) string { - if values, _ := c.Request.Header[key]; len(values) > 0 { - return values[0] - } - return "" -} - -/************************************/ -/******** RESPONSE RENDERING ********/ -/************************************/ - -func (c *Context) Status(code int) { - c.writermem.WriteHeader(code) -} - -// Header is a intelligent shortcut for c.Writer.Header().Set(key, value) -// It writes a header in the response. -// If value == "", this method removes the header `c.Writer.Header().Del(key)` -func (c *Context) Header(key, value string) { - if len(value) == 0 { - c.Writer.Header().Del(key) - } else { - c.Writer.Header().Set(key, value) - } -} - -func (c *Context) SetCookie( - name string, - value string, - maxAge int, - path string, - domain string, - secure bool, - httpOnly bool, -) { - if path == "" { - path = "/" - } - http.SetCookie(c.Writer, &http.Cookie{ - Name: name, - Value: url.QueryEscape(value), - MaxAge: maxAge, - Path: path, - Domain: domain, - Secure: secure, - HttpOnly: httpOnly, - }) -} - -func (c *Context) Cookie(name string) (string, error) { - cookie, err := c.Request.Cookie(name) - if err != nil { - return "", err - } - val, _ := url.QueryUnescape(cookie.Value) - return val, nil -} - -func (c *Context) Render(code int, r render.Render) { - c.Status(code) - if err := r.Render(c.Writer); err != nil { - panic(err) - } -} - -// HTML renders the HTTP template specified by its file name. -// It also updates the HTTP code and sets the Content-Type as "text/html". -// See http://golang.org/doc/articles/wiki/ -func (c *Context) HTML(code int, name string, obj interface{}) { - instance := c.engine.HTMLRender.Instance(name, obj) - c.Render(code, instance) -} - -// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body. -// It also sets the Content-Type as "application/json". -// WARNING: we recommend to use this only for development propuses since printing pretty JSON is -// more CPU and bandwidth consuming. Use Context.JSON() instead. -func (c *Context) IndentedJSON(code int, obj interface{}) { - c.Render(code, render.IndentedJSON{Data: obj}) -} - -// JSON serializes the given struct as JSON into the response body. -// It also sets the Content-Type as "application/json". -func (c *Context) JSON(code int, obj interface{}) { - c.Status(code) - if err := render.WriteJSON(c.Writer, obj); err != nil { - panic(err) - } -} - -// XML serializes the given struct as XML into the response body. -// It also sets the Content-Type as "application/xml". -func (c *Context) XML(code int, obj interface{}) { - c.Render(code, render.XML{Data: obj}) -} - -// YAML serializes the given struct as YAML into the response body. -func (c *Context) YAML(code int, obj interface{}) { - c.Render(code, render.YAML{Data: obj}) -} - -// String writes the given string into the response body. -func (c *Context) String(code int, format string, values ...interface{}) { - c.Status(code) - render.WriteString(c.Writer, format, values) -} - -// Redirect returns a HTTP redirect to the specific location. -func (c *Context) Redirect(code int, location string) { - c.Render(-1, render.Redirect{ - Code: code, - Location: location, - Request: c.Request, - }) -} - -// Data writes some data into the body stream and updates the HTTP code. -func (c *Context) Data(code int, contentType string, data []byte) { - c.Render(code, render.Data{ - ContentType: contentType, - Data: data, - }) -} - -// File writes the specified file into the body stream in a efficient way. -func (c *Context) File(filepath string) { - http.ServeFile(c.Writer, c.Request, filepath) -} - -// SSEvent writes a Server-Sent Event into the body stream. -func (c *Context) SSEvent(name string, message interface{}) { - c.Render(-1, sse.Event{ - Event: name, - Data: message, - }) -} - -func (c *Context) Stream(step func(w io.Writer) bool) { - w := c.Writer - clientGone := w.CloseNotify() - for { - select { - case <-clientGone: - return - default: - keepOpen := step(w) - w.Flush() - if !keepOpen { - return - } - } - } -} - -/************************************/ -/******** CONTENT NEGOTIATION *******/ -/************************************/ - -type Negotiate struct { - Offered []string - HTMLName string - HTMLData interface{} - JSONData interface{} - XMLData interface{} - Data interface{} -} - -func (c *Context) Negotiate(code int, config Negotiate) { - switch c.NegotiateFormat(config.Offered...) { - case binding.MIMEJSON: - data := chooseData(config.JSONData, config.Data) - c.JSON(code, data) - - case binding.MIMEHTML: - data := chooseData(config.HTMLData, config.Data) - c.HTML(code, config.HTMLName, data) - - case binding.MIMEXML: - data := chooseData(config.XMLData, config.Data) - c.XML(code, data) - - default: - c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) - } -} - -func (c *Context) NegotiateFormat(offered ...string) string { - assert1(len(offered) > 0, "you must provide at least one offer") - - if c.Accepted == nil { - c.Accepted = parseAccept(c.requestHeader("Accept")) - } - if len(c.Accepted) == 0 { - return offered[0] - } - for _, accepted := range c.Accepted { - for _, offert := range offered { - if accepted == offert { - return offert - } - } - } - return "" -} - -func (c *Context) SetAccepted(formats ...string) { - c.Accepted = formats -} - -/************************************/ -/***** GOLANG.ORG/X/NET/CONTEXT *****/ -/************************************/ - -func (c *Context) Deadline() (deadline time.Time, ok bool) { - return -} - -func (c *Context) Done() <-chan struct{} { - return nil -} - -func (c *Context) Err() error { - return nil -} - -func (c *Context) Value(key interface{}) interface{} { - if key == 0 { - return c.Request - } - if keyAsString, ok := key.(string); ok { - val, _ := c.Get(keyAsString) - return val - } - return nil -} diff --git a/vendor/github.com/gin-gonic/gin/debug.go b/vendor/github.com/gin-gonic/gin/debug.go deleted file mode 100644 index a121591a..00000000 --- a/vendor/github.com/gin-gonic/gin/debug.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "bytes" - "html/template" - "log" -) - -func init() { - log.SetFlags(0) -} - -// IsDebugging returns true if the framework is running in debug mode. -// Use SetMode(gin.Release) to switch to disable the debug mode. -func IsDebugging() bool { - return ginMode == debugCode -} - -func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) { - if IsDebugging() { - nuHandlers := len(handlers) - handlerName := nameOfFunction(handlers.Last()) - debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) - } -} - -func debugPrintLoadTemplate(tmpl *template.Template) { - if IsDebugging() { - var buf bytes.Buffer - for _, tmpl := range tmpl.Templates() { - buf.WriteString("\t- ") - buf.WriteString(tmpl.Name()) - buf.WriteString("\n") - } - debugPrint("Loaded HTML Templates (%d): \n%s\n", len(tmpl.Templates()), buf.String()) - } -} - -func debugPrint(format string, values ...interface{}) { - if IsDebugging() { - log.Printf("[GIN-debug] "+format, values...) - } -} - -func debugPrintWARNINGNew() { - debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production. - - using env: export GIN_MODE=release - - using code: gin.SetMode(gin.ReleaseMode) - -`) -} - -func debugPrintWARNINGSetHTMLTemplate() { - debugPrint(`[WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called -at initialization. ie. before any route is registered or the router is listening in a socket: - - router := gin.Default() - router.SetHTMLTemplate(template) // << good place - -`) -} - -func debugPrintError(err error) { - if err != nil { - debugPrint("[ERROR] %v\n", err) - } -} diff --git a/vendor/github.com/gin-gonic/gin/deprecated.go b/vendor/github.com/gin-gonic/gin/deprecated.go deleted file mode 100644 index 0488a9b0..00000000 --- a/vendor/github.com/gin-gonic/gin/deprecated.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import "log" - -func (c *Context) GetCookie(name string) (string, error) { - log.Println("GetCookie() method is deprecated. Use Cookie() instead.") - return c.Cookie(name) -} diff --git a/vendor/github.com/gin-gonic/gin/errors.go b/vendor/github.com/gin-gonic/gin/errors.go deleted file mode 100644 index 7716bfae..00000000 --- a/vendor/github.com/gin-gonic/gin/errors.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "bytes" - "encoding/json" - "fmt" - "reflect" -) - -type ErrorType uint64 - -const ( - ErrorTypeBind ErrorType = 1 << 63 // used when c.Bind() fails - ErrorTypeRender ErrorType = 1 << 62 // used when c.Render() fails - ErrorTypePrivate ErrorType = 1 << 0 - ErrorTypePublic ErrorType = 1 << 1 - - ErrorTypeAny ErrorType = 1<<64 - 1 - ErrorTypeNu = 2 -) - -type ( - Error struct { - Err error - Type ErrorType - Meta interface{} - } - - errorMsgs []*Error -) - -var _ error = &Error{} - -func (msg *Error) SetType(flags ErrorType) *Error { - msg.Type = flags - return msg -} - -func (msg *Error) SetMeta(data interface{}) *Error { - msg.Meta = data - return msg -} - -func (msg *Error) JSON() interface{} { - json := H{} - if msg.Meta != nil { - value := reflect.ValueOf(msg.Meta) - switch value.Kind() { - case reflect.Struct: - return msg.Meta - case reflect.Map: - for _, key := range value.MapKeys() { - json[key.String()] = value.MapIndex(key).Interface() - } - default: - json["meta"] = msg.Meta - } - } - if _, ok := json["error"]; !ok { - json["error"] = msg.Error() - } - return json -} - -// MarshalJSON implements the json.Marshaller interface -func (msg *Error) MarshalJSON() ([]byte, error) { - return json.Marshal(msg.JSON()) -} - -// Implements the error interface -func (msg *Error) Error() string { - return msg.Err.Error() -} - -func (msg *Error) IsType(flags ErrorType) bool { - return (msg.Type & flags) > 0 -} - -// Returns a readonly copy filterd the byte. -// ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic -func (a errorMsgs) ByType(typ ErrorType) errorMsgs { - if len(a) == 0 { - return nil - } - if typ == ErrorTypeAny { - return a - } - var result errorMsgs - for _, msg := range a { - if msg.IsType(typ) { - result = append(result, msg) - } - } - return result -} - -// Returns the last error in the slice. It returns nil if the array is empty. -// Shortcut for errors[len(errors)-1] -func (a errorMsgs) Last() *Error { - length := len(a) - if length > 0 { - return a[length-1] - } - return nil -} - -// Returns an array will all the error messages. -// Example: -// c.Error(errors.New("first")) -// c.Error(errors.New("second")) -// c.Error(errors.New("third")) -// c.Errors.Errors() // == []string{"first", "second", "third"} -func (a errorMsgs) Errors() []string { - if len(a) == 0 { - return nil - } - errorStrings := make([]string, len(a)) - for i, err := range a { - errorStrings[i] = err.Error() - } - return errorStrings -} - -func (a errorMsgs) JSON() interface{} { - switch len(a) { - case 0: - return nil - case 1: - return a.Last().JSON() - default: - json := make([]interface{}, len(a)) - for i, err := range a { - json[i] = err.JSON() - } - return json - } -} - -func (a errorMsgs) MarshalJSON() ([]byte, error) { - return json.Marshal(a.JSON()) -} - -func (a errorMsgs) String() string { - if len(a) == 0 { - return "" - } - var buffer bytes.Buffer - for i, msg := range a { - fmt.Fprintf(&buffer, "Error #%02d: %s\n", (i + 1), msg.Err) - if msg.Meta != nil { - fmt.Fprintf(&buffer, " Meta: %v\n", msg.Meta) - } - } - return buffer.String() -} diff --git a/vendor/github.com/gin-gonic/gin/fs.go b/vendor/github.com/gin-gonic/gin/fs.go deleted file mode 100644 index 6af3ded5..00000000 --- a/vendor/github.com/gin-gonic/gin/fs.go +++ /dev/null @@ -1,42 +0,0 @@ -package gin - -import ( - "net/http" - "os" -) - -type ( - onlyfilesFS struct { - fs http.FileSystem - } - neuteredReaddirFile struct { - http.File - } -) - -// Dir returns a http.Filesystem that can be used by http.FileServer(). It is used interally -// in router.Static(). -// if listDirectory == true, then it works the same as http.Dir() otherwise it returns -// a filesystem that prevents http.FileServer() to list the directory files. -func Dir(root string, listDirectory bool) http.FileSystem { - fs := http.Dir(root) - if listDirectory { - return fs - } - return &onlyfilesFS{fs} -} - -// Conforms to http.Filesystem -func (fs onlyfilesFS) Open(name string) (http.File, error) { - f, err := fs.fs.Open(name) - if err != nil { - return nil, err - } - return neuteredReaddirFile{f}, nil -} - -// Overrides the http.File default implementation -func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) { - // this disables directory listing - return nil, nil -} diff --git a/vendor/github.com/gin-gonic/gin/gin.go b/vendor/github.com/gin-gonic/gin/gin.go deleted file mode 100644 index 60f4ab29..00000000 --- a/vendor/github.com/gin-gonic/gin/gin.go +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "html/template" - "net" - "net/http" - "os" - "sync" - - "github.com/gin-gonic/gin/render" -) - -// Version is Framework's version -const Version = "v1.0rc2" - -var default404Body = []byte("404 page not found") -var default405Body = []byte("405 method not allowed") - -type HandlerFunc func(*Context) -type HandlersChain []HandlerFunc - -// Last returns the last handler in the chain. ie. the last handler is the main own. -func (c HandlersChain) Last() HandlerFunc { - length := len(c) - if length > 0 { - return c[length-1] - } - return nil -} - -type ( - RoutesInfo []RouteInfo - RouteInfo struct { - Method string - Path string - Handler string - } - - // Engine is the framework's instance, it contains the muxer, middleware and configuration settings. - // Create an instance of Engine, by using New() or Default() - Engine struct { - RouterGroup - HTMLRender render.HTMLRender - allNoRoute HandlersChain - allNoMethod HandlersChain - noRoute HandlersChain - noMethod HandlersChain - pool sync.Pool - trees methodTrees - - // Enables automatic redirection if the current route can't be matched but a - // handler for the path with (without) the trailing slash exists. - // For example if /foo/ is requested but a route only exists for /foo, the - // client is redirected to /foo with http status code 301 for GET requests - // and 307 for all other request methods. - RedirectTrailingSlash bool - - // If enabled, the router tries to fix the current request path, if no - // handle is registered for it. - // First superfluous path elements like ../ or // are removed. - // Afterwards the router does a case-insensitive lookup of the cleaned path. - // If a handle can be found for this route, the router makes a redirection - // to the corrected path with status code 301 for GET requests and 307 for - // all other request methods. - // For example /FOO and /..//Foo could be redirected to /foo. - // RedirectTrailingSlash is independent of this option. - RedirectFixedPath bool - - // If enabled, the router checks if another method is allowed for the - // current route, if the current request can not be routed. - // If this is the case, the request is answered with 'Method Not Allowed' - // and HTTP status code 405. - // If no other Method is allowed, the request is delegated to the NotFound - // handler. - HandleMethodNotAllowed bool - ForwardedByClientIP bool - } -) - -var _ IRouter = &Engine{} - -// New returns a new blank Engine instance without any middleware attached. -// By default the configuration is: -// - RedirectTrailingSlash: true -// - RedirectFixedPath: false -// - HandleMethodNotAllowed: false -// - ForwardedByClientIP: true -func New() *Engine { - debugPrintWARNINGNew() - engine := &Engine{ - RouterGroup: RouterGroup{ - Handlers: nil, - basePath: "/", - root: true, - }, - RedirectTrailingSlash: true, - RedirectFixedPath: false, - HandleMethodNotAllowed: false, - ForwardedByClientIP: true, - trees: make(methodTrees, 0, 9), - } - engine.RouterGroup.engine = engine - engine.pool.New = func() interface{} { - return engine.allocateContext() - } - return engine -} - -// Default returns an Engine instance with the Logger and Recovery middleware already attached. -func Default() *Engine { - engine := New() - engine.Use(Logger(), Recovery()) - return engine -} - -func (engine *Engine) allocateContext() *Context { - return &Context{engine: engine} -} - -func (engine *Engine) LoadHTMLGlob(pattern string) { - if IsDebugging() { - debugPrintLoadTemplate(template.Must(template.ParseGlob(pattern))) - engine.HTMLRender = render.HTMLDebug{Glob: pattern} - } else { - templ := template.Must(template.ParseGlob(pattern)) - engine.SetHTMLTemplate(templ) - } -} - -func (engine *Engine) LoadHTMLFiles(files ...string) { - if IsDebugging() { - engine.HTMLRender = render.HTMLDebug{Files: files} - } else { - templ := template.Must(template.ParseFiles(files...)) - engine.SetHTMLTemplate(templ) - } -} - -func (engine *Engine) SetHTMLTemplate(templ *template.Template) { - if len(engine.trees) > 0 { - debugPrintWARNINGSetHTMLTemplate() - } - engine.HTMLRender = render.HTMLProduction{Template: templ} -} - -// NoRoute adds handlers for NoRoute. It return a 404 code by default. -func (engine *Engine) NoRoute(handlers ...HandlerFunc) { - engine.noRoute = handlers - engine.rebuild404Handlers() -} - -// NoMethod sets the handlers called when... TODO -func (engine *Engine) NoMethod(handlers ...HandlerFunc) { - engine.noMethod = handlers - engine.rebuild405Handlers() -} - -// Use attachs a global middleware to the router. ie. the middleware attached though Use() will be -// included in the handlers chain for every single request. Even 404, 405, static files... -// For example, this is the right place for a logger or error management middleware. -func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes { - engine.RouterGroup.Use(middleware...) - engine.rebuild404Handlers() - engine.rebuild405Handlers() - return engine -} - -func (engine *Engine) rebuild404Handlers() { - engine.allNoRoute = engine.combineHandlers(engine.noRoute) -} - -func (engine *Engine) rebuild405Handlers() { - engine.allNoMethod = engine.combineHandlers(engine.noMethod) -} - -func (engine *Engine) addRoute(method, path string, handlers HandlersChain) { - assert1(path[0] == '/', "path must begin with '/'") - assert1(len(method) > 0, "HTTP method can not be empty") - assert1(len(handlers) > 0, "there must be at least one handler") - - debugPrintRoute(method, path, handlers) - root := engine.trees.get(method) - if root == nil { - root = new(node) - engine.trees = append(engine.trees, methodTree{method: method, root: root}) - } - root.addRoute(path, handlers) -} - -// Routes returns a slice of registered routes, including some useful information, such as: -// the http method, path and the handler name. -func (engine *Engine) Routes() (routes RoutesInfo) { - for _, tree := range engine.trees { - routes = iterate("", tree.method, routes, tree.root) - } - return routes -} - -func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo { - path += root.path - if len(root.handlers) > 0 { - routes = append(routes, RouteInfo{ - Method: method, - Path: path, - Handler: nameOfFunction(root.handlers.Last()), - }) - } - for _, child := range root.children { - routes = iterate(path, method, routes, child) - } - return routes -} - -// Run attaches the router to a http.Server and starts listening and serving HTTP requests. -// It is a shortcut for http.ListenAndServe(addr, router) -// Note: this method will block the calling goroutine indefinitely unless an error happens. -func (engine *Engine) Run(addr ...string) (err error) { - defer func() { debugPrintError(err) }() - - address := resolveAddress(addr) - debugPrint("Listening and serving HTTP on %s\n", address) - err = http.ListenAndServe(address, engine) - return -} - -// RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests. -// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router) -// Note: this method will block the calling goroutine indefinitely unless an error happens. -func (engine *Engine) RunTLS(addr string, certFile string, keyFile string) (err error) { - debugPrint("Listening and serving HTTPS on %s\n", addr) - defer func() { debugPrintError(err) }() - - err = http.ListenAndServeTLS(addr, certFile, keyFile, engine) - return -} - -// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests -// through the specified unix socket (ie. a file). -// Note: this method will block the calling goroutine indefinitely unless an error happens. -func (engine *Engine) RunUnix(file string) (err error) { - debugPrint("Listening and serving HTTP on unix:/%s", file) - defer func() { debugPrintError(err) }() - - os.Remove(file) - listener, err := net.Listen("unix", file) - if err != nil { - return - } - defer listener.Close() - err = http.Serve(listener, engine) - return -} - -// Conforms to the http.Handler interface. -func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { - c := engine.pool.Get().(*Context) - c.writermem.reset(w) - c.Request = req - c.reset() - - engine.handleHTTPRequest(c) - - engine.pool.Put(c) -} - -func (engine *Engine) handleHTTPRequest(context *Context) { - httpMethod := context.Request.Method - path := context.Request.URL.Path - - // Find root of the tree for the given HTTP method - t := engine.trees - for i, tl := 0, len(t); i < tl; i++ { - if t[i].method == httpMethod { - root := t[i].root - // Find route in tree - handlers, params, tsr := root.getValue(path, context.Params) - if handlers != nil { - context.handlers = handlers - context.Params = params - context.Next() - context.writermem.WriteHeaderNow() - return - - } else if httpMethod != "CONNECT" && path != "/" { - if tsr && engine.RedirectTrailingSlash { - redirectTrailingSlash(context) - return - } - if engine.RedirectFixedPath && redirectFixedPath(context, root, engine.RedirectFixedPath) { - return - } - } - break - } - } - - // TODO: unit test - if engine.HandleMethodNotAllowed { - for _, tree := range engine.trees { - if tree.method != httpMethod { - if handlers, _, _ := tree.root.getValue(path, nil); handlers != nil { - context.handlers = engine.allNoMethod - serveError(context, 405, default405Body) - return - } - } - } - } - context.handlers = engine.allNoRoute - serveError(context, 404, default404Body) -} - -var mimePlain = []string{MIMEPlain} - -func serveError(c *Context, code int, defaultMessage []byte) { - c.writermem.status = code - c.Next() - if !c.writermem.Written() { - if c.writermem.Status() == code { - c.writermem.Header()["Content-Type"] = mimePlain - c.Writer.Write(defaultMessage) - } else { - c.writermem.WriteHeaderNow() - } - } -} - -func redirectTrailingSlash(c *Context) { - req := c.Request - path := req.URL.Path - code := 301 // Permanent redirect, request with GET method - if req.Method != "GET" { - code = 307 - } - - if len(path) > 1 && path[len(path)-1] == '/' { - req.URL.Path = path[:len(path)-1] - } else { - req.URL.Path = path + "/" - } - debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String()) - http.Redirect(c.Writer, req, req.URL.String(), code) - c.writermem.WriteHeaderNow() -} - -func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool { - req := c.Request - path := req.URL.Path - - fixedPath, found := root.findCaseInsensitivePath( - cleanPath(path), - trailingSlash, - ) - if found { - code := 301 // Permanent redirect, request with GET method - if req.Method != "GET" { - code = 307 - } - req.URL.Path = string(fixedPath) - debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String()) - http.Redirect(c.Writer, req, req.URL.String(), code) - c.writermem.WriteHeaderNow() - return true - } - return false -} diff --git a/vendor/github.com/gin-gonic/gin/logger.go b/vendor/github.com/gin-gonic/gin/logger.go deleted file mode 100644 index 7c2a72be..00000000 --- a/vendor/github.com/gin-gonic/gin/logger.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "fmt" - "io" - "os" - "time" - - "github.com/mattn/go-isatty" -) - -var ( - green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) - white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) - yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109}) - red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) - blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109}) - magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109}) - cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109}) - reset = string([]byte{27, 91, 48, 109}) -) - -func ErrorLogger() HandlerFunc { - return ErrorLoggerT(ErrorTypeAny) -} - -func ErrorLoggerT(typ ErrorType) HandlerFunc { - return func(c *Context) { - c.Next() - errors := c.Errors.ByType(typ) - if len(errors) > 0 { - c.JSON(-1, errors) - } - } -} - -// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter -// By default gin.DefaultWriter = os.Stdout -func Logger() HandlerFunc { - return LoggerWithWriter(DefaultWriter) -} - -// LoggerWithWriter instance a Logger middleware with the specified writter buffer. -// Example: os.Stdout, a file opened in write mode, a socket... -func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { - isTerm := true - - if w, ok := out.(*os.File); !ok || !isatty.IsTerminal(w.Fd()) { - isTerm = false - } - - var skip map[string]struct{} - - if length := len(notlogged); length > 0 { - skip = make(map[string]struct{}, length) - - for _, path := range notlogged { - skip[path] = struct{}{} - } - } - - return func(c *Context) { - // Start timer - start := time.Now() - path := c.Request.URL.Path - - // Process request - c.Next() - - // Log only when path is not being skipped - if _, ok := skip[path]; !ok { - // Stop timer - end := time.Now() - latency := end.Sub(start) - - clientIP := c.ClientIP() - method := c.Request.Method - statusCode := c.Writer.Status() - var statusColor, methodColor string - if isTerm { - statusColor = colorForStatus(statusCode) - methodColor = colorForMethod(method) - } - comment := c.Errors.ByType(ErrorTypePrivate).String() - - fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %s |%s %s %-7s %s\n%s", - end.Format("2006/01/02 - 15:04:05"), - statusColor, statusCode, reset, - latency, - clientIP, - methodColor, reset, method, - path, - comment, - ) - } - } -} - -func colorForStatus(code int) string { - switch { - case code >= 200 && code < 300: - return green - case code >= 300 && code < 400: - return white - case code >= 400 && code < 500: - return yellow - default: - return red - } -} - -func colorForMethod(method string) string { - switch method { - case "GET": - return blue - case "POST": - return cyan - case "PUT": - return yellow - case "DELETE": - return red - case "PATCH": - return green - case "HEAD": - return magenta - case "OPTIONS": - return white - default: - return reset - } -} diff --git a/vendor/github.com/gin-gonic/gin/mode.go b/vendor/github.com/gin-gonic/gin/mode.go deleted file mode 100644 index c600b7b5..00000000 --- a/vendor/github.com/gin-gonic/gin/mode.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "io" - "os" - - "github.com/gin-gonic/gin/binding" -) - -const ENV_GIN_MODE = "GIN_MODE" - -const ( - DebugMode string = "debug" - ReleaseMode string = "release" - TestMode string = "test" -) -const ( - debugCode = iota - releaseCode - testCode -) - -// DefaultWriter is the default io.Writer used the Gin for debug output and -// middleware output like Logger() or Recovery(). -// Note that both Logger and Recovery provides custom ways to configure their -// output io.Writer. -// To support coloring in Windows use: -// import "github.com/mattn/go-colorable" -// gin.DefaultWriter = colorable.NewColorableStdout() -var DefaultWriter io.Writer = os.Stdout -var DefaultErrorWriter io.Writer = os.Stderr - -var ginMode = debugCode -var modeName = DebugMode - -func init() { - mode := os.Getenv(ENV_GIN_MODE) - if len(mode) == 0 { - SetMode(DebugMode) - } else { - SetMode(mode) - } -} - -func SetMode(value string) { - switch value { - case DebugMode: - ginMode = debugCode - case ReleaseMode: - ginMode = releaseCode - case TestMode: - ginMode = testCode - default: - panic("gin mode unknown: " + value) - } - modeName = value -} - -func DisableBindValidation() { - binding.Validator = nil -} - -func Mode() string { - return modeName -} diff --git a/vendor/github.com/gin-gonic/gin/path.go b/vendor/github.com/gin-gonic/gin/path.go deleted file mode 100644 index 43cdd047..00000000 --- a/vendor/github.com/gin-gonic/gin/path.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2013 Julien Schmidt. All rights reserved. -// Based on the path package, Copyright 2009 The Go Authors. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -package gin - -// CleanPath is the URL version of path.Clean, it returns a canonical URL path -// for p, eliminating . and .. elements. -// -// The following rules are applied iteratively until no further processing can -// be done: -// 1. Replace multiple slashes with a single slash. -// 2. Eliminate each . path name element (the current directory). -// 3. Eliminate each inner .. path name element (the parent directory) -// along with the non-.. element that precedes it. -// 4. Eliminate .. elements that begin a rooted path: -// that is, replace "/.." by "/" at the beginning of a path. -// -// If the result of this process is an empty string, "/" is returned -func cleanPath(p string) string { - // Turn empty string into "/" - if p == "" { - return "/" - } - - n := len(p) - var buf []byte - - // Invariants: - // reading from path; r is index of next byte to process. - // writing to buf; w is index of next byte to write. - - // path must start with '/' - r := 1 - w := 1 - - if p[0] != '/' { - r = 0 - buf = make([]byte, n+1) - buf[0] = '/' - } - - trailing := n > 2 && p[n-1] == '/' - - // 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 - // loop has no expensive function calls (except 1x make) - - for r < n { - switch { - case p[r] == '/': - // empty path element, trailing slash is added after the end - r++ - - case p[r] == '.' && r+1 == n: - trailing = true - r++ - - case p[r] == '.' && p[r+1] == '/': - // . element - r++ - - case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'): - // .. element: remove to last / - r += 2 - - if w > 1 { - // can backtrack - w-- - - if buf == nil { - for w > 1 && p[w] != '/' { - w-- - } - } else { - for w > 1 && buf[w] != '/' { - w-- - } - } - } - - default: - // real path element. - // add slash if needed - if w > 1 { - bufApp(&buf, p, w, '/') - w++ - } - - // copy element - for r < n && p[r] != '/' { - bufApp(&buf, p, w, p[r]) - w++ - r++ - } - } - } - - // re-append trailing slash - if trailing && w > 1 { - bufApp(&buf, p, w, '/') - w++ - } - - if buf == nil { - return p[:w] - } - return string(buf[:w]) -} - -// internal helper to lazily create a buffer if necessary -func bufApp(buf *[]byte, s string, w int, c byte) { - if *buf == nil { - if s[w] == c { - return - } - - *buf = make([]byte, len(s)) - copy(*buf, s[:w]) - } - (*buf)[w] = c -} diff --git a/vendor/github.com/gin-gonic/gin/recovery.go b/vendor/github.com/gin-gonic/gin/recovery.go deleted file mode 100644 index c502f355..00000000 --- a/vendor/github.com/gin-gonic/gin/recovery.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "log" - "net/http/httputil" - "runtime" -) - -var ( - dunno = []byte("???") - centerDot = []byte("·") - dot = []byte(".") - slash = []byte("/") -) - -// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. -func Recovery() HandlerFunc { - return RecoveryWithWriter(DefaultErrorWriter) -} - -func RecoveryWithWriter(out io.Writer) HandlerFunc { - var logger *log.Logger - if out != nil { - logger = log.New(out, "\n\n\x1b[31m", log.LstdFlags) - } - return func(c *Context) { - defer func() { - if err := recover(); err != nil { - if logger != nil { - stack := stack(3) - httprequest, _ := httputil.DumpRequest(c.Request, false) - logger.Printf("[Recovery] panic recovered:\n%s\n%s\n%s%s", string(httprequest), err, stack, reset) - } - c.AbortWithStatus(500) - } - }() - c.Next() - } -} - -// stack returns a nicely formated stack frame, skipping skip frames -func stack(skip int) []byte { - buf := new(bytes.Buffer) // the returned data - // As we loop, we open files and read them. These variables record the currently - // loaded file. - var lines [][]byte - var lastFile string - for i := skip; ; i++ { // Skip the expected number of frames - pc, file, line, ok := runtime.Caller(i) - if !ok { - break - } - // Print this much at least. If we can't find the source, it won't show. - fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) - if file != lastFile { - data, err := ioutil.ReadFile(file) - if err != nil { - continue - } - lines = bytes.Split(data, []byte{'\n'}) - lastFile = file - } - fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line)) - } - return buf.Bytes() -} - -// source returns a space-trimmed slice of the n'th line. -func source(lines [][]byte, n int) []byte { - n-- // in stack trace, lines are 1-indexed but our array is 0-indexed - if n < 0 || n >= len(lines) { - return dunno - } - return bytes.TrimSpace(lines[n]) -} - -// function returns, if possible, the name of the function containing the PC. -func function(pc uintptr) []byte { - fn := runtime.FuncForPC(pc) - if fn == nil { - return dunno - } - name := []byte(fn.Name()) - // The name includes the path name to the package, which is unnecessary - // since the file name is already included. Plus, it has center dots. - // That is, we see - // runtime/debug.*T·ptrmethod - // and want - // *T.ptrmethod - // Also the package path might contains dot (e.g. code.google.com/...), - // so first eliminate the path prefix - if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 { - name = name[lastslash+1:] - } - if period := bytes.Index(name, dot); period >= 0 { - name = name[period+1:] - } - name = bytes.Replace(name, centerDot, dot, -1) - return name -} diff --git a/vendor/github.com/gin-gonic/gin/render/data.go b/vendor/github.com/gin-gonic/gin/render/data.go deleted file mode 100644 index efa75d55..00000000 --- a/vendor/github.com/gin-gonic/gin/render/data.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import "net/http" - -type Data struct { - ContentType string - Data []byte -} - -func (r Data) Render(w http.ResponseWriter) error { - if len(r.ContentType) > 0 { - w.Header()["Content-Type"] = []string{r.ContentType} - } - w.Write(r.Data) - return nil -} diff --git a/vendor/github.com/gin-gonic/gin/render/html.go b/vendor/github.com/gin-gonic/gin/render/html.go deleted file mode 100644 index 8bfb23ac..00000000 --- a/vendor/github.com/gin-gonic/gin/render/html.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "html/template" - "net/http" -) - -type ( - HTMLRender interface { - Instance(string, interface{}) Render - } - - HTMLProduction struct { - Template *template.Template - } - - HTMLDebug struct { - Files []string - Glob string - } - - HTML struct { - Template *template.Template - Name string - Data interface{} - } -) - -var htmlContentType = []string{"text/html; charset=utf-8"} - -func (r HTMLProduction) Instance(name string, data interface{}) Render { - return HTML{ - Template: r.Template, - Name: name, - Data: data, - } -} - -func (r HTMLDebug) Instance(name string, data interface{}) Render { - return HTML{ - Template: r.loadTemplate(), - Name: name, - Data: data, - } -} -func (r HTMLDebug) loadTemplate() *template.Template { - if len(r.Files) > 0 { - return template.Must(template.ParseFiles(r.Files...)) - } - if len(r.Glob) > 0 { - return template.Must(template.ParseGlob(r.Glob)) - } - panic("the HTML debug render was created without files or glob pattern") -} - -func (r HTML) Render(w http.ResponseWriter) error { - writeContentType(w, htmlContentType) - if len(r.Name) == 0 { - return r.Template.Execute(w, r.Data) - } - return r.Template.ExecuteTemplate(w, r.Name, r.Data) -} diff --git a/vendor/github.com/gin-gonic/gin/render/json.go b/vendor/github.com/gin-gonic/gin/render/json.go deleted file mode 100644 index 32e6058d..00000000 --- a/vendor/github.com/gin-gonic/gin/render/json.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "encoding/json" - "net/http" -) - -type ( - JSON struct { - Data interface{} - } - - IndentedJSON struct { - Data interface{} - } -) - -var jsonContentType = []string{"application/json; charset=utf-8"} - -func (r JSON) Render(w http.ResponseWriter) error { - return WriteJSON(w, r.Data) -} - -func (r IndentedJSON) Render(w http.ResponseWriter) error { - writeContentType(w, jsonContentType) - jsonBytes, err := json.MarshalIndent(r.Data, "", " ") - if err != nil { - return err - } - w.Write(jsonBytes) - return nil -} - -func WriteJSON(w http.ResponseWriter, obj interface{}) error { - writeContentType(w, jsonContentType) - return json.NewEncoder(w).Encode(obj) -} diff --git a/vendor/github.com/gin-gonic/gin/render/redirect.go b/vendor/github.com/gin-gonic/gin/render/redirect.go deleted file mode 100644 index bd48d7d8..00000000 --- a/vendor/github.com/gin-gonic/gin/render/redirect.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "fmt" - "net/http" -) - -type Redirect struct { - Code int - Request *http.Request - Location string -} - -func (r Redirect) Render(w http.ResponseWriter) error { - if (r.Code < 300 || r.Code > 308) && r.Code != 201 { - panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code)) - } - http.Redirect(w, r.Request, r.Location, r.Code) - return nil -} diff --git a/vendor/github.com/gin-gonic/gin/render/render.go b/vendor/github.com/gin-gonic/gin/render/render.go deleted file mode 100644 index 3808666a..00000000 --- a/vendor/github.com/gin-gonic/gin/render/render.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import "net/http" - -type Render interface { - Render(http.ResponseWriter) error -} - -var ( - _ Render = JSON{} - _ Render = IndentedJSON{} - _ Render = XML{} - _ Render = String{} - _ Render = Redirect{} - _ Render = Data{} - _ Render = HTML{} - _ HTMLRender = HTMLDebug{} - _ HTMLRender = HTMLProduction{} - _ Render = YAML{} -) - -func writeContentType(w http.ResponseWriter, value []string) { - header := w.Header() - if val := header["Content-Type"]; len(val) == 0 { - header["Content-Type"] = value - } -} diff --git a/vendor/github.com/gin-gonic/gin/render/text.go b/vendor/github.com/gin-gonic/gin/render/text.go deleted file mode 100644 index 5a9e280b..00000000 --- a/vendor/github.com/gin-gonic/gin/render/text.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "fmt" - "io" - "net/http" -) - -type String struct { - Format string - Data []interface{} -} - -var plainContentType = []string{"text/plain; charset=utf-8"} - -func (r String) Render(w http.ResponseWriter) error { - WriteString(w, r.Format, r.Data) - return nil -} - -func WriteString(w http.ResponseWriter, format string, data []interface{}) { - writeContentType(w, plainContentType) - - if len(data) > 0 { - fmt.Fprintf(w, format, data...) - } else { - io.WriteString(w, format) - } -} diff --git a/vendor/github.com/gin-gonic/gin/render/xml.go b/vendor/github.com/gin-gonic/gin/render/xml.go deleted file mode 100644 index be22e6f2..00000000 --- a/vendor/github.com/gin-gonic/gin/render/xml.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "encoding/xml" - "net/http" -) - -type XML struct { - Data interface{} -} - -var xmlContentType = []string{"application/xml; charset=utf-8"} - -func (r XML) Render(w http.ResponseWriter) error { - writeContentType(w, xmlContentType) - return xml.NewEncoder(w).Encode(r.Data) -} diff --git a/vendor/github.com/gin-gonic/gin/render/yaml.go b/vendor/github.com/gin-gonic/gin/render/yaml.go deleted file mode 100644 index 46937d88..00000000 --- a/vendor/github.com/gin-gonic/gin/render/yaml.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package render - -import ( - "net/http" - - "gopkg.in/yaml.v2" -) - -type YAML struct { - Data interface{} -} - -var yamlContentType = []string{"application/x-yaml; charset=utf-8"} - -func (r YAML) Render(w http.ResponseWriter) error { - writeContentType(w, yamlContentType) - - bytes, err := yaml.Marshal(r.Data) - if err != nil { - return err - } - - w.Write(bytes) - return nil -} diff --git a/vendor/github.com/gin-gonic/gin/response_writer.go b/vendor/github.com/gin-gonic/gin/response_writer.go deleted file mode 100644 index fcbe230d..00000000 --- a/vendor/github.com/gin-gonic/gin/response_writer.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "bufio" - "io" - "net" - "net/http" -) - -const ( - noWritten = -1 - defaultStatus = 200 -) - -type ( - ResponseWriter interface { - http.ResponseWriter - http.Hijacker - http.Flusher - http.CloseNotifier - - // Returns the HTTP response status code of the current request. - Status() int - - // Returns the number of bytes already written into the response http body. - // See Written() - Size() int - - // Writes the string into the response body. - WriteString(string) (int, error) - - // Returns true if the response body was already written. - Written() bool - - // Forces to write the http header (status code + headers). - WriteHeaderNow() - } - - responseWriter struct { - http.ResponseWriter - size int - status int - } -) - -var _ ResponseWriter = &responseWriter{} - -func (w *responseWriter) reset(writer http.ResponseWriter) { - w.ResponseWriter = writer - w.size = noWritten - w.status = defaultStatus -} - -func (w *responseWriter) WriteHeader(code int) { - if code > 0 && w.status != code { - if w.Written() { - debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code) - } - w.status = code - } -} - -func (w *responseWriter) WriteHeaderNow() { - if !w.Written() { - w.size = 0 - w.ResponseWriter.WriteHeader(w.status) - } -} - -func (w *responseWriter) Write(data []byte) (n int, err error) { - w.WriteHeaderNow() - n, err = w.ResponseWriter.Write(data) - w.size += n - return -} - -func (w *responseWriter) WriteString(s string) (n int, err error) { - w.WriteHeaderNow() - n, err = io.WriteString(w.ResponseWriter, s) - w.size += n - return -} - -func (w *responseWriter) Status() int { - return w.status -} - -func (w *responseWriter) Size() int { - return w.size -} - -func (w *responseWriter) Written() bool { - return w.size != noWritten -} - -// Implements the http.Hijacker interface -func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - if w.size < 0 { - w.size = 0 - } - return w.ResponseWriter.(http.Hijacker).Hijack() -} - -// Implements the http.CloseNotify interface -func (w *responseWriter) CloseNotify() <-chan bool { - return w.ResponseWriter.(http.CloseNotifier).CloseNotify() -} - -// Implements the http.Flush interface -func (w *responseWriter) Flush() { - w.ResponseWriter.(http.Flusher).Flush() -} diff --git a/vendor/github.com/gin-gonic/gin/routergroup.go b/vendor/github.com/gin-gonic/gin/routergroup.go deleted file mode 100644 index f22729bb..00000000 --- a/vendor/github.com/gin-gonic/gin/routergroup.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "net/http" - "path" - "regexp" - "strings" -) - -type ( - IRouter interface { - IRoutes - Group(string, ...HandlerFunc) *RouterGroup - } - - IRoutes interface { - Use(...HandlerFunc) IRoutes - - Handle(string, string, ...HandlerFunc) IRoutes - Any(string, ...HandlerFunc) IRoutes - GET(string, ...HandlerFunc) IRoutes - POST(string, ...HandlerFunc) IRoutes - DELETE(string, ...HandlerFunc) IRoutes - PATCH(string, ...HandlerFunc) IRoutes - PUT(string, ...HandlerFunc) IRoutes - OPTIONS(string, ...HandlerFunc) IRoutes - HEAD(string, ...HandlerFunc) IRoutes - - StaticFile(string, string) IRoutes - Static(string, string) IRoutes - StaticFS(string, http.FileSystem) IRoutes - } - - // RouterGroup is used internally to configure router, a RouterGroup is associated with a prefix - // and an array of handlers (middleware) - RouterGroup struct { - Handlers HandlersChain - basePath string - engine *Engine - root bool - } -) - -var _ IRouter = &RouterGroup{} - -// Use adds middleware to the group, see example code in github. -func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes { - group.Handlers = append(group.Handlers, middleware...) - return group.returnObj() -} - -// Group creates a new router group. You should add all the routes that have common middlwares or the same path prefix. -// For example, all the routes that use a common middlware for authorization could be grouped. -func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup { - return &RouterGroup{ - Handlers: group.combineHandlers(handlers), - basePath: group.calculateAbsolutePath(relativePath), - engine: group.engine, - } -} - -func (group *RouterGroup) BasePath() string { - return group.basePath -} - -func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes { - absolutePath := group.calculateAbsolutePath(relativePath) - handlers = group.combineHandlers(handlers) - group.engine.addRoute(httpMethod, absolutePath, handlers) - return group.returnObj() -} - -// Handle registers a new request handle and middleware with the given path and method. -// The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes. -// See the example code in github. -// -// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut -// functions can be used. -// -// This function is intended for bulk loading and to allow the usage of less -// frequently used, non-standardized or custom methods (e.g. for internal -// communication with a proxy). -func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes { - if matches, err := regexp.MatchString("^[A-Z]+$", httpMethod); !matches || err != nil { - panic("http method " + httpMethod + " is not valid") - } - return group.handle(httpMethod, relativePath, handlers) -} - -// POST is a shortcut for router.Handle("POST", path, handle) -func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle("POST", relativePath, handlers) -} - -// GET is a shortcut for router.Handle("GET", path, handle) -func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle("GET", relativePath, handlers) -} - -// DELETE is a shortcut for router.Handle("DELETE", path, handle) -func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle("DELETE", relativePath, handlers) -} - -// PATCH is a shortcut for router.Handle("PATCH", path, handle) -func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle("PATCH", relativePath, handlers) -} - -// PUT is a shortcut for router.Handle("PUT", path, handle) -func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle("PUT", relativePath, handlers) -} - -// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle) -func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle("OPTIONS", relativePath, handlers) -} - -// HEAD is a shortcut for router.Handle("HEAD", path, handle) -func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes { - return group.handle("HEAD", relativePath, handlers) -} - -// Any registers a route that matches all the HTTP methods. -// GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE -func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRoutes { - group.handle("GET", relativePath, handlers) - group.handle("POST", relativePath, handlers) - group.handle("PUT", relativePath, handlers) - group.handle("PATCH", relativePath, handlers) - group.handle("HEAD", relativePath, handlers) - group.handle("OPTIONS", relativePath, handlers) - group.handle("DELETE", relativePath, handlers) - group.handle("CONNECT", relativePath, handlers) - group.handle("TRACE", relativePath, handlers) - return group.returnObj() -} - -// StaticFile registers a single route in order to server a single file of the local filesystem. -// router.StaticFile("favicon.ico", "./resources/favicon.ico") -func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes { - if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") { - panic("URL parameters can not be used when serving a static file") - } - handler := func(c *Context) { - c.File(filepath) - } - group.GET(relativePath, handler) - group.HEAD(relativePath, handler) - return group.returnObj() -} - -// Static serves files from the given file system root. -// Internally a http.FileServer is used, therefore http.NotFound is used instead -// of the Router's NotFound handler. -// To use the operating system's file system implementation, -// use : -// router.Static("/static", "/var/www") -func (group *RouterGroup) Static(relativePath, root string) IRoutes { - return group.StaticFS(relativePath, Dir(root, false)) -} - -// StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead. -// Gin by default user: gin.Dir() -func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes { - if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") { - panic("URL parameters can not be used when serving a static folder") - } - handler := group.createStaticHandler(relativePath, fs) - urlPattern := path.Join(relativePath, "/*filepath") - - // Register GET and HEAD handlers - group.GET(urlPattern, handler) - group.HEAD(urlPattern, handler) - return group.returnObj() -} - -func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc { - absolutePath := group.calculateAbsolutePath(relativePath) - fileServer := http.StripPrefix(absolutePath, http.FileServer(fs)) - _, nolisting := fs.(*onlyfilesFS) - return func(c *Context) { - if nolisting { - c.Writer.WriteHeader(404) - } - fileServer.ServeHTTP(c.Writer, c.Request) - } -} - -func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain { - finalSize := len(group.Handlers) + len(handlers) - if finalSize >= int(abortIndex) { - panic("too many handlers") - } - mergedHandlers := make(HandlersChain, finalSize) - copy(mergedHandlers, group.Handlers) - copy(mergedHandlers[len(group.Handlers):], handlers) - return mergedHandlers -} - -func (group *RouterGroup) calculateAbsolutePath(relativePath string) string { - return joinPaths(group.basePath, relativePath) -} - -func (group *RouterGroup) returnObj() IRoutes { - if group.root { - return group.engine - } - return group -} diff --git a/vendor/github.com/gin-gonic/gin/tree.go b/vendor/github.com/gin-gonic/gin/tree.go deleted file mode 100644 index 4f1da271..00000000 --- a/vendor/github.com/gin-gonic/gin/tree.go +++ /dev/null @@ -1,605 +0,0 @@ -// Copyright 2013 Julien Schmidt. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -package gin - -import ( - "strings" - "unicode" -) - -// Param is a single URL parameter, consisting of a key and a value. -type Param struct { - Key string - Value string -} - -// Params is a Param-slice, as returned by the router. -// The slice is ordered, the first URL parameter is also the first slice value. -// It is therefore safe to read values by the index. -type Params []Param - -// Get returns the value of the first Param which key matches the given name. -// If no matching Param is found, an empty string is returned. -func (ps Params) Get(name string) (string, bool) { - for _, entry := range ps { - if entry.Key == name { - return entry.Value, true - } - } - return "", false -} - -// ByName returns the value of the first Param which key matches the given name. -// If no matching Param is found, an empty string is returned. -func (ps Params) ByName(name string) (va string) { - va, _ = ps.Get(name) - return -} - -type methodTree struct { - method string - root *node -} - -type methodTrees []methodTree - -func (trees methodTrees) get(method string) *node { - for _, tree := range trees { - if tree.method == method { - return tree.root - } - } - return nil -} - -func min(a, b int) int { - if a <= b { - return a - } - return b -} - -func countParams(path string) uint8 { - var n uint - for i := 0; i < len(path); i++ { - if path[i] != ':' && path[i] != '*' { - continue - } - n++ - } - if n >= 255 { - return 255 - } - return uint8(n) -} - -type nodeType uint8 - -const ( - static nodeType = iota // default - root - param - catchAll -) - -type node struct { - path string - wildChild bool - nType nodeType - maxParams uint8 - indices string - children []*node - handlers HandlersChain - priority uint32 -} - -// increments priority of the given child and reorders if necessary -func (n *node) incrementChildPrio(pos int) int { - n.children[pos].priority++ - prio := n.children[pos].priority - - // adjust position (move to front) - newPos := pos - for newPos > 0 && n.children[newPos-1].priority < prio { - // swap node positions - tmpN := n.children[newPos-1] - n.children[newPos-1] = n.children[newPos] - n.children[newPos] = tmpN - - newPos-- - } - - // build new index char string - if newPos != pos { - n.indices = n.indices[:newPos] + // unchanged prefix, might be empty - n.indices[pos:pos+1] + // the index char we move - n.indices[newPos:pos] + n.indices[pos+1:] // rest without char at 'pos' - } - - return newPos -} - -// addRoute adds a node with the given handle to the path. -// Not concurrency-safe! -func (n *node) addRoute(path string, handlers HandlersChain) { - fullPath := path - n.priority++ - numParams := countParams(path) - - // non-empty tree - if len(n.path) > 0 || len(n.children) > 0 { - walk: - for { - // Update maxParams of the current node - if numParams > n.maxParams { - n.maxParams = numParams - } - - // Find the longest common prefix. - // This also implies that the common prefix contains no ':' or '*' - // since the existing key can't contain those chars. - i := 0 - max := min(len(path), len(n.path)) - for i < max && path[i] == n.path[i] { - i++ - } - - // Split edge - if i < len(n.path) { - child := node{ - path: n.path[i:], - wildChild: n.wildChild, - indices: n.indices, - children: n.children, - handlers: n.handlers, - priority: n.priority - 1, - } - - // Update maxParams (max of all children) - for i := range child.children { - if child.children[i].maxParams > child.maxParams { - child.maxParams = child.children[i].maxParams - } - } - - n.children = []*node{&child} - // []byte for proper unicode char conversion, see #65 - n.indices = string([]byte{n.path[i]}) - n.path = path[:i] - n.handlers = nil - n.wildChild = false - } - - // Make new node a child of this node - if i < len(path) { - path = path[i:] - - if n.wildChild { - n = n.children[0] - n.priority++ - - // Update maxParams of the child node - if numParams > n.maxParams { - n.maxParams = numParams - } - numParams-- - - // Check if the wildcard matches - if len(path) >= len(n.path) && n.path == path[:len(n.path)] { - // check for longer wildcard, e.g. :name and :names - if len(n.path) >= len(path) || path[len(n.path)] == '/' { - continue walk - } - } - - panic("path segment '" + path + - "' conflicts with existing wildcard '" + n.path + - "' in path '" + fullPath + "'") - } - - c := path[0] - - // slash after param - if n.nType == param && c == '/' && len(n.children) == 1 { - n = n.children[0] - n.priority++ - continue walk - } - - // Check if a child with the next path byte exists - for i := 0; i < len(n.indices); i++ { - if c == n.indices[i] { - i = n.incrementChildPrio(i) - n = n.children[i] - continue walk - } - } - - // Otherwise insert it - if c != ':' && c != '*' { - // []byte for proper unicode char conversion, see #65 - n.indices += string([]byte{c}) - child := &node{ - maxParams: numParams, - } - n.children = append(n.children, child) - n.incrementChildPrio(len(n.indices) - 1) - n = child - } - n.insertChild(numParams, path, fullPath, handlers) - return - - } else if i == len(path) { // Make node a (in-path) leaf - if n.handlers != nil { - panic("handlers are already registered for path ''" + fullPath + "'") - } - n.handlers = handlers - } - return - } - } else { // Empty tree - n.insertChild(numParams, path, fullPath, handlers) - n.nType = root - } -} - -func (n *node) insertChild(numParams uint8, path string, fullPath string, handlers HandlersChain) { - var offset int // already handled bytes of the path - - // find prefix until first wildcard (beginning with ':'' or '*'') - for i, max := 0, len(path); numParams > 0; i++ { - c := path[i] - if c != ':' && c != '*' { - continue - } - - // find wildcard end (either '/' or path end) - end := i + 1 - for end < max && path[end] != '/' { - switch path[end] { - // the wildcard name must not contain ':' and '*' - case ':', '*': - panic("only one wildcard per path segment is allowed, has: '" + - path[i:] + "' in path '" + fullPath + "'") - default: - end++ - } - } - - // check if this Node existing children which would be - // unreachable if we insert the wildcard here - if len(n.children) > 0 { - panic("wildcard route '" + path[i:end] + - "' conflicts with existing children in path '" + fullPath + "'") - } - - // check if the wildcard has a name - if end-i < 2 { - panic("wildcards must be named with a non-empty name in path '" + fullPath + "'") - } - - if c == ':' { // param - // split path at the beginning of the wildcard - if i > 0 { - n.path = path[offset:i] - offset = i - } - - child := &node{ - nType: param, - maxParams: numParams, - } - n.children = []*node{child} - n.wildChild = true - n = child - n.priority++ - numParams-- - - // if the path doesn't end with the wildcard, then there - // will be another non-wildcard subpath starting with '/' - if end < max { - n.path = path[offset:end] - offset = end - - child := &node{ - maxParams: numParams, - priority: 1, - } - n.children = []*node{child} - n = child - } - - } else { // catchAll - if end != max || numParams > 1 { - panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'") - } - - if len(n.path) > 0 && n.path[len(n.path)-1] == '/' { - panic("catch-all conflicts with existing handle for the path segment root in path '" + fullPath + "'") - } - - // currently fixed width 1 for '/' - i-- - if path[i] != '/' { - panic("no / before catch-all in path '" + fullPath + "'") - } - - n.path = path[offset:i] - - // first node: catchAll node with empty path - child := &node{ - wildChild: true, - nType: catchAll, - maxParams: 1, - } - n.children = []*node{child} - n.indices = string(path[i]) - n = child - n.priority++ - - // second node: node holding the variable - child = &node{ - path: path[i:], - nType: catchAll, - maxParams: 1, - handlers: handlers, - priority: 1, - } - n.children = []*node{child} - - return - } - } - - // insert remaining path part and handle to the leaf - n.path = path[offset:] - n.handlers = handlers -} - -// Returns the handle registered with the given path (key). The values of -// wildcards are saved to a map. -// If no handle can be found, a TSR (trailing slash redirect) recommendation is -// made if a handle exists with an extra (without the) trailing slash for the -// given path. -func (n *node) getValue(path string, po Params) (handlers HandlersChain, p Params, tsr bool) { - p = po -walk: // Outer loop for walking the tree - for { - if len(path) > len(n.path) { - if path[:len(n.path)] == n.path { - path = path[len(n.path):] - // If this node does not have a wildcard (param or catchAll) - // child, we can just look up the next child node and continue - // to walk down the tree - if !n.wildChild { - c := path[0] - for i := 0; i < len(n.indices); i++ { - if c == n.indices[i] { - n = n.children[i] - continue walk - } - } - - // Nothing found. - // We can recommend to redirect to the same URL without a - // trailing slash if a leaf exists for that path. - tsr = (path == "/" && n.handlers != nil) - return - } - - // handle wildcard child - n = n.children[0] - switch n.nType { - case param: - // find param end (either '/' or path end) - end := 0 - for end < len(path) && path[end] != '/' { - end++ - } - - // save param value - if cap(p) < int(n.maxParams) { - p = make(Params, 0, n.maxParams) - } - i := len(p) - p = p[:i+1] // expand slice within preallocated capacity - p[i].Key = n.path[1:] - p[i].Value = path[:end] - - // we need to go deeper! - if end < len(path) { - if len(n.children) > 0 { - path = path[end:] - n = n.children[0] - continue walk - } - - // ... but we can't - tsr = (len(path) == end+1) - return - } - - if handlers = n.handlers; handlers != nil { - return - } else if len(n.children) == 1 { - // No handle found. Check if a handle for this path + a - // trailing slash exists for TSR recommendation - n = n.children[0] - tsr = (n.path == "/" && n.handlers != nil) - } - - return - - case catchAll: - // save param value - if cap(p) < int(n.maxParams) { - p = make(Params, 0, n.maxParams) - } - i := len(p) - p = p[:i+1] // expand slice within preallocated capacity - p[i].Key = n.path[2:] - p[i].Value = path - - handlers = n.handlers - return - - default: - panic("invalid node type") - } - } - } else if path == n.path { - // We should have reached the node containing the handle. - // Check if this node has a handle registered. - if handlers = n.handlers; handlers != nil { - return - } - - if path == "/" && n.wildChild && n.nType != root { - tsr = true - return - } - - // No handle found. Check if a handle for this path + a - // trailing slash exists for trailing slash recommendation - for i := 0; i < len(n.indices); i++ { - if n.indices[i] == '/' { - n = n.children[i] - tsr = (len(n.path) == 1 && n.handlers != nil) || - (n.nType == catchAll && n.children[0].handlers != nil) - return - } - } - - return - } - - // Nothing found. We can recommend to redirect to the same URL with an - // extra trailing slash if a leaf exists for that path - tsr = (path == "/") || - (len(n.path) == len(path)+1 && n.path[len(path)] == '/' && - path == n.path[:len(n.path)-1] && n.handlers != nil) - return - } -} - -// Makes a case-insensitive lookup of the given path and tries to find a handler. -// It can optionally also fix trailing slashes. -// It returns the case-corrected path and a bool indicating whether the lookup -// was successful. -func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) (ciPath []byte, found bool) { - ciPath = make([]byte, 0, len(path)+1) // preallocate enough memory - - // Outer loop for walking the tree - for len(path) >= len(n.path) && strings.ToLower(path[:len(n.path)]) == strings.ToLower(n.path) { - path = path[len(n.path):] - ciPath = append(ciPath, n.path...) - - if len(path) > 0 { - // If this node does not have a wildcard (param or catchAll) child, - // we can just look up the next child node and continue to walk down - // the tree - if !n.wildChild { - r := unicode.ToLower(rune(path[0])) - for i, index := range n.indices { - // must use recursive approach since both index and - // ToLower(index) could exist. We must check both. - if r == unicode.ToLower(index) { - out, found := n.children[i].findCaseInsensitivePath(path, fixTrailingSlash) - if found { - return append(ciPath, out...), true - } - } - } - - // Nothing found. We can recommend to redirect to the same URL - // without a trailing slash if a leaf exists for that path - found = (fixTrailingSlash && path == "/" && n.handlers != nil) - return - } - - n = n.children[0] - switch n.nType { - case param: - // find param end (either '/' or path end) - k := 0 - for k < len(path) && path[k] != '/' { - k++ - } - - // add param value to case insensitive path - ciPath = append(ciPath, path[:k]...) - - // we need to go deeper! - if k < len(path) { - if len(n.children) > 0 { - path = path[k:] - n = n.children[0] - continue - } - - // ... but we can't - if fixTrailingSlash && len(path) == k+1 { - return ciPath, true - } - return - } - - if n.handlers != nil { - return ciPath, true - } else if fixTrailingSlash && len(n.children) == 1 { - // No handle found. Check if a handle for this path + a - // trailing slash exists - n = n.children[0] - if n.path == "/" && n.handlers != nil { - return append(ciPath, '/'), true - } - } - return - - case catchAll: - return append(ciPath, path...), true - - default: - panic("invalid node type") - } - } else { - // We should have reached the node containing the handle. - // Check if this node has a handle registered. - if n.handlers != nil { - return ciPath, true - } - - // No handle found. - // Try to fix the path by adding a trailing slash - if fixTrailingSlash { - for i := 0; i < len(n.indices); i++ { - if n.indices[i] == '/' { - n = n.children[i] - if (len(n.path) == 1 && n.handlers != nil) || - (n.nType == catchAll && n.children[0].handlers != nil) { - return append(ciPath, '/'), true - } - return - } - } - } - return - } - } - - // Nothing found. - // Try to fix the path by adding / removing a trailing slash - if fixTrailingSlash { - if path == "/" { - return ciPath, true - } - if len(path)+1 == len(n.path) && n.path[len(path)] == '/' && - strings.ToLower(path) == strings.ToLower(n.path[:len(path)]) && - n.handlers != nil { - return append(ciPath, n.path...), true - } - } - return -} diff --git a/vendor/github.com/gin-gonic/gin/utils.go b/vendor/github.com/gin-gonic/gin/utils.go deleted file mode 100644 index 18064fb5..00000000 --- a/vendor/github.com/gin-gonic/gin/utils.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package gin - -import ( - "encoding/xml" - "net/http" - "os" - "path" - "reflect" - "runtime" - "strings" -) - -const BindKey = "_gin-gonic/gin/bindkey" - -func Bind(val interface{}) HandlerFunc { - value := reflect.ValueOf(val) - if value.Kind() == reflect.Ptr { - panic(`Bind struct can not be a pointer. Example: - Use: gin.Bind(Struct{}) instead of gin.Bind(&Struct{}) -`) - } - typ := value.Type() - - return func(c *Context) { - obj := reflect.New(typ).Interface() - if c.Bind(obj) == nil { - c.Set(BindKey, obj) - } - } -} - -func WrapF(f http.HandlerFunc) HandlerFunc { - return func(c *Context) { - f(c.Writer, c.Request) - } -} - -func WrapH(h http.Handler) HandlerFunc { - return func(c *Context) { - h.ServeHTTP(c.Writer, c.Request) - } -} - -type H map[string]interface{} - -// MarshalXML allows type H to be used with xml.Marshal -func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error { - start.Name = xml.Name{ - Space: "", - Local: "map", - } - if err := e.EncodeToken(start); err != nil { - return err - } - for key, value := range h { - elem := xml.StartElement{ - Name: xml.Name{Space: "", Local: key}, - Attr: []xml.Attr{}, - } - if err := e.EncodeElement(value, elem); err != nil { - return err - } - } - if err := e.EncodeToken(xml.EndElement{Name: start.Name}); err != nil { - return err - } - return nil -} - -func assert1(guard bool, text string) { - if !guard { - panic(text) - } -} - -func filterFlags(content string) string { - for i, char := range content { - if char == ' ' || char == ';' { - return content[:i] - } - } - return content -} - -func chooseData(custom, wildcard interface{}) interface{} { - if custom == nil { - if wildcard == nil { - panic("negotiation config is invalid") - } - return wildcard - } - return custom -} - -func parseAccept(acceptHeader string) []string { - parts := strings.Split(acceptHeader, ",") - out := make([]string, 0, len(parts)) - for _, part := range parts { - index := strings.IndexByte(part, ';') - if index >= 0 { - part = part[0:index] - } - part = strings.TrimSpace(part) - if len(part) > 0 { - out = append(out, part) - } - } - return out -} - -func lastChar(str string) uint8 { - size := len(str) - if size == 0 { - panic("The length of the string can't be 0") - } - return str[size-1] -} - -func nameOfFunction(f interface{}) string { - return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() -} - -func joinPaths(absolutePath, relativePath string) string { - if len(relativePath) == 0 { - return absolutePath - } - - finalPath := path.Join(absolutePath, relativePath) - appendSlash := lastChar(relativePath) == '/' && lastChar(finalPath) != '/' - if appendSlash { - return finalPath + "/" - } - return finalPath -} - -func resolveAddress(addr []string) string { - switch len(addr) { - case 0: - if port := os.Getenv("PORT"); len(port) > 0 { - debugPrint("Environment variable PORT=\"%s\"", port) - return ":" + port - } - debugPrint("Environment variable PORT is undefined. Using port :8080 by default") - return ":8080" - case 1: - return addr[0] - default: - panic("too much parameters") - } -}