mirror of
https://github.com/crawlab-team/crawlab.git
synced 2026-01-21 17:21:09 +01:00
更新依赖安装逻辑
This commit is contained in:
@@ -27,6 +27,9 @@ ADD . /app
|
||||
# set as non-interactive
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
# set CRAWLAB_IS_DOCKER
|
||||
ENV CRAWLAB_IS_DOCKER Y
|
||||
|
||||
# install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y curl git net-tools iputils-ping ntp ntpdate python3 python3-pip \
|
||||
|
||||
@@ -13,3 +13,19 @@ type Executable struct {
|
||||
FileName string `json:"file_name"`
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
|
||||
type Lang struct {
|
||||
Name string `json:"name"`
|
||||
ExecutableName string `json:"executable_name"`
|
||||
ExecutablePath string `json:"executable_path"`
|
||||
DepExecutablePath string `json:"dep_executable_path"`
|
||||
Installed bool `json:"installed"`
|
||||
}
|
||||
|
||||
type Dependency struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Description string `json:"description"`
|
||||
Lang string `json:"lang"`
|
||||
Installed bool `json:"installed"`
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ require (
|
||||
github.com/go-playground/locales v0.12.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.16.0 // indirect
|
||||
github.com/gomodule/redigo v2.0.0+incompatible
|
||||
github.com/imroc/req v0.2.4
|
||||
github.com/leodido/go-urn v1.1.0 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
|
||||
@@ -66,6 +66,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/imroc/req v0.2.4 h1:8XbvaQpERLAJV6as/cB186DtH5f0m5zAOtHEaTQ4ac0=
|
||||
github.com/imroc/req v0.2.4/go.mod h1:J9FsaNHDTIVyW/b5r6/Df5qKEEEq2WzZKIgKSajd1AE=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
|
||||
|
||||
@@ -31,24 +31,24 @@ func main() {
|
||||
log.Error("init config error:" + err.Error())
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化配置成功")
|
||||
log.Info("initialized config successfully")
|
||||
|
||||
// 初始化日志设置
|
||||
logLevel := viper.GetString("log.level")
|
||||
if logLevel != "" {
|
||||
log.SetLevelFromString(logLevel)
|
||||
}
|
||||
log.Info("初始化日志设置成功")
|
||||
log.Info("initialized log config successfully")
|
||||
|
||||
if viper.GetString("log.isDeletePeriodically") == "Y" {
|
||||
err := services.InitDeleteLogPeriodically()
|
||||
if err != nil {
|
||||
log.Error("Init DeletePeriodically Failed")
|
||||
log.Error("init DeletePeriodically failed")
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化定期清理日志配置成功")
|
||||
log.Info("initialized periodically cleaning log successfully")
|
||||
} else {
|
||||
log.Info("默认未开启定期清理日志配置")
|
||||
log.Info("periodically cleaning log is switched off")
|
||||
}
|
||||
|
||||
// 初始化Mongodb数据库
|
||||
@@ -57,7 +57,7 @@ func main() {
|
||||
debug.PrintStack()
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化Mongodb数据库成功")
|
||||
log.Info("initialized MongoDB successfully")
|
||||
|
||||
// 初始化Redis数据库
|
||||
if err := database.InitRedis(); err != nil {
|
||||
@@ -65,7 +65,7 @@ func main() {
|
||||
debug.PrintStack()
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化Redis数据库成功")
|
||||
log.Info("initialized Redis successfully")
|
||||
|
||||
if model.IsMaster() {
|
||||
// 初始化定时任务
|
||||
@@ -74,8 +74,8 @@ func main() {
|
||||
debug.PrintStack()
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化定时任务成功")
|
||||
}
|
||||
log.Info("initialized schedule successfully")
|
||||
|
||||
// 初始化任务执行器
|
||||
if err := services.InitTaskExecutor(); err != nil {
|
||||
@@ -83,14 +83,14 @@ func main() {
|
||||
debug.PrintStack()
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化任务执行器成功")
|
||||
log.Info("initialized task executor successfully")
|
||||
|
||||
// 初始化节点服务
|
||||
if err := services.InitNodeService(); err != nil {
|
||||
log.Error("init node service error:" + err.Error())
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化节点配置成功")
|
||||
log.Info("initialized node service successfully")
|
||||
|
||||
// 初始化爬虫服务
|
||||
if err := services.InitSpiderService(); err != nil {
|
||||
@@ -98,7 +98,7 @@ func main() {
|
||||
debug.PrintStack()
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化爬虫服务成功")
|
||||
log.Info("initialized spider service successfully")
|
||||
|
||||
// 初始化用户服务
|
||||
if err := services.InitUserService(); err != nil {
|
||||
@@ -106,7 +106,15 @@ func main() {
|
||||
debug.PrintStack()
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化用户服务成功")
|
||||
log.Info("initialized user service successfully")
|
||||
|
||||
// 初始化依赖服务
|
||||
if err := services.InitDepsFetcher(); err != nil {
|
||||
log.Error("init user service error:" + err.Error())
|
||||
debug.PrintStack()
|
||||
panic(err)
|
||||
}
|
||||
log.Info("initialized dependency fetcher successfully")
|
||||
|
||||
// 以下为主节点服务
|
||||
if model.IsMaster() {
|
||||
@@ -128,6 +136,8 @@ func main() {
|
||||
authGroup.GET("/nodes/:id/tasks", routes.GetNodeTaskList) // 节点任务列表
|
||||
authGroup.GET("/nodes/:id/system", routes.GetSystemInfo) // 节点任务列表
|
||||
authGroup.DELETE("/nodes/:id", routes.DeleteNode) // 删除节点
|
||||
authGroup.GET("/nodes/:id/langs", routes.GetLangList) // 节点语言环境列表
|
||||
authGroup.GET("/nodes/:id/deps", routes.GetDepList) // 节点第三方依赖列表
|
||||
// 爬虫
|
||||
authGroup.GET("/spiders", routes.GetSpiderList) // 爬虫列表
|
||||
authGroup.GET("/spiders/:id", routes.GetSpider) // 爬虫详情
|
||||
|
||||
32
backend/routes/system.go
Normal file
32
backend/routes/system.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"crawlab/services"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func GetLangList(c *gin.Context) {
|
||||
nodeId := c.Param("id")
|
||||
c.JSON(http.StatusOK, Response{
|
||||
Status: "ok",
|
||||
Message: "success",
|
||||
Data: services.GetLangList(nodeId),
|
||||
})
|
||||
}
|
||||
|
||||
func GetDepList(c *gin.Context) {
|
||||
nodeId := c.Param("id")
|
||||
lang := c.Query("lang")
|
||||
depName := c.Query("dep_name")
|
||||
depList, err := services.GetDepList(nodeId, lang, depName)
|
||||
if err != nil {
|
||||
HandleError(http.StatusInternalServerError, c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, Response{
|
||||
Status: "ok",
|
||||
Message: "success",
|
||||
Data: depList,
|
||||
})
|
||||
}
|
||||
@@ -4,28 +4,58 @@ import (
|
||||
"crawlab/constants"
|
||||
"crawlab/database"
|
||||
"crawlab/entity"
|
||||
"crawlab/lib/cron"
|
||||
"crawlab/model"
|
||||
"crawlab/utils"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/apex/log"
|
||||
"github.com/imroc/req"
|
||||
"regexp"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type PythonDepJsonData struct {
|
||||
Info PythonDepJsonDataInfo `json:"info"`
|
||||
}
|
||||
|
||||
type PythonDepJsonDataInfo struct {
|
||||
Name string `json:"name"`
|
||||
Summary string `json:"summary"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type PythonDepNameDict struct {
|
||||
Name string `json:"name"`
|
||||
Weight int `json:"weight"`
|
||||
}
|
||||
|
||||
type PythonDepNameDictSlice []PythonDepNameDict
|
||||
|
||||
func (s PythonDepNameDictSlice) Len() int { return len(s) }
|
||||
func (s PythonDepNameDictSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s PythonDepNameDictSlice) Less(i, j int) bool { return s[i].Weight > s[j].Weight }
|
||||
|
||||
var SystemInfoChanMap = utils.NewChanMap()
|
||||
|
||||
func GetRemoteSystemInfo(id string) (sysInfo entity.SystemInfo, err error) {
|
||||
func GetRemoteSystemInfo(nodeId string) (sysInfo entity.SystemInfo, err error) {
|
||||
// 发送消息
|
||||
msg := entity.NodeMessage{
|
||||
Type: constants.MsgTypeGetSystemInfo,
|
||||
NodeId: id,
|
||||
NodeId: nodeId,
|
||||
}
|
||||
|
||||
// 序列化
|
||||
msgBytes, _ := json.Marshal(&msg)
|
||||
if _, err := database.RedisClient.Publish("nodes:"+id, utils.BytesToString(msgBytes)); err != nil {
|
||||
if _, err := database.RedisClient.Publish("nodes:"+nodeId, utils.BytesToString(msgBytes)); err != nil {
|
||||
return entity.SystemInfo{}, err
|
||||
}
|
||||
|
||||
// 通道
|
||||
ch := SystemInfoChanMap.ChanBlocked(id)
|
||||
ch := SystemInfoChanMap.ChanBlocked(nodeId)
|
||||
|
||||
// 等待响应,阻塞
|
||||
sysInfoStr := <-ch
|
||||
@@ -38,11 +68,148 @@ func GetRemoteSystemInfo(id string) (sysInfo entity.SystemInfo, err error) {
|
||||
return sysInfo, nil
|
||||
}
|
||||
|
||||
func GetSystemInfo(id string) (sysInfo entity.SystemInfo, err error) {
|
||||
if IsMasterNode(id) {
|
||||
func GetSystemInfo(nodeId string) (sysInfo entity.SystemInfo, err error) {
|
||||
if IsMasterNode(nodeId) {
|
||||
sysInfo, err = model.GetLocalSystemInfo()
|
||||
} else {
|
||||
sysInfo, err = GetRemoteSystemInfo(id)
|
||||
sysInfo, err = GetRemoteSystemInfo(nodeId)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetLangList(nodeId string) []entity.Lang {
|
||||
list := []entity.Lang{
|
||||
{Name: "Python", ExecutableName: "python", ExecutablePath: "/usr/local/bin/python", DepExecutablePath: "/usr/local/bin/pip"},
|
||||
{Name: "NodeJS", ExecutableName: "node", ExecutablePath: "/usr/local/bin/node"},
|
||||
{Name: "Java", ExecutableName: "java", ExecutablePath: "/usr/local/bin/java"},
|
||||
}
|
||||
for i, lang := range list {
|
||||
list[i].Installed = isInstalledLang(nodeId, lang)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func GetLangFromLangName(nodeId string, name string) entity.Lang {
|
||||
langList := GetLangList(nodeId)
|
||||
for _, lang := range langList {
|
||||
if lang.ExecutableName == name {
|
||||
return lang
|
||||
}
|
||||
}
|
||||
return entity.Lang{}
|
||||
}
|
||||
|
||||
func GetDepList(nodeId string, langExecutableName string, searchDepName string) ([]entity.Dependency, error) {
|
||||
// TODO: support other languages
|
||||
// 获取语言
|
||||
lang := GetLangFromLangName(nodeId, langExecutableName)
|
||||
|
||||
// 如果没有依赖列表,先获取
|
||||
if len(DepList) == 0 {
|
||||
FetchDepList()
|
||||
}
|
||||
|
||||
// 过滤相似的依赖
|
||||
var depNameList PythonDepNameDictSlice
|
||||
for _, depName := range DepList {
|
||||
if strings.Contains(strings.ToLower(depName), strings.ToLower(searchDepName)) {
|
||||
var weight int
|
||||
if strings.ToLower(depName) == strings.ToLower(searchDepName) {
|
||||
weight = 3
|
||||
} else if strings.HasPrefix(strings.ToLower(depName), strings.ToLower(searchDepName)) {
|
||||
weight = 2
|
||||
} else {
|
||||
weight = 1
|
||||
}
|
||||
depNameList = append(depNameList, PythonDepNameDict{
|
||||
Name: depName,
|
||||
Weight: weight,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var depList []entity.Dependency
|
||||
var goSync sync.WaitGroup
|
||||
sort.Stable(depNameList)
|
||||
for i, depNameDict := range depNameList {
|
||||
if i > 20 {
|
||||
break
|
||||
}
|
||||
goSync.Add(1)
|
||||
go func(depName string, n *sync.WaitGroup) {
|
||||
url := fmt.Sprintf("https://pypi.org/pypi/%s/json", depName)
|
||||
res, err := req.Get(url)
|
||||
if err != nil {
|
||||
n.Done()
|
||||
return
|
||||
}
|
||||
var data PythonDepJsonData
|
||||
if err := res.ToJSON(&data); err != nil {
|
||||
n.Done()
|
||||
return
|
||||
}
|
||||
dep := entity.Dependency{
|
||||
Name: depName,
|
||||
Version: data.Info.Version,
|
||||
Description: data.Info.Summary,
|
||||
Lang: lang.ExecutableName,
|
||||
Installed: false,
|
||||
}
|
||||
depList = append(depList, dep)
|
||||
n.Done()
|
||||
}(depNameDict.Name, &goSync)
|
||||
}
|
||||
goSync.Wait()
|
||||
|
||||
return depList, nil
|
||||
}
|
||||
|
||||
func isInstalledLang(nodeId string, lang entity.Lang) bool {
|
||||
sysInfo, err := GetSystemInfo(nodeId)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, exec := range sysInfo.Executables {
|
||||
if exec.Path == lang.ExecutablePath {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func FetchDepList() {
|
||||
url := "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
res, err := req.Get(url)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
}
|
||||
text, err := res.ToString()
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
}
|
||||
var list []string
|
||||
regex := regexp.MustCompile("<a href=\".*/\">(.*)</a>")
|
||||
for _, line := range strings.Split(text, "\n") {
|
||||
arr := regex.FindStringSubmatch(line)
|
||||
if len(arr) < 2 {
|
||||
continue
|
||||
}
|
||||
list = append(list, arr[1])
|
||||
}
|
||||
DepList = list
|
||||
}
|
||||
|
||||
var DepList []string
|
||||
|
||||
func InitDepsFetcher() error {
|
||||
c := cron.New(cron.WithSeconds())
|
||||
c.Start()
|
||||
if _, err := c.AddFunc("0 */5 * * * *", FetchDepList); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
1
backend/vendor/github.com/apex/log/.gitignore
generated
vendored
1
backend/vendor/github.com/apex/log/.gitignore
generated
vendored
@@ -1 +0,0 @@
|
||||
.envrc
|
||||
12
backend/vendor/github.com/apex/log/History.md
generated
vendored
12
backend/vendor/github.com/apex/log/History.md
generated
vendored
@@ -1,12 +0,0 @@
|
||||
|
||||
v1.1.1 / 2019-06-24
|
||||
===================
|
||||
|
||||
* add go.mod
|
||||
* add rough pass at apexlogs handler
|
||||
|
||||
v1.1.0 / 2018-10-11
|
||||
===================
|
||||
|
||||
* fix: cli handler to show non-string fields appropriately
|
||||
* fix: cli using fatih/color to better support windows
|
||||
22
backend/vendor/github.com/apex/log/LICENSE
generated
vendored
22
backend/vendor/github.com/apex/log/LICENSE
generated
vendored
@@ -1,22 +0,0 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2015 TJ Holowaychuk tj@tjholowaychuk.com
|
||||
|
||||
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.
|
||||
2
backend/vendor/github.com/apex/log/Makefile
generated
vendored
2
backend/vendor/github.com/apex/log/Makefile
generated
vendored
@@ -1,2 +0,0 @@
|
||||
|
||||
include github.com/tj/make/golang
|
||||
29
backend/vendor/github.com/apex/log/Readme.md
generated
vendored
29
backend/vendor/github.com/apex/log/Readme.md
generated
vendored
@@ -1,29 +0,0 @@
|
||||
|
||||

|
||||
|
||||
Package log implements a simple structured logging API inspired by Logrus, designed with centralization in mind. Read more on [Medium](https://medium.com/@tjholowaychuk/apex-log-e8d9627f4a9a#.rav8yhkud).
|
||||
|
||||
## Handlers
|
||||
|
||||
- __cli__ – human-friendly CLI output
|
||||
- __discard__ – discards all logs
|
||||
- __es__ – Elasticsearch handler
|
||||
- __graylog__ – Graylog handler
|
||||
- __json__ – JSON output handler
|
||||
- __kinesis__ – AWS Kinesis handler
|
||||
- __level__ – level filter handler
|
||||
- __logfmt__ – logfmt plain-text formatter
|
||||
- __memory__ – in-memory handler for tests
|
||||
- __multi__ – fan-out to multiple handlers
|
||||
- __papertrail__ – Papertrail handler
|
||||
- __text__ – human-friendly colored output
|
||||
- __delta__ – outputs the delta between log calls and spinner
|
||||
|
||||
---
|
||||
|
||||
[](https://semaphoreci.com/tj/log)
|
||||
[](https://godoc.org/github.com/apex/log)
|
||||

|
||||

|
||||
|
||||
<a href="https://apex.sh"><img src="http://tjholowaychuk.com:6000/svg/sponsor"></a>
|
||||
45
backend/vendor/github.com/apex/log/default.go
generated
vendored
45
backend/vendor/github.com/apex/log/default.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// field used for sorting.
|
||||
type field struct {
|
||||
Name string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// by sorts fields by name.
|
||||
type byName []field
|
||||
|
||||
func (a byName) Len() int { return len(a) }
|
||||
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byName) Less(i, j int) bool { return a[i].Name < a[j].Name }
|
||||
|
||||
// handleStdLog outpouts to the stlib log.
|
||||
func handleStdLog(e *Entry) error {
|
||||
level := levelNames[e.Level]
|
||||
|
||||
var fields []field
|
||||
|
||||
for k, v := range e.Fields {
|
||||
fields = append(fields, field{k, v})
|
||||
}
|
||||
|
||||
sort.Sort(byName(fields))
|
||||
|
||||
var b bytes.Buffer
|
||||
fmt.Fprintf(&b, "%5s %-25s", level, e.Message)
|
||||
|
||||
for _, f := range fields {
|
||||
fmt.Fprintf(&b, " %s=%v", f.Name, f.Value)
|
||||
}
|
||||
|
||||
log.Println(b.String())
|
||||
|
||||
return nil
|
||||
}
|
||||
10
backend/vendor/github.com/apex/log/doc.go
generated
vendored
10
backend/vendor/github.com/apex/log/doc.go
generated
vendored
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
Package log implements a simple structured logging API designed with few assumptions. Designed for
|
||||
centralized logging solutions such as Kinesis which require encoding and decoding before fanning-out
|
||||
to handlers.
|
||||
|
||||
You may use this package with inline handlers, much like Logrus, however a centralized solution
|
||||
is recommended so that apps do not need to be re-deployed to add or remove logging service
|
||||
providers.
|
||||
*/
|
||||
package log
|
||||
172
backend/vendor/github.com/apex/log/entry.go
generated
vendored
172
backend/vendor/github.com/apex/log/entry.go
generated
vendored
@@ -1,172 +0,0 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// assert interface compliance.
|
||||
var _ Interface = (*Entry)(nil)
|
||||
|
||||
// Now returns the current time.
|
||||
var Now = time.Now
|
||||
|
||||
// Entry represents a single log entry.
|
||||
type Entry struct {
|
||||
Logger *Logger `json:"-"`
|
||||
Fields Fields `json:"fields"`
|
||||
Level Level `json:"level"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Message string `json:"message"`
|
||||
start time.Time
|
||||
fields []Fields
|
||||
}
|
||||
|
||||
// NewEntry returns a new entry for `log`.
|
||||
func NewEntry(log *Logger) *Entry {
|
||||
return &Entry{
|
||||
Logger: log,
|
||||
}
|
||||
}
|
||||
|
||||
// WithFields returns a new entry with `fields` set.
|
||||
func (e *Entry) WithFields(fields Fielder) *Entry {
|
||||
f := []Fields{}
|
||||
f = append(f, e.fields...)
|
||||
f = append(f, fields.Fields())
|
||||
return &Entry{
|
||||
Logger: e.Logger,
|
||||
fields: f,
|
||||
}
|
||||
}
|
||||
|
||||
// WithField returns a new entry with the `key` and `value` set.
|
||||
func (e *Entry) WithField(key string, value interface{}) *Entry {
|
||||
return e.WithFields(Fields{key: value})
|
||||
}
|
||||
|
||||
// WithError returns a new entry with the "error" set to `err`.
|
||||
//
|
||||
// The given error may implement .Fielder, if it does the method
|
||||
// will add all its `.Fields()` into the returned entry.
|
||||
func (e *Entry) WithError(err error) *Entry {
|
||||
ctx := e.WithField("error", err.Error())
|
||||
|
||||
if s, ok := err.(stackTracer); ok {
|
||||
frame := s.StackTrace()[0]
|
||||
|
||||
name := fmt.Sprintf("%n", frame)
|
||||
file := fmt.Sprintf("%+s", frame)
|
||||
line := fmt.Sprintf("%d", frame)
|
||||
|
||||
parts := strings.Split(file, "\n\t")
|
||||
if len(parts) > 1 {
|
||||
file = parts[1]
|
||||
}
|
||||
|
||||
ctx = ctx.WithField("source", fmt.Sprintf("%s: %s:%s", name, file, line))
|
||||
}
|
||||
|
||||
if f, ok := err.(Fielder); ok {
|
||||
ctx = ctx.WithFields(f.Fields())
|
||||
}
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Debug level message.
|
||||
func (e *Entry) Debug(msg string) {
|
||||
e.Logger.log(DebugLevel, e, msg)
|
||||
}
|
||||
|
||||
// Info level message.
|
||||
func (e *Entry) Info(msg string) {
|
||||
e.Logger.log(InfoLevel, e, msg)
|
||||
}
|
||||
|
||||
// Warn level message.
|
||||
func (e *Entry) Warn(msg string) {
|
||||
e.Logger.log(WarnLevel, e, msg)
|
||||
}
|
||||
|
||||
// Error level message.
|
||||
func (e *Entry) Error(msg string) {
|
||||
e.Logger.log(ErrorLevel, e, msg)
|
||||
}
|
||||
|
||||
// Fatal level message, followed by an exit.
|
||||
func (e *Entry) Fatal(msg string) {
|
||||
e.Logger.log(FatalLevel, e, msg)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Debugf level formatted message.
|
||||
func (e *Entry) Debugf(msg string, v ...interface{}) {
|
||||
e.Debug(fmt.Sprintf(msg, v...))
|
||||
}
|
||||
|
||||
// Infof level formatted message.
|
||||
func (e *Entry) Infof(msg string, v ...interface{}) {
|
||||
e.Info(fmt.Sprintf(msg, v...))
|
||||
}
|
||||
|
||||
// Warnf level formatted message.
|
||||
func (e *Entry) Warnf(msg string, v ...interface{}) {
|
||||
e.Warn(fmt.Sprintf(msg, v...))
|
||||
}
|
||||
|
||||
// Errorf level formatted message.
|
||||
func (e *Entry) Errorf(msg string, v ...interface{}) {
|
||||
e.Error(fmt.Sprintf(msg, v...))
|
||||
}
|
||||
|
||||
// Fatalf level formatted message, followed by an exit.
|
||||
func (e *Entry) Fatalf(msg string, v ...interface{}) {
|
||||
e.Fatal(fmt.Sprintf(msg, v...))
|
||||
}
|
||||
|
||||
// Trace returns a new entry with a Stop method to fire off
|
||||
// a corresponding completion log, useful with defer.
|
||||
func (e *Entry) Trace(msg string) *Entry {
|
||||
e.Info(msg)
|
||||
v := e.WithFields(e.Fields)
|
||||
v.Message = msg
|
||||
v.start = time.Now()
|
||||
return v
|
||||
}
|
||||
|
||||
// Stop should be used with Trace, to fire off the completion message. When
|
||||
// an `err` is passed the "error" field is set, and the log level is error.
|
||||
func (e *Entry) Stop(err *error) {
|
||||
if err == nil || *err == nil {
|
||||
e.WithField("duration", time.Since(e.start)).Info(e.Message)
|
||||
} else {
|
||||
e.WithField("duration", time.Since(e.start)).WithError(*err).Error(e.Message)
|
||||
}
|
||||
}
|
||||
|
||||
// mergedFields returns the fields list collapsed into a single map.
|
||||
func (e *Entry) mergedFields() Fields {
|
||||
f := Fields{}
|
||||
|
||||
for _, fields := range e.fields {
|
||||
for k, v := range fields {
|
||||
f[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// finalize returns a copy of the Entry with Fields merged.
|
||||
func (e *Entry) finalize(level Level, msg string) *Entry {
|
||||
return &Entry{
|
||||
Logger: e.Logger,
|
||||
Fields: e.mergedFields(),
|
||||
Level: level,
|
||||
Message: msg,
|
||||
Timestamp: Now(),
|
||||
}
|
||||
}
|
||||
25
backend/vendor/github.com/apex/log/go.mod
generated
vendored
25
backend/vendor/github.com/apex/log/go.mod
generated
vendored
@@ -1,25 +0,0 @@
|
||||
module github.com/apex/log
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a
|
||||
github.com/aphistic/sweet v0.2.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.20.6
|
||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/go-logfmt/logfmt v0.4.0
|
||||
github.com/google/uuid v1.1.1 // indirect
|
||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.2
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/rogpeppe/fastuuid v1.1.0
|
||||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
|
||||
github.com/smartystreets/gunit v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/tj/assert v0.0.0-20171129193455-018094318fb0
|
||||
github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2
|
||||
github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b
|
||||
github.com/tj/go-spin v1.1.0
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect
|
||||
)
|
||||
90
backend/vendor/github.com/apex/log/go.sum
generated
vendored
90
backend/vendor/github.com/apex/log/go.sum
generated
vendored
@@ -1,90 +0,0 @@
|
||||
github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a h1:2KLQMJ8msqoPHIPDufkxVcoTtcmE5+1sL9950m4R9Pk=
|
||||
github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
|
||||
github.com/aphistic/sweet v0.2.0 h1:I4z+fAUqvKfvZV/CHi5dV0QuwbmIvYYFDjG0Ss5QpAs=
|
||||
github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
|
||||
github.com/aws/aws-sdk-go v1.20.6 h1:kmy4Gvdlyez1fV4kw5RYxZzWKVyuHZHgPWeU/YvRsV4=
|
||||
github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo=
|
||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 h1:K//n/AqR5HjG3qxbrBCL4vJPW0MVFSs9CPK1OOJdRME=
|
||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/fastuuid v1.1.0 h1:INyGLmTCMGFr6OVIb977ghJvABML2CMVjPoRfNDdYDo=
|
||||
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
|
||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 h1:hp2CYQUINdZMHdvTdXtPOY2ainKl4IoMcpAXEf2xj3Q=
|
||||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
|
||||
github.com/smartystreets/gunit v1.0.0 h1:RyPDUFcJbvtXlhJPk7v+wnxZRY2EUokhEYl2EJOPToI=
|
||||
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/tj/assert v0.0.0-20171129193455-018094318fb0 h1:Rw8kxzWo1mr6FSaYXjQELRe88y2KdfynXdnK72rdjtA=
|
||||
github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
|
||||
github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2 h1:eGaGNxrtoZf/mBURsnNQKDR7u50Klgcf2eFDQEnc8Bc=
|
||||
github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
|
||||
github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b h1:m74UWYy+HBs+jMFR9mdZU6shPewugMyH5+GV6LNgW8w=
|
||||
github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
|
||||
github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=
|
||||
github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
19
backend/vendor/github.com/apex/log/interface.go
generated
vendored
19
backend/vendor/github.com/apex/log/interface.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
package log
|
||||
|
||||
// Interface represents the API of both Logger and Entry.
|
||||
type Interface interface {
|
||||
WithFields(fields Fielder) *Entry
|
||||
WithField(key string, value interface{}) *Entry
|
||||
WithError(err error) *Entry
|
||||
Debug(msg string)
|
||||
Info(msg string)
|
||||
Warn(msg string)
|
||||
Error(msg string)
|
||||
Fatal(msg string)
|
||||
Debugf(msg string, v ...interface{})
|
||||
Infof(msg string, v ...interface{})
|
||||
Warnf(msg string, v ...interface{})
|
||||
Errorf(msg string, v ...interface{})
|
||||
Fatalf(msg string, v ...interface{})
|
||||
Trace(msg string) *Entry
|
||||
}
|
||||
81
backend/vendor/github.com/apex/log/levels.go
generated
vendored
81
backend/vendor/github.com/apex/log/levels.go
generated
vendored
@@ -1,81 +0,0 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrInvalidLevel is returned if the severity level is invalid.
|
||||
var ErrInvalidLevel = errors.New("invalid level")
|
||||
|
||||
// Level of severity.
|
||||
type Level int
|
||||
|
||||
// Log levels.
|
||||
const (
|
||||
InvalidLevel Level = iota - 1
|
||||
DebugLevel
|
||||
InfoLevel
|
||||
WarnLevel
|
||||
ErrorLevel
|
||||
FatalLevel
|
||||
)
|
||||
|
||||
var levelNames = [...]string{
|
||||
DebugLevel: "debug",
|
||||
InfoLevel: "info",
|
||||
WarnLevel: "warn",
|
||||
ErrorLevel: "error",
|
||||
FatalLevel: "fatal",
|
||||
}
|
||||
|
||||
var levelStrings = map[string]Level{
|
||||
"debug": DebugLevel,
|
||||
"info": InfoLevel,
|
||||
"warn": WarnLevel,
|
||||
"warning": WarnLevel,
|
||||
"error": ErrorLevel,
|
||||
"fatal": FatalLevel,
|
||||
}
|
||||
|
||||
// String implementation.
|
||||
func (l Level) String() string {
|
||||
return levelNames[l]
|
||||
}
|
||||
|
||||
// MarshalJSON implementation.
|
||||
func (l Level) MarshalJSON() ([]byte, error) {
|
||||
return []byte(`"` + l.String() + `"`), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implementation.
|
||||
func (l *Level) UnmarshalJSON(b []byte) error {
|
||||
v, err := ParseLevel(string(bytes.Trim(b, `"`)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*l = v
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseLevel parses level string.
|
||||
func ParseLevel(s string) (Level, error) {
|
||||
l, ok := levelStrings[strings.ToLower(s)]
|
||||
if !ok {
|
||||
return InvalidLevel, ErrInvalidLevel
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// MustParseLevel parses level string or panics.
|
||||
func MustParseLevel(s string) Level {
|
||||
l, err := ParseLevel(s)
|
||||
if err != nil {
|
||||
panic("invalid log level")
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
149
backend/vendor/github.com/apex/log/logger.go
generated
vendored
149
backend/vendor/github.com/apex/log/logger.go
generated
vendored
@@ -1,149 +0,0 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
stdlog "log"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// assert interface compliance.
|
||||
var _ Interface = (*Logger)(nil)
|
||||
|
||||
// Fielder is an interface for providing fields to custom types.
|
||||
type Fielder interface {
|
||||
Fields() Fields
|
||||
}
|
||||
|
||||
// Fields represents a map of entry level data used for structured logging.
|
||||
type Fields map[string]interface{}
|
||||
|
||||
// Fields implements Fielder.
|
||||
func (f Fields) Fields() Fields {
|
||||
return f
|
||||
}
|
||||
|
||||
// Get field value by name.
|
||||
func (f Fields) Get(name string) interface{} {
|
||||
return f[name]
|
||||
}
|
||||
|
||||
// Names returns field names sorted.
|
||||
func (f Fields) Names() (v []string) {
|
||||
for k := range f {
|
||||
v = append(v, k)
|
||||
}
|
||||
|
||||
sort.Strings(v)
|
||||
return
|
||||
}
|
||||
|
||||
// The HandlerFunc type is an adapter to allow the use of ordinary functions as
|
||||
// log handlers. If f is a function with the appropriate signature,
|
||||
// HandlerFunc(f) is a Handler object that calls f.
|
||||
type HandlerFunc func(*Entry) error
|
||||
|
||||
// HandleLog calls f(e).
|
||||
func (f HandlerFunc) HandleLog(e *Entry) error {
|
||||
return f(e)
|
||||
}
|
||||
|
||||
// Handler is used to handle log events, outputting them to
|
||||
// stdio or sending them to remote services. See the "handlers"
|
||||
// directory for implementations.
|
||||
//
|
||||
// It is left up to Handlers to implement thread-safety.
|
||||
type Handler interface {
|
||||
HandleLog(*Entry) error
|
||||
}
|
||||
|
||||
// Logger represents a logger with configurable Level and Handler.
|
||||
type Logger struct {
|
||||
Handler Handler
|
||||
Level Level
|
||||
}
|
||||
|
||||
// WithFields returns a new entry with `fields` set.
|
||||
func (l *Logger) WithFields(fields Fielder) *Entry {
|
||||
return NewEntry(l).WithFields(fields.Fields())
|
||||
}
|
||||
|
||||
// WithField returns a new entry with the `key` and `value` set.
|
||||
//
|
||||
// Note that the `key` should not have spaces in it - use camel
|
||||
// case or underscores
|
||||
func (l *Logger) WithField(key string, value interface{}) *Entry {
|
||||
return NewEntry(l).WithField(key, value)
|
||||
}
|
||||
|
||||
// WithError returns a new entry with the "error" set to `err`.
|
||||
func (l *Logger) WithError(err error) *Entry {
|
||||
return NewEntry(l).WithError(err)
|
||||
}
|
||||
|
||||
// Debug level message.
|
||||
func (l *Logger) Debug(msg string) {
|
||||
NewEntry(l).Debug(msg)
|
||||
}
|
||||
|
||||
// Info level message.
|
||||
func (l *Logger) Info(msg string) {
|
||||
NewEntry(l).Info(msg)
|
||||
}
|
||||
|
||||
// Warn level message.
|
||||
func (l *Logger) Warn(msg string) {
|
||||
NewEntry(l).Warn(msg)
|
||||
}
|
||||
|
||||
// Error level message.
|
||||
func (l *Logger) Error(msg string) {
|
||||
NewEntry(l).Error(msg)
|
||||
}
|
||||
|
||||
// Fatal level message, followed by an exit.
|
||||
func (l *Logger) Fatal(msg string) {
|
||||
NewEntry(l).Fatal(msg)
|
||||
}
|
||||
|
||||
// Debugf level formatted message.
|
||||
func (l *Logger) Debugf(msg string, v ...interface{}) {
|
||||
NewEntry(l).Debugf(msg, v...)
|
||||
}
|
||||
|
||||
// Infof level formatted message.
|
||||
func (l *Logger) Infof(msg string, v ...interface{}) {
|
||||
NewEntry(l).Infof(msg, v...)
|
||||
}
|
||||
|
||||
// Warnf level formatted message.
|
||||
func (l *Logger) Warnf(msg string, v ...interface{}) {
|
||||
NewEntry(l).Warnf(msg, v...)
|
||||
}
|
||||
|
||||
// Errorf level formatted message.
|
||||
func (l *Logger) Errorf(msg string, v ...interface{}) {
|
||||
NewEntry(l).Errorf(msg, v...)
|
||||
}
|
||||
|
||||
// Fatalf level formatted message, followed by an exit.
|
||||
func (l *Logger) Fatalf(msg string, v ...interface{}) {
|
||||
NewEntry(l).Fatalf(msg, v...)
|
||||
}
|
||||
|
||||
// Trace returns a new entry with a Stop method to fire off
|
||||
// a corresponding completion log, useful with defer.
|
||||
func (l *Logger) Trace(msg string) *Entry {
|
||||
return NewEntry(l).Trace(msg)
|
||||
}
|
||||
|
||||
// log the message, invoking the handler. We clone the entry here
|
||||
// to bypass the overhead in Entry methods when the level is not
|
||||
// met.
|
||||
func (l *Logger) log(level Level, e *Entry, msg string) {
|
||||
if level < l.Level {
|
||||
return
|
||||
}
|
||||
|
||||
if err := l.Handler.HandleLog(e.finalize(level, msg)); err != nil {
|
||||
stdlog.Printf("error logging: %s", err)
|
||||
}
|
||||
}
|
||||
100
backend/vendor/github.com/apex/log/pkg.go
generated
vendored
100
backend/vendor/github.com/apex/log/pkg.go
generated
vendored
@@ -1,100 +0,0 @@
|
||||
package log
|
||||
|
||||
// singletons ftw?
|
||||
var Log Interface = &Logger{
|
||||
Handler: HandlerFunc(handleStdLog),
|
||||
Level: InfoLevel,
|
||||
}
|
||||
|
||||
// SetHandler sets the handler. This is not thread-safe.
|
||||
// The default handler outputs to the stdlib log.
|
||||
func SetHandler(h Handler) {
|
||||
if logger, ok := Log.(*Logger); ok {
|
||||
logger.Handler = h
|
||||
}
|
||||
}
|
||||
|
||||
// SetLevel sets the log level. This is not thread-safe.
|
||||
func SetLevel(l Level) {
|
||||
if logger, ok := Log.(*Logger); ok {
|
||||
logger.Level = l
|
||||
}
|
||||
}
|
||||
|
||||
// SetLevelFromString sets the log level from a string, panicing when invalid. This is not thread-safe.
|
||||
func SetLevelFromString(s string) {
|
||||
if logger, ok := Log.(*Logger); ok {
|
||||
logger.Level = MustParseLevel(s)
|
||||
}
|
||||
}
|
||||
|
||||
// WithFields returns a new entry with `fields` set.
|
||||
func WithFields(fields Fielder) *Entry {
|
||||
return Log.WithFields(fields)
|
||||
}
|
||||
|
||||
// WithField returns a new entry with the `key` and `value` set.
|
||||
func WithField(key string, value interface{}) *Entry {
|
||||
return Log.WithField(key, value)
|
||||
}
|
||||
|
||||
// WithError returns a new entry with the "error" set to `err`.
|
||||
func WithError(err error) *Entry {
|
||||
return Log.WithError(err)
|
||||
}
|
||||
|
||||
// Debug level message.
|
||||
func Debug(msg string) {
|
||||
Log.Debug(msg)
|
||||
}
|
||||
|
||||
// Info level message.
|
||||
func Info(msg string) {
|
||||
Log.Info(msg)
|
||||
}
|
||||
|
||||
// Warn level message.
|
||||
func Warn(msg string) {
|
||||
Log.Warn(msg)
|
||||
}
|
||||
|
||||
// Error level message.
|
||||
func Error(msg string) {
|
||||
Log.Error(msg)
|
||||
}
|
||||
|
||||
// Fatal level message, followed by an exit.
|
||||
func Fatal(msg string) {
|
||||
Log.Fatal(msg)
|
||||
}
|
||||
|
||||
// Debugf level formatted message.
|
||||
func Debugf(msg string, v ...interface{}) {
|
||||
Log.Debugf(msg, v...)
|
||||
}
|
||||
|
||||
// Infof level formatted message.
|
||||
func Infof(msg string, v ...interface{}) {
|
||||
Log.Infof(msg, v...)
|
||||
}
|
||||
|
||||
// Warnf level formatted message.
|
||||
func Warnf(msg string, v ...interface{}) {
|
||||
Log.Warnf(msg, v...)
|
||||
}
|
||||
|
||||
// Errorf level formatted message.
|
||||
func Errorf(msg string, v ...interface{}) {
|
||||
Log.Errorf(msg, v...)
|
||||
}
|
||||
|
||||
// Fatalf level formatted message, followed by an exit.
|
||||
func Fatalf(msg string, v ...interface{}) {
|
||||
Log.Fatalf(msg, v...)
|
||||
}
|
||||
|
||||
// Trace returns a new entry with a Stop method to fire off
|
||||
// a corresponding completion log, useful with defer.
|
||||
func Trace(msg string) *Entry {
|
||||
return Log.Trace(msg)
|
||||
}
|
||||
8
backend/vendor/github.com/apex/log/stack.go
generated
vendored
8
backend/vendor/github.com/apex/log/stack.go
generated
vendored
@@ -1,8 +0,0 @@
|
||||
package log
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
// stackTracer interface.
|
||||
type stackTracer interface {
|
||||
StackTrace() errors.StackTrace
|
||||
}
|
||||
4
backend/vendor/github.com/dgrijalva/jwt-go/.gitignore
generated
vendored
4
backend/vendor/github.com/dgrijalva/jwt-go/.gitignore
generated
vendored
@@ -1,4 +0,0 @@
|
||||
.DS_Store
|
||||
bin
|
||||
|
||||
|
||||
13
backend/vendor/github.com/dgrijalva/jwt-go/.travis.yml
generated
vendored
13
backend/vendor/github.com/dgrijalva/jwt-go/.travis.yml
generated
vendored
@@ -1,13 +0,0 @@
|
||||
language: go
|
||||
|
||||
script:
|
||||
- go vet ./...
|
||||
- go test -v ./...
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- tip
|
||||
8
backend/vendor/github.com/dgrijalva/jwt-go/LICENSE
generated
vendored
8
backend/vendor/github.com/dgrijalva/jwt-go/LICENSE
generated
vendored
@@ -1,8 +0,0 @@
|
||||
Copyright (c) 2012 Dave Grijalva
|
||||
|
||||
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.
|
||||
|
||||
97
backend/vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md
generated
vendored
97
backend/vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md
generated
vendored
@@ -1,97 +0,0 @@
|
||||
## Migration Guide from v2 -> v3
|
||||
|
||||
Version 3 adds several new, frequently requested features. To do so, it introduces a few breaking changes. We've worked to keep these as minimal as possible. This guide explains the breaking changes and how you can quickly update your code.
|
||||
|
||||
### `Token.Claims` is now an interface type
|
||||
|
||||
The most requested feature from the 2.0 verison of this library was the ability to provide a custom type to the JSON parser for claims. This was implemented by introducing a new interface, `Claims`, to replace `map[string]interface{}`. We also included two concrete implementations of `Claims`: `MapClaims` and `StandardClaims`.
|
||||
|
||||
`MapClaims` is an alias for `map[string]interface{}` with built in validation behavior. It is the default claims type when using `Parse`. The usage is unchanged except you must type cast the claims property.
|
||||
|
||||
The old example for parsing a token looked like this..
|
||||
|
||||
```go
|
||||
if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
|
||||
fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
|
||||
}
|
||||
```
|
||||
|
||||
is now directly mapped to...
|
||||
|
||||
```go
|
||||
if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
|
||||
}
|
||||
```
|
||||
|
||||
`StandardClaims` is designed to be embedded in your custom type. You can supply a custom claims type with the new `ParseWithClaims` function. Here's an example of using a custom claims type.
|
||||
|
||||
```go
|
||||
type MyCustomClaims struct {
|
||||
User string
|
||||
*StandardClaims
|
||||
}
|
||||
|
||||
if token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, keyLookupFunc); err == nil {
|
||||
claims := token.Claims.(*MyCustomClaims)
|
||||
fmt.Printf("Token for user %v expires %v", claims.User, claims.StandardClaims.ExpiresAt)
|
||||
}
|
||||
```
|
||||
|
||||
### `ParseFromRequest` has been moved
|
||||
|
||||
To keep this library focused on the tokens without becoming overburdened with complex request processing logic, `ParseFromRequest` and its new companion `ParseFromRequestWithClaims` have been moved to a subpackage, `request`. The method signatues have also been augmented to receive a new argument: `Extractor`.
|
||||
|
||||
`Extractors` do the work of picking the token string out of a request. The interface is simple and composable.
|
||||
|
||||
This simple parsing example:
|
||||
|
||||
```go
|
||||
if token, err := jwt.ParseFromRequest(tokenString, req, keyLookupFunc); err == nil {
|
||||
fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
|
||||
}
|
||||
```
|
||||
|
||||
is directly mapped to:
|
||||
|
||||
```go
|
||||
if token, err := request.ParseFromRequest(req, request.OAuth2Extractor, keyLookupFunc); err == nil {
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
|
||||
}
|
||||
```
|
||||
|
||||
There are several concrete `Extractor` types provided for your convenience:
|
||||
|
||||
* `HeaderExtractor` will search a list of headers until one contains content.
|
||||
* `ArgumentExtractor` will search a list of keys in request query and form arguments until one contains content.
|
||||
* `MultiExtractor` will try a list of `Extractors` in order until one returns content.
|
||||
* `AuthorizationHeaderExtractor` will look in the `Authorization` header for a `Bearer` token.
|
||||
* `OAuth2Extractor` searches the places an OAuth2 token would be specified (per the spec): `Authorization` header and `access_token` argument
|
||||
* `PostExtractionFilter` wraps an `Extractor`, allowing you to process the content before it's parsed. A simple example is stripping the `Bearer ` text from a header
|
||||
|
||||
|
||||
### RSA signing methods no longer accept `[]byte` keys
|
||||
|
||||
Due to a [critical vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/), we've decided the convenience of accepting `[]byte` instead of `rsa.PublicKey` or `rsa.PrivateKey` isn't worth the risk of misuse.
|
||||
|
||||
To replace this behavior, we've added two helper methods: `ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error)` and `ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error)`. These are just simple helpers for unpacking PEM encoded PKCS1 and PKCS8 keys. If your keys are encoded any other way, all you need to do is convert them to the `crypto/rsa` package's types.
|
||||
|
||||
```go
|
||||
func keyLookupFunc(*Token) (interface{}, error) {
|
||||
// Don't forget to validate the alg is what you expect:
|
||||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
||||
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
|
||||
// Look up key
|
||||
key, err := lookupPublicKey(token.Header["kid"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unpack key from PEM encoded PKCS8
|
||||
return jwt.ParseRSAPublicKeyFromPEM(key)
|
||||
}
|
||||
```
|
||||
100
backend/vendor/github.com/dgrijalva/jwt-go/README.md
generated
vendored
100
backend/vendor/github.com/dgrijalva/jwt-go/README.md
generated
vendored
@@ -1,100 +0,0 @@
|
||||
# jwt-go
|
||||
|
||||
[](https://travis-ci.org/dgrijalva/jwt-go)
|
||||
[](https://godoc.org/github.com/dgrijalva/jwt-go)
|
||||
|
||||
A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html)
|
||||
|
||||
**NEW VERSION COMING:** There have been a lot of improvements suggested since the version 3.0.0 released in 2016. I'm working now on cutting two different releases: 3.2.0 will contain any non-breaking changes or enhancements. 4.0.0 will follow shortly which will include breaking changes. See the 4.0.0 milestone to get an idea of what's coming. If you have other ideas, or would like to participate in 4.0.0, now's the time. If you depend on this library and don't want to be interrupted, I recommend you use your dependency mangement tool to pin to version 3.
|
||||
|
||||
**SECURITY NOTICE:** Some older versions of Go have a security issue in the cryotp/elliptic. Recommendation is to upgrade to at least 1.8.3. See issue #216 for more detail.
|
||||
|
||||
**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided.
|
||||
|
||||
## What the heck is a JWT?
|
||||
|
||||
JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens.
|
||||
|
||||
In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](http://tools.ietf.org/html/rfc4648) encoded. The last part is the signature, encoded the same way.
|
||||
|
||||
The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used.
|
||||
|
||||
The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [the RFC](http://self-issued.info/docs/draft-jones-json-web-token.html) for information about reserved keys and the proper way to add your own.
|
||||
|
||||
## What's in the box?
|
||||
|
||||
This library supports the parsing and verification as well as the generation and signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA, RSA-PSS, and ECDSA, though hooks are present for adding your own.
|
||||
|
||||
## Examples
|
||||
|
||||
See [the project documentation](https://godoc.org/github.com/dgrijalva/jwt-go) for examples of usage:
|
||||
|
||||
* [Simple example of parsing and validating a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac)
|
||||
* [Simple example of building and signing a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-New--Hmac)
|
||||
* [Directory of Examples](https://godoc.org/github.com/dgrijalva/jwt-go#pkg-examples)
|
||||
|
||||
## Extensions
|
||||
|
||||
This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`.
|
||||
|
||||
Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go
|
||||
|
||||
## Compliance
|
||||
|
||||
This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences:
|
||||
|
||||
* In order to protect against accidental use of [Unsecured JWTs](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#UnsecuredJWT), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key.
|
||||
|
||||
## Project Status & Versioning
|
||||
|
||||
This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason).
|
||||
|
||||
This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `master`. Periodically, versions will be tagged from `master`. You can find all the releases on [the project releases page](https://github.com/dgrijalva/jwt-go/releases).
|
||||
|
||||
While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v3`. It will do the right thing WRT semantic versioning.
|
||||
|
||||
**BREAKING CHANGES:***
|
||||
* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code.
|
||||
|
||||
## Usage Tips
|
||||
|
||||
### Signing vs Encryption
|
||||
|
||||
A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data:
|
||||
|
||||
* The author of the token was in the possession of the signing secret
|
||||
* The data has not been modified since it was signed
|
||||
|
||||
It's important to know that JWT does not provide encryption, which means anyone who has access to the token can read its contents. If you need to protect (encrypt) the data, there is a companion spec, `JWE`, that provides this functionality. JWE is currently outside the scope of this library.
|
||||
|
||||
### Choosing a Signing Method
|
||||
|
||||
There are several signing methods available, and you should probably take the time to learn about the various options before choosing one. The principal design decision is most likely going to be symmetric vs asymmetric.
|
||||
|
||||
Symmetric signing methods, such as HSA, use only a single secret. This is probably the simplest signing method to use since any `[]byte` can be used as a valid secret. They are also slightly computationally faster to use, though this rarely is enough to matter. Symmetric signing methods work the best when both producers and consumers of tokens are trusted, or even the same system. Since the same secret is used to both sign and validate tokens, you can't easily distribute the key for validation.
|
||||
|
||||
Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification.
|
||||
|
||||
### Signing Methods and Key Types
|
||||
|
||||
Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones:
|
||||
|
||||
* The [HMAC signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation
|
||||
* The [RSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation
|
||||
* The [ECDSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation
|
||||
|
||||
### JWT and OAuth
|
||||
|
||||
It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication.
|
||||
|
||||
Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
|
||||
|
||||
* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth.
|
||||
* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
|
||||
* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
|
||||
|
||||
## More
|
||||
|
||||
Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
|
||||
|
||||
The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation.
|
||||
118
backend/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
generated
vendored
118
backend/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
generated
vendored
@@ -1,118 +0,0 @@
|
||||
## `jwt-go` Version History
|
||||
|
||||
#### 3.2.0
|
||||
|
||||
* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
|
||||
* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate
|
||||
* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before.
|
||||
* Deprecated `ParseFromRequestWithClaims` to simplify API in the future.
|
||||
|
||||
#### 3.1.0
|
||||
|
||||
* Improvements to `jwt` command line tool
|
||||
* Added `SkipClaimsValidation` option to `Parser`
|
||||
* Documentation updates
|
||||
|
||||
#### 3.0.0
|
||||
|
||||
* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
|
||||
* Dropped support for `[]byte` keys when using RSA signing methods. This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods.
|
||||
* `ParseFromRequest` has been moved to `request` subpackage and usage has changed
|
||||
* The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`. The default value is type `MapClaims`, which is an alias to `map[string]interface{}`. This makes it possible to use a custom type when decoding claims.
|
||||
* Other Additions and Changes
|
||||
* Added `Claims` interface type to allow users to decode the claims into a custom type
|
||||
* Added `ParseWithClaims`, which takes a third argument of type `Claims`. Use this function instead of `Parse` if you have a custom type you'd like to decode into.
|
||||
* Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage
|
||||
* Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims`
|
||||
* Added new interface type `Extractor`, which is used for extracting JWT strings from http requests. Used with `ParseFromRequest` and `ParseFromRequestWithClaims`.
|
||||
* Added several new, more specific, validation errors to error type bitmask
|
||||
* Moved examples from README to executable example files
|
||||
* Signing method registry is now thread safe
|
||||
* Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser)
|
||||
|
||||
#### 2.7.0
|
||||
|
||||
This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes.
|
||||
|
||||
* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying
|
||||
* Error text for expired tokens includes how long it's been expired
|
||||
* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM`
|
||||
* Documentation updates
|
||||
|
||||
#### 2.6.0
|
||||
|
||||
* Exposed inner error within ValidationError
|
||||
* Fixed validation errors when using UseJSONNumber flag
|
||||
* Added several unit tests
|
||||
|
||||
#### 2.5.0
|
||||
|
||||
* Added support for signing method none. You shouldn't use this. The API tries to make this clear.
|
||||
* Updated/fixed some documentation
|
||||
* Added more helpful error message when trying to parse tokens that begin with `BEARER `
|
||||
|
||||
#### 2.4.0
|
||||
|
||||
* Added new type, Parser, to allow for configuration of various parsing parameters
|
||||
* You can now specify a list of valid signing methods. Anything outside this set will be rejected.
|
||||
* You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON
|
||||
* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go)
|
||||
* Fixed some bugs with ECDSA parsing
|
||||
|
||||
#### 2.3.0
|
||||
|
||||
* Added support for ECDSA signing methods
|
||||
* Added support for RSA PSS signing methods (requires go v1.4)
|
||||
|
||||
#### 2.2.0
|
||||
|
||||
* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`. Result will now be the parsed token and an error, instead of a panic.
|
||||
|
||||
#### 2.1.0
|
||||
|
||||
Backwards compatible API change that was missed in 2.0.0.
|
||||
|
||||
* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte`
|
||||
|
||||
#### 2.0.0
|
||||
|
||||
There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change.
|
||||
|
||||
The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
|
||||
|
||||
It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
|
||||
|
||||
* **Compatibility Breaking Changes**
|
||||
* `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct`
|
||||
* `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct`
|
||||
* `KeyFunc` now returns `interface{}` instead of `[]byte`
|
||||
* `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key
|
||||
* `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key
|
||||
* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`. Specific sizes are now just instances of this type.
|
||||
* Added public package global `SigningMethodHS256`
|
||||
* Added public package global `SigningMethodHS384`
|
||||
* Added public package global `SigningMethodHS512`
|
||||
* Renamed type `SigningMethodRS256` to `SigningMethodRSA`. Specific sizes are now just instances of this type.
|
||||
* Added public package global `SigningMethodRS256`
|
||||
* Added public package global `SigningMethodRS384`
|
||||
* Added public package global `SigningMethodRS512`
|
||||
* Moved sample private key for HMAC tests from an inline value to a file on disk. Value is unchanged.
|
||||
* Refactored the RSA implementation to be easier to read
|
||||
* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM`
|
||||
|
||||
#### 1.0.2
|
||||
|
||||
* Fixed bug in parsing public keys from certificates
|
||||
* Added more tests around the parsing of keys for RS256
|
||||
* Code refactoring in RS256 implementation. No functional changes
|
||||
|
||||
#### 1.0.1
|
||||
|
||||
* Fixed panic if RS256 signing method was passed an invalid key
|
||||
|
||||
#### 1.0.0
|
||||
|
||||
* First versioned release
|
||||
* API stabilized
|
||||
* Supports creating, signing, parsing, and validating JWT tokens
|
||||
* Supports RS256 and HS256 signing methods
|
||||
134
backend/vendor/github.com/dgrijalva/jwt-go/claims.go
generated
vendored
134
backend/vendor/github.com/dgrijalva/jwt-go/claims.go
generated
vendored
@@ -1,134 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// For a type to be a Claims object, it must just have a Valid method that determines
|
||||
// if the token is invalid for any supported reason
|
||||
type Claims interface {
|
||||
Valid() error
|
||||
}
|
||||
|
||||
// Structured version of Claims Section, as referenced at
|
||||
// https://tools.ietf.org/html/rfc7519#section-4.1
|
||||
// See examples for how to use this with your own claim types
|
||||
type StandardClaims struct {
|
||||
Audience string `json:"aud,omitempty"`
|
||||
ExpiresAt int64 `json:"exp,omitempty"`
|
||||
Id string `json:"jti,omitempty"`
|
||||
IssuedAt int64 `json:"iat,omitempty"`
|
||||
Issuer string `json:"iss,omitempty"`
|
||||
NotBefore int64 `json:"nbf,omitempty"`
|
||||
Subject string `json:"sub,omitempty"`
|
||||
}
|
||||
|
||||
// Validates time based claims "exp, iat, nbf".
|
||||
// There is no accounting for clock skew.
|
||||
// As well, if any of the above claims are not in the token, it will still
|
||||
// be considered a valid claim.
|
||||
func (c StandardClaims) Valid() error {
|
||||
vErr := new(ValidationError)
|
||||
now := TimeFunc().Unix()
|
||||
|
||||
// The claims below are optional, by default, so if they are set to the
|
||||
// default value in Go, let's not fail the verification for them.
|
||||
if c.VerifyExpiresAt(now, false) == false {
|
||||
delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0))
|
||||
vErr.Inner = fmt.Errorf("token is expired by %v", delta)
|
||||
vErr.Errors |= ValidationErrorExpired
|
||||
}
|
||||
|
||||
if c.VerifyIssuedAt(now, false) == false {
|
||||
vErr.Inner = fmt.Errorf("Token used before issued")
|
||||
vErr.Errors |= ValidationErrorIssuedAt
|
||||
}
|
||||
|
||||
if c.VerifyNotBefore(now, false) == false {
|
||||
vErr.Inner = fmt.Errorf("token is not valid yet")
|
||||
vErr.Errors |= ValidationErrorNotValidYet
|
||||
}
|
||||
|
||||
if vErr.valid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return vErr
|
||||
}
|
||||
|
||||
// Compares the aud claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
|
||||
return verifyAud(c.Audience, cmp, req)
|
||||
}
|
||||
|
||||
// Compares the exp claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
|
||||
return verifyExp(c.ExpiresAt, cmp, req)
|
||||
}
|
||||
|
||||
// Compares the iat claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
|
||||
return verifyIat(c.IssuedAt, cmp, req)
|
||||
}
|
||||
|
||||
// Compares the iss claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
|
||||
return verifyIss(c.Issuer, cmp, req)
|
||||
}
|
||||
|
||||
// Compares the nbf claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
|
||||
return verifyNbf(c.NotBefore, cmp, req)
|
||||
}
|
||||
|
||||
// ----- helpers
|
||||
|
||||
func verifyAud(aud string, cmp string, required bool) bool {
|
||||
if aud == "" {
|
||||
return !required
|
||||
}
|
||||
if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func verifyExp(exp int64, now int64, required bool) bool {
|
||||
if exp == 0 {
|
||||
return !required
|
||||
}
|
||||
return now <= exp
|
||||
}
|
||||
|
||||
func verifyIat(iat int64, now int64, required bool) bool {
|
||||
if iat == 0 {
|
||||
return !required
|
||||
}
|
||||
return now >= iat
|
||||
}
|
||||
|
||||
func verifyIss(iss string, cmp string, required bool) bool {
|
||||
if iss == "" {
|
||||
return !required
|
||||
}
|
||||
if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func verifyNbf(nbf int64, now int64, required bool) bool {
|
||||
if nbf == 0 {
|
||||
return !required
|
||||
}
|
||||
return now >= nbf
|
||||
}
|
||||
4
backend/vendor/github.com/dgrijalva/jwt-go/doc.go
generated
vendored
4
backend/vendor/github.com/dgrijalva/jwt-go/doc.go
generated
vendored
@@ -1,4 +0,0 @@
|
||||
// Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html
|
||||
//
|
||||
// See README.md for more info.
|
||||
package jwt
|
||||
148
backend/vendor/github.com/dgrijalva/jwt-go/ecdsa.go
generated
vendored
148
backend/vendor/github.com/dgrijalva/jwt-go/ecdsa.go
generated
vendored
@@ -1,148 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var (
|
||||
// Sadly this is missing from crypto/ecdsa compared to crypto/rsa
|
||||
ErrECDSAVerification = errors.New("crypto/ecdsa: verification error")
|
||||
)
|
||||
|
||||
// Implements the ECDSA family of signing methods signing methods
|
||||
// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
|
||||
type SigningMethodECDSA struct {
|
||||
Name string
|
||||
Hash crypto.Hash
|
||||
KeySize int
|
||||
CurveBits int
|
||||
}
|
||||
|
||||
// Specific instances for EC256 and company
|
||||
var (
|
||||
SigningMethodES256 *SigningMethodECDSA
|
||||
SigningMethodES384 *SigningMethodECDSA
|
||||
SigningMethodES512 *SigningMethodECDSA
|
||||
)
|
||||
|
||||
func init() {
|
||||
// ES256
|
||||
SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256}
|
||||
RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod {
|
||||
return SigningMethodES256
|
||||
})
|
||||
|
||||
// ES384
|
||||
SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384}
|
||||
RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod {
|
||||
return SigningMethodES384
|
||||
})
|
||||
|
||||
// ES512
|
||||
SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521}
|
||||
RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod {
|
||||
return SigningMethodES512
|
||||
})
|
||||
}
|
||||
|
||||
func (m *SigningMethodECDSA) Alg() string {
|
||||
return m.Name
|
||||
}
|
||||
|
||||
// Implements the Verify method from SigningMethod
|
||||
// For this verify method, key must be an ecdsa.PublicKey struct
|
||||
func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error {
|
||||
var err error
|
||||
|
||||
// Decode the signature
|
||||
var sig []byte
|
||||
if sig, err = DecodeSegment(signature); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the key
|
||||
var ecdsaKey *ecdsa.PublicKey
|
||||
switch k := key.(type) {
|
||||
case *ecdsa.PublicKey:
|
||||
ecdsaKey = k
|
||||
default:
|
||||
return ErrInvalidKeyType
|
||||
}
|
||||
|
||||
if len(sig) != 2*m.KeySize {
|
||||
return ErrECDSAVerification
|
||||
}
|
||||
|
||||
r := big.NewInt(0).SetBytes(sig[:m.KeySize])
|
||||
s := big.NewInt(0).SetBytes(sig[m.KeySize:])
|
||||
|
||||
// Create hasher
|
||||
if !m.Hash.Available() {
|
||||
return ErrHashUnavailable
|
||||
}
|
||||
hasher := m.Hash.New()
|
||||
hasher.Write([]byte(signingString))
|
||||
|
||||
// Verify the signature
|
||||
if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus == true {
|
||||
return nil
|
||||
} else {
|
||||
return ErrECDSAVerification
|
||||
}
|
||||
}
|
||||
|
||||
// Implements the Sign method from SigningMethod
|
||||
// For this signing method, key must be an ecdsa.PrivateKey struct
|
||||
func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
|
||||
// Get the key
|
||||
var ecdsaKey *ecdsa.PrivateKey
|
||||
switch k := key.(type) {
|
||||
case *ecdsa.PrivateKey:
|
||||
ecdsaKey = k
|
||||
default:
|
||||
return "", ErrInvalidKeyType
|
||||
}
|
||||
|
||||
// Create the hasher
|
||||
if !m.Hash.Available() {
|
||||
return "", ErrHashUnavailable
|
||||
}
|
||||
|
||||
hasher := m.Hash.New()
|
||||
hasher.Write([]byte(signingString))
|
||||
|
||||
// Sign the string and return r, s
|
||||
if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil {
|
||||
curveBits := ecdsaKey.Curve.Params().BitSize
|
||||
|
||||
if m.CurveBits != curveBits {
|
||||
return "", ErrInvalidKey
|
||||
}
|
||||
|
||||
keyBytes := curveBits / 8
|
||||
if curveBits%8 > 0 {
|
||||
keyBytes += 1
|
||||
}
|
||||
|
||||
// We serialize the outpus (r and s) into big-endian byte arrays and pad
|
||||
// them with zeros on the left to make sure the sizes work out. Both arrays
|
||||
// must be keyBytes long, and the output must be 2*keyBytes long.
|
||||
rBytes := r.Bytes()
|
||||
rBytesPadded := make([]byte, keyBytes)
|
||||
copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
|
||||
|
||||
sBytes := s.Bytes()
|
||||
sBytesPadded := make([]byte, keyBytes)
|
||||
copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
|
||||
|
||||
out := append(rBytesPadded, sBytesPadded...)
|
||||
|
||||
return EncodeSegment(out), nil
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
67
backend/vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go
generated
vendored
67
backend/vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go
generated
vendored
@@ -1,67 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotECPublicKey = errors.New("Key is not a valid ECDSA public key")
|
||||
ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private key")
|
||||
)
|
||||
|
||||
// Parse PEM encoded Elliptic Curve Private Key Structure
|
||||
func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
|
||||
var err error
|
||||
|
||||
// Parse PEM block
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(key); block == nil {
|
||||
return nil, ErrKeyMustBePEMEncoded
|
||||
}
|
||||
|
||||
// Parse the key
|
||||
var parsedKey interface{}
|
||||
if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pkey *ecdsa.PrivateKey
|
||||
var ok bool
|
||||
if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
|
||||
return nil, ErrNotECPrivateKey
|
||||
}
|
||||
|
||||
return pkey, nil
|
||||
}
|
||||
|
||||
// Parse PEM encoded PKCS1 or PKCS8 public key
|
||||
func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
|
||||
var err error
|
||||
|
||||
// Parse PEM block
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(key); block == nil {
|
||||
return nil, ErrKeyMustBePEMEncoded
|
||||
}
|
||||
|
||||
// Parse the key
|
||||
var parsedKey interface{}
|
||||
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
|
||||
if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
|
||||
parsedKey = cert.PublicKey
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var pkey *ecdsa.PublicKey
|
||||
var ok bool
|
||||
if pkey, ok = parsedKey.(*ecdsa.PublicKey); !ok {
|
||||
return nil, ErrNotECPublicKey
|
||||
}
|
||||
|
||||
return pkey, nil
|
||||
}
|
||||
59
backend/vendor/github.com/dgrijalva/jwt-go/errors.go
generated
vendored
59
backend/vendor/github.com/dgrijalva/jwt-go/errors.go
generated
vendored
@@ -1,59 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Error constants
|
||||
var (
|
||||
ErrInvalidKey = errors.New("key is invalid")
|
||||
ErrInvalidKeyType = errors.New("key is of invalid type")
|
||||
ErrHashUnavailable = errors.New("the requested hash function is unavailable")
|
||||
)
|
||||
|
||||
// The errors that might occur when parsing and validating a token
|
||||
const (
|
||||
ValidationErrorMalformed uint32 = 1 << iota // Token is malformed
|
||||
ValidationErrorUnverifiable // Token could not be verified because of signing problems
|
||||
ValidationErrorSignatureInvalid // Signature validation failed
|
||||
|
||||
// Standard Claim validation errors
|
||||
ValidationErrorAudience // AUD validation failed
|
||||
ValidationErrorExpired // EXP validation failed
|
||||
ValidationErrorIssuedAt // IAT validation failed
|
||||
ValidationErrorIssuer // ISS validation failed
|
||||
ValidationErrorNotValidYet // NBF validation failed
|
||||
ValidationErrorId // JTI validation failed
|
||||
ValidationErrorClaimsInvalid // Generic claims validation error
|
||||
)
|
||||
|
||||
// Helper for constructing a ValidationError with a string error message
|
||||
func NewValidationError(errorText string, errorFlags uint32) *ValidationError {
|
||||
return &ValidationError{
|
||||
text: errorText,
|
||||
Errors: errorFlags,
|
||||
}
|
||||
}
|
||||
|
||||
// The error from Parse if token is not valid
|
||||
type ValidationError struct {
|
||||
Inner error // stores the error returned by external dependencies, i.e.: KeyFunc
|
||||
Errors uint32 // bitfield. see ValidationError... constants
|
||||
text string // errors that do not have a valid error just have text
|
||||
}
|
||||
|
||||
// Validation error is an error type
|
||||
func (e ValidationError) Error() string {
|
||||
if e.Inner != nil {
|
||||
return e.Inner.Error()
|
||||
} else if e.text != "" {
|
||||
return e.text
|
||||
} else {
|
||||
return "token is invalid"
|
||||
}
|
||||
}
|
||||
|
||||
// No errors
|
||||
func (e *ValidationError) valid() bool {
|
||||
return e.Errors == 0
|
||||
}
|
||||
95
backend/vendor/github.com/dgrijalva/jwt-go/hmac.go
generated
vendored
95
backend/vendor/github.com/dgrijalva/jwt-go/hmac.go
generated
vendored
@@ -1,95 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Implements the HMAC-SHA family of signing methods signing methods
|
||||
// Expects key type of []byte for both signing and validation
|
||||
type SigningMethodHMAC struct {
|
||||
Name string
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
// Specific instances for HS256 and company
|
||||
var (
|
||||
SigningMethodHS256 *SigningMethodHMAC
|
||||
SigningMethodHS384 *SigningMethodHMAC
|
||||
SigningMethodHS512 *SigningMethodHMAC
|
||||
ErrSignatureInvalid = errors.New("signature is invalid")
|
||||
)
|
||||
|
||||
func init() {
|
||||
// HS256
|
||||
SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256}
|
||||
RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod {
|
||||
return SigningMethodHS256
|
||||
})
|
||||
|
||||
// HS384
|
||||
SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384}
|
||||
RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod {
|
||||
return SigningMethodHS384
|
||||
})
|
||||
|
||||
// HS512
|
||||
SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512}
|
||||
RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod {
|
||||
return SigningMethodHS512
|
||||
})
|
||||
}
|
||||
|
||||
func (m *SigningMethodHMAC) Alg() string {
|
||||
return m.Name
|
||||
}
|
||||
|
||||
// Verify the signature of HSXXX tokens. Returns nil if the signature is valid.
|
||||
func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error {
|
||||
// Verify the key is the right type
|
||||
keyBytes, ok := key.([]byte)
|
||||
if !ok {
|
||||
return ErrInvalidKeyType
|
||||
}
|
||||
|
||||
// Decode signature, for comparison
|
||||
sig, err := DecodeSegment(signature)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Can we use the specified hashing method?
|
||||
if !m.Hash.Available() {
|
||||
return ErrHashUnavailable
|
||||
}
|
||||
|
||||
// This signing method is symmetric, so we validate the signature
|
||||
// by reproducing the signature from the signing string and key, then
|
||||
// comparing that against the provided signature.
|
||||
hasher := hmac.New(m.Hash.New, keyBytes)
|
||||
hasher.Write([]byte(signingString))
|
||||
if !hmac.Equal(sig, hasher.Sum(nil)) {
|
||||
return ErrSignatureInvalid
|
||||
}
|
||||
|
||||
// No validation errors. Signature is good.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Implements the Sign method from SigningMethod for this signing method.
|
||||
// Key must be []byte
|
||||
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
|
||||
if keyBytes, ok := key.([]byte); ok {
|
||||
if !m.Hash.Available() {
|
||||
return "", ErrHashUnavailable
|
||||
}
|
||||
|
||||
hasher := hmac.New(m.Hash.New, keyBytes)
|
||||
hasher.Write([]byte(signingString))
|
||||
|
||||
return EncodeSegment(hasher.Sum(nil)), nil
|
||||
}
|
||||
|
||||
return "", ErrInvalidKeyType
|
||||
}
|
||||
94
backend/vendor/github.com/dgrijalva/jwt-go/map_claims.go
generated
vendored
94
backend/vendor/github.com/dgrijalva/jwt-go/map_claims.go
generated
vendored
@@ -1,94 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
// "fmt"
|
||||
)
|
||||
|
||||
// Claims type that uses the map[string]interface{} for JSON decoding
|
||||
// This is the default claims type if you don't supply one
|
||||
type MapClaims map[string]interface{}
|
||||
|
||||
// Compares the aud claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
|
||||
aud, _ := m["aud"].(string)
|
||||
return verifyAud(aud, cmp, req)
|
||||
}
|
||||
|
||||
// Compares the exp claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
|
||||
switch exp := m["exp"].(type) {
|
||||
case float64:
|
||||
return verifyExp(int64(exp), cmp, req)
|
||||
case json.Number:
|
||||
v, _ := exp.Int64()
|
||||
return verifyExp(v, cmp, req)
|
||||
}
|
||||
return req == false
|
||||
}
|
||||
|
||||
// Compares the iat claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
|
||||
switch iat := m["iat"].(type) {
|
||||
case float64:
|
||||
return verifyIat(int64(iat), cmp, req)
|
||||
case json.Number:
|
||||
v, _ := iat.Int64()
|
||||
return verifyIat(v, cmp, req)
|
||||
}
|
||||
return req == false
|
||||
}
|
||||
|
||||
// Compares the iss claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (m MapClaims) VerifyIssuer(cmp string, req bool) bool {
|
||||
iss, _ := m["iss"].(string)
|
||||
return verifyIss(iss, cmp, req)
|
||||
}
|
||||
|
||||
// Compares the nbf claim against cmp.
|
||||
// If required is false, this method will return true if the value matches or is unset
|
||||
func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
|
||||
switch nbf := m["nbf"].(type) {
|
||||
case float64:
|
||||
return verifyNbf(int64(nbf), cmp, req)
|
||||
case json.Number:
|
||||
v, _ := nbf.Int64()
|
||||
return verifyNbf(v, cmp, req)
|
||||
}
|
||||
return req == false
|
||||
}
|
||||
|
||||
// Validates time based claims "exp, iat, nbf".
|
||||
// There is no accounting for clock skew.
|
||||
// As well, if any of the above claims are not in the token, it will still
|
||||
// be considered a valid claim.
|
||||
func (m MapClaims) Valid() error {
|
||||
vErr := new(ValidationError)
|
||||
now := TimeFunc().Unix()
|
||||
|
||||
if m.VerifyExpiresAt(now, false) == false {
|
||||
vErr.Inner = errors.New("Token is expired")
|
||||
vErr.Errors |= ValidationErrorExpired
|
||||
}
|
||||
|
||||
if m.VerifyIssuedAt(now, false) == false {
|
||||
vErr.Inner = errors.New("Token used before issued")
|
||||
vErr.Errors |= ValidationErrorIssuedAt
|
||||
}
|
||||
|
||||
if m.VerifyNotBefore(now, false) == false {
|
||||
vErr.Inner = errors.New("Token is not valid yet")
|
||||
vErr.Errors |= ValidationErrorNotValidYet
|
||||
}
|
||||
|
||||
if vErr.valid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return vErr
|
||||
}
|
||||
52
backend/vendor/github.com/dgrijalva/jwt-go/none.go
generated
vendored
52
backend/vendor/github.com/dgrijalva/jwt-go/none.go
generated
vendored
@@ -1,52 +0,0 @@
|
||||
package jwt
|
||||
|
||||
// Implements the none signing method. This is required by the spec
|
||||
// but you probably should never use it.
|
||||
var SigningMethodNone *signingMethodNone
|
||||
|
||||
const UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing method allowed"
|
||||
|
||||
var NoneSignatureTypeDisallowedError error
|
||||
|
||||
type signingMethodNone struct{}
|
||||
type unsafeNoneMagicConstant string
|
||||
|
||||
func init() {
|
||||
SigningMethodNone = &signingMethodNone{}
|
||||
NoneSignatureTypeDisallowedError = NewValidationError("'none' signature type is not allowed", ValidationErrorSignatureInvalid)
|
||||
|
||||
RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod {
|
||||
return SigningMethodNone
|
||||
})
|
||||
}
|
||||
|
||||
func (m *signingMethodNone) Alg() string {
|
||||
return "none"
|
||||
}
|
||||
|
||||
// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key
|
||||
func (m *signingMethodNone) Verify(signingString, signature string, key interface{}) (err error) {
|
||||
// Key must be UnsafeAllowNoneSignatureType to prevent accidentally
|
||||
// accepting 'none' signing method
|
||||
if _, ok := key.(unsafeNoneMagicConstant); !ok {
|
||||
return NoneSignatureTypeDisallowedError
|
||||
}
|
||||
// If signing method is none, signature must be an empty string
|
||||
if signature != "" {
|
||||
return NewValidationError(
|
||||
"'none' signing method with non-empty signature",
|
||||
ValidationErrorSignatureInvalid,
|
||||
)
|
||||
}
|
||||
|
||||
// Accept 'none' signing method.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key
|
||||
func (m *signingMethodNone) Sign(signingString string, key interface{}) (string, error) {
|
||||
if _, ok := key.(unsafeNoneMagicConstant); ok {
|
||||
return "", nil
|
||||
}
|
||||
return "", NoneSignatureTypeDisallowedError
|
||||
}
|
||||
148
backend/vendor/github.com/dgrijalva/jwt-go/parser.go
generated
vendored
148
backend/vendor/github.com/dgrijalva/jwt-go/parser.go
generated
vendored
@@ -1,148 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
ValidMethods []string // If populated, only these methods will be considered valid
|
||||
UseJSONNumber bool // Use JSON Number format in JSON decoder
|
||||
SkipClaimsValidation bool // Skip claims validation during token parsing
|
||||
}
|
||||
|
||||
// Parse, validate, and return a token.
|
||||
// keyFunc will receive the parsed token and should return the key for validating.
|
||||
// If everything is kosher, err will be nil
|
||||
func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
|
||||
return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
|
||||
}
|
||||
|
||||
func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
|
||||
token, parts, err := p.ParseUnverified(tokenString, claims)
|
||||
if err != nil {
|
||||
return token, err
|
||||
}
|
||||
|
||||
// Verify signing method is in the required set
|
||||
if p.ValidMethods != nil {
|
||||
var signingMethodValid = false
|
||||
var alg = token.Method.Alg()
|
||||
for _, m := range p.ValidMethods {
|
||||
if m == alg {
|
||||
signingMethodValid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !signingMethodValid {
|
||||
// signing method is not in the listed set
|
||||
return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup key
|
||||
var key interface{}
|
||||
if keyFunc == nil {
|
||||
// keyFunc was not provided. short circuiting validation
|
||||
return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
|
||||
}
|
||||
if key, err = keyFunc(token); err != nil {
|
||||
// keyFunc returned an error
|
||||
if ve, ok := err.(*ValidationError); ok {
|
||||
return token, ve
|
||||
}
|
||||
return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
|
||||
}
|
||||
|
||||
vErr := &ValidationError{}
|
||||
|
||||
// Validate Claims
|
||||
if !p.SkipClaimsValidation {
|
||||
if err := token.Claims.Valid(); err != nil {
|
||||
|
||||
// If the Claims Valid returned an error, check if it is a validation error,
|
||||
// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
|
||||
if e, ok := err.(*ValidationError); !ok {
|
||||
vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
|
||||
} else {
|
||||
vErr = e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform validation
|
||||
token.Signature = parts[2]
|
||||
if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
|
||||
vErr.Inner = err
|
||||
vErr.Errors |= ValidationErrorSignatureInvalid
|
||||
}
|
||||
|
||||
if vErr.valid() {
|
||||
token.Valid = true
|
||||
return token, nil
|
||||
}
|
||||
|
||||
return token, vErr
|
||||
}
|
||||
|
||||
// WARNING: Don't use this method unless you know what you're doing
|
||||
//
|
||||
// This method parses the token but doesn't validate the signature. It's only
|
||||
// ever useful in cases where you know the signature is valid (because it has
|
||||
// been checked previously in the stack) and you want to extract values from
|
||||
// it.
|
||||
func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
|
||||
parts = strings.Split(tokenString, ".")
|
||||
if len(parts) != 3 {
|
||||
return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
|
||||
}
|
||||
|
||||
token = &Token{Raw: tokenString}
|
||||
|
||||
// parse Header
|
||||
var headerBytes []byte
|
||||
if headerBytes, err = DecodeSegment(parts[0]); err != nil {
|
||||
if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
|
||||
return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
|
||||
}
|
||||
return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
|
||||
}
|
||||
if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
|
||||
return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
|
||||
}
|
||||
|
||||
// parse Claims
|
||||
var claimBytes []byte
|
||||
token.Claims = claims
|
||||
|
||||
if claimBytes, err = DecodeSegment(parts[1]); err != nil {
|
||||
return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
|
||||
}
|
||||
dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
|
||||
if p.UseJSONNumber {
|
||||
dec.UseNumber()
|
||||
}
|
||||
// JSON Decode. Special case for map type to avoid weird pointer behavior
|
||||
if c, ok := token.Claims.(MapClaims); ok {
|
||||
err = dec.Decode(&c)
|
||||
} else {
|
||||
err = dec.Decode(&claims)
|
||||
}
|
||||
// Handle decode error
|
||||
if err != nil {
|
||||
return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
|
||||
}
|
||||
|
||||
// Lookup signature method
|
||||
if method, ok := token.Header["alg"].(string); ok {
|
||||
if token.Method = GetSigningMethod(method); token.Method == nil {
|
||||
return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
|
||||
}
|
||||
} else {
|
||||
return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
|
||||
}
|
||||
|
||||
return token, parts, nil
|
||||
}
|
||||
101
backend/vendor/github.com/dgrijalva/jwt-go/rsa.go
generated
vendored
101
backend/vendor/github.com/dgrijalva/jwt-go/rsa.go
generated
vendored
@@ -1,101 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
)
|
||||
|
||||
// Implements the RSA family of signing methods signing methods
|
||||
// Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation
|
||||
type SigningMethodRSA struct {
|
||||
Name string
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
// Specific instances for RS256 and company
|
||||
var (
|
||||
SigningMethodRS256 *SigningMethodRSA
|
||||
SigningMethodRS384 *SigningMethodRSA
|
||||
SigningMethodRS512 *SigningMethodRSA
|
||||
)
|
||||
|
||||
func init() {
|
||||
// RS256
|
||||
SigningMethodRS256 = &SigningMethodRSA{"RS256", crypto.SHA256}
|
||||
RegisterSigningMethod(SigningMethodRS256.Alg(), func() SigningMethod {
|
||||
return SigningMethodRS256
|
||||
})
|
||||
|
||||
// RS384
|
||||
SigningMethodRS384 = &SigningMethodRSA{"RS384", crypto.SHA384}
|
||||
RegisterSigningMethod(SigningMethodRS384.Alg(), func() SigningMethod {
|
||||
return SigningMethodRS384
|
||||
})
|
||||
|
||||
// RS512
|
||||
SigningMethodRS512 = &SigningMethodRSA{"RS512", crypto.SHA512}
|
||||
RegisterSigningMethod(SigningMethodRS512.Alg(), func() SigningMethod {
|
||||
return SigningMethodRS512
|
||||
})
|
||||
}
|
||||
|
||||
func (m *SigningMethodRSA) Alg() string {
|
||||
return m.Name
|
||||
}
|
||||
|
||||
// Implements the Verify method from SigningMethod
|
||||
// For this signing method, must be an *rsa.PublicKey structure.
|
||||
func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error {
|
||||
var err error
|
||||
|
||||
// Decode the signature
|
||||
var sig []byte
|
||||
if sig, err = DecodeSegment(signature); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var rsaKey *rsa.PublicKey
|
||||
var ok bool
|
||||
|
||||
if rsaKey, ok = key.(*rsa.PublicKey); !ok {
|
||||
return ErrInvalidKeyType
|
||||
}
|
||||
|
||||
// Create hasher
|
||||
if !m.Hash.Available() {
|
||||
return ErrHashUnavailable
|
||||
}
|
||||
hasher := m.Hash.New()
|
||||
hasher.Write([]byte(signingString))
|
||||
|
||||
// Verify the signature
|
||||
return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig)
|
||||
}
|
||||
|
||||
// Implements the Sign method from SigningMethod
|
||||
// For this signing method, must be an *rsa.PrivateKey structure.
|
||||
func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) {
|
||||
var rsaKey *rsa.PrivateKey
|
||||
var ok bool
|
||||
|
||||
// Validate type of key
|
||||
if rsaKey, ok = key.(*rsa.PrivateKey); !ok {
|
||||
return "", ErrInvalidKey
|
||||
}
|
||||
|
||||
// Create the hasher
|
||||
if !m.Hash.Available() {
|
||||
return "", ErrHashUnavailable
|
||||
}
|
||||
|
||||
hasher := m.Hash.New()
|
||||
hasher.Write([]byte(signingString))
|
||||
|
||||
// Sign the string and return the encoded bytes
|
||||
if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil {
|
||||
return EncodeSegment(sigBytes), nil
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
126
backend/vendor/github.com/dgrijalva/jwt-go/rsa_pss.go
generated
vendored
126
backend/vendor/github.com/dgrijalva/jwt-go/rsa_pss.go
generated
vendored
@@ -1,126 +0,0 @@
|
||||
// +build go1.4
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
)
|
||||
|
||||
// Implements the RSAPSS family of signing methods signing methods
|
||||
type SigningMethodRSAPSS struct {
|
||||
*SigningMethodRSA
|
||||
Options *rsa.PSSOptions
|
||||
}
|
||||
|
||||
// Specific instances for RS/PS and company
|
||||
var (
|
||||
SigningMethodPS256 *SigningMethodRSAPSS
|
||||
SigningMethodPS384 *SigningMethodRSAPSS
|
||||
SigningMethodPS512 *SigningMethodRSAPSS
|
||||
)
|
||||
|
||||
func init() {
|
||||
// PS256
|
||||
SigningMethodPS256 = &SigningMethodRSAPSS{
|
||||
&SigningMethodRSA{
|
||||
Name: "PS256",
|
||||
Hash: crypto.SHA256,
|
||||
},
|
||||
&rsa.PSSOptions{
|
||||
SaltLength: rsa.PSSSaltLengthAuto,
|
||||
Hash: crypto.SHA256,
|
||||
},
|
||||
}
|
||||
RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod {
|
||||
return SigningMethodPS256
|
||||
})
|
||||
|
||||
// PS384
|
||||
SigningMethodPS384 = &SigningMethodRSAPSS{
|
||||
&SigningMethodRSA{
|
||||
Name: "PS384",
|
||||
Hash: crypto.SHA384,
|
||||
},
|
||||
&rsa.PSSOptions{
|
||||
SaltLength: rsa.PSSSaltLengthAuto,
|
||||
Hash: crypto.SHA384,
|
||||
},
|
||||
}
|
||||
RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod {
|
||||
return SigningMethodPS384
|
||||
})
|
||||
|
||||
// PS512
|
||||
SigningMethodPS512 = &SigningMethodRSAPSS{
|
||||
&SigningMethodRSA{
|
||||
Name: "PS512",
|
||||
Hash: crypto.SHA512,
|
||||
},
|
||||
&rsa.PSSOptions{
|
||||
SaltLength: rsa.PSSSaltLengthAuto,
|
||||
Hash: crypto.SHA512,
|
||||
},
|
||||
}
|
||||
RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod {
|
||||
return SigningMethodPS512
|
||||
})
|
||||
}
|
||||
|
||||
// Implements the Verify method from SigningMethod
|
||||
// For this verify method, key must be an rsa.PublicKey struct
|
||||
func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error {
|
||||
var err error
|
||||
|
||||
// Decode the signature
|
||||
var sig []byte
|
||||
if sig, err = DecodeSegment(signature); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var rsaKey *rsa.PublicKey
|
||||
switch k := key.(type) {
|
||||
case *rsa.PublicKey:
|
||||
rsaKey = k
|
||||
default:
|
||||
return ErrInvalidKey
|
||||
}
|
||||
|
||||
// Create hasher
|
||||
if !m.Hash.Available() {
|
||||
return ErrHashUnavailable
|
||||
}
|
||||
hasher := m.Hash.New()
|
||||
hasher.Write([]byte(signingString))
|
||||
|
||||
return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, m.Options)
|
||||
}
|
||||
|
||||
// Implements the Sign method from SigningMethod
|
||||
// For this signing method, key must be an rsa.PrivateKey struct
|
||||
func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) {
|
||||
var rsaKey *rsa.PrivateKey
|
||||
|
||||
switch k := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
rsaKey = k
|
||||
default:
|
||||
return "", ErrInvalidKeyType
|
||||
}
|
||||
|
||||
// Create the hasher
|
||||
if !m.Hash.Available() {
|
||||
return "", ErrHashUnavailable
|
||||
}
|
||||
|
||||
hasher := m.Hash.New()
|
||||
hasher.Write([]byte(signingString))
|
||||
|
||||
// Sign the string and return the encoded bytes
|
||||
if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil {
|
||||
return EncodeSegment(sigBytes), nil
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
101
backend/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go
generated
vendored
101
backend/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go
generated
vendored
@@ -1,101 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key")
|
||||
ErrNotRSAPrivateKey = errors.New("Key is not a valid RSA private key")
|
||||
ErrNotRSAPublicKey = errors.New("Key is not a valid RSA public key")
|
||||
)
|
||||
|
||||
// Parse PEM encoded PKCS1 or PKCS8 private key
|
||||
func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
|
||||
var err error
|
||||
|
||||
// Parse PEM block
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(key); block == nil {
|
||||
return nil, ErrKeyMustBePEMEncoded
|
||||
}
|
||||
|
||||
var parsedKey interface{}
|
||||
if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
|
||||
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var pkey *rsa.PrivateKey
|
||||
var ok bool
|
||||
if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
|
||||
return nil, ErrNotRSAPrivateKey
|
||||
}
|
||||
|
||||
return pkey, nil
|
||||
}
|
||||
|
||||
// Parse PEM encoded PKCS1 or PKCS8 private key protected with password
|
||||
func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
|
||||
var err error
|
||||
|
||||
// Parse PEM block
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(key); block == nil {
|
||||
return nil, ErrKeyMustBePEMEncoded
|
||||
}
|
||||
|
||||
var parsedKey interface{}
|
||||
|
||||
var blockDecrypted []byte
|
||||
if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil {
|
||||
if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var pkey *rsa.PrivateKey
|
||||
var ok bool
|
||||
if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
|
||||
return nil, ErrNotRSAPrivateKey
|
||||
}
|
||||
|
||||
return pkey, nil
|
||||
}
|
||||
|
||||
// Parse PEM encoded PKCS1 or PKCS8 public key
|
||||
func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
|
||||
var err error
|
||||
|
||||
// Parse PEM block
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(key); block == nil {
|
||||
return nil, ErrKeyMustBePEMEncoded
|
||||
}
|
||||
|
||||
// Parse the key
|
||||
var parsedKey interface{}
|
||||
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
|
||||
if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
|
||||
parsedKey = cert.PublicKey
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var pkey *rsa.PublicKey
|
||||
var ok bool
|
||||
if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
|
||||
return nil, ErrNotRSAPublicKey
|
||||
}
|
||||
|
||||
return pkey, nil
|
||||
}
|
||||
35
backend/vendor/github.com/dgrijalva/jwt-go/signing_method.go
generated
vendored
35
backend/vendor/github.com/dgrijalva/jwt-go/signing_method.go
generated
vendored
@@ -1,35 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var signingMethods = map[string]func() SigningMethod{}
|
||||
var signingMethodLock = new(sync.RWMutex)
|
||||
|
||||
// Implement SigningMethod to add new methods for signing or verifying tokens.
|
||||
type SigningMethod interface {
|
||||
Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid
|
||||
Sign(signingString string, key interface{}) (string, error) // Returns encoded signature or error
|
||||
Alg() string // returns the alg identifier for this method (example: 'HS256')
|
||||
}
|
||||
|
||||
// Register the "alg" name and a factory function for signing method.
|
||||
// This is typically done during init() in the method's implementation
|
||||
func RegisterSigningMethod(alg string, f func() SigningMethod) {
|
||||
signingMethodLock.Lock()
|
||||
defer signingMethodLock.Unlock()
|
||||
|
||||
signingMethods[alg] = f
|
||||
}
|
||||
|
||||
// Get a signing method from an "alg" string
|
||||
func GetSigningMethod(alg string) (method SigningMethod) {
|
||||
signingMethodLock.RLock()
|
||||
defer signingMethodLock.RUnlock()
|
||||
|
||||
if methodF, ok := signingMethods[alg]; ok {
|
||||
method = methodF()
|
||||
}
|
||||
return
|
||||
}
|
||||
108
backend/vendor/github.com/dgrijalva/jwt-go/token.go
generated
vendored
108
backend/vendor/github.com/dgrijalva/jwt-go/token.go
generated
vendored
@@ -1,108 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time).
|
||||
// You can override it to use another time value. This is useful for testing or if your
|
||||
// server uses a different time zone than your tokens.
|
||||
var TimeFunc = time.Now
|
||||
|
||||
// Parse methods use this callback function to supply
|
||||
// the key for verification. The function receives the parsed,
|
||||
// but unverified Token. This allows you to use properties in the
|
||||
// Header of the token (such as `kid`) to identify which key to use.
|
||||
type Keyfunc func(*Token) (interface{}, error)
|
||||
|
||||
// A JWT Token. Different fields will be used depending on whether you're
|
||||
// creating or parsing/verifying a token.
|
||||
type Token struct {
|
||||
Raw string // The raw token. Populated when you Parse a token
|
||||
Method SigningMethod // The signing method used or to be used
|
||||
Header map[string]interface{} // The first segment of the token
|
||||
Claims Claims // The second segment of the token
|
||||
Signature string // The third segment of the token. Populated when you Parse a token
|
||||
Valid bool // Is the token valid? Populated when you Parse/Verify a token
|
||||
}
|
||||
|
||||
// Create a new Token. Takes a signing method
|
||||
func New(method SigningMethod) *Token {
|
||||
return NewWithClaims(method, MapClaims{})
|
||||
}
|
||||
|
||||
func NewWithClaims(method SigningMethod, claims Claims) *Token {
|
||||
return &Token{
|
||||
Header: map[string]interface{}{
|
||||
"typ": "JWT",
|
||||
"alg": method.Alg(),
|
||||
},
|
||||
Claims: claims,
|
||||
Method: method,
|
||||
}
|
||||
}
|
||||
|
||||
// Get the complete, signed token
|
||||
func (t *Token) SignedString(key interface{}) (string, error) {
|
||||
var sig, sstr string
|
||||
var err error
|
||||
if sstr, err = t.SigningString(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if sig, err = t.Method.Sign(sstr, key); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.Join([]string{sstr, sig}, "."), nil
|
||||
}
|
||||
|
||||
// Generate the signing string. This is the
|
||||
// most expensive part of the whole deal. Unless you
|
||||
// need this for something special, just go straight for
|
||||
// the SignedString.
|
||||
func (t *Token) SigningString() (string, error) {
|
||||
var err error
|
||||
parts := make([]string, 2)
|
||||
for i, _ := range parts {
|
||||
var jsonValue []byte
|
||||
if i == 0 {
|
||||
if jsonValue, err = json.Marshal(t.Header); err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
if jsonValue, err = json.Marshal(t.Claims); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
parts[i] = EncodeSegment(jsonValue)
|
||||
}
|
||||
return strings.Join(parts, "."), nil
|
||||
}
|
||||
|
||||
// Parse, validate, and return a token.
|
||||
// keyFunc will receive the parsed token and should return the key for validating.
|
||||
// If everything is kosher, err will be nil
|
||||
func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
|
||||
return new(Parser).Parse(tokenString, keyFunc)
|
||||
}
|
||||
|
||||
func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
|
||||
return new(Parser).ParseWithClaims(tokenString, claims, keyFunc)
|
||||
}
|
||||
|
||||
// Encode JWT specific base64url encoding with padding stripped
|
||||
func EncodeSegment(seg []byte) string {
|
||||
return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
|
||||
}
|
||||
|
||||
// Decode JWT specific base64url encoding with padding stripped
|
||||
func DecodeSegment(seg string) ([]byte, error) {
|
||||
if l := len(seg) % 4; l > 0 {
|
||||
seg += strings.Repeat("=", 4-l)
|
||||
}
|
||||
|
||||
return base64.URLEncoding.DecodeString(seg)
|
||||
}
|
||||
5
backend/vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
5
backend/vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
@@ -1,5 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
6
backend/vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
6
backend/vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
@@ -1,6 +0,0 @@
|
||||
# Setup a Global .gitignore for OS and editor generated files:
|
||||
# https://help.github.com/articles/ignoring-files
|
||||
# git config --global core.excludesfile ~/.gitignore_global
|
||||
|
||||
.vagrant
|
||||
*.sublime-project
|
||||
30
backend/vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
30
backend/vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
@@ -1,30 +0,0 @@
|
||||
sudo: false
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
fast_finish: true
|
||||
|
||||
before_script:
|
||||
- go get -u github.com/golang/lint/golint
|
||||
|
||||
script:
|
||||
- go test -v --race ./...
|
||||
|
||||
after_script:
|
||||
- test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
|
||||
- test -z "$(golint ./... | tee /dev/stderr)"
|
||||
- go vet ./...
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
52
backend/vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
52
backend/vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
@@ -1,52 +0,0 @@
|
||||
# Names should be added to this file as
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
# You can update this list using the following command:
|
||||
#
|
||||
# $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Aaron L <aaron@bettercoder.net>
|
||||
Adrien Bustany <adrien@bustany.org>
|
||||
Amit Krishnan <amit.krishnan@oracle.com>
|
||||
Anmol Sethi <me@anmol.io>
|
||||
Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
|
||||
Bruno Bigras <bigras.bruno@gmail.com>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Case Nelson <case@teammating.com>
|
||||
Chris Howey <chris@howey.me> <howeyc@gmail.com>
|
||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||
Daniel Wagner-Hall <dawagner@gmail.com>
|
||||
Dave Cheney <dave@cheney.net>
|
||||
Evan Phoenix <evan@fallingsnow.net>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Hari haran <hariharan.uno@gmail.com>
|
||||
John C Barstow
|
||||
Kelvin Fo <vmirage@gmail.com>
|
||||
Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
|
||||
Matt Layher <mdlayher@gmail.com>
|
||||
Nathan Youngman <git@nathany.com>
|
||||
Nickolai Zeldovich <nickolai@csail.mit.edu>
|
||||
Patrick <patrick@dropbox.com>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Pawel Knap <pawelknap88@gmail.com>
|
||||
Pieter Droogendijk <pieter@binky.org.uk>
|
||||
Pursuit92 <JoshChase@techpursuit.net>
|
||||
Riku Voipio <riku.voipio@linaro.org>
|
||||
Rob Figueiredo <robfig@gmail.com>
|
||||
Rodrigo Chiossi <rodrigochiossi@gmail.com>
|
||||
Slawek Ligus <root@ooz.ie>
|
||||
Soge Zhang <zhssoge@gmail.com>
|
||||
Tiffany Jernigan <tiffany.jernigan@intel.com>
|
||||
Tilak Sharma <tilaks@google.com>
|
||||
Tom Payne <twpayne@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Vahe Khachikyan <vahe@live.ca>
|
||||
Yukang <moorekang@gmail.com>
|
||||
bronze1man <bronze1man@gmail.com>
|
||||
debrando <denis.brandolini@gmail.com>
|
||||
henrikedwards <henrik.edwards@gmail.com>
|
||||
铁哥 <guotie.9@gmail.com>
|
||||
317
backend/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
317
backend/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
@@ -1,317 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## v1.4.7 / 2018-01-09
|
||||
|
||||
* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
|
||||
* Tests: Fix missing verb on format string (thanks @rchiossi)
|
||||
* Linux: Fix deadlock in Remove (thanks @aarondl)
|
||||
* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne)
|
||||
* Docs: Moved FAQ into the README (thanks @vahe)
|
||||
* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich)
|
||||
* Docs: replace references to OS X with macOS
|
||||
|
||||
## v1.4.2 / 2016-10-10
|
||||
|
||||
* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack)
|
||||
|
||||
## v1.4.1 / 2016-10-04
|
||||
|
||||
* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack)
|
||||
|
||||
## v1.4.0 / 2016-10-01
|
||||
|
||||
* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie)
|
||||
|
||||
## v1.3.1 / 2016-06-28
|
||||
|
||||
* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc)
|
||||
|
||||
## v1.3.0 / 2016-04-19
|
||||
|
||||
* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135)
|
||||
|
||||
## v1.2.10 / 2016-03-02
|
||||
|
||||
* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj)
|
||||
|
||||
## v1.2.9 / 2016-01-13
|
||||
|
||||
kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep)
|
||||
|
||||
## v1.2.8 / 2015-12-17
|
||||
|
||||
* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test)
|
||||
* inotify: fix race in test
|
||||
* enable race detection for continuous integration (Linux, Mac, Windows)
|
||||
|
||||
## v1.2.5 / 2015-10-17
|
||||
|
||||
* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki)
|
||||
* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken)
|
||||
* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie)
|
||||
* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion)
|
||||
|
||||
## v1.2.1 / 2015-10-14
|
||||
|
||||
* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx)
|
||||
|
||||
## v1.2.0 / 2015-02-08
|
||||
|
||||
* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD)
|
||||
* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD)
|
||||
* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59)
|
||||
|
||||
## v1.1.1 / 2015-02-05
|
||||
|
||||
* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD)
|
||||
|
||||
## v1.1.0 / 2014-12-12
|
||||
|
||||
* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43)
|
||||
* add low-level functions
|
||||
* only need to store flags on directories
|
||||
* less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13)
|
||||
* done can be an unbuffered channel
|
||||
* remove calls to os.NewSyscallError
|
||||
* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher)
|
||||
* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48)
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v1.0.4 / 2014-09-07
|
||||
|
||||
* kqueue: add dragonfly to the build tags.
|
||||
* Rename source code files, rearrange code so exported APIs are at the top.
|
||||
* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang)
|
||||
|
||||
## v1.0.3 / 2014-08-19
|
||||
|
||||
* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36)
|
||||
|
||||
## v1.0.2 / 2014-08-17
|
||||
|
||||
* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||
* [Fix] Make ./path and path equivalent. (thanks @zhsso)
|
||||
|
||||
## v1.0.0 / 2014-08-15
|
||||
|
||||
* [API] Remove AddWatch on Windows, use Add.
|
||||
* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30)
|
||||
* Minor updates based on feedback from golint.
|
||||
|
||||
## dev / 2014-07-09
|
||||
|
||||
* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify).
|
||||
* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno)
|
||||
|
||||
## dev / 2014-07-04
|
||||
|
||||
* kqueue: fix incorrect mutex used in Close()
|
||||
* Update example to demonstrate usage of Op.
|
||||
|
||||
## dev / 2014-06-28
|
||||
|
||||
* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4)
|
||||
* Fix for String() method on Event (thanks Alex Brainman)
|
||||
* Don't build on Plan 9 or Solaris (thanks @4ad)
|
||||
|
||||
## dev / 2014-06-21
|
||||
|
||||
* Events channel of type Event rather than *Event.
|
||||
* [internal] use syscall constants directly for inotify and kqueue.
|
||||
* [internal] kqueue: rename events to kevents and fileEvent to event.
|
||||
|
||||
## dev / 2014-06-19
|
||||
|
||||
* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally).
|
||||
* [internal] remove cookie from Event struct (unused).
|
||||
* [internal] Event struct has the same definition across every OS.
|
||||
* [internal] remove internal watch and removeWatch methods.
|
||||
|
||||
## dev / 2014-06-12
|
||||
|
||||
* [API] Renamed Watch() to Add() and RemoveWatch() to Remove().
|
||||
* [API] Pluralized channel names: Events and Errors.
|
||||
* [API] Renamed FileEvent struct to Event.
|
||||
* [API] Op constants replace methods like IsCreate().
|
||||
|
||||
## dev / 2014-06-12
|
||||
|
||||
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||
|
||||
## dev / 2014-05-23
|
||||
|
||||
* [API] Remove current implementation of WatchFlags.
|
||||
* current implementation doesn't take advantage of OS for efficiency
|
||||
* provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes
|
||||
* no tests for the current implementation
|
||||
* not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
|
||||
|
||||
## v0.9.3 / 2014-12-31
|
||||
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v0.9.2 / 2014-08-17
|
||||
|
||||
* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||
|
||||
## v0.9.1 / 2014-06-12
|
||||
|
||||
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||
|
||||
## v0.9.0 / 2014-01-17
|
||||
|
||||
* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
|
||||
* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
|
||||
* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
|
||||
|
||||
## v0.8.12 / 2013-11-13
|
||||
|
||||
* [API] Remove FD_SET and friends from Linux adapter
|
||||
|
||||
## v0.8.11 / 2013-11-02
|
||||
|
||||
* [Doc] Add Changelog [#72][] (thanks @nathany)
|
||||
* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond)
|
||||
|
||||
## v0.8.10 / 2013-10-19
|
||||
|
||||
* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
|
||||
* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
|
||||
* [Doc] specify OS-specific limits in README (thanks @debrando)
|
||||
|
||||
## v0.8.9 / 2013-09-08
|
||||
|
||||
* [Doc] Contributing (thanks @nathany)
|
||||
* [Doc] update package path in example code [#63][] (thanks @paulhammond)
|
||||
* [Doc] GoCI badge in README (Linux only) [#60][]
|
||||
* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
|
||||
|
||||
## v0.8.8 / 2013-06-17
|
||||
|
||||
* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
|
||||
|
||||
## v0.8.7 / 2013-06-03
|
||||
|
||||
* [API] Make syscall flags internal
|
||||
* [Fix] inotify: ignore event changes
|
||||
* [Fix] race in symlink test [#45][] (reported by @srid)
|
||||
* [Fix] tests on Windows
|
||||
* lower case error messages
|
||||
|
||||
## v0.8.6 / 2013-05-23
|
||||
|
||||
* kqueue: Use EVT_ONLY flag on Darwin
|
||||
* [Doc] Update README with full example
|
||||
|
||||
## v0.8.5 / 2013-05-09
|
||||
|
||||
* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
|
||||
|
||||
## v0.8.4 / 2013-04-07
|
||||
|
||||
* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
|
||||
|
||||
## v0.8.3 / 2013-03-13
|
||||
|
||||
* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
|
||||
* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
|
||||
|
||||
## v0.8.2 / 2013-02-07
|
||||
|
||||
* [Doc] add Authors
|
||||
* [Fix] fix data races for map access [#29][] (thanks @fsouza)
|
||||
|
||||
## v0.8.1 / 2013-01-09
|
||||
|
||||
* [Fix] Windows path separators
|
||||
* [Doc] BSD License
|
||||
|
||||
## v0.8.0 / 2012-11-09
|
||||
|
||||
* kqueue: directory watching improvements (thanks @vmirage)
|
||||
* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
|
||||
* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
|
||||
|
||||
## v0.7.4 / 2012-10-09
|
||||
|
||||
* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
|
||||
* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
|
||||
* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
|
||||
* [Fix] kqueue: modify after recreation of file
|
||||
|
||||
## v0.7.3 / 2012-09-27
|
||||
|
||||
* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
|
||||
* [Fix] kqueue: no longer get duplicate CREATE events
|
||||
|
||||
## v0.7.2 / 2012-09-01
|
||||
|
||||
* kqueue: events for created directories
|
||||
|
||||
## v0.7.1 / 2012-07-14
|
||||
|
||||
* [Fix] for renaming files
|
||||
|
||||
## v0.7.0 / 2012-07-02
|
||||
|
||||
* [Feature] FSNotify flags
|
||||
* [Fix] inotify: Added file name back to event path
|
||||
|
||||
## v0.6.0 / 2012-06-06
|
||||
|
||||
* kqueue: watch files after directory created (thanks @tmc)
|
||||
|
||||
## v0.5.1 / 2012-05-22
|
||||
|
||||
* [Fix] inotify: remove all watches before Close()
|
||||
|
||||
## v0.5.0 / 2012-05-03
|
||||
|
||||
* [API] kqueue: return errors during watch instead of sending over channel
|
||||
* kqueue: match symlink behavior on Linux
|
||||
* inotify: add `DELETE_SELF` (requested by @taralx)
|
||||
* [Fix] kqueue: handle EINTR (reported by @robfig)
|
||||
* [Doc] Godoc example [#1][] (thanks @davecheney)
|
||||
|
||||
## v0.4.0 / 2012-03-30
|
||||
|
||||
* Go 1 released: build with go tool
|
||||
* [Feature] Windows support using winfsnotify
|
||||
* Windows does not have attribute change notifications
|
||||
* Roll attribute notifications into IsModify
|
||||
|
||||
## v0.3.0 / 2012-02-19
|
||||
|
||||
* kqueue: add files when watch directory
|
||||
|
||||
## v0.2.0 / 2011-12-30
|
||||
|
||||
* update to latest Go weekly code
|
||||
|
||||
## v0.1.0 / 2011-10-19
|
||||
|
||||
* kqueue: add watch on file creation to match inotify
|
||||
* kqueue: create file event
|
||||
* inotify: ignore `IN_IGNORED` events
|
||||
* event String()
|
||||
* linux: common FileEvent functions
|
||||
* initial commit
|
||||
|
||||
[#79]: https://github.com/howeyc/fsnotify/pull/79
|
||||
[#77]: https://github.com/howeyc/fsnotify/pull/77
|
||||
[#72]: https://github.com/howeyc/fsnotify/issues/72
|
||||
[#71]: https://github.com/howeyc/fsnotify/issues/71
|
||||
[#70]: https://github.com/howeyc/fsnotify/issues/70
|
||||
[#63]: https://github.com/howeyc/fsnotify/issues/63
|
||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||
[#60]: https://github.com/howeyc/fsnotify/issues/60
|
||||
[#59]: https://github.com/howeyc/fsnotify/issues/59
|
||||
[#49]: https://github.com/howeyc/fsnotify/issues/49
|
||||
[#45]: https://github.com/howeyc/fsnotify/issues/45
|
||||
[#40]: https://github.com/howeyc/fsnotify/issues/40
|
||||
[#36]: https://github.com/howeyc/fsnotify/issues/36
|
||||
[#33]: https://github.com/howeyc/fsnotify/issues/33
|
||||
[#29]: https://github.com/howeyc/fsnotify/issues/29
|
||||
[#25]: https://github.com/howeyc/fsnotify/issues/25
|
||||
[#24]: https://github.com/howeyc/fsnotify/issues/24
|
||||
[#21]: https://github.com/howeyc/fsnotify/issues/21
|
||||
77
backend/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
77
backend/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
@@ -1,77 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
## Issues
|
||||
|
||||
* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues).
|
||||
* Please indicate the platform you are using fsnotify on.
|
||||
* A code example to reproduce the problem is appreciated.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
### Contributor License Agreement
|
||||
|
||||
fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
|
||||
|
||||
Please indicate that you have signed the CLA in your pull request.
|
||||
|
||||
### How fsnotify is Developed
|
||||
|
||||
* Development is done on feature branches.
|
||||
* Tests are run on BSD, Linux, macOS and Windows.
|
||||
* Pull requests are reviewed and [applied to master][am] using [hub][].
|
||||
* Maintainers may modify or squash commits rather than asking contributors to.
|
||||
* To issue a new release, the maintainers will:
|
||||
* Update the CHANGELOG
|
||||
* Tag a version, which will become available through gopkg.in.
|
||||
|
||||
### How to Fork
|
||||
|
||||
For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
|
||||
|
||||
1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`)
|
||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
3. Ensure everything works and the tests pass (see below)
|
||||
4. Commit your changes (`git commit -am 'Add some feature'`)
|
||||
|
||||
Contribute upstream:
|
||||
|
||||
1. Fork fsnotify on GitHub
|
||||
2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
|
||||
3. Push to the branch (`git push fork my-new-feature`)
|
||||
4. Create a new Pull Request on GitHub
|
||||
|
||||
This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/).
|
||||
|
||||
### Testing
|
||||
|
||||
fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows.
|
||||
|
||||
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
|
||||
|
||||
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
|
||||
|
||||
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
|
||||
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
|
||||
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
|
||||
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
|
||||
* When you're done, you will want to halt or destroy the Vagrant boxes.
|
||||
|
||||
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
|
||||
|
||||
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
|
||||
|
||||
### Maintainers
|
||||
|
||||
Help maintaining fsnotify is welcome. To be a maintainer:
|
||||
|
||||
* Submit a pull request and sign the CLA as above.
|
||||
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
|
||||
|
||||
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
|
||||
|
||||
All code changes should be internal pull requests.
|
||||
|
||||
Releases are tagged using [Semantic Versioning](http://semver.org/).
|
||||
|
||||
[hub]: https://github.com/github/hub
|
||||
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
|
||||
28
backend/vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
28
backend/vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
@@ -1,28 +0,0 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2012 fsnotify Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
79
backend/vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
79
backend/vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
@@ -1,79 +0,0 @@
|
||||
# File system notifications for Go
|
||||
|
||||
[](https://godoc.org/github.com/fsnotify/fsnotify) [](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
|
||||
|
||||
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
|
||||
|
||||
```console
|
||||
go get -u golang.org/x/sys/...
|
||||
```
|
||||
|
||||
Cross platform: Windows, Linux, BSD and macOS.
|
||||
|
||||
|Adapter |OS |Status |
|
||||
|----------|----------|----------|
|
||||
|inotify |Linux 2.6.27 or later, Android\*|Supported [](https://travis-ci.org/fsnotify/fsnotify)|
|
||||
|kqueue |BSD, macOS, iOS\*|Supported [](https://travis-ci.org/fsnotify/fsnotify)|
|
||||
|ReadDirectoryChangesW|Windows|Supported [](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
|
||||
|FSEvents |macOS |[Planned](https://github.com/fsnotify/fsnotify/issues/11)|
|
||||
|FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)|
|
||||
|fanotify |Linux 2.6.37+ | |
|
||||
|USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)|
|
||||
|Polling |*All* |[Maybe](https://github.com/fsnotify/fsnotify/issues/9)|
|
||||
|
||||
\* Android and iOS are untested.
|
||||
|
||||
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
|
||||
|
||||
## API stability
|
||||
|
||||
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
|
||||
|
||||
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
|
||||
|
||||
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
||||
|
||||
## Example
|
||||
|
||||
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
|
||||
|
||||
## FAQ
|
||||
|
||||
**When a file is moved to another directory is it still being watched?**
|
||||
|
||||
No (it shouldn't be, unless you are watching where it was moved to).
|
||||
|
||||
**When I watch a directory, are all subdirectories watched as well?**
|
||||
|
||||
No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]).
|
||||
|
||||
**Do I have to watch the Error and Event channels in a separate goroutine?**
|
||||
|
||||
As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7])
|
||||
|
||||
**Why am I receiving multiple events for the same file on OS X?**
|
||||
|
||||
Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]).
|
||||
|
||||
**How many files can be watched at once?**
|
||||
|
||||
There are OS-specific limits as to how many watches can be created:
|
||||
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
|
||||
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
|
||||
|
||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||
[#18]: https://github.com/fsnotify/fsnotify/issues/18
|
||||
[#11]: https://github.com/fsnotify/fsnotify/issues/11
|
||||
[#7]: https://github.com/howeyc/fsnotify/issues/7
|
||||
|
||||
[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md
|
||||
|
||||
## Related Projects
|
||||
|
||||
* [notify](https://github.com/rjeczalik/notify)
|
||||
* [fsevents](https://github.com/fsnotify/fsevents)
|
||||
|
||||
37
backend/vendor/github.com/fsnotify/fsnotify/fen.go
generated
vendored
37
backend/vendor/github.com/fsnotify/fsnotify/fen.go
generated
vendored
@@ -1,37 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build solaris
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct {
|
||||
Events chan Event
|
||||
Errors chan error
|
||||
}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
return nil, errors.New("FEN based watcher not yet supported for fsnotify\n")
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove stops watching the the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
return nil
|
||||
}
|
||||
66
backend/vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
66
backend/vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
@@ -1,66 +0,0 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !plan9
|
||||
|
||||
// Package fsnotify provides a platform-independent interface for file system notifications.
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Event represents a single file system notification.
|
||||
type Event struct {
|
||||
Name string // Relative path to the file or directory.
|
||||
Op Op // File operation that triggered the event.
|
||||
}
|
||||
|
||||
// Op describes a set of file operations.
|
||||
type Op uint32
|
||||
|
||||
// These are the generalized file operations that can trigger a notification.
|
||||
const (
|
||||
Create Op = 1 << iota
|
||||
Write
|
||||
Remove
|
||||
Rename
|
||||
Chmod
|
||||
)
|
||||
|
||||
func (op Op) String() string {
|
||||
// Use a buffer for efficient string concatenation
|
||||
var buffer bytes.Buffer
|
||||
|
||||
if op&Create == Create {
|
||||
buffer.WriteString("|CREATE")
|
||||
}
|
||||
if op&Remove == Remove {
|
||||
buffer.WriteString("|REMOVE")
|
||||
}
|
||||
if op&Write == Write {
|
||||
buffer.WriteString("|WRITE")
|
||||
}
|
||||
if op&Rename == Rename {
|
||||
buffer.WriteString("|RENAME")
|
||||
}
|
||||
if op&Chmod == Chmod {
|
||||
buffer.WriteString("|CHMOD")
|
||||
}
|
||||
if buffer.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
return buffer.String()[1:] // Strip leading pipe
|
||||
}
|
||||
|
||||
// String returns a string representation of the event in the form
|
||||
// "file: REMOVE|WRITE|..."
|
||||
func (e Event) String() string {
|
||||
return fmt.Sprintf("%q: %s", e.Name, e.Op.String())
|
||||
}
|
||||
|
||||
// Common errors that can be reported by a watcher
|
||||
var ErrEventOverflow = errors.New("fsnotify queue overflow")
|
||||
337
backend/vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
337
backend/vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
@@ -1,337 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct {
|
||||
Events chan Event
|
||||
Errors chan error
|
||||
mu sync.Mutex // Map access
|
||||
fd int
|
||||
poller *fdPoller
|
||||
watches map[string]*watch // Map of inotify watches (key: path)
|
||||
paths map[int]string // Map of watched paths (key: watch descriptor)
|
||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||
doneResp chan struct{} // Channel to respond to Close
|
||||
}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
// Create inotify fd
|
||||
fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC)
|
||||
if fd == -1 {
|
||||
return nil, errno
|
||||
}
|
||||
// Create epoll
|
||||
poller, err := newFdPoller(fd)
|
||||
if err != nil {
|
||||
unix.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
w := &Watcher{
|
||||
fd: fd,
|
||||
poller: poller,
|
||||
watches: make(map[string]*watch),
|
||||
paths: make(map[int]string),
|
||||
Events: make(chan Event),
|
||||
Errors: make(chan error),
|
||||
done: make(chan struct{}),
|
||||
doneResp: make(chan struct{}),
|
||||
}
|
||||
|
||||
go w.readEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (w *Watcher) isClosed() bool {
|
||||
select {
|
||||
case <-w.done:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Send 'close' signal to goroutine, and set the Watcher to closed.
|
||||
close(w.done)
|
||||
|
||||
// Wake up goroutine
|
||||
w.poller.wake()
|
||||
|
||||
// Wait for goroutine to close
|
||||
<-w.doneResp
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
name = filepath.Clean(name)
|
||||
if w.isClosed() {
|
||||
return errors.New("inotify instance already closed")
|
||||
}
|
||||
|
||||
const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
|
||||
unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
|
||||
unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
|
||||
|
||||
var flags uint32 = agnosticEvents
|
||||
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
watchEntry := w.watches[name]
|
||||
if watchEntry != nil {
|
||||
flags |= watchEntry.flags | unix.IN_MASK_ADD
|
||||
}
|
||||
wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
|
||||
if wd == -1 {
|
||||
return errno
|
||||
}
|
||||
|
||||
if watchEntry == nil {
|
||||
w.watches[name] = &watch{wd: uint32(wd), flags: flags}
|
||||
w.paths[wd] = name
|
||||
} else {
|
||||
watchEntry.wd = uint32(wd)
|
||||
watchEntry.flags = flags
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove stops watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
name = filepath.Clean(name)
|
||||
|
||||
// Fetch the watch.
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
watch, ok := w.watches[name]
|
||||
|
||||
// Remove it from inotify.
|
||||
if !ok {
|
||||
return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
|
||||
}
|
||||
|
||||
// We successfully removed the watch if InotifyRmWatch doesn't return an
|
||||
// error, we need to clean up our internal state to ensure it matches
|
||||
// inotify's kernel state.
|
||||
delete(w.paths, int(watch.wd))
|
||||
delete(w.watches, name)
|
||||
|
||||
// inotify_rm_watch will return EINVAL if the file has been deleted;
|
||||
// the inotify will already have been removed.
|
||||
// watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
|
||||
// by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE
|
||||
// so that EINVAL means that the wd is being rm_watch()ed or its file removed
|
||||
// by another thread and we have not received IN_IGNORE event.
|
||||
success, errno := unix.InotifyRmWatch(w.fd, watch.wd)
|
||||
if success == -1 {
|
||||
// TODO: Perhaps it's not helpful to return an error here in every case.
|
||||
// the only two possible errors are:
|
||||
// EBADF, which happens when w.fd is not a valid file descriptor of any kind.
|
||||
// EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
|
||||
// Watch descriptors are invalidated when they are removed explicitly or implicitly;
|
||||
// explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
|
||||
return errno
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||
}
|
||||
|
||||
// readEvents reads from the inotify file descriptor, converts the
|
||||
// received events into Event objects and sends them via the Events channel
|
||||
func (w *Watcher) readEvents() {
|
||||
var (
|
||||
buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
|
||||
n int // Number of bytes read with read()
|
||||
errno error // Syscall errno
|
||||
ok bool // For poller.wait
|
||||
)
|
||||
|
||||
defer close(w.doneResp)
|
||||
defer close(w.Errors)
|
||||
defer close(w.Events)
|
||||
defer unix.Close(w.fd)
|
||||
defer w.poller.close()
|
||||
|
||||
for {
|
||||
// See if we have been closed.
|
||||
if w.isClosed() {
|
||||
return
|
||||
}
|
||||
|
||||
ok, errno = w.poller.wait()
|
||||
if errno != nil {
|
||||
select {
|
||||
case w.Errors <- errno:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
n, errno = unix.Read(w.fd, buf[:])
|
||||
// If a signal interrupted execution, see if we've been asked to close, and try again.
|
||||
// http://man7.org/linux/man-pages/man7/signal.7.html :
|
||||
// "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
|
||||
if errno == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
|
||||
// unix.Read might have been woken up by Close. If so, we're done.
|
||||
if w.isClosed() {
|
||||
return
|
||||
}
|
||||
|
||||
if n < unix.SizeofInotifyEvent {
|
||||
var err error
|
||||
if n == 0 {
|
||||
// If EOF is received. This should really never happen.
|
||||
err = io.EOF
|
||||
} else if n < 0 {
|
||||
// If an error occurred while reading.
|
||||
err = errno
|
||||
} else {
|
||||
// Read was too short.
|
||||
err = errors.New("notify: short read in readEvents()")
|
||||
}
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var offset uint32
|
||||
// We don't know how many events we just read into the buffer
|
||||
// While the offset points to at least one whole event...
|
||||
for offset <= uint32(n-unix.SizeofInotifyEvent) {
|
||||
// Point "raw" to the event in the buffer
|
||||
raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
|
||||
|
||||
mask := uint32(raw.Mask)
|
||||
nameLen := uint32(raw.Len)
|
||||
|
||||
if mask&unix.IN_Q_OVERFLOW != 0 {
|
||||
select {
|
||||
case w.Errors <- ErrEventOverflow:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// If the event happened to the watched directory or the watched file, the kernel
|
||||
// doesn't append the filename to the event, but we would like to always fill the
|
||||
// the "Name" field with a valid filename. We retrieve the path of the watch from
|
||||
// the "paths" map.
|
||||
w.mu.Lock()
|
||||
name, ok := w.paths[int(raw.Wd)]
|
||||
// IN_DELETE_SELF occurs when the file/directory being watched is removed.
|
||||
// This is a sign to clean up the maps, otherwise we are no longer in sync
|
||||
// with the inotify kernel state which has already deleted the watch
|
||||
// automatically.
|
||||
if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
|
||||
delete(w.paths, int(raw.Wd))
|
||||
delete(w.watches, name)
|
||||
}
|
||||
w.mu.Unlock()
|
||||
|
||||
if nameLen > 0 {
|
||||
// Point "bytes" at the first byte of the filename
|
||||
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))
|
||||
// The filename is padded with NULL bytes. TrimRight() gets rid of those.
|
||||
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
|
||||
}
|
||||
|
||||
event := newEvent(name, mask)
|
||||
|
||||
// Send the events that are not ignored on the events channel
|
||||
if !event.ignoreLinux(mask) {
|
||||
select {
|
||||
case w.Events <- event:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Move to the next event in the buffer
|
||||
offset += unix.SizeofInotifyEvent + nameLen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Certain types of events can be "ignored" and not sent over the Events
|
||||
// channel. Such as events marked ignore by the kernel, or MODIFY events
|
||||
// against files that do not exist.
|
||||
func (e *Event) ignoreLinux(mask uint32) bool {
|
||||
// Ignore anything the inotify API says to ignore
|
||||
if mask&unix.IN_IGNORED == unix.IN_IGNORED {
|
||||
return true
|
||||
}
|
||||
|
||||
// If the event is not a DELETE or RENAME, the file must exist.
|
||||
// Otherwise the event is ignored.
|
||||
// *Note*: this was put in place because it was seen that a MODIFY
|
||||
// event was sent after the DELETE. This ignores that MODIFY and
|
||||
// assumes a DELETE will come or has come if the file doesn't exist.
|
||||
if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
|
||||
_, statErr := os.Lstat(e.Name)
|
||||
return os.IsNotExist(statErr)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// newEvent returns an platform-independent Event based on an inotify mask.
|
||||
func newEvent(name string, mask uint32) Event {
|
||||
e := Event{Name: name}
|
||||
if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
||||
e.Op |= Create
|
||||
}
|
||||
if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE {
|
||||
e.Op |= Remove
|
||||
}
|
||||
if mask&unix.IN_MODIFY == unix.IN_MODIFY {
|
||||
e.Op |= Write
|
||||
}
|
||||
if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
||||
e.Op |= Rename
|
||||
}
|
||||
if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
|
||||
e.Op |= Chmod
|
||||
}
|
||||
return e
|
||||
}
|
||||
187
backend/vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
187
backend/vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
@@ -1,187 +0,0 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type fdPoller struct {
|
||||
fd int // File descriptor (as returned by the inotify_init() syscall)
|
||||
epfd int // Epoll file descriptor
|
||||
pipe [2]int // Pipe for waking up
|
||||
}
|
||||
|
||||
func emptyPoller(fd int) *fdPoller {
|
||||
poller := new(fdPoller)
|
||||
poller.fd = fd
|
||||
poller.epfd = -1
|
||||
poller.pipe[0] = -1
|
||||
poller.pipe[1] = -1
|
||||
return poller
|
||||
}
|
||||
|
||||
// Create a new inotify poller.
|
||||
// This creates an inotify handler, and an epoll handler.
|
||||
func newFdPoller(fd int) (*fdPoller, error) {
|
||||
var errno error
|
||||
poller := emptyPoller(fd)
|
||||
defer func() {
|
||||
if errno != nil {
|
||||
poller.close()
|
||||
}
|
||||
}()
|
||||
poller.fd = fd
|
||||
|
||||
// Create epoll fd
|
||||
poller.epfd, errno = unix.EpollCreate1(0)
|
||||
if poller.epfd == -1 {
|
||||
return nil, errno
|
||||
}
|
||||
// Create pipe; pipe[0] is the read end, pipe[1] the write end.
|
||||
errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK)
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
// Register inotify fd with epoll
|
||||
event := unix.EpollEvent{
|
||||
Fd: int32(poller.fd),
|
||||
Events: unix.EPOLLIN,
|
||||
}
|
||||
errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event)
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
// Register pipe fd with epoll
|
||||
event = unix.EpollEvent{
|
||||
Fd: int32(poller.pipe[0]),
|
||||
Events: unix.EPOLLIN,
|
||||
}
|
||||
errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event)
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
return poller, nil
|
||||
}
|
||||
|
||||
// Wait using epoll.
|
||||
// Returns true if something is ready to be read,
|
||||
// false if there is not.
|
||||
func (poller *fdPoller) wait() (bool, error) {
|
||||
// 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
|
||||
// I don't know whether epoll_wait returns the number of events returned,
|
||||
// or the total number of events ready.
|
||||
// I decided to catch both by making the buffer one larger than the maximum.
|
||||
events := make([]unix.EpollEvent, 7)
|
||||
for {
|
||||
n, errno := unix.EpollWait(poller.epfd, events, -1)
|
||||
if n == -1 {
|
||||
if errno == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
return false, errno
|
||||
}
|
||||
if n == 0 {
|
||||
// If there are no events, try again.
|
||||
continue
|
||||
}
|
||||
if n > 6 {
|
||||
// This should never happen. More events were returned than should be possible.
|
||||
return false, errors.New("epoll_wait returned more events than I know what to do with")
|
||||
}
|
||||
ready := events[:n]
|
||||
epollhup := false
|
||||
epollerr := false
|
||||
epollin := false
|
||||
for _, event := range ready {
|
||||
if event.Fd == int32(poller.fd) {
|
||||
if event.Events&unix.EPOLLHUP != 0 {
|
||||
// This should not happen, but if it does, treat it as a wakeup.
|
||||
epollhup = true
|
||||
}
|
||||
if event.Events&unix.EPOLLERR != 0 {
|
||||
// If an error is waiting on the file descriptor, we should pretend
|
||||
// something is ready to read, and let unix.Read pick up the error.
|
||||
epollerr = true
|
||||
}
|
||||
if event.Events&unix.EPOLLIN != 0 {
|
||||
// There is data to read.
|
||||
epollin = true
|
||||
}
|
||||
}
|
||||
if event.Fd == int32(poller.pipe[0]) {
|
||||
if event.Events&unix.EPOLLHUP != 0 {
|
||||
// Write pipe descriptor was closed, by us. This means we're closing down the
|
||||
// watcher, and we should wake up.
|
||||
}
|
||||
if event.Events&unix.EPOLLERR != 0 {
|
||||
// If an error is waiting on the pipe file descriptor.
|
||||
// This is an absolute mystery, and should never ever happen.
|
||||
return false, errors.New("Error on the pipe descriptor.")
|
||||
}
|
||||
if event.Events&unix.EPOLLIN != 0 {
|
||||
// This is a regular wakeup, so we have to clear the buffer.
|
||||
err := poller.clearWake()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if epollhup || epollerr || epollin {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Close the write end of the poller.
|
||||
func (poller *fdPoller) wake() error {
|
||||
buf := make([]byte, 1)
|
||||
n, errno := unix.Write(poller.pipe[1], buf)
|
||||
if n == -1 {
|
||||
if errno == unix.EAGAIN {
|
||||
// Buffer is full, poller will wake.
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (poller *fdPoller) clearWake() error {
|
||||
// You have to be woken up a LOT in order to get to 100!
|
||||
buf := make([]byte, 100)
|
||||
n, errno := unix.Read(poller.pipe[0], buf)
|
||||
if n == -1 {
|
||||
if errno == unix.EAGAIN {
|
||||
// Buffer is empty, someone else cleared our wake.
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close all poller file descriptors, but not the one passed to it.
|
||||
func (poller *fdPoller) close() {
|
||||
if poller.pipe[1] != -1 {
|
||||
unix.Close(poller.pipe[1])
|
||||
}
|
||||
if poller.pipe[0] != -1 {
|
||||
unix.Close(poller.pipe[0])
|
||||
}
|
||||
if poller.epfd != -1 {
|
||||
unix.Close(poller.epfd)
|
||||
}
|
||||
}
|
||||
521
backend/vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
521
backend/vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
@@ -1,521 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build freebsd openbsd netbsd dragonfly darwin
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct {
|
||||
Events chan Event
|
||||
Errors chan error
|
||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||
|
||||
kq int // File descriptor (as returned by the kqueue() syscall).
|
||||
|
||||
mu sync.Mutex // Protects access to watcher data
|
||||
watches map[string]int // Map of watched file descriptors (key: path).
|
||||
externalWatches map[string]bool // Map of watches added by user of the library.
|
||||
dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue.
|
||||
paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events.
|
||||
fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events).
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
}
|
||||
|
||||
type pathInfo struct {
|
||||
name string
|
||||
isDir bool
|
||||
}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
kq, err := kqueue()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w := &Watcher{
|
||||
kq: kq,
|
||||
watches: make(map[string]int),
|
||||
dirFlags: make(map[string]uint32),
|
||||
paths: make(map[int]pathInfo),
|
||||
fileExists: make(map[string]bool),
|
||||
externalWatches: make(map[string]bool),
|
||||
Events: make(chan Event),
|
||||
Errors: make(chan error),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
go w.readEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
w.mu.Lock()
|
||||
if w.isClosed {
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
w.isClosed = true
|
||||
|
||||
// copy paths to remove while locked
|
||||
var pathsToRemove = make([]string, 0, len(w.watches))
|
||||
for name := range w.watches {
|
||||
pathsToRemove = append(pathsToRemove, name)
|
||||
}
|
||||
w.mu.Unlock()
|
||||
// unlock before calling Remove, which also locks
|
||||
|
||||
for _, name := range pathsToRemove {
|
||||
w.Remove(name)
|
||||
}
|
||||
|
||||
// send a "quit" message to the reader goroutine
|
||||
close(w.done)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
w.mu.Lock()
|
||||
w.externalWatches[name] = true
|
||||
w.mu.Unlock()
|
||||
_, err := w.addWatch(name, noteAllEvents)
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove stops watching the the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
name = filepath.Clean(name)
|
||||
w.mu.Lock()
|
||||
watchfd, ok := w.watches[name]
|
||||
w.mu.Unlock()
|
||||
if !ok {
|
||||
return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
|
||||
}
|
||||
|
||||
const registerRemove = unix.EV_DELETE
|
||||
if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
unix.Close(watchfd)
|
||||
|
||||
w.mu.Lock()
|
||||
isDir := w.paths[watchfd].isDir
|
||||
delete(w.watches, name)
|
||||
delete(w.paths, watchfd)
|
||||
delete(w.dirFlags, name)
|
||||
w.mu.Unlock()
|
||||
|
||||
// Find all watched paths that are in this directory that are not external.
|
||||
if isDir {
|
||||
var pathsToRemove []string
|
||||
w.mu.Lock()
|
||||
for _, path := range w.paths {
|
||||
wdir, _ := filepath.Split(path.name)
|
||||
if filepath.Clean(wdir) == name {
|
||||
if !w.externalWatches[path.name] {
|
||||
pathsToRemove = append(pathsToRemove, path.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
w.mu.Unlock()
|
||||
for _, name := range pathsToRemove {
|
||||
// Since these are internal, not much sense in propagating error
|
||||
// to the user, as that will just confuse them with an error about
|
||||
// a path they did not explicitly watch themselves.
|
||||
w.Remove(name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
|
||||
const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME
|
||||
|
||||
// keventWaitTime to block on each read from kevent
|
||||
var keventWaitTime = durationToTimespec(100 * time.Millisecond)
|
||||
|
||||
// addWatch adds name to the watched file set.
|
||||
// The flags are interpreted as described in kevent(2).
|
||||
// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks.
|
||||
func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
|
||||
var isDir bool
|
||||
// Make ./name and name equivalent
|
||||
name = filepath.Clean(name)
|
||||
|
||||
w.mu.Lock()
|
||||
if w.isClosed {
|
||||
w.mu.Unlock()
|
||||
return "", errors.New("kevent instance already closed")
|
||||
}
|
||||
watchfd, alreadyWatching := w.watches[name]
|
||||
// We already have a watch, but we can still override flags.
|
||||
if alreadyWatching {
|
||||
isDir = w.paths[watchfd].isDir
|
||||
}
|
||||
w.mu.Unlock()
|
||||
|
||||
if !alreadyWatching {
|
||||
fi, err := os.Lstat(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Don't watch sockets.
|
||||
if fi.Mode()&os.ModeSocket == os.ModeSocket {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Don't watch named pipes.
|
||||
if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Follow Symlinks
|
||||
// Unfortunately, Linux can add bogus symlinks to watch list without
|
||||
// issue, and Windows can't do symlinks period (AFAIK). To maintain
|
||||
// consistency, we will act like everything is fine. There will simply
|
||||
// be no file events for broken symlinks.
|
||||
// Hence the returns of nil on errors.
|
||||
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
name, err = filepath.EvalSymlinks(name)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
_, alreadyWatching = w.watches[name]
|
||||
w.mu.Unlock()
|
||||
|
||||
if alreadyWatching {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
fi, err = os.Lstat(name)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
watchfd, err = unix.Open(name, openMode, 0700)
|
||||
if watchfd == -1 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
isDir = fi.IsDir()
|
||||
}
|
||||
|
||||
const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE
|
||||
if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil {
|
||||
unix.Close(watchfd)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !alreadyWatching {
|
||||
w.mu.Lock()
|
||||
w.watches[name] = watchfd
|
||||
w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
if isDir {
|
||||
// Watch the directory if it has not been watched before,
|
||||
// or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles)
|
||||
w.mu.Lock()
|
||||
|
||||
watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
|
||||
(!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE)
|
||||
// Store flags so this watch can be updated later
|
||||
w.dirFlags[name] = flags
|
||||
w.mu.Unlock()
|
||||
|
||||
if watchDir {
|
||||
if err := w.watchDirectoryFiles(name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// readEvents reads from kqueue and converts the received kevents into
|
||||
// Event values that it sends down the Events channel.
|
||||
func (w *Watcher) readEvents() {
|
||||
eventBuffer := make([]unix.Kevent_t, 10)
|
||||
|
||||
loop:
|
||||
for {
|
||||
// See if there is a message on the "done" channel
|
||||
select {
|
||||
case <-w.done:
|
||||
break loop
|
||||
default:
|
||||
}
|
||||
|
||||
// Get new events
|
||||
kevents, err := read(w.kq, eventBuffer, &keventWaitTime)
|
||||
// EINTR is okay, the syscall was interrupted before timeout expired.
|
||||
if err != nil && err != unix.EINTR {
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
case <-w.done:
|
||||
break loop
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Flush the events we received to the Events channel
|
||||
for len(kevents) > 0 {
|
||||
kevent := &kevents[0]
|
||||
watchfd := int(kevent.Ident)
|
||||
mask := uint32(kevent.Fflags)
|
||||
w.mu.Lock()
|
||||
path := w.paths[watchfd]
|
||||
w.mu.Unlock()
|
||||
event := newEvent(path.name, mask)
|
||||
|
||||
if path.isDir && !(event.Op&Remove == Remove) {
|
||||
// Double check to make sure the directory exists. This can happen when
|
||||
// we do a rm -fr on a recursively watched folders and we receive a
|
||||
// modification event first but the folder has been deleted and later
|
||||
// receive the delete event
|
||||
if _, err := os.Lstat(event.Name); os.IsNotExist(err) {
|
||||
// mark is as delete event
|
||||
event.Op |= Remove
|
||||
}
|
||||
}
|
||||
|
||||
if event.Op&Rename == Rename || event.Op&Remove == Remove {
|
||||
w.Remove(event.Name)
|
||||
w.mu.Lock()
|
||||
delete(w.fileExists, event.Name)
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) {
|
||||
w.sendDirectoryChangeEvents(event.Name)
|
||||
} else {
|
||||
// Send the event on the Events channel.
|
||||
select {
|
||||
case w.Events <- event:
|
||||
case <-w.done:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
if event.Op&Remove == Remove {
|
||||
// Look for a file that may have overwritten this.
|
||||
// For example, mv f1 f2 will delete f2, then create f2.
|
||||
if path.isDir {
|
||||
fileDir := filepath.Clean(event.Name)
|
||||
w.mu.Lock()
|
||||
_, found := w.watches[fileDir]
|
||||
w.mu.Unlock()
|
||||
if found {
|
||||
// make sure the directory exists before we watch for changes. When we
|
||||
// do a recursive watch and perform rm -fr, the parent directory might
|
||||
// have gone missing, ignore the missing directory and let the
|
||||
// upcoming delete event remove the watch from the parent directory.
|
||||
if _, err := os.Lstat(fileDir); err == nil {
|
||||
w.sendDirectoryChangeEvents(fileDir)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filePath := filepath.Clean(event.Name)
|
||||
if fileInfo, err := os.Lstat(filePath); err == nil {
|
||||
w.sendFileCreatedEventIfNew(filePath, fileInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move to next event
|
||||
kevents = kevents[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup
|
||||
err := unix.Close(w.kq)
|
||||
if err != nil {
|
||||
// only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors.
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
default:
|
||||
}
|
||||
}
|
||||
close(w.Events)
|
||||
close(w.Errors)
|
||||
}
|
||||
|
||||
// newEvent returns an platform-independent Event based on kqueue Fflags.
|
||||
func newEvent(name string, mask uint32) Event {
|
||||
e := Event{Name: name}
|
||||
if mask&unix.NOTE_DELETE == unix.NOTE_DELETE {
|
||||
e.Op |= Remove
|
||||
}
|
||||
if mask&unix.NOTE_WRITE == unix.NOTE_WRITE {
|
||||
e.Op |= Write
|
||||
}
|
||||
if mask&unix.NOTE_RENAME == unix.NOTE_RENAME {
|
||||
e.Op |= Rename
|
||||
}
|
||||
if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB {
|
||||
e.Op |= Chmod
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func newCreateEvent(name string) Event {
|
||||
return Event{Name: name, Op: Create}
|
||||
}
|
||||
|
||||
// watchDirectoryFiles to mimic inotify when adding a watch on a directory
|
||||
func (w *Watcher) watchDirectoryFiles(dirPath string) error {
|
||||
// Get all files
|
||||
files, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, fileInfo := range files {
|
||||
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||
filePath, err = w.internalWatch(filePath, fileInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
w.fileExists[filePath] = true
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendDirectoryEvents searches the directory for newly created files
|
||||
// and sends them over the event channel. This functionality is to have
|
||||
// the BSD version of fsnotify match Linux inotify which provides a
|
||||
// create event for files created in a watched directory.
|
||||
func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
|
||||
// Get all files
|
||||
files, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Search for new files
|
||||
for _, fileInfo := range files {
|
||||
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||
err := w.sendFileCreatedEventIfNew(filePath, fileInfo)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sendFileCreatedEvent sends a create event if the file isn't already being tracked.
|
||||
func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) {
|
||||
w.mu.Lock()
|
||||
_, doesExist := w.fileExists[filePath]
|
||||
w.mu.Unlock()
|
||||
if !doesExist {
|
||||
// Send create event
|
||||
select {
|
||||
case w.Events <- newCreateEvent(filePath):
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// like watchDirectoryFiles (but without doing another ReadDir)
|
||||
filePath, err = w.internalWatch(filePath, fileInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
w.fileExists[filePath] = true
|
||||
w.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) {
|
||||
if fileInfo.IsDir() {
|
||||
// mimic Linux providing delete events for subdirectories
|
||||
// but preserve the flags used if currently watching subdirectory
|
||||
w.mu.Lock()
|
||||
flags := w.dirFlags[name]
|
||||
w.mu.Unlock()
|
||||
|
||||
flags |= unix.NOTE_DELETE | unix.NOTE_RENAME
|
||||
return w.addWatch(name, flags)
|
||||
}
|
||||
|
||||
// watch file to mimic Linux inotify
|
||||
return w.addWatch(name, noteAllEvents)
|
||||
}
|
||||
|
||||
// kqueue creates a new kernel event queue and returns a descriptor.
|
||||
func kqueue() (kq int, err error) {
|
||||
kq, err = unix.Kqueue()
|
||||
if kq == -1 {
|
||||
return kq, err
|
||||
}
|
||||
return kq, nil
|
||||
}
|
||||
|
||||
// register events with the queue
|
||||
func register(kq int, fds []int, flags int, fflags uint32) error {
|
||||
changes := make([]unix.Kevent_t, len(fds))
|
||||
|
||||
for i, fd := range fds {
|
||||
// SetKevent converts int to the platform-specific types:
|
||||
unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags)
|
||||
changes[i].Fflags = fflags
|
||||
}
|
||||
|
||||
// register the events
|
||||
success, err := unix.Kevent(kq, changes, nil, nil)
|
||||
if success == -1 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// read retrieves pending events, or waits until an event occurs.
|
||||
// A timeout of nil blocks indefinitely, while 0 polls the queue.
|
||||
func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) {
|
||||
n, err := unix.Kevent(kq, nil, events, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return events[0:n], nil
|
||||
}
|
||||
|
||||
// durationToTimespec prepares a timeout value
|
||||
func durationToTimespec(d time.Duration) unix.Timespec {
|
||||
return unix.NsecToTimespec(d.Nanoseconds())
|
||||
}
|
||||
11
backend/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
generated
vendored
11
backend/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
generated
vendored
@@ -1,11 +0,0 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build freebsd openbsd netbsd dragonfly
|
||||
|
||||
package fsnotify
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const openMode = unix.O_NONBLOCK | unix.O_RDONLY
|
||||
12
backend/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
generated
vendored
12
backend/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
generated
vendored
@@ -1,12 +0,0 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package fsnotify
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
// note: this constant is not defined on BSD
|
||||
const openMode = unix.O_EVTONLY
|
||||
561
backend/vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
561
backend/vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
@@ -1,561 +0,0 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct {
|
||||
Events chan Event
|
||||
Errors chan error
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
mu sync.Mutex // Map access
|
||||
port syscall.Handle // Handle to completion port
|
||||
watches watchMap // Map of watches (key: i-number)
|
||||
input chan *input // Inputs to the reader are sent on this channel
|
||||
quit chan chan<- error
|
||||
}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
|
||||
if e != nil {
|
||||
return nil, os.NewSyscallError("CreateIoCompletionPort", e)
|
||||
}
|
||||
w := &Watcher{
|
||||
port: port,
|
||||
watches: make(watchMap),
|
||||
input: make(chan *input, 1),
|
||||
Events: make(chan Event, 50),
|
||||
Errors: make(chan error),
|
||||
quit: make(chan chan<- error, 1),
|
||||
}
|
||||
go w.readEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
if w.isClosed {
|
||||
return nil
|
||||
}
|
||||
w.isClosed = true
|
||||
|
||||
// Send "quit" message to the reader goroutine
|
||||
ch := make(chan error)
|
||||
w.quit <- ch
|
||||
if err := w.wakeupReader(); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-ch
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
if w.isClosed {
|
||||
return errors.New("watcher already closed")
|
||||
}
|
||||
in := &input{
|
||||
op: opAddWatch,
|
||||
path: filepath.Clean(name),
|
||||
flags: sysFSALLEVENTS,
|
||||
reply: make(chan error),
|
||||
}
|
||||
w.input <- in
|
||||
if err := w.wakeupReader(); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-in.reply
|
||||
}
|
||||
|
||||
// Remove stops watching the the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
in := &input{
|
||||
op: opRemoveWatch,
|
||||
path: filepath.Clean(name),
|
||||
reply: make(chan error),
|
||||
}
|
||||
w.input <- in
|
||||
if err := w.wakeupReader(); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-in.reply
|
||||
}
|
||||
|
||||
const (
|
||||
// Options for AddWatch
|
||||
sysFSONESHOT = 0x80000000
|
||||
sysFSONLYDIR = 0x1000000
|
||||
|
||||
// Events
|
||||
sysFSACCESS = 0x1
|
||||
sysFSALLEVENTS = 0xfff
|
||||
sysFSATTRIB = 0x4
|
||||
sysFSCLOSE = 0x18
|
||||
sysFSCREATE = 0x100
|
||||
sysFSDELETE = 0x200
|
||||
sysFSDELETESELF = 0x400
|
||||
sysFSMODIFY = 0x2
|
||||
sysFSMOVE = 0xc0
|
||||
sysFSMOVEDFROM = 0x40
|
||||
sysFSMOVEDTO = 0x80
|
||||
sysFSMOVESELF = 0x800
|
||||
|
||||
// Special events
|
||||
sysFSIGNORED = 0x8000
|
||||
sysFSQOVERFLOW = 0x4000
|
||||
)
|
||||
|
||||
func newEvent(name string, mask uint32) Event {
|
||||
e := Event{Name: name}
|
||||
if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
|
||||
e.Op |= Create
|
||||
}
|
||||
if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF {
|
||||
e.Op |= Remove
|
||||
}
|
||||
if mask&sysFSMODIFY == sysFSMODIFY {
|
||||
e.Op |= Write
|
||||
}
|
||||
if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM {
|
||||
e.Op |= Rename
|
||||
}
|
||||
if mask&sysFSATTRIB == sysFSATTRIB {
|
||||
e.Op |= Chmod
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
const (
|
||||
opAddWatch = iota
|
||||
opRemoveWatch
|
||||
)
|
||||
|
||||
const (
|
||||
provisional uint64 = 1 << (32 + iota)
|
||||
)
|
||||
|
||||
type input struct {
|
||||
op int
|
||||
path string
|
||||
flags uint32
|
||||
reply chan error
|
||||
}
|
||||
|
||||
type inode struct {
|
||||
handle syscall.Handle
|
||||
volume uint32
|
||||
index uint64
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
ov syscall.Overlapped
|
||||
ino *inode // i-number
|
||||
path string // Directory path
|
||||
mask uint64 // Directory itself is being watched with these notify flags
|
||||
names map[string]uint64 // Map of names being watched and their notify flags
|
||||
rename string // Remembers the old name while renaming a file
|
||||
buf [4096]byte
|
||||
}
|
||||
|
||||
type indexMap map[uint64]*watch
|
||||
type watchMap map[uint32]indexMap
|
||||
|
||||
func (w *Watcher) wakeupReader() error {
|
||||
e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
|
||||
if e != nil {
|
||||
return os.NewSyscallError("PostQueuedCompletionStatus", e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDir(pathname string) (dir string, err error) {
|
||||
attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
|
||||
if e != nil {
|
||||
return "", os.NewSyscallError("GetFileAttributes", e)
|
||||
}
|
||||
if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||
dir = pathname
|
||||
} else {
|
||||
dir, _ = filepath.Split(pathname)
|
||||
dir = filepath.Clean(dir)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getIno(path string) (ino *inode, err error) {
|
||||
h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
|
||||
syscall.FILE_LIST_DIRECTORY,
|
||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||
nil, syscall.OPEN_EXISTING,
|
||||
syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
|
||||
if e != nil {
|
||||
return nil, os.NewSyscallError("CreateFile", e)
|
||||
}
|
||||
var fi syscall.ByHandleFileInformation
|
||||
if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
|
||||
syscall.CloseHandle(h)
|
||||
return nil, os.NewSyscallError("GetFileInformationByHandle", e)
|
||||
}
|
||||
ino = &inode{
|
||||
handle: h,
|
||||
volume: fi.VolumeSerialNumber,
|
||||
index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
|
||||
}
|
||||
return ino, nil
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (m watchMap) get(ino *inode) *watch {
|
||||
if i := m[ino.volume]; i != nil {
|
||||
return i[ino.index]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (m watchMap) set(ino *inode, watch *watch) {
|
||||
i := m[ino.volume]
|
||||
if i == nil {
|
||||
i = make(indexMap)
|
||||
m[ino.volume] = i
|
||||
}
|
||||
i[ino.index] = watch
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) addWatch(pathname string, flags uint64) error {
|
||||
dir, err := getDir(pathname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if flags&sysFSONLYDIR != 0 && pathname != dir {
|
||||
return nil
|
||||
}
|
||||
ino, err := getIno(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.mu.Lock()
|
||||
watchEntry := w.watches.get(ino)
|
||||
w.mu.Unlock()
|
||||
if watchEntry == nil {
|
||||
if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
|
||||
syscall.CloseHandle(ino.handle)
|
||||
return os.NewSyscallError("CreateIoCompletionPort", e)
|
||||
}
|
||||
watchEntry = &watch{
|
||||
ino: ino,
|
||||
path: dir,
|
||||
names: make(map[string]uint64),
|
||||
}
|
||||
w.mu.Lock()
|
||||
w.watches.set(ino, watchEntry)
|
||||
w.mu.Unlock()
|
||||
flags |= provisional
|
||||
} else {
|
||||
syscall.CloseHandle(ino.handle)
|
||||
}
|
||||
if pathname == dir {
|
||||
watchEntry.mask |= flags
|
||||
} else {
|
||||
watchEntry.names[filepath.Base(pathname)] |= flags
|
||||
}
|
||||
if err = w.startRead(watchEntry); err != nil {
|
||||
return err
|
||||
}
|
||||
if pathname == dir {
|
||||
watchEntry.mask &= ^provisional
|
||||
} else {
|
||||
watchEntry.names[filepath.Base(pathname)] &= ^provisional
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) remWatch(pathname string) error {
|
||||
dir, err := getDir(pathname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ino, err := getIno(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.mu.Lock()
|
||||
watch := w.watches.get(ino)
|
||||
w.mu.Unlock()
|
||||
if watch == nil {
|
||||
return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
|
||||
}
|
||||
if pathname == dir {
|
||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||
watch.mask = 0
|
||||
} else {
|
||||
name := filepath.Base(pathname)
|
||||
w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
|
||||
delete(watch.names, name)
|
||||
}
|
||||
return w.startRead(watch)
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) deleteWatch(watch *watch) {
|
||||
for name, mask := range watch.names {
|
||||
if mask&provisional == 0 {
|
||||
w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
|
||||
}
|
||||
delete(watch.names, name)
|
||||
}
|
||||
if watch.mask != 0 {
|
||||
if watch.mask&provisional == 0 {
|
||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||
}
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) startRead(watch *watch) error {
|
||||
if e := syscall.CancelIo(watch.ino.handle); e != nil {
|
||||
w.Errors <- os.NewSyscallError("CancelIo", e)
|
||||
w.deleteWatch(watch)
|
||||
}
|
||||
mask := toWindowsFlags(watch.mask)
|
||||
for _, m := range watch.names {
|
||||
mask |= toWindowsFlags(m)
|
||||
}
|
||||
if mask == 0 {
|
||||
if e := syscall.CloseHandle(watch.ino.handle); e != nil {
|
||||
w.Errors <- os.NewSyscallError("CloseHandle", e)
|
||||
}
|
||||
w.mu.Lock()
|
||||
delete(w.watches[watch.ino.volume], watch.ino.index)
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
|
||||
uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
|
||||
if e != nil {
|
||||
err := os.NewSyscallError("ReadDirectoryChanges", e)
|
||||
if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
|
||||
// Watched directory was probably removed
|
||||
if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) {
|
||||
if watch.mask&sysFSONESHOT != 0 {
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readEvents reads from the I/O completion port, converts the
|
||||
// received events into Event objects and sends them via the Events channel.
|
||||
// Entry point to the I/O thread.
|
||||
func (w *Watcher) readEvents() {
|
||||
var (
|
||||
n, key uint32
|
||||
ov *syscall.Overlapped
|
||||
)
|
||||
runtime.LockOSThread()
|
||||
|
||||
for {
|
||||
e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
|
||||
watch := (*watch)(unsafe.Pointer(ov))
|
||||
|
||||
if watch == nil {
|
||||
select {
|
||||
case ch := <-w.quit:
|
||||
w.mu.Lock()
|
||||
var indexes []indexMap
|
||||
for _, index := range w.watches {
|
||||
indexes = append(indexes, index)
|
||||
}
|
||||
w.mu.Unlock()
|
||||
for _, index := range indexes {
|
||||
for _, watch := range index {
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
}
|
||||
}
|
||||
var err error
|
||||
if e := syscall.CloseHandle(w.port); e != nil {
|
||||
err = os.NewSyscallError("CloseHandle", e)
|
||||
}
|
||||
close(w.Events)
|
||||
close(w.Errors)
|
||||
ch <- err
|
||||
return
|
||||
case in := <-w.input:
|
||||
switch in.op {
|
||||
case opAddWatch:
|
||||
in.reply <- w.addWatch(in.path, uint64(in.flags))
|
||||
case opRemoveWatch:
|
||||
in.reply <- w.remWatch(in.path)
|
||||
}
|
||||
default:
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch e {
|
||||
case syscall.ERROR_MORE_DATA:
|
||||
if watch == nil {
|
||||
w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
|
||||
} else {
|
||||
// The i/o succeeded but the buffer is full.
|
||||
// In theory we should be building up a full packet.
|
||||
// In practice we can get away with just carrying on.
|
||||
n = uint32(unsafe.Sizeof(watch.buf))
|
||||
}
|
||||
case syscall.ERROR_ACCESS_DENIED:
|
||||
// Watched directory was probably removed
|
||||
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
continue
|
||||
case syscall.ERROR_OPERATION_ABORTED:
|
||||
// CancelIo was called on this handle
|
||||
continue
|
||||
default:
|
||||
w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e)
|
||||
continue
|
||||
case nil:
|
||||
}
|
||||
|
||||
var offset uint32
|
||||
for {
|
||||
if n == 0 {
|
||||
w.Events <- newEvent("", sysFSQOVERFLOW)
|
||||
w.Errors <- errors.New("short read in readEvents()")
|
||||
break
|
||||
}
|
||||
|
||||
// Point "raw" to the event in the buffer
|
||||
raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
|
||||
buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
|
||||
name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
|
||||
fullname := filepath.Join(watch.path, name)
|
||||
|
||||
var mask uint64
|
||||
switch raw.Action {
|
||||
case syscall.FILE_ACTION_REMOVED:
|
||||
mask = sysFSDELETESELF
|
||||
case syscall.FILE_ACTION_MODIFIED:
|
||||
mask = sysFSMODIFY
|
||||
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||
watch.rename = name
|
||||
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||
if watch.names[watch.rename] != 0 {
|
||||
watch.names[name] |= watch.names[watch.rename]
|
||||
delete(watch.names, watch.rename)
|
||||
mask = sysFSMOVESELF
|
||||
}
|
||||
}
|
||||
|
||||
sendNameEvent := func() {
|
||||
if w.sendEvent(fullname, watch.names[name]&mask) {
|
||||
if watch.names[name]&sysFSONESHOT != 0 {
|
||||
delete(watch.names, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||
sendNameEvent()
|
||||
}
|
||||
if raw.Action == syscall.FILE_ACTION_REMOVED {
|
||||
w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
|
||||
delete(watch.names, name)
|
||||
}
|
||||
if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
|
||||
if watch.mask&sysFSONESHOT != 0 {
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||
fullname = filepath.Join(watch.path, watch.rename)
|
||||
sendNameEvent()
|
||||
}
|
||||
|
||||
// Move to the next event in the buffer
|
||||
if raw.NextEntryOffset == 0 {
|
||||
break
|
||||
}
|
||||
offset += raw.NextEntryOffset
|
||||
|
||||
// Error!
|
||||
if offset >= n {
|
||||
w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err := w.startRead(watch); err != nil {
|
||||
w.Errors <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Watcher) sendEvent(name string, mask uint64) bool {
|
||||
if mask == 0 {
|
||||
return false
|
||||
}
|
||||
event := newEvent(name, uint32(mask))
|
||||
select {
|
||||
case ch := <-w.quit:
|
||||
w.quit <- ch
|
||||
case w.Events <- event:
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func toWindowsFlags(mask uint64) uint32 {
|
||||
var m uint32
|
||||
if mask&sysFSACCESS != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
|
||||
}
|
||||
if mask&sysFSMODIFY != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
|
||||
}
|
||||
if mask&sysFSATTRIB != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
|
||||
}
|
||||
if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func toFSnotifyFlags(action uint32) uint64 {
|
||||
switch action {
|
||||
case syscall.FILE_ACTION_ADDED:
|
||||
return sysFSCREATE
|
||||
case syscall.FILE_ACTION_REMOVED:
|
||||
return sysFSDELETE
|
||||
case syscall.FILE_ACTION_MODIFIED:
|
||||
return sysFSMODIFY
|
||||
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||
return sysFSMOVEDFROM
|
||||
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||
return sysFSMOVEDTO
|
||||
}
|
||||
return 0
|
||||
}
|
||||
26
backend/vendor/github.com/gin-contrib/sse/.travis.yml
generated
vendored
26
backend/vendor/github.com/gin-contrib/sse/.travis.yml
generated
vendored
@@ -1,26 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- master
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=on
|
||||
- go: 1.12.x
|
||||
env: GO111MODULE=on
|
||||
|
||||
script:
|
||||
- go test -v -covermode=count -coverprofile=coverage.out
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
21
backend/vendor/github.com/gin-contrib/sse/LICENSE
generated
vendored
21
backend/vendor/github.com/gin-contrib/sse/LICENSE
generated
vendored
@@ -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.
|
||||
58
backend/vendor/github.com/gin-contrib/sse/README.md
generated
vendored
58
backend/vendor/github.com/gin-contrib/sse/README.md
generated
vendored
@@ -1,58 +0,0 @@
|
||||
# Server-Sent Events
|
||||
|
||||
[](https://godoc.org/github.com/gin-contrib/sse)
|
||||
[](https://travis-ci.org/gin-contrib/sse)
|
||||
[](https://codecov.io/gh/gin-contrib/sse)
|
||||
[](https://goreportcard.com/report/github.com/gin-contrib/sse)
|
||||
|
||||
Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is [standardized as part of HTML5[1] by the W3C](http://www.w3.org/TR/2009/WD-eventsource-20091029/).
|
||||
|
||||
- [Read this great SSE introduction by the HTML5Rocks guys](http://www.html5rocks.com/en/tutorials/eventsource/basics/)
|
||||
- [Browser support](http://caniuse.com/#feat=eventsource)
|
||||
|
||||
## Sample code
|
||||
|
||||
```go
|
||||
import "github.com/gin-contrib/sse"
|
||||
|
||||
func httpHandler(w http.ResponseWriter, req *http.Request) {
|
||||
// data can be a primitive like a string, an integer or a float
|
||||
sse.Encode(w, sse.Event{
|
||||
Event: "message",
|
||||
Data: "some data\nmore data",
|
||||
})
|
||||
|
||||
// also a complex type, like a map, a struct or a slice
|
||||
sse.Encode(w, sse.Event{
|
||||
Id: "124",
|
||||
Event: "message",
|
||||
Data: map[string]interface{}{
|
||||
"user": "manu",
|
||||
"date": time.Now().Unix(),
|
||||
"content": "hi!",
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
```
|
||||
event: message
|
||||
data: some data\\nmore data
|
||||
|
||||
id: 124
|
||||
event: message
|
||||
data: {"content":"hi!","date":1431540810,"user":"manu"}
|
||||
|
||||
```
|
||||
|
||||
## Content-Type
|
||||
|
||||
```go
|
||||
fmt.Println(sse.ContentType)
|
||||
```
|
||||
```
|
||||
text/event-stream
|
||||
```
|
||||
|
||||
## Decoding support
|
||||
|
||||
There is a client-side implementation of SSE coming soon.
|
||||
116
backend/vendor/github.com/gin-contrib/sse/sse-decoder.go
generated
vendored
116
backend/vendor/github.com/gin-contrib/sse/sse-decoder.go
generated
vendored
@@ -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 sse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type decoder struct {
|
||||
events []Event
|
||||
}
|
||||
|
||||
func Decode(r io.Reader) ([]Event, error) {
|
||||
var dec decoder
|
||||
return dec.decode(r)
|
||||
}
|
||||
|
||||
func (d *decoder) dispatchEvent(event Event, data string) {
|
||||
dataLength := len(data)
|
||||
if dataLength > 0 {
|
||||
//If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer.
|
||||
data = data[:dataLength-1]
|
||||
dataLength--
|
||||
}
|
||||
if dataLength == 0 && event.Event == "" {
|
||||
return
|
||||
}
|
||||
if event.Event == "" {
|
||||
event.Event = "message"
|
||||
}
|
||||
event.Data = data
|
||||
d.events = append(d.events, event)
|
||||
}
|
||||
|
||||
func (d *decoder) decode(r io.Reader) ([]Event, error) {
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var currentEvent Event
|
||||
var dataBuffer *bytes.Buffer = new(bytes.Buffer)
|
||||
// TODO (and unit tests)
|
||||
// Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair,
|
||||
// a single U+000A LINE FEED (LF) character,
|
||||
// or a single U+000D CARRIAGE RETURN (CR) character.
|
||||
lines := bytes.Split(buf, []byte{'\n'})
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
// If the line is empty (a blank line). Dispatch the event.
|
||||
d.dispatchEvent(currentEvent, dataBuffer.String())
|
||||
|
||||
// reset current event and data buffer
|
||||
currentEvent = Event{}
|
||||
dataBuffer.Reset()
|
||||
continue
|
||||
}
|
||||
if line[0] == byte(':') {
|
||||
// If the line starts with a U+003A COLON character (:), ignore the line.
|
||||
continue
|
||||
}
|
||||
|
||||
var field, value []byte
|
||||
colonIndex := bytes.IndexRune(line, ':')
|
||||
if colonIndex != -1 {
|
||||
// If the line contains a U+003A COLON character character (:)
|
||||
// Collect the characters on the line before the first U+003A COLON character (:),
|
||||
// and let field be that string.
|
||||
field = line[:colonIndex]
|
||||
// Collect the characters on the line after the first U+003A COLON character (:),
|
||||
// and let value be that string.
|
||||
value = line[colonIndex+1:]
|
||||
// If value starts with a single U+0020 SPACE character, remove it from value.
|
||||
if len(value) > 0 && value[0] == ' ' {
|
||||
value = value[1:]
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the string is not empty but does not contain a U+003A COLON character character (:)
|
||||
// Use the whole line as the field name, and the empty string as the field value.
|
||||
field = line
|
||||
value = []byte{}
|
||||
}
|
||||
// The steps to process the field given a field name and a field value depend on the field name,
|
||||
// as given in the following list. Field names must be compared literally,
|
||||
// with no case folding performed.
|
||||
switch string(field) {
|
||||
case "event":
|
||||
// Set the event name buffer to field value.
|
||||
currentEvent.Event = string(value)
|
||||
case "id":
|
||||
// Set the event stream's last event ID to the field value.
|
||||
currentEvent.Id = string(value)
|
||||
case "retry":
|
||||
// If the field value consists of only characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9),
|
||||
// then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer.
|
||||
// Otherwise, ignore the field.
|
||||
currentEvent.Id = string(value)
|
||||
case "data":
|
||||
// Append the field value to the data buffer,
|
||||
dataBuffer.Write(value)
|
||||
// then append a single U+000A LINE FEED (LF) character to the data buffer.
|
||||
dataBuffer.WriteString("\n")
|
||||
default:
|
||||
//Otherwise. The field is ignored.
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Once the end of the file is reached, the user agent must dispatch the event one final time.
|
||||
d.dispatchEvent(currentEvent, dataBuffer.String())
|
||||
|
||||
return d.events, nil
|
||||
}
|
||||
110
backend/vendor/github.com/gin-contrib/sse/sse-encoder.go
generated
vendored
110
backend/vendor/github.com/gin-contrib/sse/sse-encoder.go
generated
vendored
@@ -1,110 +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 sse
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Server-Sent Events
|
||||
// W3C Working Draft 29 October 2009
|
||||
// http://www.w3.org/TR/2009/WD-eventsource-20091029/
|
||||
|
||||
const ContentType = "text/event-stream"
|
||||
|
||||
var contentType = []string{ContentType}
|
||||
var noCache = []string{"no-cache"}
|
||||
|
||||
var fieldReplacer = strings.NewReplacer(
|
||||
"\n", "\\n",
|
||||
"\r", "\\r")
|
||||
|
||||
var dataReplacer = strings.NewReplacer(
|
||||
"\n", "\ndata:",
|
||||
"\r", "\\r")
|
||||
|
||||
type Event struct {
|
||||
Event string
|
||||
Id string
|
||||
Retry uint
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
func Encode(writer io.Writer, event Event) error {
|
||||
w := checkWriter(writer)
|
||||
writeId(w, event.Id)
|
||||
writeEvent(w, event.Event)
|
||||
writeRetry(w, event.Retry)
|
||||
return writeData(w, event.Data)
|
||||
}
|
||||
|
||||
func writeId(w stringWriter, id string) {
|
||||
if len(id) > 0 {
|
||||
w.WriteString("id:")
|
||||
fieldReplacer.WriteString(w, id)
|
||||
w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeEvent(w stringWriter, event string) {
|
||||
if len(event) > 0 {
|
||||
w.WriteString("event:")
|
||||
fieldReplacer.WriteString(w, event)
|
||||
w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeRetry(w stringWriter, retry uint) {
|
||||
if retry > 0 {
|
||||
w.WriteString("retry:")
|
||||
w.WriteString(strconv.FormatUint(uint64(retry), 10))
|
||||
w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeData(w stringWriter, data interface{}) error {
|
||||
w.WriteString("data:")
|
||||
switch kindOfData(data) {
|
||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteString("\n")
|
||||
default:
|
||||
dataReplacer.WriteString(w, fmt.Sprint(data))
|
||||
w.WriteString("\n\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r Event) Render(w http.ResponseWriter) error {
|
||||
r.WriteContentType(w)
|
||||
return Encode(w, r)
|
||||
}
|
||||
|
||||
func (r Event) WriteContentType(w http.ResponseWriter) {
|
||||
header := w.Header()
|
||||
header["Content-Type"] = contentType
|
||||
|
||||
if _, exist := header["Cache-Control"]; !exist {
|
||||
header["Cache-Control"] = noCache
|
||||
}
|
||||
}
|
||||
|
||||
func kindOfData(data interface{}) reflect.Kind {
|
||||
value := reflect.ValueOf(data)
|
||||
valueType := value.Kind()
|
||||
if valueType == reflect.Ptr {
|
||||
valueType = value.Elem().Kind()
|
||||
}
|
||||
return valueType
|
||||
}
|
||||
24
backend/vendor/github.com/gin-contrib/sse/writer.go
generated
vendored
24
backend/vendor/github.com/gin-contrib/sse/writer.go
generated
vendored
@@ -1,24 +0,0 @@
|
||||
package sse
|
||||
|
||||
import "io"
|
||||
|
||||
type stringWriter interface {
|
||||
io.Writer
|
||||
WriteString(string) (int, error)
|
||||
}
|
||||
|
||||
type stringWrapper struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (w stringWrapper) WriteString(str string) (int, error) {
|
||||
return w.Writer.Write([]byte(str))
|
||||
}
|
||||
|
||||
func checkWriter(writer io.Writer) stringWriter {
|
||||
if w, ok := writer.(stringWriter); ok {
|
||||
return w
|
||||
} else {
|
||||
return stringWrapper{writer}
|
||||
}
|
||||
}
|
||||
7
backend/vendor/github.com/gin-gonic/gin/.gitignore
generated
vendored
7
backend/vendor/github.com/gin-gonic/gin/.gitignore
generated
vendored
@@ -1,7 +0,0 @@
|
||||
vendor/*
|
||||
!vendor/vendor.json
|
||||
coverage.out
|
||||
count.out
|
||||
test
|
||||
profile.out
|
||||
tmp.out
|
||||
44
backend/vendor/github.com/gin-gonic/gin/.travis.yml
generated
vendored
44
backend/vendor/github.com/gin-gonic/gin/.travis.yml
generated
vendored
@@ -1,44 +0,0 @@
|
||||
language: go
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- go: 1.8.x
|
||||
- go: 1.9.x
|
||||
- go: 1.10.x
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=on
|
||||
- go: 1.12.x
|
||||
env: GO111MODULE=on
|
||||
- go: master
|
||||
env: GO111MODULE=on
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
||||
before_install:
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi
|
||||
|
||||
install:
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make install; fi
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi
|
||||
|
||||
go_import_path: github.com/gin-gonic/gin
|
||||
|
||||
script:
|
||||
- make vet
|
||||
- make fmt-check
|
||||
- make misspell-check
|
||||
- make test
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/7f95bf605c4d356372f4
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
231
backend/vendor/github.com/gin-gonic/gin/AUTHORS.md
generated
vendored
231
backend/vendor/github.com/gin-gonic/gin/AUTHORS.md
generated
vendored
@@ -1,231 +0,0 @@
|
||||
List of all the awesome people working to make Gin the best Web Framework in Go.
|
||||
|
||||
## gin 1.x series authors
|
||||
|
||||
**Gin Core Team:** Bo-Yi Wu (@appleboy), 田欧 (@thinkerou), Javier Provecho (@javierprovecho)
|
||||
|
||||
## gin 0.x series authors
|
||||
|
||||
**Maintainers:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho)
|
||||
|
||||
People and companies, who have contributed, in alphabetical order.
|
||||
|
||||
**@858806258 (杰哥)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@achedeuzot (Klemen Sever)**
|
||||
- Fix newline debug printing
|
||||
|
||||
|
||||
**@adammck (Adam Mckaig)**
|
||||
- Add MIT license
|
||||
|
||||
|
||||
**@AlexanderChen1989 (Alexander)**
|
||||
- Typos in README
|
||||
|
||||
|
||||
**@alexanderdidenko (Aleksandr Didenko)**
|
||||
- Add support multipart/form-data
|
||||
|
||||
|
||||
**@alexandernyquist (Alexander Nyquist)**
|
||||
- Using template.Must to fix multiple return issue
|
||||
- ★ Added support for OPTIONS verb
|
||||
- ★ Setting response headers before calling WriteHeader
|
||||
- Improved documentation for model binding
|
||||
- ★ Added Content.Redirect()
|
||||
- ★ Added tons of Unit tests
|
||||
|
||||
|
||||
**@austinheap (Austin Heap)**
|
||||
- Added travis CI integration
|
||||
|
||||
|
||||
**@andredublin (Andre Dublin)**
|
||||
- Fix typo in comment
|
||||
|
||||
|
||||
**@bredov (Ludwig Valda Vasquez)**
|
||||
- Fix html templating in debug mode
|
||||
|
||||
|
||||
**@bluele (Jun Kimura)**
|
||||
- Fixes code examples in README
|
||||
|
||||
|
||||
**@chad-russell**
|
||||
- ★ Support for serializing gin.H into XML
|
||||
|
||||
|
||||
**@dickeyxxx (Jeff Dickey)**
|
||||
- Typos in README
|
||||
- Add example about serving static files
|
||||
|
||||
|
||||
**@donileo (Adonis)**
|
||||
- Add NoMethod handler
|
||||
|
||||
|
||||
**@dutchcoders (DutchCoders)**
|
||||
- ★ Fix security bug that allows client to spoof ip
|
||||
- Fix typo. r.HTMLTemplates -> SetHTMLTemplate
|
||||
|
||||
|
||||
**@el3ctro- (Joshua Loper)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@ethankan (Ethan Kan)**
|
||||
- Unsigned integers in binding
|
||||
|
||||
|
||||
**(Evgeny Persienko)**
|
||||
- Validate sub structures
|
||||
|
||||
|
||||
**@frankbille (Frank Bille)**
|
||||
- Add support for HTTP Realm Auth
|
||||
|
||||
|
||||
**@fmd (Fareed Dudhia)**
|
||||
- Fix typo. SetHTTPTemplate -> SetHTMLTemplate
|
||||
|
||||
|
||||
**@ironiridis (Christopher Harrington)**
|
||||
- Remove old reference
|
||||
|
||||
|
||||
**@jammie-stackhouse (Jamie Stackhouse)**
|
||||
- Add more shortcuts for router methods
|
||||
|
||||
|
||||
**@jasonrhansen**
|
||||
- Fix spelling and grammar errors in documentation
|
||||
|
||||
|
||||
**@JasonSoft (Jason Lee)**
|
||||
- Fix typo in comment
|
||||
|
||||
|
||||
**@joiggama (Ignacio Galindo)**
|
||||
- Add utf-8 charset header on renders
|
||||
|
||||
|
||||
**@julienschmidt (Julien Schmidt)**
|
||||
- gofmt the code examples
|
||||
|
||||
|
||||
**@kelcecil (Kel Cecil)**
|
||||
- Fix readme typo
|
||||
|
||||
|
||||
**@kyledinh (Kyle Dinh)**
|
||||
- Adds RunTLS()
|
||||
|
||||
|
||||
**@LinusU (Linus Unnebäck)**
|
||||
- Small fixes in README
|
||||
|
||||
|
||||
**@loongmxbt (Saint Asky)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@lucas-clemente (Lucas Clemente)**
|
||||
- ★ work around path.Join removing trailing slashes from routes
|
||||
|
||||
|
||||
**@mattn (Yasuhiro Matsumoto)**
|
||||
- Improve color logger
|
||||
|
||||
|
||||
**@mdigger (Dmitry Sedykh)**
|
||||
- Fixes Form binding when content-type is x-www-form-urlencoded
|
||||
- No repeat call c.Writer.Status() in gin.Logger
|
||||
- Fixes Content-Type for json render
|
||||
|
||||
|
||||
**@mirzac (Mirza Ceric)**
|
||||
- Fix debug printing
|
||||
|
||||
|
||||
**@mopemope (Yutaka Matsubara)**
|
||||
- ★ Adds Godep support (Dependencies Manager)
|
||||
- Fix variadic parameter in the flexible render API
|
||||
- Fix Corrupted plain render
|
||||
- Add Pluggable View Renderer Example
|
||||
|
||||
|
||||
**@msemenistyi (Mykyta Semenistyi)**
|
||||
- update Readme.md. Add code to String method
|
||||
|
||||
|
||||
**@msoedov (Sasha Myasoedov)**
|
||||
- ★ Adds tons of unit tests.
|
||||
|
||||
|
||||
**@ngerakines (Nick Gerakines)**
|
||||
- ★ Improves API, c.GET() doesn't panic
|
||||
- Adds MustGet() method
|
||||
|
||||
|
||||
**@r8k (Rajiv Kilaparti)**
|
||||
- Fix Port usage in README.
|
||||
|
||||
|
||||
**@rayrod2030 (Ray Rodriguez)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@rns**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@RobAWilkinson (Robert Wilkinson)**
|
||||
- Add example of forms and params
|
||||
|
||||
|
||||
**@rogierlommers (Rogier Lommers)**
|
||||
- Add updated static serve example
|
||||
|
||||
|
||||
**@se77en (Damon Zhao)**
|
||||
- Improve color logging
|
||||
|
||||
|
||||
**@silasb (Silas Baronda)**
|
||||
- Fixing quotes in README
|
||||
|
||||
|
||||
**@SkuliOskarsson (Skuli Oskarsson)**
|
||||
- Fixes some texts in README II
|
||||
|
||||
|
||||
**@slimmy (Jimmy Pettersson)**
|
||||
- Added messages for required bindings
|
||||
|
||||
|
||||
**@smira (Andrey Smirnov)**
|
||||
- Add support for ignored/unexported fields in binding
|
||||
|
||||
|
||||
**@superalsrk (SRK.Lyu)**
|
||||
- Update httprouter godeps
|
||||
|
||||
|
||||
**@tebeka (Miki Tebeka)**
|
||||
- Use net/http constants instead of numeric values
|
||||
|
||||
|
||||
**@techjanitor**
|
||||
- Update context.go reserved IPs
|
||||
|
||||
|
||||
**@yosssi (Keiji Yoshida)**
|
||||
- Fix link in README
|
||||
|
||||
|
||||
**@yuyabee**
|
||||
- Fixed README
|
||||
604
backend/vendor/github.com/gin-gonic/gin/BENCHMARKS.md
generated
vendored
604
backend/vendor/github.com/gin-gonic/gin/BENCHMARKS.md
generated
vendored
@@ -1,604 +0,0 @@
|
||||
|
||||
## Benchmark System
|
||||
|
||||
**VM HOST:** DigitalOcean
|
||||
**Machine:** 4 CPU, 8 GB RAM. Ubuntu 16.04.2 x64
|
||||
**Date:** July 19th, 2017
|
||||
**Go Version:** 1.8.3 linux/amd64
|
||||
**Source:** [Go HTTP Router Benchmark](https://github.com/julienschmidt/go-http-routing-benchmark)
|
||||
|
||||
## Static Routes: 157
|
||||
|
||||
```
|
||||
Gin: 30512 Bytes
|
||||
|
||||
HttpServeMux: 17344 Bytes
|
||||
Ace: 30080 Bytes
|
||||
Bear: 30472 Bytes
|
||||
Beego: 96408 Bytes
|
||||
Bone: 37904 Bytes
|
||||
Denco: 10464 Bytes
|
||||
Echo: 73680 Bytes
|
||||
GocraftWeb: 55720 Bytes
|
||||
Goji: 27200 Bytes
|
||||
Gojiv2: 104464 Bytes
|
||||
GoJsonRest: 136472 Bytes
|
||||
GoRestful: 914904 Bytes
|
||||
GorillaMux: 675568 Bytes
|
||||
HttpRouter: 21128 Bytes
|
||||
HttpTreeMux: 73448 Bytes
|
||||
Kocha: 115072 Bytes
|
||||
LARS: 30120 Bytes
|
||||
Macaron: 37984 Bytes
|
||||
Martini: 310832 Bytes
|
||||
Pat: 20464 Bytes
|
||||
Possum: 91328 Bytes
|
||||
R2router: 23712 Bytes
|
||||
Rivet: 23880 Bytes
|
||||
Tango: 28008 Bytes
|
||||
TigerTonic: 80368 Bytes
|
||||
Traffic: 626480 Bytes
|
||||
Vulcan: 369064 Bytes
|
||||
```
|
||||
|
||||
## GithubAPI Routes: 203
|
||||
|
||||
```
|
||||
Gin: 52672 Bytes
|
||||
|
||||
Ace: 48992 Bytes
|
||||
Bear: 161592 Bytes
|
||||
Beego: 147992 Bytes
|
||||
Bone: 97728 Bytes
|
||||
Denco: 36440 Bytes
|
||||
Echo: 95672 Bytes
|
||||
GocraftWeb: 95640 Bytes
|
||||
Goji: 86088 Bytes
|
||||
Gojiv2: 144392 Bytes
|
||||
GoJsonRest: 134648 Bytes
|
||||
GoRestful: 1410760 Bytes
|
||||
GorillaMux: 1509488 Bytes
|
||||
HttpRouter: 37464 Bytes
|
||||
HttpTreeMux: 78800 Bytes
|
||||
Kocha: 785408 Bytes
|
||||
LARS: 49032 Bytes
|
||||
Macaron: 132712 Bytes
|
||||
Martini: 564352 Bytes
|
||||
Pat: 21200 Bytes
|
||||
Possum: 83888 Bytes
|
||||
R2router: 47104 Bytes
|
||||
Rivet: 42840 Bytes
|
||||
Tango: 54584 Bytes
|
||||
TigerTonic: 96384 Bytes
|
||||
Traffic: 1061920 Bytes
|
||||
Vulcan: 465296 Bytes
|
||||
```
|
||||
|
||||
## GPlusAPI Routes: 13
|
||||
|
||||
```
|
||||
Gin: 3968 Bytes
|
||||
|
||||
Ace: 3600 Bytes
|
||||
Bear: 7112 Bytes
|
||||
Beego: 10048 Bytes
|
||||
Bone: 6480 Bytes
|
||||
Denco: 3256 Bytes
|
||||
Echo: 9000 Bytes
|
||||
GocraftWeb: 7496 Bytes
|
||||
Goji: 2912 Bytes
|
||||
Gojiv2: 7376 Bytes
|
||||
GoJsonRest: 11544 Bytes
|
||||
GoRestful: 88776 Bytes
|
||||
GorillaMux: 71488 Bytes
|
||||
HttpRouter: 2712 Bytes
|
||||
HttpTreeMux: 7440 Bytes
|
||||
Kocha: 128880 Bytes
|
||||
LARS: 3640 Bytes
|
||||
Macaron: 8656 Bytes
|
||||
Martini: 23936 Bytes
|
||||
Pat: 1856 Bytes
|
||||
Possum: 7248 Bytes
|
||||
R2router: 3928 Bytes
|
||||
Rivet: 3064 Bytes
|
||||
Tango: 4912 Bytes
|
||||
TigerTonic: 9408 Bytes
|
||||
Traffic: 49472 Bytes
|
||||
Vulcan: 25496 Bytes
|
||||
```
|
||||
|
||||
## ParseAPI Routes: 26
|
||||
|
||||
```
|
||||
Gin: 6928 Bytes
|
||||
|
||||
Ace: 6592 Bytes
|
||||
Bear: 12320 Bytes
|
||||
Beego: 18960 Bytes
|
||||
Bone: 11024 Bytes
|
||||
Denco: 4184 Bytes
|
||||
Echo: 11168 Bytes
|
||||
GocraftWeb: 12800 Bytes
|
||||
Goji: 5232 Bytes
|
||||
Gojiv2: 14464 Bytes
|
||||
GoJsonRest: 14216 Bytes
|
||||
GoRestful: 127368 Bytes
|
||||
GorillaMux: 123016 Bytes
|
||||
HttpRouter: 4976 Bytes
|
||||
HttpTreeMux: 7848 Bytes
|
||||
Kocha: 181712 Bytes
|
||||
LARS: 6632 Bytes
|
||||
Macaron: 13648 Bytes
|
||||
Martini: 45952 Bytes
|
||||
Pat: 2560 Bytes
|
||||
Possum: 9200 Bytes
|
||||
R2router: 7056 Bytes
|
||||
Rivet: 5680 Bytes
|
||||
Tango: 8664 Bytes
|
||||
TigerTonic: 9840 Bytes
|
||||
Traffic: 93480 Bytes
|
||||
Vulcan: 44504 Bytes
|
||||
```
|
||||
|
||||
## Static Routes
|
||||
|
||||
```
|
||||
BenchmarkGin_StaticAll 50000 34506 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_StaticAll 30000 49657 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpServeMux_StaticAll 2000 1183737 ns/op 96 B/op 8 allocs/op
|
||||
BenchmarkBeego_StaticAll 5000 412621 ns/op 57776 B/op 628 allocs/op
|
||||
BenchmarkBear_StaticAll 10000 149242 ns/op 20336 B/op 461 allocs/op
|
||||
BenchmarkBone_StaticAll 10000 118583 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkDenco_StaticAll 100000 13247 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_StaticAll 20000 79914 ns/op 5024 B/op 157 allocs/op
|
||||
BenchmarkGocraftWeb_StaticAll 10000 211823 ns/op 46440 B/op 785 allocs/op
|
||||
BenchmarkGoji_StaticAll 10000 109390 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGojiv2_StaticAll 3000 415533 ns/op 145696 B/op 1099 allocs/op
|
||||
BenchmarkGoJsonRest_StaticAll 5000 364403 ns/op 51653 B/op 1727 allocs/op
|
||||
BenchmarkGoRestful_StaticAll 500 2578579 ns/op 314936 B/op 3144 allocs/op
|
||||
BenchmarkGorillaMux_StaticAll 500 2704856 ns/op 115648 B/op 1578 allocs/op
|
||||
BenchmarkHttpRouter_StaticAll 100000 18541 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_StaticAll 100000 22332 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_StaticAll 50000 31176 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkLARS_StaticAll 50000 40840 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_StaticAll 5000 517656 ns/op 120576 B/op 1413 allocs/op
|
||||
BenchmarkMartini_StaticAll 300 4462289 ns/op 125442 B/op 1717 allocs/op
|
||||
BenchmarkPat_StaticAll 500 2157275 ns/op 533904 B/op 11123 allocs/op
|
||||
BenchmarkPossum_StaticAll 10000 254701 ns/op 65312 B/op 471 allocs/op
|
||||
BenchmarkR2router_StaticAll 10000 133956 ns/op 22608 B/op 628 allocs/op
|
||||
BenchmarkRivet_StaticAll 30000 46812 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkTango_StaticAll 5000 390613 ns/op 39225 B/op 1256 allocs/op
|
||||
BenchmarkTigerTonic_StaticAll 20000 88060 ns/op 7504 B/op 157 allocs/op
|
||||
BenchmarkTraffic_StaticAll 500 2910236 ns/op 729736 B/op 14287 allocs/op
|
||||
BenchmarkVulcan_StaticAll 5000 277366 ns/op 15386 B/op 471 allocs/op
|
||||
```
|
||||
|
||||
## Micro Benchmarks
|
||||
|
||||
```
|
||||
BenchmarkGin_Param 20000000 113 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_Param 5000000 375 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkBear_Param 1000000 1709 ns/op 456 B/op 5 allocs/op
|
||||
BenchmarkBeego_Param 1000000 2484 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_Param 1000000 2391 ns/op 688 B/op 5 allocs/op
|
||||
BenchmarkDenco_Param 10000000 240 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkEcho_Param 5000000 366 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGocraftWeb_Param 1000000 2343 ns/op 648 B/op 8 allocs/op
|
||||
BenchmarkGoji_Param 1000000 1197 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_Param 1000000 2771 ns/op 944 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_Param 1000000 2993 ns/op 649 B/op 13 allocs/op
|
||||
BenchmarkGoRestful_Param 200000 8860 ns/op 2296 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_Param 500000 4461 ns/op 1056 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_Param 10000000 175 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Param 1000000 1167 ns/op 352 B/op 3 allocs/op
|
||||
BenchmarkKocha_Param 3000000 429 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkLARS_Param 10000000 134 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_Param 500000 4635 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_Param 200000 9933 ns/op 1072 B/op 10 allocs/op
|
||||
BenchmarkPat_Param 1000000 2929 ns/op 648 B/op 12 allocs/op
|
||||
BenchmarkPossum_Param 1000000 2503 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_Param 1000000 1507 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_Param 5000000 297 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTango_Param 1000000 1862 ns/op 248 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_Param 500000 5660 ns/op 992 B/op 17 allocs/op
|
||||
BenchmarkTraffic_Param 200000 8408 ns/op 1960 B/op 21 allocs/op
|
||||
BenchmarkVulcan_Param 2000000 963 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_Param5 2000000 740 ns/op 160 B/op 1 allocs/op
|
||||
BenchmarkBear_Param5 1000000 2777 ns/op 501 B/op 5 allocs/op
|
||||
BenchmarkBeego_Param5 1000000 3740 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_Param5 1000000 2950 ns/op 736 B/op 5 allocs/op
|
||||
BenchmarkDenco_Param5 2000000 644 ns/op 160 B/op 1 allocs/op
|
||||
BenchmarkEcho_Param5 3000000 558 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_Param5 10000000 198 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_Param5 500000 3870 ns/op 920 B/op 11 allocs/op
|
||||
BenchmarkGoji_Param5 1000000 1746 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_Param5 1000000 3214 ns/op 1008 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_Param5 500000 5509 ns/op 1097 B/op 16 allocs/op
|
||||
BenchmarkGoRestful_Param5 200000 11232 ns/op 2392 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_Param5 300000 7777 ns/op 1184 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_Param5 3000000 631 ns/op 160 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Param5 1000000 2800 ns/op 576 B/op 6 allocs/op
|
||||
BenchmarkKocha_Param5 1000000 2053 ns/op 440 B/op 10 allocs/op
|
||||
BenchmarkLARS_Param5 10000000 232 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_Param5 500000 5888 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_Param5 200000 12807 ns/op 1232 B/op 11 allocs/op
|
||||
BenchmarkPat_Param5 300000 7320 ns/op 964 B/op 32 allocs/op
|
||||
BenchmarkPossum_Param5 1000000 2495 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_Param5 1000000 1844 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_Param5 2000000 935 ns/op 240 B/op 1 allocs/op
|
||||
BenchmarkTango_Param5 1000000 2327 ns/op 360 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_Param5 100000 18514 ns/op 2551 B/op 43 allocs/op
|
||||
BenchmarkTraffic_Param5 200000 11997 ns/op 2248 B/op 25 allocs/op
|
||||
BenchmarkVulcan_Param5 1000000 1333 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_Param20 1000000 2031 ns/op 640 B/op 1 allocs/op
|
||||
BenchmarkBear_Param20 200000 7285 ns/op 1664 B/op 5 allocs/op
|
||||
BenchmarkBeego_Param20 300000 6224 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_Param20 200000 8023 ns/op 1903 B/op 5 allocs/op
|
||||
BenchmarkDenco_Param20 1000000 2262 ns/op 640 B/op 1 allocs/op
|
||||
BenchmarkEcho_Param20 1000000 1387 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_Param20 3000000 503 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_Param20 100000 14408 ns/op 3795 B/op 15 allocs/op
|
||||
BenchmarkGoji_Param20 500000 5272 ns/op 1247 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_Param20 1000000 4163 ns/op 1248 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_Param20 100000 17866 ns/op 4485 B/op 20 allocs/op
|
||||
BenchmarkGoRestful_Param20 100000 21022 ns/op 4724 B/op 23 allocs/op
|
||||
BenchmarkGorillaMux_Param20 100000 17055 ns/op 3547 B/op 13 allocs/op
|
||||
BenchmarkHttpRouter_Param20 1000000 1748 ns/op 640 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Param20 200000 12246 ns/op 3196 B/op 10 allocs/op
|
||||
BenchmarkKocha_Param20 300000 6861 ns/op 1808 B/op 27 allocs/op
|
||||
BenchmarkLARS_Param20 3000000 526 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_Param20 100000 13069 ns/op 2906 B/op 12 allocs/op
|
||||
BenchmarkMartini_Param20 100000 23602 ns/op 3597 B/op 13 allocs/op
|
||||
BenchmarkPat_Param20 50000 32143 ns/op 4688 B/op 111 allocs/op
|
||||
BenchmarkPossum_Param20 1000000 2396 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_Param20 200000 8907 ns/op 2283 B/op 7 allocs/op
|
||||
BenchmarkRivet_Param20 1000000 3280 ns/op 1024 B/op 1 allocs/op
|
||||
BenchmarkTango_Param20 500000 4640 ns/op 856 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_Param20 20000 67581 ns/op 10532 B/op 138 allocs/op
|
||||
BenchmarkTraffic_Param20 50000 40313 ns/op 7941 B/op 45 allocs/op
|
||||
BenchmarkVulcan_Param20 1000000 2264 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_ParamWrite 3000000 532 ns/op 40 B/op 2 allocs/op
|
||||
BenchmarkBear_ParamWrite 1000000 1778 ns/op 456 B/op 5 allocs/op
|
||||
BenchmarkBeego_ParamWrite 1000000 2596 ns/op 376 B/op 5 allocs/op
|
||||
BenchmarkBone_ParamWrite 1000000 2519 ns/op 688 B/op 5 allocs/op
|
||||
BenchmarkDenco_ParamWrite 5000000 411 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkEcho_ParamWrite 2000000 718 ns/op 40 B/op 2 allocs/op
|
||||
BenchmarkGin_ParamWrite 5000000 283 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_ParamWrite 1000000 2561 ns/op 656 B/op 9 allocs/op
|
||||
BenchmarkGoji_ParamWrite 1000000 1378 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_ParamWrite 1000000 3128 ns/op 976 B/op 10 allocs/op
|
||||
BenchmarkGoJsonRest_ParamWrite 500000 4446 ns/op 1128 B/op 18 allocs/op
|
||||
BenchmarkGoRestful_ParamWrite 200000 10291 ns/op 2304 B/op 22 allocs/op
|
||||
BenchmarkGorillaMux_ParamWrite 500000 5153 ns/op 1064 B/op 12 allocs/op
|
||||
BenchmarkHttpRouter_ParamWrite 5000000 263 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_ParamWrite 1000000 1351 ns/op 352 B/op 3 allocs/op
|
||||
BenchmarkKocha_ParamWrite 3000000 538 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkLARS_ParamWrite 5000000 316 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_ParamWrite 500000 5756 ns/op 1160 B/op 14 allocs/op
|
||||
BenchmarkMartini_ParamWrite 200000 13097 ns/op 1176 B/op 14 allocs/op
|
||||
BenchmarkPat_ParamWrite 500000 4954 ns/op 1072 B/op 17 allocs/op
|
||||
BenchmarkPossum_ParamWrite 1000000 2499 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_ParamWrite 1000000 1531 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_ParamWrite 3000000 570 ns/op 112 B/op 2 allocs/op
|
||||
BenchmarkTango_ParamWrite 2000000 957 ns/op 136 B/op 4 allocs/op
|
||||
BenchmarkTigerTonic_ParamWrite 200000 7025 ns/op 1424 B/op 23 allocs/op
|
||||
BenchmarkTraffic_ParamWrite 200000 10112 ns/op 2384 B/op 25 allocs/op
|
||||
BenchmarkVulcan_ParamWrite 1000000 1006 ns/op 98 B/op 3 allocs/op
|
||||
```
|
||||
|
||||
## GitHub
|
||||
|
||||
```
|
||||
BenchmarkGin_GithubStatic 10000000 156 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_GithubStatic 5000000 294 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBear_GithubStatic 2000000 893 ns/op 120 B/op 3 allocs/op
|
||||
BenchmarkBeego_GithubStatic 1000000 2491 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GithubStatic 50000 25300 ns/op 2880 B/op 60 allocs/op
|
||||
BenchmarkDenco_GithubStatic 20000000 76.0 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_GithubStatic 2000000 516 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGocraftWeb_GithubStatic 1000000 1448 ns/op 296 B/op 5 allocs/op
|
||||
BenchmarkGoji_GithubStatic 3000000 496 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGojiv2_GithubStatic 1000000 2941 ns/op 928 B/op 7 allocs/op
|
||||
BenchmarkGoRestful_GithubStatic 100000 27256 ns/op 3224 B/op 22 allocs/op
|
||||
BenchmarkGoJsonRest_GithubStatic 1000000 2196 ns/op 329 B/op 11 allocs/op
|
||||
BenchmarkGorillaMux_GithubStatic 50000 31617 ns/op 736 B/op 10 allocs/op
|
||||
BenchmarkHttpRouter_GithubStatic 20000000 88.4 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_GithubStatic 10000000 134 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_GithubStatic 20000000 113 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkLARS_GithubStatic 10000000 195 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GithubStatic 500000 3740 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkMartini_GithubStatic 50000 27673 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkPat_GithubStatic 100000 19470 ns/op 3648 B/op 76 allocs/op
|
||||
BenchmarkPossum_GithubStatic 1000000 1729 ns/op 416 B/op 3 allocs/op
|
||||
BenchmarkR2router_GithubStatic 2000000 879 ns/op 144 B/op 4 allocs/op
|
||||
BenchmarkRivet_GithubStatic 10000000 231 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkTango_GithubStatic 1000000 2325 ns/op 248 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GithubStatic 3000000 610 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTraffic_GithubStatic 20000 62973 ns/op 18904 B/op 148 allocs/op
|
||||
BenchmarkVulcan_GithubStatic 1000000 1447 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GithubParam 2000000 686 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkBear_GithubParam 1000000 2155 ns/op 496 B/op 5 allocs/op
|
||||
BenchmarkBeego_GithubParam 1000000 2713 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GithubParam 100000 15088 ns/op 1760 B/op 18 allocs/op
|
||||
BenchmarkDenco_GithubParam 2000000 629 ns/op 128 B/op 1 allocs/op
|
||||
BenchmarkEcho_GithubParam 2000000 653 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_GithubParam 5000000 255 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GithubParam 1000000 3145 ns/op 712 B/op 9 allocs/op
|
||||
BenchmarkGoji_GithubParam 1000000 1916 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_GithubParam 1000000 3975 ns/op 1024 B/op 10 allocs/op
|
||||
BenchmarkGoJsonRest_GithubParam 300000 4134 ns/op 713 B/op 14 allocs/op
|
||||
BenchmarkGoRestful_GithubParam 50000 30782 ns/op 2360 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_GithubParam 100000 17148 ns/op 1088 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_GithubParam 3000000 523 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_GithubParam 1000000 1671 ns/op 384 B/op 4 allocs/op
|
||||
BenchmarkKocha_GithubParam 1000000 1021 ns/op 128 B/op 5 allocs/op
|
||||
BenchmarkLARS_GithubParam 5000000 283 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GithubParam 500000 4270 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_GithubParam 100000 21728 ns/op 1152 B/op 11 allocs/op
|
||||
BenchmarkPat_GithubParam 200000 11208 ns/op 2464 B/op 48 allocs/op
|
||||
BenchmarkPossum_GithubParam 1000000 2334 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_GithubParam 1000000 1487 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_GithubParam 2000000 782 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkTango_GithubParam 1000000 2653 ns/op 344 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GithubParam 300000 14073 ns/op 1440 B/op 24 allocs/op
|
||||
BenchmarkTraffic_GithubParam 50000 29164 ns/op 5992 B/op 52 allocs/op
|
||||
BenchmarkVulcan_GithubParam 1000000 2529 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GithubAll 10000 134059 ns/op 13792 B/op 167 allocs/op
|
||||
BenchmarkBear_GithubAll 5000 534445 ns/op 86448 B/op 943 allocs/op
|
||||
BenchmarkBeego_GithubAll 3000 592444 ns/op 74705 B/op 812 allocs/op
|
||||
BenchmarkBone_GithubAll 200 6957308 ns/op 698784 B/op 8453 allocs/op
|
||||
BenchmarkDenco_GithubAll 10000 158819 ns/op 20224 B/op 167 allocs/op
|
||||
BenchmarkEcho_GithubAll 10000 154700 ns/op 6496 B/op 203 allocs/op
|
||||
BenchmarkGin_GithubAll 30000 48375 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GithubAll 3000 570806 ns/op 131656 B/op 1686 allocs/op
|
||||
BenchmarkGoji_GithubAll 2000 818034 ns/op 56112 B/op 334 allocs/op
|
||||
BenchmarkGojiv2_GithubAll 2000 1213973 ns/op 274768 B/op 3712 allocs/op
|
||||
BenchmarkGoJsonRest_GithubAll 2000 785796 ns/op 134371 B/op 2737 allocs/op
|
||||
BenchmarkGoRestful_GithubAll 300 5238188 ns/op 689672 B/op 4519 allocs/op
|
||||
BenchmarkGorillaMux_GithubAll 100 10257726 ns/op 211840 B/op 2272 allocs/op
|
||||
BenchmarkHttpRouter_GithubAll 20000 105414 ns/op 13792 B/op 167 allocs/op
|
||||
BenchmarkHttpTreeMux_GithubAll 10000 319934 ns/op 65856 B/op 671 allocs/op
|
||||
BenchmarkKocha_GithubAll 10000 209442 ns/op 23304 B/op 843 allocs/op
|
||||
BenchmarkLARS_GithubAll 20000 62565 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GithubAll 2000 1161270 ns/op 204194 B/op 2000 allocs/op
|
||||
BenchmarkMartini_GithubAll 200 9991713 ns/op 226549 B/op 2325 allocs/op
|
||||
BenchmarkPat_GithubAll 200 5590793 ns/op 1499568 B/op 27435 allocs/op
|
||||
BenchmarkPossum_GithubAll 10000 319768 ns/op 84448 B/op 609 allocs/op
|
||||
BenchmarkR2router_GithubAll 10000 305134 ns/op 77328 B/op 979 allocs/op
|
||||
BenchmarkRivet_GithubAll 10000 132134 ns/op 16272 B/op 167 allocs/op
|
||||
BenchmarkTango_GithubAll 3000 552754 ns/op 63826 B/op 1618 allocs/op
|
||||
BenchmarkTigerTonic_GithubAll 1000 1439483 ns/op 239104 B/op 5374 allocs/op
|
||||
BenchmarkTraffic_GithubAll 100 11383067 ns/op 2659329 B/op 21848 allocs/op
|
||||
BenchmarkVulcan_GithubAll 5000 394253 ns/op 19894 B/op 609 allocs/op
|
||||
```
|
||||
|
||||
## Google+
|
||||
|
||||
```
|
||||
BenchmarkGin_GPlusStatic 10000000 183 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_GPlusStatic 5000000 276 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBear_GPlusStatic 2000000 652 ns/op 104 B/op 3 allocs/op
|
||||
BenchmarkBeego_GPlusStatic 1000000 2239 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GPlusStatic 5000000 380 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkDenco_GPlusStatic 30000000 45.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_GPlusStatic 5000000 338 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGocraftWeb_GPlusStatic 1000000 1158 ns/op 280 B/op 5 allocs/op
|
||||
BenchmarkGoji_GPlusStatic 5000000 331 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGojiv2_GPlusStatic 1000000 2106 ns/op 928 B/op 7 allocs/op
|
||||
BenchmarkGoJsonRest_GPlusStatic 1000000 1626 ns/op 329 B/op 11 allocs/op
|
||||
BenchmarkGoRestful_GPlusStatic 300000 7598 ns/op 1976 B/op 20 allocs/op
|
||||
BenchmarkGorillaMux_GPlusStatic 1000000 2629 ns/op 736 B/op 10 allocs/op
|
||||
BenchmarkHttpRouter_GPlusStatic 30000000 52.5 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlusStatic 20000000 85.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_GPlusStatic 20000000 89.2 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkLARS_GPlusStatic 10000000 162 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GPlusStatic 500000 3479 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkMartini_GPlusStatic 200000 9092 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkPat_GPlusStatic 3000000 493 ns/op 96 B/op 2 allocs/op
|
||||
BenchmarkPossum_GPlusStatic 1000000 1467 ns/op 416 B/op 3 allocs/op
|
||||
BenchmarkR2router_GPlusStatic 2000000 788 ns/op 144 B/op 4 allocs/op
|
||||
BenchmarkRivet_GPlusStatic 20000000 114 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkTango_GPlusStatic 1000000 1534 ns/op 200 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GPlusStatic 5000000 282 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkTraffic_GPlusStatic 500000 3798 ns/op 1192 B/op 15 allocs/op
|
||||
BenchmarkVulcan_GPlusStatic 2000000 1125 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GPlusParam 3000000 528 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_GPlusParam 1000000 1570 ns/op 480 B/op 5 allocs/op
|
||||
BenchmarkBeego_GPlusParam 1000000 2369 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GPlusParam 1000000 2028 ns/op 688 B/op 5 allocs/op
|
||||
BenchmarkDenco_GPlusParam 5000000 385 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_GPlusParam 3000000 441 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_GPlusParam 10000000 174 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlusParam 1000000 2033 ns/op 648 B/op 8 allocs/op
|
||||
BenchmarkGoji_GPlusParam 1000000 1399 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_GPlusParam 1000000 2641 ns/op 944 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_GPlusParam 1000000 2824 ns/op 649 B/op 13 allocs/op
|
||||
BenchmarkGoRestful_GPlusParam 200000 8875 ns/op 2296 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_GPlusParam 200000 6291 ns/op 1056 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_GPlusParam 5000000 316 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlusParam 1000000 1129 ns/op 352 B/op 3 allocs/op
|
||||
BenchmarkKocha_GPlusParam 3000000 538 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkLARS_GPlusParam 10000000 198 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GPlusParam 500000 3554 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_GPlusParam 200000 9831 ns/op 1072 B/op 10 allocs/op
|
||||
BenchmarkPat_GPlusParam 1000000 2706 ns/op 688 B/op 12 allocs/op
|
||||
BenchmarkPossum_GPlusParam 1000000 2297 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_GPlusParam 1000000 1318 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_GPlusParam 5000000 399 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTango_GPlusParam 1000000 2070 ns/op 264 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GPlusParam 500000 4853 ns/op 1056 B/op 17 allocs/op
|
||||
BenchmarkTraffic_GPlusParam 200000 8278 ns/op 1976 B/op 21 allocs/op
|
||||
BenchmarkVulcan_GPlusParam 1000000 1243 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GPlus2Params 3000000 549 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_GPlus2Params 1000000 2112 ns/op 496 B/op 5 allocs/op
|
||||
BenchmarkBeego_GPlus2Params 500000 2750 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GPlus2Params 300000 7032 ns/op 1040 B/op 9 allocs/op
|
||||
BenchmarkDenco_GPlus2Params 3000000 502 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_GPlus2Params 3000000 641 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_GPlus2Params 5000000 250 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlus2Params 1000000 2681 ns/op 712 B/op 9 allocs/op
|
||||
BenchmarkGoji_GPlus2Params 1000000 1926 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_GPlus2Params 500000 3996 ns/op 1024 B/op 11 allocs/op
|
||||
BenchmarkGoJsonRest_GPlus2Params 500000 3886 ns/op 713 B/op 14 allocs/op
|
||||
BenchmarkGoRestful_GPlus2Params 200000 10376 ns/op 2360 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_GPlus2Params 100000 14162 ns/op 1088 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_GPlus2Params 5000000 336 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlus2Params 1000000 1523 ns/op 384 B/op 4 allocs/op
|
||||
BenchmarkKocha_GPlus2Params 2000000 970 ns/op 128 B/op 5 allocs/op
|
||||
BenchmarkLARS_GPlus2Params 5000000 238 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GPlus2Params 500000 4016 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_GPlus2Params 100000 21253 ns/op 1200 B/op 13 allocs/op
|
||||
BenchmarkPat_GPlus2Params 200000 8632 ns/op 2256 B/op 34 allocs/op
|
||||
BenchmarkPossum_GPlus2Params 1000000 2171 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_GPlus2Params 1000000 1340 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_GPlus2Params 3000000 557 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkTango_GPlus2Params 1000000 2186 ns/op 344 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GPlus2Params 200000 9060 ns/op 1488 B/op 24 allocs/op
|
||||
BenchmarkTraffic_GPlus2Params 100000 20324 ns/op 3272 B/op 31 allocs/op
|
||||
BenchmarkVulcan_GPlus2Params 1000000 2039 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GPlusAll 300000 6603 ns/op 640 B/op 11 allocs/op
|
||||
BenchmarkBear_GPlusAll 100000 22363 ns/op 5488 B/op 61 allocs/op
|
||||
BenchmarkBeego_GPlusAll 50000 38757 ns/op 4784 B/op 52 allocs/op
|
||||
BenchmarkBone_GPlusAll 20000 54916 ns/op 10336 B/op 98 allocs/op
|
||||
BenchmarkDenco_GPlusAll 300000 4959 ns/op 672 B/op 11 allocs/op
|
||||
BenchmarkEcho_GPlusAll 200000 6558 ns/op 416 B/op 13 allocs/op
|
||||
BenchmarkGin_GPlusAll 500000 2757 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlusAll 50000 34615 ns/op 8040 B/op 103 allocs/op
|
||||
BenchmarkGoji_GPlusAll 100000 16002 ns/op 3696 B/op 22 allocs/op
|
||||
BenchmarkGojiv2_GPlusAll 50000 35060 ns/op 12624 B/op 115 allocs/op
|
||||
BenchmarkGoJsonRest_GPlusAll 50000 41479 ns/op 8117 B/op 170 allocs/op
|
||||
BenchmarkGoRestful_GPlusAll 10000 131653 ns/op 32024 B/op 275 allocs/op
|
||||
BenchmarkGorillaMux_GPlusAll 10000 101380 ns/op 13296 B/op 142 allocs/op
|
||||
BenchmarkHttpRouter_GPlusAll 500000 3711 ns/op 640 B/op 11 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlusAll 100000 14438 ns/op 4032 B/op 38 allocs/op
|
||||
BenchmarkKocha_GPlusAll 200000 8039 ns/op 976 B/op 43 allocs/op
|
||||
BenchmarkLARS_GPlusAll 500000 2630 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GPlusAll 30000 51123 ns/op 13152 B/op 128 allocs/op
|
||||
BenchmarkMartini_GPlusAll 10000 176157 ns/op 14016 B/op 145 allocs/op
|
||||
BenchmarkPat_GPlusAll 20000 69911 ns/op 16576 B/op 298 allocs/op
|
||||
BenchmarkPossum_GPlusAll 100000 20716 ns/op 5408 B/op 39 allocs/op
|
||||
BenchmarkR2router_GPlusAll 100000 17463 ns/op 5040 B/op 63 allocs/op
|
||||
BenchmarkRivet_GPlusAll 300000 5142 ns/op 768 B/op 11 allocs/op
|
||||
BenchmarkTango_GPlusAll 50000 27321 ns/op 3656 B/op 104 allocs/op
|
||||
BenchmarkTigerTonic_GPlusAll 20000 77597 ns/op 14512 B/op 288 allocs/op
|
||||
BenchmarkTraffic_GPlusAll 10000 151406 ns/op 37360 B/op 392 allocs/op
|
||||
BenchmarkVulcan_GPlusAll 100000 18555 ns/op 1274 B/op 39 allocs/op
|
||||
```
|
||||
|
||||
## Parse.com
|
||||
|
||||
```
|
||||
BenchmarkGin_ParseStatic 10000000 133 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_ParseStatic 5000000 241 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBear_ParseStatic 2000000 728 ns/op 120 B/op 3 allocs/op
|
||||
BenchmarkBeego_ParseStatic 1000000 2623 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_ParseStatic 1000000 1285 ns/op 144 B/op 3 allocs/op
|
||||
BenchmarkDenco_ParseStatic 30000000 57.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_ParseStatic 5000000 342 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGocraftWeb_ParseStatic 1000000 1478 ns/op 296 B/op 5 allocs/op
|
||||
BenchmarkGoji_ParseStatic 3000000 415 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGojiv2_ParseStatic 1000000 2087 ns/op 928 B/op 7 allocs/op
|
||||
BenchmarkGoJsonRest_ParseStatic 1000000 1712 ns/op 329 B/op 11 allocs/op
|
||||
BenchmarkGoRestful_ParseStatic 200000 11072 ns/op 3224 B/op 22 allocs/op
|
||||
BenchmarkGorillaMux_ParseStatic 500000 4129 ns/op 752 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_ParseStatic 30000000 52.4 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_ParseStatic 20000000 109 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_ParseStatic 20000000 81.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkLARS_ParseStatic 10000000 150 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_ParseStatic 1000000 3288 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkMartini_ParseStatic 200000 9110 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkPat_ParseStatic 1000000 1135 ns/op 240 B/op 5 allocs/op
|
||||
BenchmarkPossum_ParseStatic 1000000 1557 ns/op 416 B/op 3 allocs/op
|
||||
BenchmarkR2router_ParseStatic 2000000 730 ns/op 144 B/op 4 allocs/op
|
||||
BenchmarkRivet_ParseStatic 10000000 121 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkTango_ParseStatic 1000000 1688 ns/op 248 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_ParseStatic 3000000 427 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTraffic_ParseStatic 500000 5962 ns/op 1816 B/op 20 allocs/op
|
||||
BenchmarkVulcan_ParseStatic 2000000 969 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_ParseParam 3000000 497 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_ParseParam 1000000 1473 ns/op 467 B/op 5 allocs/op
|
||||
BenchmarkBeego_ParseParam 1000000 2384 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_ParseParam 1000000 2513 ns/op 768 B/op 6 allocs/op
|
||||
BenchmarkDenco_ParseParam 5000000 364 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_ParseParam 5000000 418 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_ParseParam 10000000 163 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_ParseParam 1000000 2361 ns/op 664 B/op 8 allocs/op
|
||||
BenchmarkGoji_ParseParam 1000000 1590 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_ParseParam 1000000 2851 ns/op 976 B/op 9 allocs/op
|
||||
BenchmarkGoJsonRest_ParseParam 1000000 2965 ns/op 649 B/op 13 allocs/op
|
||||
BenchmarkGoRestful_ParseParam 200000 12207 ns/op 3544 B/op 23 allocs/op
|
||||
BenchmarkGorillaMux_ParseParam 500000 5187 ns/op 1088 B/op 12 allocs/op
|
||||
BenchmarkHttpRouter_ParseParam 5000000 275 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_ParseParam 1000000 1108 ns/op 352 B/op 3 allocs/op
|
||||
BenchmarkKocha_ParseParam 3000000 495 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkLARS_ParseParam 10000000 192 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_ParseParam 500000 4103 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_ParseParam 200000 9878 ns/op 1072 B/op 10 allocs/op
|
||||
BenchmarkPat_ParseParam 500000 3657 ns/op 1120 B/op 17 allocs/op
|
||||
BenchmarkPossum_ParseParam 1000000 2084 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_ParseParam 1000000 1251 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_ParseParam 5000000 335 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTango_ParseParam 1000000 1854 ns/op 280 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_ParseParam 500000 4582 ns/op 1008 B/op 17 allocs/op
|
||||
BenchmarkTraffic_ParseParam 200000 8125 ns/op 2248 B/op 23 allocs/op
|
||||
BenchmarkVulcan_ParseParam 1000000 1148 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_Parse2Params 3000000 539 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_Parse2Params 1000000 1778 ns/op 496 B/op 5 allocs/op
|
||||
BenchmarkBeego_Parse2Params 1000000 2519 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_Parse2Params 1000000 2596 ns/op 720 B/op 5 allocs/op
|
||||
BenchmarkDenco_Parse2Params 3000000 492 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_Parse2Params 3000000 484 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_Parse2Params 10000000 193 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_Parse2Params 1000000 2575 ns/op 712 B/op 9 allocs/op
|
||||
BenchmarkGoji_Parse2Params 1000000 1373 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_Parse2Params 500000 2416 ns/op 960 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_Parse2Params 300000 3452 ns/op 713 B/op 14 allocs/op
|
||||
BenchmarkGoRestful_Parse2Params 100000 17719 ns/op 6008 B/op 25 allocs/op
|
||||
BenchmarkGorillaMux_Parse2Params 300000 5102 ns/op 1088 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_Parse2Params 5000000 303 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Parse2Params 1000000 1372 ns/op 384 B/op 4 allocs/op
|
||||
BenchmarkKocha_Parse2Params 2000000 874 ns/op 128 B/op 5 allocs/op
|
||||
BenchmarkLARS_Parse2Params 10000000 192 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_Parse2Params 500000 3871 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_Parse2Params 200000 9954 ns/op 1152 B/op 11 allocs/op
|
||||
BenchmarkPat_Parse2Params 500000 4194 ns/op 832 B/op 17 allocs/op
|
||||
BenchmarkPossum_Parse2Params 1000000 2121 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_Parse2Params 1000000 1415 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_Parse2Params 3000000 457 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkTango_Parse2Params 1000000 1914 ns/op 312 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_Parse2Params 300000 6895 ns/op 1408 B/op 24 allocs/op
|
||||
BenchmarkTraffic_Parse2Params 200000 8317 ns/op 2040 B/op 22 allocs/op
|
||||
BenchmarkVulcan_Parse2Params 1000000 1274 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_ParseAll 200000 10401 ns/op 640 B/op 16 allocs/op
|
||||
BenchmarkBear_ParseAll 50000 37743 ns/op 8928 B/op 110 allocs/op
|
||||
BenchmarkBeego_ParseAll 20000 63193 ns/op 9568 B/op 104 allocs/op
|
||||
BenchmarkBone_ParseAll 20000 61767 ns/op 14160 B/op 131 allocs/op
|
||||
BenchmarkDenco_ParseAll 300000 7036 ns/op 928 B/op 16 allocs/op
|
||||
BenchmarkEcho_ParseAll 200000 11824 ns/op 832 B/op 26 allocs/op
|
||||
BenchmarkGin_ParseAll 300000 4199 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_ParseAll 30000 51758 ns/op 13728 B/op 181 allocs/op
|
||||
BenchmarkGoji_ParseAll 50000 29614 ns/op 5376 B/op 32 allocs/op
|
||||
BenchmarkGojiv2_ParseAll 20000 68676 ns/op 24464 B/op 199 allocs/op
|
||||
BenchmarkGoJsonRest_ParseAll 20000 76135 ns/op 13866 B/op 321 allocs/op
|
||||
BenchmarkGoRestful_ParseAll 5000 389487 ns/op 110928 B/op 600 allocs/op
|
||||
BenchmarkGorillaMux_ParseAll 10000 221250 ns/op 24864 B/op 292 allocs/op
|
||||
BenchmarkHttpRouter_ParseAll 200000 6444 ns/op 640 B/op 16 allocs/op
|
||||
BenchmarkHttpTreeMux_ParseAll 50000 30702 ns/op 5728 B/op 51 allocs/op
|
||||
BenchmarkKocha_ParseAll 200000 13712 ns/op 1112 B/op 54 allocs/op
|
||||
BenchmarkLARS_ParseAll 300000 6925 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_ParseAll 20000 96278 ns/op 24576 B/op 250 allocs/op
|
||||
BenchmarkMartini_ParseAll 5000 271352 ns/op 25072 B/op 253 allocs/op
|
||||
BenchmarkPat_ParseAll 20000 74941 ns/op 17264 B/op 343 allocs/op
|
||||
BenchmarkPossum_ParseAll 50000 39947 ns/op 10816 B/op 78 allocs/op
|
||||
BenchmarkR2router_ParseAll 50000 42479 ns/op 8352 B/op 120 allocs/op
|
||||
BenchmarkRivet_ParseAll 200000 7726 ns/op 912 B/op 16 allocs/op
|
||||
BenchmarkTango_ParseAll 30000 50014 ns/op 7168 B/op 208 allocs/op
|
||||
BenchmarkTigerTonic_ParseAll 10000 106550 ns/op 19728 B/op 379 allocs/op
|
||||
BenchmarkTraffic_ParseAll 10000 216037 ns/op 57776 B/op 642 allocs/op
|
||||
BenchmarkVulcan_ParseAll 50000 34379 ns/op 2548 B/op 78 allocs/op
|
||||
```
|
||||
269
backend/vendor/github.com/gin-gonic/gin/CHANGELOG.md
generated
vendored
269
backend/vendor/github.com/gin-gonic/gin/CHANGELOG.md
generated
vendored
@@ -1,269 +0,0 @@
|
||||
|
||||
### Gin 1.4.0
|
||||
|
||||
- [NEW] Support for [Go Modules](https://github.com/golang/go/wiki/Modules) [#1569](https://github.com/gin-gonic/gin/pull/1569)
|
||||
- [NEW] Refactor of form mapping multipart requesta [#1829](https://github.com/gin-gonic/gin/pull/1829)
|
||||
- [FIX] Truncate Latency precision in long running request [#1830](https://github.com/gin-gonic/gin/pull/1830)
|
||||
- [FIX] IsTerm flag should not be affected by DisableConsoleColor method. [#1802](https://github.com/gin-gonic/gin/pull/1802)
|
||||
- [NEW] Supporting file binding [#1264](https://github.com/gin-gonic/gin/pull/1264)
|
||||
- [NEW] Add support for mapping arrays [#1797](https://github.com/gin-gonic/gin/pull/1797)
|
||||
- [FIX] Readme updates [#1793](https://github.com/gin-gonic/gin/pull/1793) [#1788](https://github.com/gin-gonic/gin/pull/1788) [1789](https://github.com/gin-gonic/gin/pull/1789)
|
||||
- [FIX] StaticFS: Fixed Logging two log lines on 404. [#1805](https://github.com/gin-gonic/gin/pull/1805), [#1804](https://github.com/gin-gonic/gin/pull/1804)
|
||||
- [NEW] Make context.Keys available as LogFormatterParams [#1779](https://github.com/gin-gonic/gin/pull/1779)
|
||||
- [NEW] Use internal/json for Marshal/Unmarshal [#1791](https://github.com/gin-gonic/gin/pull/1791)
|
||||
- [NEW] Support mapping time.Duration [#1794](https://github.com/gin-gonic/gin/pull/1794)
|
||||
- [NEW] Refactor form mappings [#1749](https://github.com/gin-gonic/gin/pull/1749)
|
||||
- [NEW] Added flag to context.Stream indicates if client disconnected in middle of stream [#1252](https://github.com/gin-gonic/gin/pull/1252)
|
||||
- [FIX] Moved [examples](https://github.com/gin-gonic/examples) to stand alone Repo [#1775](https://github.com/gin-gonic/gin/pull/1775)
|
||||
- [NEW] Extend context.File to allow for the content-dispositon attachments via a new method context.Attachment [#1260](https://github.com/gin-gonic/gin/pull/1260)
|
||||
- [FIX] Support HTTP content negotiation wildcards [#1112](https://github.com/gin-gonic/gin/pull/1112)
|
||||
- [NEW] Add prefix from X-Forwarded-Prefix in redirectTrailingSlash [#1238](https://github.com/gin-gonic/gin/pull/1238)
|
||||
- [FIX] context.Copy() race condition [#1020](https://github.com/gin-gonic/gin/pull/1020)
|
||||
- [NEW] Add context.HandlerNames() [#1729](https://github.com/gin-gonic/gin/pull/1729)
|
||||
- [FIX] Change color methods to public in the defaultLogger. [#1771](https://github.com/gin-gonic/gin/pull/1771)
|
||||
- [FIX] Update writeHeaders method to use http.Header.Set [#1722](https://github.com/gin-gonic/gin/pull/1722)
|
||||
- [NEW] Add response size to LogFormatterParams [#1752](https://github.com/gin-gonic/gin/pull/1752)
|
||||
- [NEW] Allow ignoring field on form mapping [#1733](https://github.com/gin-gonic/gin/pull/1733)
|
||||
- [NEW] Add a function to force color in console output. [#1724](https://github.com/gin-gonic/gin/pull/1724)
|
||||
- [FIX] Context.Next() - recheck len of handlers on every iteration. [#1745](https://github.com/gin-gonic/gin/pull/1745)
|
||||
- [FIX] Fix all errcheck warnings [#1739](https://github.com/gin-gonic/gin/pull/1739) [#1653](https://github.com/gin-gonic/gin/pull/1653)
|
||||
- [NEW] context: inherits context cancellation and deadline from http.Request context for Go>=1.7 [#1690](https://github.com/gin-gonic/gin/pull/1690)
|
||||
- [NEW] Binding for URL Params [#1694](https://github.com/gin-gonic/gin/pull/1694)
|
||||
- [NEW] Add LoggerWithFormatter method [#1677](https://github.com/gin-gonic/gin/pull/1677)
|
||||
- [FIX] CI testing updates [#1671](https://github.com/gin-gonic/gin/pull/1671) [#1670](https://github.com/gin-gonic/gin/pull/1670) [#1682](https://github.com/gin-gonic/gin/pull/1682) [#1669](https://github.com/gin-gonic/gin/pull/1669)
|
||||
- [FIX] StaticFS(): Send 404 when path does not exist [#1663](https://github.com/gin-gonic/gin/pull/1663)
|
||||
- [FIX] Handle nil body for JSON binding [#1638](https://github.com/gin-gonic/gin/pull/1638)
|
||||
- [FIX] Support bind uri param [#1612](https://github.com/gin-gonic/gin/pull/1612)
|
||||
- [FIX] recovery: fix issue with syscall import on google app engine [#1640](https://github.com/gin-gonic/gin/pull/1640)
|
||||
- [FIX] Make sure the debug log contains line breaks [#1650](https://github.com/gin-gonic/gin/pull/1650)
|
||||
- [FIX] Panic stack trace being printed during recovery of broken pipe [#1089](https://github.com/gin-gonic/gin/pull/1089) [#1259](https://github.com/gin-gonic/gin/pull/1259)
|
||||
- [NEW] RunFd method to run http.Server through a file descriptor [#1609](https://github.com/gin-gonic/gin/pull/1609)
|
||||
- [NEW] Yaml binding support [#1618](https://github.com/gin-gonic/gin/pull/1618)
|
||||
- [FIX] Pass MaxMultipartMemory when FormFile is called [#1600](https://github.com/gin-gonic/gin/pull/1600)
|
||||
- [FIX] LoadHTML* tests [#1559](https://github.com/gin-gonic/gin/pull/1559)
|
||||
- [FIX] Removed use of sync.pool from HandleContext [#1565](https://github.com/gin-gonic/gin/pull/1565)
|
||||
- [FIX] Format output log to os.Stderr [#1571](https://github.com/gin-gonic/gin/pull/1571)
|
||||
- [FIX] Make logger use a yellow background and a darkgray text for legibility [#1570](https://github.com/gin-gonic/gin/pull/1570)
|
||||
- [FIX] Remove sensitive request information from panic log. [#1370](https://github.com/gin-gonic/gin/pull/1370)
|
||||
- [FIX] log.Println() does not print timestamp [#829](https://github.com/gin-gonic/gin/pull/829) [#1560](https://github.com/gin-gonic/gin/pull/1560)
|
||||
- [NEW] Add PureJSON renderer [#694](https://github.com/gin-gonic/gin/pull/694)
|
||||
- [FIX] Add missing copyright and update if/else [#1497](https://github.com/gin-gonic/gin/pull/1497)
|
||||
- [FIX] Update msgpack usage [#1498](https://github.com/gin-gonic/gin/pull/1498)
|
||||
- [FIX] Use protobuf on render [#1496](https://github.com/gin-gonic/gin/pull/1496)
|
||||
- [FIX] Add support for Protobuf format response [#1479](https://github.com/gin-gonic/gin/pull/1479)
|
||||
- [NEW] Set default time format in form binding [#1487](https://github.com/gin-gonic/gin/pull/1487)
|
||||
- [FIX] Add BindXML and ShouldBindXML [#1485](https://github.com/gin-gonic/gin/pull/1485)
|
||||
- [NEW] Upgrade dependency libraries [#1491](https://github.com/gin-gonic/gin/pull/1491)
|
||||
|
||||
|
||||
### Gin 1.3.0
|
||||
|
||||
- [NEW] Add [`func (*Context) QueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.QueryMap), [`func (*Context) GetQueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetQueryMap), [`func (*Context) PostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.PostFormMap) and [`func (*Context) GetPostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetPostFormMap) to support `type map[string]string` as query string or form parameters, see [#1383](https://github.com/gin-gonic/gin/pull/1383)
|
||||
- [NEW] Add [`func (*Context) AsciiJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.AsciiJSON), see [#1358](https://github.com/gin-gonic/gin/pull/1358)
|
||||
- [NEW] Add `Pusher()` in [`type ResponseWriter`](https://godoc.org/github.com/gin-gonic/gin#ResponseWriter) for supporting http2 push, see [#1273](https://github.com/gin-gonic/gin/pull/1273)
|
||||
- [NEW] Add [`func (*Context) DataFromReader`](https://godoc.org/github.com/gin-gonic/gin#Context.DataFromReader) for serving dynamic data, see [#1304](https://github.com/gin-gonic/gin/pull/1304)
|
||||
- [NEW] Add [`func (*Context) ShouldBindBodyWith`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith) allowing to call binding multiple times, see [#1341](https://github.com/gin-gonic/gin/pull/1341)
|
||||
- [NEW] Support pointers in form binding, see [#1336](https://github.com/gin-gonic/gin/pull/1336)
|
||||
- [NEW] Add [`func (*Context) JSONP`](https://godoc.org/github.com/gin-gonic/gin#Context.JSONP), see [#1333](https://github.com/gin-gonic/gin/pull/1333)
|
||||
- [NEW] Support default value in form binding, see [#1138](https://github.com/gin-gonic/gin/pull/1138)
|
||||
- [NEW] Expose validator engine in [`type StructValidator`](https://godoc.org/github.com/gin-gonic/gin/binding#StructValidator), see [#1277](https://github.com/gin-gonic/gin/pull/1277)
|
||||
- [NEW] Add [`func (*Context) ShouldBind`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind), [`func (*Context) ShouldBindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindQuery) and [`func (*Context) ShouldBindJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindJSON), see [#1047](https://github.com/gin-gonic/gin/pull/1047)
|
||||
- [NEW] Add support for `time.Time` location in form binding, see [#1117](https://github.com/gin-gonic/gin/pull/1117)
|
||||
- [NEW] Add [`func (*Context) BindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.BindQuery), see [#1029](https://github.com/gin-gonic/gin/pull/1029)
|
||||
- [NEW] Make [jsonite](https://github.com/json-iterator/go) optional with build tags, see [#1026](https://github.com/gin-gonic/gin/pull/1026)
|
||||
- [NEW] Show query string in logger, see [#999](https://github.com/gin-gonic/gin/pull/999)
|
||||
- [NEW] Add [`func (*Context) SecureJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.SecureJSON), see [#987](https://github.com/gin-gonic/gin/pull/987) and [#993](https://github.com/gin-gonic/gin/pull/993)
|
||||
- [DEPRECATE] `func (*Context) GetCookie` for [`func (*Context) Cookie`](https://godoc.org/github.com/gin-gonic/gin#Context.Cookie)
|
||||
- [FIX] Don't display color tags if [`func DisableConsoleColor`](https://godoc.org/github.com/gin-gonic/gin#DisableConsoleColor) called, see [#1072](https://github.com/gin-gonic/gin/pull/1072)
|
||||
- [FIX] Gin Mode `""` when calling [`func Mode`](https://godoc.org/github.com/gin-gonic/gin#Mode) now returns `const DebugMode`, see [#1250](https://github.com/gin-gonic/gin/pull/1250)
|
||||
- [FIX] `Flush()` now doesn't overwrite `responseWriter` status code, see [#1460](https://github.com/gin-gonic/gin/pull/1460)
|
||||
|
||||
### Gin 1.2.0
|
||||
|
||||
- [NEW] Switch from godeps to govendor
|
||||
- [NEW] Add support for Let's Encrypt via gin-gonic/autotls
|
||||
- [NEW] Improve README examples and add extra at examples folder
|
||||
- [NEW] Improved support with App Engine
|
||||
- [NEW] Add custom template delimiters, see #860
|
||||
- [NEW] Add Template Func Maps, see #962
|
||||
- [NEW] Add \*context.Handler(), see #928
|
||||
- [NEW] Add \*context.GetRawData()
|
||||
- [NEW] Add \*context.GetHeader() (request)
|
||||
- [NEW] Add \*context.AbortWithStatusJSON() (JSON content type)
|
||||
- [NEW] Add \*context.Keys type cast helpers
|
||||
- [NEW] Add \*context.ShouldBindWith()
|
||||
- [NEW] Add \*context.MustBindWith()
|
||||
- [NEW] Add \*engine.SetFuncMap()
|
||||
- [DEPRECATE] On next release: \*context.BindWith(), see #855
|
||||
- [FIX] Refactor render
|
||||
- [FIX] Reworked tests
|
||||
- [FIX] logger now supports cygwin
|
||||
- [FIX] Use X-Forwarded-For before X-Real-Ip
|
||||
- [FIX] time.Time binding (#904)
|
||||
|
||||
### Gin 1.1.4
|
||||
|
||||
- [NEW] Support google appengine for IsTerminal func
|
||||
|
||||
### Gin 1.1.3
|
||||
|
||||
- [FIX] Reverted Logger: skip ANSI color commands
|
||||
|
||||
### Gin 1.1
|
||||
|
||||
- [NEW] Implement QueryArray and PostArray methods
|
||||
- [NEW] Refactor GetQuery and GetPostForm
|
||||
- [NEW] Add contribution guide
|
||||
- [FIX] Corrected typos in README
|
||||
- [FIX] Removed additional Iota
|
||||
- [FIX] Changed imports to gopkg instead of github in README (#733)
|
||||
- [FIX] Logger: skip ANSI color commands if output is not a tty
|
||||
|
||||
### Gin 1.0rc2 (...)
|
||||
|
||||
- [PERFORMANCE] Fast path for writing Content-Type.
|
||||
- [PERFORMANCE] Much faster 404 routing
|
||||
- [PERFORMANCE] Allocation optimizations
|
||||
- [PERFORMANCE] Faster root tree lookup
|
||||
- [PERFORMANCE] Zero overhead, String() and JSON() rendering.
|
||||
- [PERFORMANCE] Faster ClientIP parsing
|
||||
- [PERFORMANCE] Much faster SSE implementation
|
||||
- [NEW] Benchmarks suite
|
||||
- [NEW] Bind validation can be disabled and replaced with custom validators.
|
||||
- [NEW] More flexible HTML render
|
||||
- [NEW] Multipart and PostForm bindings
|
||||
- [NEW] Adds method to return all the registered routes
|
||||
- [NEW] Context.HandlerName() returns the main handler's name
|
||||
- [NEW] Adds Error.IsType() helper
|
||||
- [FIX] Binding multipart form
|
||||
- [FIX] Integration tests
|
||||
- [FIX] Crash when binding non struct object in Context.
|
||||
- [FIX] RunTLS() implementation
|
||||
- [FIX] Logger() unit tests
|
||||
- [FIX] Adds SetHTMLTemplate() warning
|
||||
- [FIX] Context.IsAborted()
|
||||
- [FIX] More unit tests
|
||||
- [FIX] JSON, XML, HTML renders accept custom content-types
|
||||
- [FIX] gin.AbortIndex is unexported
|
||||
- [FIX] Better approach to avoid directory listing in StaticFS()
|
||||
- [FIX] Context.ClientIP() always returns the IP with trimmed spaces.
|
||||
- [FIX] Better warning when running in debug mode.
|
||||
- [FIX] Google App Engine integration. debugPrint does not use os.Stdout
|
||||
- [FIX] Fixes integer overflow in error type
|
||||
- [FIX] Error implements the json.Marshaller interface
|
||||
- [FIX] MIT license in every file
|
||||
|
||||
|
||||
### Gin 1.0rc1 (May 22, 2015)
|
||||
|
||||
- [PERFORMANCE] Zero allocation router
|
||||
- [PERFORMANCE] Faster JSON, XML and text rendering
|
||||
- [PERFORMANCE] Custom hand optimized HttpRouter for Gin
|
||||
- [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations
|
||||
- [NEW] Built-in support for golang.org/x/net/context
|
||||
- [NEW] Any(path, handler). Create a route that matches any path
|
||||
- [NEW] Refactored rendering pipeline (faster and static typeded)
|
||||
- [NEW] Refactored errors API
|
||||
- [NEW] IndentedJSON() prints pretty JSON
|
||||
- [NEW] Added gin.DefaultWriter
|
||||
- [NEW] UNIX socket support
|
||||
- [NEW] RouterGroup.BasePath is exposed
|
||||
- [NEW] JSON validation using go-validate-yourself (very powerful options)
|
||||
- [NEW] Completed suite of unit tests
|
||||
- [NEW] HTTP streaming with c.Stream()
|
||||
- [NEW] StaticFile() creates a router for serving just one file.
|
||||
- [NEW] StaticFS() has an option to disable directory listing.
|
||||
- [NEW] StaticFS() for serving static files through virtual filesystems
|
||||
- [NEW] Server-Sent Events native support
|
||||
- [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler
|
||||
- [NEW] Added LoggerWithWriter() middleware
|
||||
- [NEW] Added RecoveryWithWriter() middleware
|
||||
- [NEW] Added DefaultPostFormValue()
|
||||
- [NEW] Added DefaultFormValue()
|
||||
- [NEW] Added DefaultParamValue()
|
||||
- [FIX] BasicAuth() when using custom realm
|
||||
- [FIX] Bug when serving static files in nested routing group
|
||||
- [FIX] Redirect using built-in http.Redirect()
|
||||
- [FIX] Logger when printing the requested path
|
||||
- [FIX] Documentation typos
|
||||
- [FIX] Context.Engine renamed to Context.engine
|
||||
- [FIX] Better debugging messages
|
||||
- [FIX] ErrorLogger
|
||||
- [FIX] Debug HTTP render
|
||||
- [FIX] Refactored binding and render modules
|
||||
- [FIX] Refactored Context initialization
|
||||
- [FIX] Refactored BasicAuth()
|
||||
- [FIX] NoMethod/NoRoute handlers
|
||||
- [FIX] Hijacking http
|
||||
- [FIX] Better support for Google App Engine (using log instead of fmt)
|
||||
|
||||
|
||||
### Gin 0.6 (Mar 9, 2015)
|
||||
|
||||
- [NEW] Support multipart/form-data
|
||||
- [NEW] NoMethod handler
|
||||
- [NEW] Validate sub structures
|
||||
- [NEW] Support for HTTP Realm Auth
|
||||
- [FIX] Unsigned integers in binding
|
||||
- [FIX] Improve color logger
|
||||
|
||||
|
||||
### Gin 0.5 (Feb 7, 2015)
|
||||
|
||||
- [NEW] Content Negotiation
|
||||
- [FIX] Solved security bug that allow a client to spoof ip
|
||||
- [FIX] Fix unexported/ignored fields in binding
|
||||
|
||||
|
||||
### Gin 0.4 (Aug 21, 2014)
|
||||
|
||||
- [NEW] Development mode
|
||||
- [NEW] Unit tests
|
||||
- [NEW] Add Content.Redirect()
|
||||
- [FIX] Deferring WriteHeader()
|
||||
- [FIX] Improved documentation for model binding
|
||||
|
||||
|
||||
### Gin 0.3 (Jul 18, 2014)
|
||||
|
||||
- [PERFORMANCE] Normal log and error log are printed in the same call.
|
||||
- [PERFORMANCE] Improve performance of NoRouter()
|
||||
- [PERFORMANCE] Improve context's memory locality, reduce CPU cache faults.
|
||||
- [NEW] Flexible rendering API
|
||||
- [NEW] Add Context.File()
|
||||
- [NEW] Add shorcut RunTLS() for http.ListenAndServeTLS
|
||||
- [FIX] Rename NotFound404() to NoRoute()
|
||||
- [FIX] Errors in context are purged
|
||||
- [FIX] Adds HEAD method in Static file serving
|
||||
- [FIX] Refactors Static() file serving
|
||||
- [FIX] Using keyed initialization to fix app-engine integration
|
||||
- [FIX] Can't unmarshal JSON array, #63
|
||||
- [FIX] Renaming Context.Req to Context.Request
|
||||
- [FIX] Check application/x-www-form-urlencoded when parsing form
|
||||
|
||||
|
||||
### Gin 0.2b (Jul 08, 2014)
|
||||
- [PERFORMANCE] Using sync.Pool to allocatio/gc overhead
|
||||
- [NEW] Travis CI integration
|
||||
- [NEW] Completely new logger
|
||||
- [NEW] New API for serving static files. gin.Static()
|
||||
- [NEW] gin.H() can be serialized into XML
|
||||
- [NEW] Typed errors. Errors can be typed. Internet/external/custom.
|
||||
- [NEW] Support for Godeps
|
||||
- [NEW] Travis/Godocs badges in README
|
||||
- [NEW] New Bind() and BindWith() methods for parsing request body.
|
||||
- [NEW] Add Content.Copy()
|
||||
- [NEW] Add context.LastError()
|
||||
- [NEW] Add shorcut for OPTIONS HTTP method
|
||||
- [FIX] Tons of README fixes
|
||||
- [FIX] Header is written before body
|
||||
- [FIX] BasicAuth() and changes API a little bit
|
||||
- [FIX] Recovery() middleware only prints panics
|
||||
- [FIX] Context.Get() does not panic anymore. Use MustGet() instead.
|
||||
- [FIX] Multiple http.WriteHeader() in NotFound handlers
|
||||
- [FIX] Engine.Run() panics if http server can't be setted up
|
||||
- [FIX] Crash when route path doesn't start with '/'
|
||||
- [FIX] Do not update header when status code is negative
|
||||
- [FIX] Setting response headers before calling WriteHeader in context.String()
|
||||
- [FIX] Add MIT license
|
||||
- [FIX] Changes behaviour of ErrorLogger() and Logger()
|
||||
46
backend/vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md
generated
vendored
46
backend/vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md
generated
vendored
@@ -1,46 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at teamgingonic@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
13
backend/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md
generated
vendored
13
backend/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md
generated
vendored
@@ -1,13 +0,0 @@
|
||||
## 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 `master`
|
||||
- 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.
|
||||
21
backend/vendor/github.com/gin-gonic/gin/LICENSE
generated
vendored
21
backend/vendor/github.com/gin-gonic/gin/LICENSE
generated
vendored
@@ -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.
|
||||
80
backend/vendor/github.com/gin-gonic/gin/Makefile
generated
vendored
80
backend/vendor/github.com/gin-gonic/gin/Makefile
generated
vendored
@@ -1,80 +0,0 @@
|
||||
GO ?= go
|
||||
GOFMT ?= gofmt "-s"
|
||||
PACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/)
|
||||
VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/ | grep -v /examples/)
|
||||
GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*")
|
||||
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'gin$$|binding$$|render$$' | grep -v examples)
|
||||
|
||||
all: install
|
||||
|
||||
install: deps
|
||||
govendor sync
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
echo "mode: count" > coverage.out
|
||||
for d in $(TESTFOLDER); do \
|
||||
$(GO) test -v -covermode=count -coverprofile=profile.out $$d > tmp.out; \
|
||||
cat tmp.out; \
|
||||
if grep -q "^--- FAIL" tmp.out; then \
|
||||
rm tmp.out; \
|
||||
exit 1; \
|
||||
elif grep -q "build failed" tmp.out; then \
|
||||
rm tmp.out; \
|
||||
exit 1; \
|
||||
elif grep -q "setup failed" tmp.out; then \
|
||||
rm tmp.out; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
if [ -f profile.out ]; then \
|
||||
cat profile.out | grep -v "mode:" >> coverage.out; \
|
||||
rm profile.out; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
$(GOFMT) -w $(GOFILES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check:
|
||||
@diff=$$($(GOFMT) -d $(GOFILES)); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make fmt' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
exit 1; \
|
||||
fi;
|
||||
|
||||
vet:
|
||||
$(GO) vet $(VETPACKAGES)
|
||||
|
||||
deps:
|
||||
@hash govendor > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/kardianos/govendor; \
|
||||
fi
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u golang.org/x/lint/golint; \
|
||||
fi
|
||||
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
|
||||
|
||||
.PHONY: misspell-check
|
||||
misspell-check:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -error $(GOFILES)
|
||||
|
||||
.PHONY: misspell
|
||||
misspell:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -w $(GOFILES)
|
||||
|
||||
.PHONY: tools
|
||||
tools:
|
||||
go install golang.org/x/lint/golint; \
|
||||
go install github.com/client9/misspell/cmd/misspell;
|
||||
2070
backend/vendor/github.com/gin-gonic/gin/README.md
generated
vendored
2070
backend/vendor/github.com/gin-gonic/gin/README.md
generated
vendored
File diff suppressed because it is too large
Load Diff
96
backend/vendor/github.com/gin-gonic/gin/auth.go
generated
vendored
96
backend/vendor/github.com/gin-gonic/gin/auth.go
generated
vendored
@@ -1,96 +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"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// AuthUserKey is the cookie name for user credential in basic auth.
|
||||
const AuthUserKey = "user"
|
||||
|
||||
// Accounts defines a key/value for user/pass list of authorized logins.
|
||||
type Accounts map[string]string
|
||||
|
||||
type authPair struct {
|
||||
value string
|
||||
user string
|
||||
}
|
||||
|
||||
type authPairs []authPair
|
||||
|
||||
func (a authPairs) searchCredential(authValue string) (string, bool) {
|
||||
if authValue == "" {
|
||||
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.requestHeader("Authorization"))
|
||||
if !found {
|
||||
// Credentials doesn't match, we return 401 and abort handlers chain.
|
||||
c.Header("WWW-Authenticate", realm)
|
||||
c.AbortWithStatus(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// The user credentials was found, set user's id to key AuthUserKey in this context, the user's id 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(user != "", "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
|
||||
}
|
||||
113
backend/vendor/github.com/gin-gonic/gin/binding/binding.go
generated
vendored
113
backend/vendor/github.com/gin-gonic/gin/binding/binding.go
generated
vendored
@@ -1,113 +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"
|
||||
|
||||
// Content-Type MIME of the most common data formats.
|
||||
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"
|
||||
MIMEMSGPACK = "application/x-msgpack"
|
||||
MIMEMSGPACK2 = "application/msgpack"
|
||||
MIMEYAML = "application/x-yaml"
|
||||
)
|
||||
|
||||
// Binding describes the interface which needs to be implemented for binding the
|
||||
// data present in the request such as JSON request body, query parameters or
|
||||
// the form POST.
|
||||
type Binding interface {
|
||||
Name() string
|
||||
Bind(*http.Request, interface{}) error
|
||||
}
|
||||
|
||||
// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
|
||||
// but it reads the body from supplied bytes instead of req.Body.
|
||||
type BindingBody interface {
|
||||
Binding
|
||||
BindBody([]byte, interface{}) error
|
||||
}
|
||||
|
||||
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
||||
// but it read the Params.
|
||||
type BindingUri interface {
|
||||
Name() string
|
||||
BindUri(map[string][]string, interface{}) error
|
||||
}
|
||||
|
||||
// StructValidator is the minimal interface which needs to be implemented in
|
||||
// order for it to be used as the validator engine for ensuring the correctness
|
||||
// of the request. Gin provides a default implementation for this using
|
||||
// https://github.com/go-playground/validator/tree/v8.18.2.
|
||||
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
|
||||
|
||||
// Engine returns the underlying validator engine which powers the
|
||||
// StructValidator implementation.
|
||||
Engine() interface{}
|
||||
}
|
||||
|
||||
// Validator is the default validator which implements the StructValidator
|
||||
// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2
|
||||
// under the hood.
|
||||
var Validator StructValidator = &defaultValidator{}
|
||||
|
||||
// These implement the Binding interface and can be used to bind the data
|
||||
// present in the request to struct instances.
|
||||
var (
|
||||
JSON = jsonBinding{}
|
||||
XML = xmlBinding{}
|
||||
Form = formBinding{}
|
||||
Query = queryBinding{}
|
||||
FormPost = formPostBinding{}
|
||||
FormMultipart = formMultipartBinding{}
|
||||
ProtoBuf = protobufBinding{}
|
||||
MsgPack = msgpackBinding{}
|
||||
YAML = yamlBinding{}
|
||||
Uri = uriBinding{}
|
||||
)
|
||||
|
||||
// Default returns the appropriate Binding instance based on the HTTP method
|
||||
// and the content type.
|
||||
func Default(method, contentType string) Binding {
|
||||
if method == "GET" {
|
||||
return Form
|
||||
}
|
||||
|
||||
switch contentType {
|
||||
case MIMEJSON:
|
||||
return JSON
|
||||
case MIMEXML, MIMEXML2:
|
||||
return XML
|
||||
case MIMEPROTOBUF:
|
||||
return ProtoBuf
|
||||
case MIMEMSGPACK, MIMEMSGPACK2:
|
||||
return MsgPack
|
||||
case MIMEYAML:
|
||||
return YAML
|
||||
case MIMEMultipartPOSTForm:
|
||||
return FormMultipart
|
||||
default: // case MIMEPOSTForm:
|
||||
return Form
|
||||
}
|
||||
}
|
||||
|
||||
func validate(obj interface{}) error {
|
||||
if Validator == nil {
|
||||
return nil
|
||||
}
|
||||
return Validator.ValidateStruct(obj)
|
||||
}
|
||||
51
backend/vendor/github.com/gin-gonic/gin/binding/default_validator.go
generated
vendored
51
backend/vendor/github.com/gin-gonic/gin/binding/default_validator.go
generated
vendored
@@ -1,51 +0,0 @@
|
||||
// Copyright 2017 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 (
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"gopkg.in/go-playground/validator.v8"
|
||||
)
|
||||
|
||||
type defaultValidator struct {
|
||||
once sync.Once
|
||||
validate *validator.Validate
|
||||
}
|
||||
|
||||
var _ StructValidator = &defaultValidator{}
|
||||
|
||||
// ValidateStruct receives any kind of type, but only performed struct or pointer to struct type.
|
||||
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
|
||||
value := reflect.ValueOf(obj)
|
||||
valueType := value.Kind()
|
||||
if valueType == reflect.Ptr {
|
||||
valueType = value.Elem().Kind()
|
||||
}
|
||||
if valueType == reflect.Struct {
|
||||
v.lazyinit()
|
||||
if err := v.validate.Struct(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Engine returns the underlying validator engine which powers the default
|
||||
// Validator instance. This is useful if you want to register custom validations
|
||||
// or struct level validations. See validator GoDoc for more info -
|
||||
// https://godoc.org/gopkg.in/go-playground/validator.v8
|
||||
func (v *defaultValidator) Engine() interface{} {
|
||||
v.lazyinit()
|
||||
return v.validate
|
||||
}
|
||||
|
||||
func (v *defaultValidator) lazyinit() {
|
||||
v.once.Do(func() {
|
||||
config := &validator.Config{TagName: "binding"}
|
||||
v.validate = validator.New(config)
|
||||
})
|
||||
}
|
||||
89
backend/vendor/github.com/gin-gonic/gin/binding/form.go
generated
vendored
89
backend/vendor/github.com/gin-gonic/gin/binding/form.go
generated
vendored
@@ -1,89 +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 (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const defaultMemory = 32 * 1024 * 1024
|
||||
|
||||
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
|
||||
}
|
||||
if err := req.ParseMultipartForm(defaultMemory); err != nil {
|
||||
if err != http.ErrNotMultipart {
|
||||
return err
|
||||
}
|
||||
}
|
||||
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(defaultMemory); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mappingByPtr(obj, (*multipartRequest)(req), "form"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
type multipartRequest http.Request
|
||||
|
||||
var _ setter = (*multipartRequest)(nil)
|
||||
|
||||
var (
|
||||
multipartFileHeaderStructType = reflect.TypeOf(multipart.FileHeader{})
|
||||
)
|
||||
|
||||
// TrySet tries to set a value by the multipart request with the binding a form file
|
||||
func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) {
|
||||
if value.Type() == multipartFileHeaderStructType {
|
||||
_, file, err := (*http.Request)(r).FormFile(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if file != nil {
|
||||
value.Set(reflect.ValueOf(*file))
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return setByForm(value, field, r.MultipartForm.Value, key, opt)
|
||||
}
|
||||
330
backend/vendor/github.com/gin-gonic/gin/binding/form_mapping.go
generated
vendored
330
backend/vendor/github.com/gin-gonic/gin/binding/form_mapping.go
generated
vendored
@@ -1,330 +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"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin/internal/json"
|
||||
)
|
||||
|
||||
var errUnknownType = errors.New("Unknown type")
|
||||
|
||||
func mapUri(ptr interface{}, m map[string][]string) error {
|
||||
return mapFormByTag(ptr, m, "uri")
|
||||
}
|
||||
|
||||
func mapForm(ptr interface{}, form map[string][]string) error {
|
||||
return mapFormByTag(ptr, form, "form")
|
||||
}
|
||||
|
||||
var emptyField = reflect.StructField{}
|
||||
|
||||
func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
|
||||
return mappingByPtr(ptr, formSource(form), tag)
|
||||
}
|
||||
|
||||
// setter tries to set value on a walking by fields of a struct
|
||||
type setter interface {
|
||||
TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error)
|
||||
}
|
||||
|
||||
type formSource map[string][]string
|
||||
|
||||
var _ setter = formSource(nil)
|
||||
|
||||
// TrySet tries to set a value by request's form source (like map[string][]string)
|
||||
func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) {
|
||||
return setByForm(value, field, form, tagValue, opt)
|
||||
}
|
||||
|
||||
func mappingByPtr(ptr interface{}, setter setter, tag string) error {
|
||||
_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
|
||||
return err
|
||||
}
|
||||
|
||||
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
||||
var vKind = value.Kind()
|
||||
|
||||
if vKind == reflect.Ptr {
|
||||
var isNew bool
|
||||
vPtr := value
|
||||
if value.IsNil() {
|
||||
isNew = true
|
||||
vPtr = reflect.New(value.Type().Elem())
|
||||
}
|
||||
isSetted, err := mapping(vPtr.Elem(), field, setter, tag)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if isNew && isSetted {
|
||||
value.Set(vPtr)
|
||||
}
|
||||
return isSetted, nil
|
||||
}
|
||||
|
||||
ok, err := tryToSetValue(value, field, setter, tag)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if ok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if vKind == reflect.Struct {
|
||||
tValue := value.Type()
|
||||
|
||||
var isSetted bool
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
if !value.Field(i).CanSet() {
|
||||
continue
|
||||
}
|
||||
ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isSetted = isSetted || ok
|
||||
}
|
||||
return isSetted, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
type setOptions struct {
|
||||
isDefaultExists bool
|
||||
defaultValue string
|
||||
}
|
||||
|
||||
func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
||||
var tagValue string
|
||||
var setOpt setOptions
|
||||
|
||||
tagValue = field.Tag.Get(tag)
|
||||
tagValue, opts := head(tagValue, ",")
|
||||
|
||||
if tagValue == "-" { // just ignoring this field
|
||||
return false, nil
|
||||
}
|
||||
if tagValue == "" { // default value is FieldName
|
||||
tagValue = field.Name
|
||||
}
|
||||
if tagValue == "" { // when field is "emptyField" variable
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var opt string
|
||||
for len(opts) > 0 {
|
||||
opt, opts = head(opts, ",")
|
||||
|
||||
k, v := head(opt, "=")
|
||||
switch k {
|
||||
case "default":
|
||||
setOpt.isDefaultExists = true
|
||||
setOpt.defaultValue = v
|
||||
}
|
||||
}
|
||||
|
||||
return setter.TrySet(value, field, tagValue, setOpt)
|
||||
}
|
||||
|
||||
func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSetted bool, err error) {
|
||||
vs, ok := form[tagValue]
|
||||
if !ok && !opt.isDefaultExists {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch value.Kind() {
|
||||
case reflect.Slice:
|
||||
if !ok {
|
||||
vs = []string{opt.defaultValue}
|
||||
}
|
||||
return true, setSlice(vs, value, field)
|
||||
case reflect.Array:
|
||||
if !ok {
|
||||
vs = []string{opt.defaultValue}
|
||||
}
|
||||
if len(vs) != value.Len() {
|
||||
return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
|
||||
}
|
||||
return true, setArray(vs, value, field)
|
||||
default:
|
||||
var val string
|
||||
if !ok {
|
||||
val = opt.defaultValue
|
||||
}
|
||||
|
||||
if len(vs) > 0 {
|
||||
val = vs[0]
|
||||
}
|
||||
return true, setWithProperType(val, value, field)
|
||||
}
|
||||
}
|
||||
|
||||
func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
|
||||
switch value.Kind() {
|
||||
case reflect.Int:
|
||||
return setIntField(val, 0, value)
|
||||
case reflect.Int8:
|
||||
return setIntField(val, 8, value)
|
||||
case reflect.Int16:
|
||||
return setIntField(val, 16, value)
|
||||
case reflect.Int32:
|
||||
return setIntField(val, 32, value)
|
||||
case reflect.Int64:
|
||||
switch value.Interface().(type) {
|
||||
case time.Duration:
|
||||
return setTimeDuration(val, value, field)
|
||||
}
|
||||
return setIntField(val, 64, value)
|
||||
case reflect.Uint:
|
||||
return setUintField(val, 0, value)
|
||||
case reflect.Uint8:
|
||||
return setUintField(val, 8, value)
|
||||
case reflect.Uint16:
|
||||
return setUintField(val, 16, value)
|
||||
case reflect.Uint32:
|
||||
return setUintField(val, 32, value)
|
||||
case reflect.Uint64:
|
||||
return setUintField(val, 64, value)
|
||||
case reflect.Bool:
|
||||
return setBoolField(val, value)
|
||||
case reflect.Float32:
|
||||
return setFloatField(val, 32, value)
|
||||
case reflect.Float64:
|
||||
return setFloatField(val, 64, value)
|
||||
case reflect.String:
|
||||
value.SetString(val)
|
||||
case reflect.Struct:
|
||||
switch value.Interface().(type) {
|
||||
case time.Time:
|
||||
return setTimeField(val, field, value)
|
||||
}
|
||||
return json.Unmarshal([]byte(val), value.Addr().Interface())
|
||||
case reflect.Map:
|
||||
return json.Unmarshal([]byte(val), value.Addr().Interface())
|
||||
default:
|
||||
return errUnknownType
|
||||
}
|
||||
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 err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
|
||||
timeFormat := structField.Tag.Get("time_format")
|
||||
if timeFormat == "" {
|
||||
timeFormat = time.RFC3339
|
||||
}
|
||||
|
||||
if val == "" {
|
||||
value.Set(reflect.ValueOf(time.Time{}))
|
||||
return nil
|
||||
}
|
||||
|
||||
l := time.Local
|
||||
if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
|
||||
l = time.UTC
|
||||
}
|
||||
|
||||
if locTag := structField.Tag.Get("time_location"); locTag != "" {
|
||||
loc, err := time.LoadLocation(locTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = loc
|
||||
}
|
||||
|
||||
t, err := time.ParseInLocation(timeFormat, val, l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
value.Set(reflect.ValueOf(t))
|
||||
return nil
|
||||
}
|
||||
|
||||
func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
|
||||
for i, s := range vals {
|
||||
err := setWithProperType(s, value.Index(i), field)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
|
||||
slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
|
||||
err := setArray(vals, slice, field)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value.Set(slice)
|
||||
return nil
|
||||
}
|
||||
|
||||
func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error {
|
||||
d, err := time.ParseDuration(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value.Set(reflect.ValueOf(d))
|
||||
return nil
|
||||
}
|
||||
|
||||
func head(str, sep string) (head string, tail string) {
|
||||
idx := strings.Index(str, sep)
|
||||
if idx < 0 {
|
||||
return str, ""
|
||||
}
|
||||
return str[:idx], str[idx+len(sep):]
|
||||
}
|
||||
47
backend/vendor/github.com/gin-gonic/gin/binding/json.go
generated
vendored
47
backend/vendor/github.com/gin-gonic/gin/binding/json.go
generated
vendored
@@ -1,47 +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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin/internal/json"
|
||||
)
|
||||
|
||||
// EnableDecoderUseNumber is used to call the UseNumber method on the JSON
|
||||
// Decoder instance. UseNumber causes the Decoder to unmarshal a number into an
|
||||
// interface{} as a Number instead of as a float64.
|
||||
var EnableDecoderUseNumber = false
|
||||
|
||||
type jsonBinding struct{}
|
||||
|
||||
func (jsonBinding) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if req == nil || req.Body == nil {
|
||||
return fmt.Errorf("invalid request")
|
||||
}
|
||||
return decodeJSON(req.Body, obj)
|
||||
}
|
||||
|
||||
func (jsonBinding) BindBody(body []byte, obj interface{}) error {
|
||||
return decodeJSON(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
func decodeJSON(r io.Reader, obj interface{}) error {
|
||||
decoder := json.NewDecoder(r)
|
||||
if EnableDecoderUseNumber {
|
||||
decoder.UseNumber()
|
||||
}
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
35
backend/vendor/github.com/gin-gonic/gin/binding/msgpack.go
generated
vendored
35
backend/vendor/github.com/gin-gonic/gin/binding/msgpack.go
generated
vendored
@@ -1,35 +0,0 @@
|
||||
// Copyright 2017 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 (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/ugorji/go/codec"
|
||||
)
|
||||
|
||||
type msgpackBinding struct{}
|
||||
|
||||
func (msgpackBinding) Name() string {
|
||||
return "msgpack"
|
||||
}
|
||||
|
||||
func (msgpackBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
return decodeMsgPack(req.Body, obj)
|
||||
}
|
||||
|
||||
func (msgpackBinding) BindBody(body []byte, obj interface{}) error {
|
||||
return decodeMsgPack(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
func decodeMsgPack(r io.Reader, obj interface{}) error {
|
||||
cdc := new(codec.MsgpackHandle)
|
||||
if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
36
backend/vendor/github.com/gin-gonic/gin/binding/protobuf.go
generated
vendored
36
backend/vendor/github.com/gin-gonic/gin/binding/protobuf.go
generated
vendored
@@ -1,36 +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 (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type protobufBinding struct{}
|
||||
|
||||
func (protobufBinding) Name() string {
|
||||
return "protobuf"
|
||||
}
|
||||
|
||||
func (b protobufBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
buf, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.BindBody(buf, obj)
|
||||
}
|
||||
|
||||
func (protobufBinding) BindBody(body []byte, obj interface{}) error {
|
||||
if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil {
|
||||
return err
|
||||
}
|
||||
// Here it's same to return validate(obj), but util now we can't add
|
||||
// `binding:""` to the struct which automatically generate by gen-proto
|
||||
return nil
|
||||
// return validate(obj)
|
||||
}
|
||||
21
backend/vendor/github.com/gin-gonic/gin/binding/query.go
generated
vendored
21
backend/vendor/github.com/gin-gonic/gin/binding/query.go
generated
vendored
@@ -1,21 +0,0 @@
|
||||
// Copyright 2017 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 queryBinding struct{}
|
||||
|
||||
func (queryBinding) Name() string {
|
||||
return "query"
|
||||
}
|
||||
|
||||
func (queryBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
values := req.URL.Query()
|
||||
if err := mapForm(obj, values); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
18
backend/vendor/github.com/gin-gonic/gin/binding/uri.go
generated
vendored
18
backend/vendor/github.com/gin-gonic/gin/binding/uri.go
generated
vendored
@@ -1,18 +0,0 @@
|
||||
// Copyright 2018 Gin Core Team. 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
|
||||
|
||||
type uriBinding struct{}
|
||||
|
||||
func (uriBinding) Name() string {
|
||||
return "uri"
|
||||
}
|
||||
|
||||
func (uriBinding) BindUri(m map[string][]string, obj interface{}) error {
|
||||
if err := mapUri(obj, m); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
33
backend/vendor/github.com/gin-gonic/gin/binding/xml.go
generated
vendored
33
backend/vendor/github.com/gin-gonic/gin/binding/xml.go
generated
vendored
@@ -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 binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type xmlBinding struct{}
|
||||
|
||||
func (xmlBinding) Name() string {
|
||||
return "xml"
|
||||
}
|
||||
|
||||
func (xmlBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
return decodeXML(req.Body, obj)
|
||||
}
|
||||
|
||||
func (xmlBinding) BindBody(body []byte, obj interface{}) error {
|
||||
return decodeXML(bytes.NewReader(body), obj)
|
||||
}
|
||||
func decodeXML(r io.Reader, obj interface{}) error {
|
||||
decoder := xml.NewDecoder(r)
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
35
backend/vendor/github.com/gin-gonic/gin/binding/yaml.go
generated
vendored
35
backend/vendor/github.com/gin-gonic/gin/binding/yaml.go
generated
vendored
@@ -1,35 +0,0 @@
|
||||
// Copyright 2018 Gin Core Team. 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 (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type yamlBinding struct{}
|
||||
|
||||
func (yamlBinding) Name() string {
|
||||
return "yaml"
|
||||
}
|
||||
|
||||
func (yamlBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
return decodeYAML(req.Body, obj)
|
||||
}
|
||||
|
||||
func (yamlBinding) BindBody(body []byte, obj interface{}) error {
|
||||
return decodeYAML(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
func decodeYAML(r io.Reader, obj interface{}) error {
|
||||
decoder := yaml.NewDecoder(r)
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
5
backend/vendor/github.com/gin-gonic/gin/codecov.yml
generated
vendored
5
backend/vendor/github.com/gin-gonic/gin/codecov.yml
generated
vendored
@@ -1,5 +0,0 @@
|
||||
coverage:
|
||||
notify:
|
||||
gitter:
|
||||
default:
|
||||
url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165
|
||||
1023
backend/vendor/github.com/gin-gonic/gin/context.go
generated
vendored
1023
backend/vendor/github.com/gin-gonic/gin/context.go
generated
vendored
File diff suppressed because it is too large
Load Diff
11
backend/vendor/github.com/gin-gonic/gin/context_appengine.go
generated
vendored
11
backend/vendor/github.com/gin-gonic/gin/context_appengine.go
generated
vendored
@@ -1,11 +0,0 @@
|
||||
// +build appengine
|
||||
|
||||
// Copyright 2017 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
|
||||
|
||||
func init() {
|
||||
defaultAppEngine = true
|
||||
}
|
||||
103
backend/vendor/github.com/gin-gonic/gin/debug.go
generated
vendored
103
backend/vendor/github.com/gin-gonic/gin/debug.go
generated
vendored
@@ -1,103 +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"
|
||||
"html/template"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const ginSupportMinGoVer = 8
|
||||
|
||||
// IsDebugging returns true if the framework is running in debug mode.
|
||||
// Use SetMode(gin.ReleaseMode) to disable debug mode.
|
||||
func IsDebugging() bool {
|
||||
return ginMode == debugCode
|
||||
}
|
||||
|
||||
// DebugPrintRouteFunc indicates debug log output format.
|
||||
var DebugPrintRouteFunc func(httpMethod, absolutePath, handlerName string, nuHandlers int)
|
||||
|
||||
func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) {
|
||||
if IsDebugging() {
|
||||
nuHandlers := len(handlers)
|
||||
handlerName := nameOfFunction(handlers.Last())
|
||||
if DebugPrintRouteFunc == nil {
|
||||
debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers)
|
||||
} else {
|
||||
DebugPrintRouteFunc(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() {
|
||||
if !strings.HasSuffix(format, "\n") {
|
||||
format += "\n"
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "[GIN-debug] "+format, values...)
|
||||
}
|
||||
}
|
||||
|
||||
func getMinVer(v string) (uint64, error) {
|
||||
first := strings.IndexByte(v, '.')
|
||||
last := strings.LastIndexByte(v, '.')
|
||||
if first == last {
|
||||
return strconv.ParseUint(v[first+1:], 10, 64)
|
||||
}
|
||||
return strconv.ParseUint(v[first+1:last], 10, 64)
|
||||
}
|
||||
|
||||
func debugPrintWARNINGDefault() {
|
||||
if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer {
|
||||
debugPrint(`[WARNING] Now Gin requires Go 1.8 or later and Go 1.9 will be required soon.
|
||||
|
||||
`)
|
||||
}
|
||||
debugPrint(`[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
|
||||
|
||||
`)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
21
backend/vendor/github.com/gin-gonic/gin/deprecated.go
generated
vendored
21
backend/vendor/github.com/gin-gonic/gin/deprecated.go
generated
vendored
@@ -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 gin
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to
|
||||
be deprecated, please check issue #662 and either use MustBindWith() if you
|
||||
want HTTP 400 to be automatically returned if any error occur, or use
|
||||
ShouldBindWith() if you need to manage the error.`)
|
||||
return c.MustBindWith(obj, b)
|
||||
}
|
||||
6
backend/vendor/github.com/gin-gonic/gin/doc.go
generated
vendored
6
backend/vendor/github.com/gin-gonic/gin/doc.go
generated
vendored
@@ -1,6 +0,0 @@
|
||||
/*
|
||||
Package gin implements a HTTP web framework called gin.
|
||||
|
||||
See https://gin-gonic.com/ for more information about gin.
|
||||
*/
|
||||
package gin // import "github.com/gin-gonic/gin"
|
||||
169
backend/vendor/github.com/gin-gonic/gin/errors.go
generated
vendored
169
backend/vendor/github.com/gin-gonic/gin/errors.go
generated
vendored
@@ -1,169 +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"
|
||||
"reflect"
|
||||
|
||||
"github.com/gin-gonic/gin/internal/json"
|
||||
)
|
||||
|
||||
// ErrorType is an unsigned 64-bit error code as defined in the gin spec.
|
||||
type ErrorType uint64
|
||||
|
||||
const (
|
||||
// ErrorTypeBind is used when Context.Bind() fails.
|
||||
ErrorTypeBind ErrorType = 1 << 63
|
||||
// ErrorTypeRender is used when Context.Render() fails.
|
||||
ErrorTypeRender ErrorType = 1 << 62
|
||||
// ErrorTypePrivate indicates a private error.
|
||||
ErrorTypePrivate ErrorType = 1 << 0
|
||||
// ErrorTypePublic indicates a public error.
|
||||
ErrorTypePublic ErrorType = 1 << 1
|
||||
// ErrorTypeAny indicates any other error.
|
||||
ErrorTypeAny ErrorType = 1<<64 - 1
|
||||
// ErrorTypeNu indicates any other error.
|
||||
ErrorTypeNu = 2
|
||||
)
|
||||
|
||||
// Error represents a error's specification.
|
||||
type Error struct {
|
||||
Err error
|
||||
Type ErrorType
|
||||
Meta interface{}
|
||||
}
|
||||
|
||||
type errorMsgs []*Error
|
||||
|
||||
var _ error = &Error{}
|
||||
|
||||
// SetType sets the error's type.
|
||||
func (msg *Error) SetType(flags ErrorType) *Error {
|
||||
msg.Type = flags
|
||||
return msg
|
||||
}
|
||||
|
||||
// SetMeta sets the error's meta data.
|
||||
func (msg *Error) SetMeta(data interface{}) *Error {
|
||||
msg.Meta = data
|
||||
return msg
|
||||
}
|
||||
|
||||
// JSON creates a properly formatted JSON
|
||||
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())
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (msg Error) Error() string {
|
||||
return msg.Err.Error()
|
||||
}
|
||||
|
||||
// IsType judges one error.
|
||||
func (msg *Error) IsType(flags ErrorType) bool {
|
||||
return (msg.Type & flags) > 0
|
||||
}
|
||||
|
||||
// ByType returns a readonly copy filtered 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
|
||||
}
|
||||
|
||||
// Last 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 {
|
||||
if length := len(a); length > 0 {
|
||||
return a[length-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Errors 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
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaller interface.
|
||||
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()
|
||||
}
|
||||
45
backend/vendor/github.com/gin-gonic/gin/fs.go
generated
vendored
45
backend/vendor/github.com/gin-gonic/gin/fs.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
// Copyright 2017 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"
|
||||
"os"
|
||||
)
|
||||
|
||||
type onlyfilesFS struct {
|
||||
fs http.FileSystem
|
||||
}
|
||||
|
||||
type neuteredReaddirFile struct {
|
||||
http.File
|
||||
}
|
||||
|
||||
// Dir returns a http.Filesystem that can be used by http.FileServer(). It is used internally
|
||||
// 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}
|
||||
}
|
||||
|
||||
// Open 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
|
||||
}
|
||||
|
||||
// Readdir overrides the http.File default implementation.
|
||||
func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
|
||||
// this disables directory listing
|
||||
return nil, nil
|
||||
}
|
||||
477
backend/vendor/github.com/gin-gonic/gin/gin.go
generated
vendored
477
backend/vendor/github.com/gin-gonic/gin/gin.go
generated
vendored
@@ -1,477 +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"
|
||||
"html/template"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
|
||||
"github.com/gin-gonic/gin/render"
|
||||
)
|
||||
|
||||
const defaultMultipartMemory = 32 << 20 // 32 MB
|
||||
|
||||
var (
|
||||
default404Body = []byte("404 page not found")
|
||||
default405Body = []byte("405 method not allowed")
|
||||
defaultAppEngine bool
|
||||
)
|
||||
|
||||
// HandlerFunc defines the handler used by gin middleware as return value.
|
||||
type HandlerFunc func(*Context)
|
||||
|
||||
// HandlersChain defines a HandlerFunc array.
|
||||
type HandlersChain []HandlerFunc
|
||||
|
||||
// Last returns the last handler in the chain. ie. the last handler is the main own.
|
||||
func (c HandlersChain) Last() HandlerFunc {
|
||||
if length := len(c); length > 0 {
|
||||
return c[length-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RouteInfo represents a request route's specification which contains method and path and its handler.
|
||||
type RouteInfo struct {
|
||||
Method string
|
||||
Path string
|
||||
Handler string
|
||||
HandlerFunc HandlerFunc
|
||||
}
|
||||
|
||||
// RoutesInfo defines a RouteInfo array.
|
||||
type RoutesInfo []RouteInfo
|
||||
|
||||
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
|
||||
// Create an instance of Engine, by using New() or Default()
|
||||
type Engine struct {
|
||||
RouterGroup
|
||||
|
||||
// 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
|
||||
|
||||
// #726 #755 If enabled, it will thrust some headers starting with
|
||||
// 'X-AppEngine...' for better integration with that PaaS.
|
||||
AppEngine bool
|
||||
|
||||
// If enabled, the url.RawPath will be used to find parameters.
|
||||
UseRawPath bool
|
||||
|
||||
// If true, the path value will be unescaped.
|
||||
// If UseRawPath is false (by default), the UnescapePathValues effectively is true,
|
||||
// as url.Path gonna be used, which is already unescaped.
|
||||
UnescapePathValues bool
|
||||
|
||||
// Value of 'maxMemory' param that is given to http.Request's ParseMultipartForm
|
||||
// method call.
|
||||
MaxMultipartMemory int64
|
||||
|
||||
delims render.Delims
|
||||
secureJsonPrefix string
|
||||
HTMLRender render.HTMLRender
|
||||
FuncMap template.FuncMap
|
||||
allNoRoute HandlersChain
|
||||
allNoMethod HandlersChain
|
||||
noRoute HandlersChain
|
||||
noMethod HandlersChain
|
||||
pool sync.Pool
|
||||
trees methodTrees
|
||||
}
|
||||
|
||||
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
|
||||
// - UseRawPath: false
|
||||
// - UnescapePathValues: true
|
||||
func New() *Engine {
|
||||
debugPrintWARNINGNew()
|
||||
engine := &Engine{
|
||||
RouterGroup: RouterGroup{
|
||||
Handlers: nil,
|
||||
basePath: "/",
|
||||
root: true,
|
||||
},
|
||||
FuncMap: template.FuncMap{},
|
||||
RedirectTrailingSlash: true,
|
||||
RedirectFixedPath: false,
|
||||
HandleMethodNotAllowed: false,
|
||||
ForwardedByClientIP: true,
|
||||
AppEngine: defaultAppEngine,
|
||||
UseRawPath: false,
|
||||
UnescapePathValues: true,
|
||||
MaxMultipartMemory: defaultMultipartMemory,
|
||||
trees: make(methodTrees, 0, 9),
|
||||
delims: render.Delims{Left: "{{", Right: "}}"},
|
||||
secureJsonPrefix: "while(1);",
|
||||
}
|
||||
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 {
|
||||
debugPrintWARNINGDefault()
|
||||
engine := New()
|
||||
engine.Use(Logger(), Recovery())
|
||||
return engine
|
||||
}
|
||||
|
||||
func (engine *Engine) allocateContext() *Context {
|
||||
return &Context{engine: engine}
|
||||
}
|
||||
|
||||
// Delims sets template left and right delims and returns a Engine instance.
|
||||
func (engine *Engine) Delims(left, right string) *Engine {
|
||||
engine.delims = render.Delims{Left: left, Right: right}
|
||||
return engine
|
||||
}
|
||||
|
||||
// SecureJsonPrefix sets the secureJsonPrefix used in Context.SecureJSON.
|
||||
func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
|
||||
engine.secureJsonPrefix = prefix
|
||||
return engine
|
||||
}
|
||||
|
||||
// LoadHTMLGlob loads HTML files identified by glob pattern
|
||||
// and associates the result with HTML renderer.
|
||||
func (engine *Engine) LoadHTMLGlob(pattern string) {
|
||||
left := engine.delims.Left
|
||||
right := engine.delims.Right
|
||||
templ := template.Must(template.New("").Delims(left, right).Funcs(engine.FuncMap).ParseGlob(pattern))
|
||||
|
||||
if IsDebugging() {
|
||||
debugPrintLoadTemplate(templ)
|
||||
engine.HTMLRender = render.HTMLDebug{Glob: pattern, FuncMap: engine.FuncMap, Delims: engine.delims}
|
||||
return
|
||||
}
|
||||
|
||||
engine.SetHTMLTemplate(templ)
|
||||
}
|
||||
|
||||
// LoadHTMLFiles loads a slice of HTML files
|
||||
// and associates the result with HTML renderer.
|
||||
func (engine *Engine) LoadHTMLFiles(files ...string) {
|
||||
if IsDebugging() {
|
||||
engine.HTMLRender = render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims}
|
||||
return
|
||||
}
|
||||
|
||||
templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseFiles(files...))
|
||||
engine.SetHTMLTemplate(templ)
|
||||
}
|
||||
|
||||
// SetHTMLTemplate associate a template with HTML renderer.
|
||||
func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
|
||||
if len(engine.trees) > 0 {
|
||||
debugPrintWARNINGSetHTMLTemplate()
|
||||
}
|
||||
|
||||
engine.HTMLRender = render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)}
|
||||
}
|
||||
|
||||
// SetFuncMap sets the FuncMap used for template.FuncMap.
|
||||
func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
|
||||
engine.FuncMap = funcMap
|
||||
}
|
||||
|
||||
// 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 attaches 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(method != "", "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 {
|
||||
handlerFunc := root.handlers.Last()
|
||||
routes = append(routes, RouteInfo{
|
||||
Method: method,
|
||||
Path: path,
|
||||
Handler: nameOfFunction(handlerFunc),
|
||||
HandlerFunc: handlerFunc,
|
||||
})
|
||||
}
|
||||
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, certFile, 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()
|
||||
os.Chmod(file, 0777)
|
||||
err = http.Serve(listener, engine)
|
||||
return
|
||||
}
|
||||
|
||||
// RunFd attaches the router to a http.Server and starts listening and serving HTTP requests
|
||||
// through the specified file descriptor.
|
||||
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
||||
func (engine *Engine) RunFd(fd int) (err error) {
|
||||
debugPrint("Listening and serving HTTP on fd@%d", fd)
|
||||
defer func() { debugPrintError(err) }()
|
||||
|
||||
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd))
|
||||
listener, err := net.FileListener(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer listener.Close()
|
||||
err = http.Serve(listener, engine)
|
||||
return
|
||||
}
|
||||
|
||||
// ServeHTTP 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)
|
||||
}
|
||||
|
||||
// HandleContext re-enter a context that has been rewritten.
|
||||
// This can be done by setting c.Request.URL.Path to your new target.
|
||||
// Disclaimer: You can loop yourself to death with this, use wisely.
|
||||
func (engine *Engine) HandleContext(c *Context) {
|
||||
oldIndexValue := c.index
|
||||
c.reset()
|
||||
engine.handleHTTPRequest(c)
|
||||
|
||||
c.index = oldIndexValue
|
||||
}
|
||||
|
||||
func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||
httpMethod := c.Request.Method
|
||||
rPath := c.Request.URL.Path
|
||||
unescape := false
|
||||
if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
|
||||
rPath = c.Request.URL.RawPath
|
||||
unescape = engine.UnescapePathValues
|
||||
}
|
||||
rPath = cleanPath(rPath)
|
||||
|
||||
// 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 {
|
||||
continue
|
||||
}
|
||||
root := t[i].root
|
||||
// Find route in tree
|
||||
handlers, params, tsr := root.getValue(rPath, c.Params, unescape)
|
||||
if handlers != nil {
|
||||
c.handlers = handlers
|
||||
c.Params = params
|
||||
c.Next()
|
||||
c.writermem.WriteHeaderNow()
|
||||
return
|
||||
}
|
||||
if httpMethod != "CONNECT" && rPath != "/" {
|
||||
if tsr && engine.RedirectTrailingSlash {
|
||||
redirectTrailingSlash(c)
|
||||
return
|
||||
}
|
||||
if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if engine.HandleMethodNotAllowed {
|
||||
for _, tree := range engine.trees {
|
||||
if tree.method == httpMethod {
|
||||
continue
|
||||
}
|
||||
if handlers, _, _ := tree.root.getValue(rPath, nil, unescape); handlers != nil {
|
||||
c.handlers = engine.allNoMethod
|
||||
serveError(c, http.StatusMethodNotAllowed, default405Body)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
c.handlers = engine.allNoRoute
|
||||
serveError(c, http.StatusNotFound, default404Body)
|
||||
}
|
||||
|
||||
var mimePlain = []string{MIMEPlain}
|
||||
|
||||
func serveError(c *Context, code int, defaultMessage []byte) {
|
||||
c.writermem.status = code
|
||||
c.Next()
|
||||
if c.writermem.Written() {
|
||||
return
|
||||
}
|
||||
if c.writermem.Status() == code {
|
||||
c.writermem.Header()["Content-Type"] = mimePlain
|
||||
_, err := c.Writer.Write(defaultMessage)
|
||||
if err != nil {
|
||||
debugPrint("cannot write message to writer during serve error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
c.writermem.WriteHeaderNow()
|
||||
return
|
||||
}
|
||||
|
||||
func redirectTrailingSlash(c *Context) {
|
||||
req := c.Request
|
||||
p := req.URL.Path
|
||||
if prefix := path.Clean(c.Request.Header.Get("X-Forwarded-Prefix")); prefix != "." {
|
||||
p = prefix + "/" + req.URL.Path
|
||||
}
|
||||
code := http.StatusMovedPermanently // Permanent redirect, request with GET method
|
||||
if req.Method != "GET" {
|
||||
code = http.StatusTemporaryRedirect
|
||||
}
|
||||
|
||||
req.URL.Path = p + "/"
|
||||
if length := len(p); length > 1 && p[length-1] == '/' {
|
||||
req.URL.Path = p[:length-1]
|
||||
}
|
||||
debugPrint("redirecting request %d: %s --> %s", code, p, 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
|
||||
rPath := req.URL.Path
|
||||
|
||||
if fixedPath, ok := root.findCaseInsensitivePath(cleanPath(rPath), trailingSlash); ok {
|
||||
code := http.StatusMovedPermanently // Permanent redirect, request with GET method
|
||||
if req.Method != "GET" {
|
||||
code = http.StatusTemporaryRedirect
|
||||
}
|
||||
req.URL.Path = string(fixedPath)
|
||||
debugPrint("redirecting request %d: %s --> %s", code, rPath, req.URL.String())
|
||||
http.Redirect(c.Writer, req, req.URL.String(), code)
|
||||
c.writermem.WriteHeaderNow()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
18
backend/vendor/github.com/gin-gonic/gin/go.mod
generated
vendored
18
backend/vendor/github.com/gin-gonic/gin/go.mod
generated
vendored
@@ -1,18 +0,0 @@
|
||||
module github.com/gin-gonic/gin
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3
|
||||
github.com/golang/protobuf v1.3.1
|
||||
github.com/json-iterator/go v1.1.6
|
||||
github.com/mattn/go-isatty v0.0.7
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/ugorji/go v1.1.4
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2
|
||||
gopkg.in/yaml.v2 v2.2.2
|
||||
)
|
||||
36
backend/vendor/github.com/gin-gonic/gin/go.sum
generated
vendored
36
backend/vendor/github.com/gin-gonic/gin/go.sum
generated
vendored
@@ -1,36 +0,0 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
22
backend/vendor/github.com/gin-gonic/gin/internal/json/json.go
generated
vendored
22
backend/vendor/github.com/gin-gonic/gin/internal/json/json.go
generated
vendored
@@ -1,22 +0,0 @@
|
||||
// Copyright 2017 Bo-Yi Wu. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !jsoniter
|
||||
|
||||
package json
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
var (
|
||||
// Marshal is exported by gin/json package.
|
||||
Marshal = json.Marshal
|
||||
// Unmarshal is exported by gin/json package.
|
||||
Unmarshal = json.Unmarshal
|
||||
// MarshalIndent is exported by gin/json package.
|
||||
MarshalIndent = json.MarshalIndent
|
||||
// NewDecoder is exported by gin/json package.
|
||||
NewDecoder = json.NewDecoder
|
||||
// NewEncoder is exported by gin/json package.
|
||||
NewEncoder = json.NewEncoder
|
||||
)
|
||||
23
backend/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go
generated
vendored
23
backend/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
// Copyright 2017 Bo-Yi Wu. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build jsoniter
|
||||
|
||||
package json
|
||||
|
||||
import "github.com/json-iterator/go"
|
||||
|
||||
var (
|
||||
json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
// Marshal is exported by gin/json package.
|
||||
Marshal = json.Marshal
|
||||
// Unmarshal is exported by gin/json package.
|
||||
Unmarshal = json.Unmarshal
|
||||
// MarshalIndent is exported by gin/json package.
|
||||
MarshalIndent = json.MarshalIndent
|
||||
// NewDecoder is exported by gin/json package.
|
||||
NewDecoder = json.NewDecoder
|
||||
// NewEncoder is exported by gin/json package.
|
||||
NewEncoder = json.NewEncoder
|
||||
)
|
||||
270
backend/vendor/github.com/gin-gonic/gin/logger.go
generated
vendored
270
backend/vendor/github.com/gin-gonic/gin/logger.go
generated
vendored
@@ -1,270 +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"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
type consoleColorModeValue int
|
||||
|
||||
const (
|
||||
autoColor consoleColorModeValue = iota
|
||||
disableColor
|
||||
forceColor
|
||||
)
|
||||
|
||||
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, 48, 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})
|
||||
consoleColorMode = autoColor
|
||||
)
|
||||
|
||||
// LoggerConfig defines the config for Logger middleware.
|
||||
type LoggerConfig struct {
|
||||
// Optional. Default value is gin.defaultLogFormatter
|
||||
Formatter LogFormatter
|
||||
|
||||
// Output is a writer where logs are written.
|
||||
// Optional. Default value is gin.DefaultWriter.
|
||||
Output io.Writer
|
||||
|
||||
// SkipPaths is a url path array which logs are not written.
|
||||
// Optional.
|
||||
SkipPaths []string
|
||||
}
|
||||
|
||||
// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
|
||||
type LogFormatter func(params LogFormatterParams) string
|
||||
|
||||
// LogFormatterParams is the structure any formatter will be handed when time to log comes
|
||||
type LogFormatterParams struct {
|
||||
Request *http.Request
|
||||
|
||||
// TimeStamp shows the time after the server returns a response.
|
||||
TimeStamp time.Time
|
||||
// StatusCode is HTTP response code.
|
||||
StatusCode int
|
||||
// Latency is how much time the server cost to process a certain request.
|
||||
Latency time.Duration
|
||||
// ClientIP equals Context's ClientIP method.
|
||||
ClientIP string
|
||||
// Method is the HTTP method given to the request.
|
||||
Method string
|
||||
// Path is a path the client requests.
|
||||
Path string
|
||||
// ErrorMessage is set if error has occurred in processing the request.
|
||||
ErrorMessage string
|
||||
// isTerm shows whether does gin's output descriptor refers to a terminal.
|
||||
isTerm bool
|
||||
// BodySize is the size of the Response Body
|
||||
BodySize int
|
||||
// Keys are the keys set on the request's context.
|
||||
Keys map[string]interface{}
|
||||
}
|
||||
|
||||
// StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal.
|
||||
func (p *LogFormatterParams) StatusCodeColor() string {
|
||||
code := p.StatusCode
|
||||
|
||||
switch {
|
||||
case code >= http.StatusOK && code < http.StatusMultipleChoices:
|
||||
return green
|
||||
case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
|
||||
return white
|
||||
case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
|
||||
return yellow
|
||||
default:
|
||||
return red
|
||||
}
|
||||
}
|
||||
|
||||
// MethodColor is the ANSI color for appropriately logging http method to a terminal.
|
||||
func (p *LogFormatterParams) MethodColor() string {
|
||||
method := p.Method
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// ResetColor resets all escape attributes.
|
||||
func (p *LogFormatterParams) ResetColor() string {
|
||||
return reset
|
||||
}
|
||||
|
||||
// IsOutputColor indicates whether can colors be outputted to the log.
|
||||
func (p *LogFormatterParams) IsOutputColor() bool {
|
||||
return consoleColorMode == forceColor || (consoleColorMode == autoColor && p.isTerm)
|
||||
}
|
||||
|
||||
// defaultLogFormatter is the default log format function Logger middleware uses.
|
||||
var defaultLogFormatter = func(param LogFormatterParams) string {
|
||||
var statusColor, methodColor, resetColor string
|
||||
if param.IsOutputColor() {
|
||||
statusColor = param.StatusCodeColor()
|
||||
methodColor = param.MethodColor()
|
||||
resetColor = param.ResetColor()
|
||||
}
|
||||
|
||||
if param.Latency > time.Minute {
|
||||
// Truncate in a golang < 1.8 safe way
|
||||
param.Latency = param.Latency - param.Latency%time.Second
|
||||
}
|
||||
return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %s\n%s",
|
||||
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
|
||||
statusColor, param.StatusCode, resetColor,
|
||||
param.Latency,
|
||||
param.ClientIP,
|
||||
methodColor, param.Method, resetColor,
|
||||
param.Path,
|
||||
param.ErrorMessage,
|
||||
)
|
||||
}
|
||||
|
||||
// DisableConsoleColor disables color output in the console.
|
||||
func DisableConsoleColor() {
|
||||
consoleColorMode = disableColor
|
||||
}
|
||||
|
||||
// ForceConsoleColor force color output in the console.
|
||||
func ForceConsoleColor() {
|
||||
consoleColorMode = forceColor
|
||||
}
|
||||
|
||||
// ErrorLogger returns a handlerfunc for any error type.
|
||||
func ErrorLogger() HandlerFunc {
|
||||
return ErrorLoggerT(ErrorTypeAny)
|
||||
}
|
||||
|
||||
// ErrorLoggerT returns a handlerfunc for a given error type.
|
||||
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 LoggerWithConfig(LoggerConfig{})
|
||||
}
|
||||
|
||||
// LoggerWithFormatter instance a Logger middleware with the specified log format function.
|
||||
func LoggerWithFormatter(f LogFormatter) HandlerFunc {
|
||||
return LoggerWithConfig(LoggerConfig{
|
||||
Formatter: f,
|
||||
})
|
||||
}
|
||||
|
||||
// LoggerWithWriter instance a Logger middleware with the specified writer buffer.
|
||||
// Example: os.Stdout, a file opened in write mode, a socket...
|
||||
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
|
||||
return LoggerWithConfig(LoggerConfig{
|
||||
Output: out,
|
||||
SkipPaths: notlogged,
|
||||
})
|
||||
}
|
||||
|
||||
// LoggerWithConfig instance a Logger middleware with config.
|
||||
func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
|
||||
formatter := conf.Formatter
|
||||
if formatter == nil {
|
||||
formatter = defaultLogFormatter
|
||||
}
|
||||
|
||||
out := conf.Output
|
||||
if out == nil {
|
||||
out = DefaultWriter
|
||||
}
|
||||
|
||||
notlogged := conf.SkipPaths
|
||||
|
||||
isTerm := true
|
||||
|
||||
if w, ok := out.(*os.File); !ok || os.Getenv("TERM") == "dumb" ||
|
||||
(!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(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
|
||||
raw := c.Request.URL.RawQuery
|
||||
|
||||
// Process request
|
||||
c.Next()
|
||||
|
||||
// Log only when path is not being skipped
|
||||
if _, ok := skip[path]; !ok {
|
||||
param := LogFormatterParams{
|
||||
Request: c.Request,
|
||||
isTerm: isTerm,
|
||||
Keys: c.Keys,
|
||||
}
|
||||
|
||||
// Stop timer
|
||||
param.TimeStamp = time.Now()
|
||||
param.Latency = param.TimeStamp.Sub(start)
|
||||
|
||||
param.ClientIP = c.ClientIP()
|
||||
param.Method = c.Request.Method
|
||||
param.StatusCode = c.Writer.Status()
|
||||
param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()
|
||||
|
||||
param.BodySize = c.Writer.Size()
|
||||
|
||||
if raw != "" {
|
||||
path = path + "?" + raw
|
||||
}
|
||||
|
||||
param.Path = path
|
||||
|
||||
fmt.Fprint(out, formatter(param))
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user