haiswork 5 years ago
commit
da96f3196f
100 changed files with 6936 additions and 0 deletions
  1. 8
    0
      .gitignore
  2. 18
    0
      Makefile
  3. 2
    0
      README.md
  4. 18
    0
      cmd/http/handler/index.go
  5. 60
    0
      cmd/http/http.go
  6. 18
    0
      cmd/http/middleware/auth.go
  7. 35
    0
      cmd/http/router/router.go
  8. 26
    0
      cmd/http/router/v1.go
  9. 4
    0
      cmd/http/router/v2.go
  10. 10
    0
      cmd/tcp/handler/index.go
  11. 43
    0
      cmd/tcp/middleware/auth.go
  12. 18
    0
      cmd/tcp/router/router.go
  13. 17
    0
      cmd/tcp/router/v1.go
  14. 74
    0
      cmd/tcp/tcp.go
  15. 107
    0
      cmd/tcp/tcp_test.go
  16. 23
    0
      cmd/version/version.go
  17. 91
    0
      config/config.go
  18. 31
    0
      docs/docs.go
  19. 12
    0
      docs/swagger/swagger.json
  20. 9
    0
      docs/swagger/swagger.yaml
  21. 30
    0
      go.mod
  22. 184
    0
      go.sum
  23. 0
    0
      internal/.gitkeep
  24. 1
    0
      languages/en-US.ini
  25. 1
    0
      languages/zh-CN.ini
  26. 29
    0
      main.go
  27. 0
    0
      migrations/.gitkeep
  28. 6
    0
      service/api/README.md
  29. 39
    0
      service/api/common.go
  30. 1
    0
      service/service.go
  31. 10
    0
      service/store/cache/auth.go
  32. 12
    0
      service/store/cache/auth_test.go
  33. 60
    0
      service/store/cache/cache.go
  34. 11
    0
      service/store/cache/cache_test.go
  35. 69
    0
      service/store/mysql/mysql.go
  36. 66
    0
      vendor/git.links123.net/links123.com/pkg/middleware/auth/auth.go
  37. 14
    0
      vendor/git.links123.net/links123.com/pkg/middleware/auth/go.mod
  38. 21
    0
      vendor/git.links123.net/links123.com/pkg/middleware/auth/go.sum
  39. 44
    0
      vendor/git.links123.net/links123.com/pkg/middleware/auth/optional_auth.go
  40. 12
    0
      vendor/git.links123.net/links123.com/pkg/middleware/auth/session.go
  41. 20
    0
      vendor/git.links123.net/links123.com/pkg/middleware/auth/session_debug.go
  42. 52
    0
      vendor/git.links123.net/links123.com/pkg/middleware/auth/session_redis.go
  43. 30
    0
      vendor/git.links123.net/links123.com/pkg/middleware/cors/cors.go
  44. 12
    0
      vendor/git.links123.net/links123.com/pkg/middleware/cors/go.mod
  45. 17
    0
      vendor/git.links123.net/links123.com/pkg/middleware/cors/go.sum
  46. 5
    0
      vendor/git.links123.net/links123.com/pkg/request/error.go
  47. 14
    0
      vendor/git.links123.net/links123.com/pkg/request/go.mod
  48. 21
    0
      vendor/git.links123.net/links123.com/pkg/request/go.sum
  49. 65
    0
      vendor/git.links123.net/links123.com/pkg/request/request.go
  50. 14
    0
      vendor/git.links123.net/links123.com/pkg/utils/encrypt.go
  51. 1
    0
      vendor/git.links123.net/links123.com/pkg/utils/go.mod
  52. 9
    0
      vendor/git.links123.net/links123.com/pkg/utils/time.go
  53. 20
    0
      vendor/git.links123.net/links123.com/pkg/utils/unit.go
  54. 5
    0
      vendor/github.com/PuerkitoBio/purell/.gitignore
  55. 7
    0
      vendor/github.com/PuerkitoBio/purell/.travis.yml
  56. 12
    0
      vendor/github.com/PuerkitoBio/purell/LICENSE
  57. 187
    0
      vendor/github.com/PuerkitoBio/purell/README.md
  58. 379
    0
      vendor/github.com/PuerkitoBio/purell/purell.go
  59. 15
    0
      vendor/github.com/PuerkitoBio/urlesc/.travis.yml
  60. 27
    0
      vendor/github.com/PuerkitoBio/urlesc/LICENSE
  61. 16
    0
      vendor/github.com/PuerkitoBio/urlesc/README.md
  62. 180
    0
      vendor/github.com/PuerkitoBio/urlesc/urlesc.go
  63. 22
    0
      vendor/github.com/Unknwon/i18n/.gitignore
  64. 191
    0
      vendor/github.com/Unknwon/i18n/LICENSE
  65. 12
    0
      vendor/github.com/Unknwon/i18n/Makefile
  66. 136
    0
      vendor/github.com/Unknwon/i18n/README.md
  67. 231
    0
      vendor/github.com/Unknwon/i18n/i18n.go
  68. 19
    0
      vendor/github.com/braintree/manners/LICENSE
  69. 36
    0
      vendor/github.com/braintree/manners/README.md
  70. 7
    0
      vendor/github.com/braintree/manners/interfaces.go
  71. 292
    0
      vendor/github.com/braintree/manners/server.go
  72. 47
    0
      vendor/github.com/braintree/manners/static.go
  73. 15
    0
      vendor/github.com/davecgh/go-spew/LICENSE
  74. 145
    0
      vendor/github.com/davecgh/go-spew/spew/bypass.go
  75. 38
    0
      vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
  76. 341
    0
      vendor/github.com/davecgh/go-spew/spew/common.go
  77. 306
    0
      vendor/github.com/davecgh/go-spew/spew/config.go
  78. 211
    0
      vendor/github.com/davecgh/go-spew/spew/doc.go
  79. 509
    0
      vendor/github.com/davecgh/go-spew/spew/dump.go
  80. 419
    0
      vendor/github.com/davecgh/go-spew/spew/format.go
  81. 148
    0
      vendor/github.com/davecgh/go-spew/spew/spew.go
  82. 4
    0
      vendor/github.com/dgrijalva/jwt-go/.gitignore
  83. 13
    0
      vendor/github.com/dgrijalva/jwt-go/.travis.yml
  84. 8
    0
      vendor/github.com/dgrijalva/jwt-go/LICENSE
  85. 97
    0
      vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md
  86. 100
    0
      vendor/github.com/dgrijalva/jwt-go/README.md
  87. 118
    0
      vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
  88. 134
    0
      vendor/github.com/dgrijalva/jwt-go/claims.go
  89. 4
    0
      vendor/github.com/dgrijalva/jwt-go/doc.go
  90. 148
    0
      vendor/github.com/dgrijalva/jwt-go/ecdsa.go
  91. 67
    0
      vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go
  92. 59
    0
      vendor/github.com/dgrijalva/jwt-go/errors.go
  93. 95
    0
      vendor/github.com/dgrijalva/jwt-go/hmac.go
  94. 94
    0
      vendor/github.com/dgrijalva/jwt-go/map_claims.go
  95. 52
    0
      vendor/github.com/dgrijalva/jwt-go/none.go
  96. 148
    0
      vendor/github.com/dgrijalva/jwt-go/parser.go
  97. 101
    0
      vendor/github.com/dgrijalva/jwt-go/rsa.go
  98. 126
    0
      vendor/github.com/dgrijalva/jwt-go/rsa_pss.go
  99. 101
    0
      vendor/github.com/dgrijalva/jwt-go/rsa_utils.go
  100. 0
    0
      vendor/github.com/dgrijalva/jwt-go/signing_method.go

+ 8
- 0
.gitignore View File

@@ -0,0 +1,8 @@
1
+# debug
2
+/skeleton
3
+/debug
4
+/.env
5
+# editor workspace
6
+/.vscode
7
+
8
+monitor_status

+ 18
- 0
Makefile View File

@@ -0,0 +1,18 @@
1
+help: ## Show Help
2
+	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
3
+
4
+dep: ## Get build dependencies
5
+	go get -v -u github.com/codegangsta/gin
6
+	go get -u github.com/swaggo/swag/cmd/swag
7
+
8
+build: ## Build the app
9
+	go build -ldflags "-X main.apiVersion=1.0  -X 'main.gitCommit=`git rev-parse HEAD`' -X 'main.built=`date`'"
10
+
11
+doc: ## Generate doc for api
12
+	swag init
13
+
14
+test: ## Launch tests
15
+	go test -v ./...
16
+
17
+http: ## Run default http service with hot reload
18
+	gin -p 8080 -a 8080 --immediate -b debug run http

+ 2
- 0
README.md View File

@@ -0,0 +1,2 @@
1
+# monitor status
2
+http 状态监控

+ 18
- 0
cmd/http/handler/index.go View File

@@ -0,0 +1,18 @@
1
+package handler
2
+
3
+import (
4
+	"git.links123.net/links123.com/pkg/request"
5
+	"git.links123.net/links123.com/skeleton/service/api"
6
+	"github.com/Unknwon/i18n"
7
+	"github.com/gin-gonic/gin"
8
+)
9
+
10
+// Healthy health check for gin
11
+func Healthy(ctx *gin.Context) {
12
+	cp := &api.CommonParams{}
13
+	if request.ParseParamFail(ctx, cp) {
14
+		return
15
+	}
16
+
17
+	request.Success(ctx, gin.H{"msg": i18n.Tr(cp.TargetStr, "hi", "Paul")})
18
+}

+ 60
- 0
cmd/http/http.go View File

@@ -0,0 +1,60 @@
1
+package http
2
+
3
+import (
4
+	"os"
5
+	"os/signal"
6
+	"strings"
7
+	"syscall"
8
+
9
+	"git.links123.net/links123.com/skeleton/cmd/http/router"
10
+	"git.links123.net/links123.com/skeleton/service/store/cache"
11
+	"git.links123.net/links123.com/skeleton/service/store/mysql"
12
+	"github.com/braintree/manners"
13
+	"github.com/sirupsen/logrus"
14
+	"github.com/spf13/cobra"
15
+)
16
+
17
+// RunCommand cobra subcommand http
18
+func RunCommand() *cobra.Command {
19
+	var host, port string
20
+	cmd := &cobra.Command{
21
+		Use:   "http",
22
+		Short: "Run the http service",
23
+		Run: func(cmd *cobra.Command, args []string) {
24
+			go Start(host, port)
25
+			// 阻塞退出 捕获信号
26
+			signalChan := make(chan os.Signal)
27
+			signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
28
+			logrus.Infof("caught signal %+v, begin garbage collection", <-signalChan)
29
+			Stop()
30
+		},
31
+	}
32
+	cmd.PersistentFlags().StringVarP(&host, "host", "o", "127.0.0.1", "server hostname")
33
+	cmd.PersistentFlags().StringVarP(&port, "port", "p", "8080", "server port")
34
+
35
+	return cmd
36
+}
37
+
38
+// Start use for cobra or testing
39
+func Start(host, port string) {
40
+	// init db
41
+	mysql.Init()
42
+	// init cache
43
+	cache.Init()
44
+	// build router
45
+	r := router.BuildRouter()
46
+	// start server
47
+	err := manners.ListenAndServe(strings.Join([]string{host, port}, ":"), r)
48
+	if err != nil {
49
+		panic(err)
50
+	}
51
+}
52
+
53
+// Stop stop the http service graceful
54
+func Stop() {
55
+	if manners.Close() {
56
+		logrus.Info("http server stopped")
57
+	}
58
+	cache.Close()
59
+	mysql.Close()
60
+}

+ 18
- 0
cmd/http/middleware/auth.go View File

@@ -0,0 +1,18 @@
1
+package middleware
2
+
3
+import (
4
+	"git.links123.net/links123.com/pkg/middleware/auth"
5
+	"git.links123.net/links123.com/skeleton/config"
6
+	"git.links123.net/links123.com/skeleton/service/store/cache"
7
+	"github.com/gin-gonic/gin"
8
+)
9
+
10
+// Auth 必须认证
11
+func Auth() gin.HandlerFunc {
12
+	return auth.Auth(config.C.App.Secret, cache.AuthSessionStore())
13
+}
14
+
15
+// OptionalAuth 可选认证 如果传了token就会解析其用户
16
+func OptionalAuth() gin.HandlerFunc {
17
+	return auth.OptionalAuth(config.C.App.Secret)
18
+}

+ 35
- 0
cmd/http/router/router.go View File

@@ -0,0 +1,35 @@
1
+package router
2
+
3
+import (
4
+	"git.links123.net/links123.com/pkg/middleware/cors"
5
+	"git.links123.net/links123.com/skeleton/cmd/http/handler"
6
+	"git.links123.net/links123.com/skeleton/config"
7
+	_ "git.links123.net/links123.com/skeleton/docs" // for swagger
8
+	"github.com/gin-gonic/gin"
9
+	"github.com/swaggo/gin-swagger"
10
+	"github.com/swaggo/gin-swagger/swaggerFiles"
11
+)
12
+
13
+var r = gin.Default()
14
+
15
+// BuildRouter gin router
16
+func BuildRouter() *gin.Engine {
17
+	// gin config
18
+	r.RedirectTrailingSlash = true
19
+	r.RedirectFixedPath = true
20
+	if config.C.App.Debug {
21
+		// set gin debug mode
22
+		gin.SetMode(gin.DebugMode)
23
+		// swagger doc in debug mode
24
+		r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
25
+	}
26
+	// service health check for aliyun
27
+	r.HEAD("/", handler.Healthy)
28
+
29
+	r.Use(cors.Cors())
30
+
31
+	registerV1Router()
32
+	registerV2Router()
33
+
34
+	return r
35
+}

+ 26
- 0
cmd/http/router/v1.go View File

@@ -0,0 +1,26 @@
1
+package router
2
+
3
+import (
4
+	"git.links123.net/links123.com/skeleton/cmd/http/handler"
5
+	"git.links123.net/links123.com/skeleton/cmd/http/middleware"
6
+)
7
+
8
+func registerV1Router() {
9
+	// All user can access
10
+	v1NoAuth := r.Group("/v1")
11
+	{
12
+		v1NoAuth.GET("/hello", handler.Healthy)
13
+	}
14
+
15
+	// All user can access, you can get user id in handle
16
+	v1OptionAuth := r.Group("/v1").Use(middleware.OptionalAuth())
17
+	{
18
+		v1OptionAuth.POST("/hello/option/auth", handler.Healthy)
19
+	}
20
+
21
+	// Only the login user can access
22
+	v1Auth := r.Group("/v1").Use(middleware.Auth())
23
+	{
24
+		v1Auth.POST("/hello/auth", handler.Healthy)
25
+	}
26
+}

+ 4
- 0
cmd/http/router/v2.go View File

@@ -0,0 +1,4 @@
1
+package router
2
+
3
+// The same with v1.go, but register r.Group("/v2") for upgrading from v1 and compact old app
4
+func registerV2Router() {}

+ 10
- 0
cmd/tcp/handler/index.go View File

@@ -0,0 +1,10 @@
1
+package handler
2
+
3
+import (
4
+	"github.com/wpajqz/linker"
5
+)
6
+
7
+// Healthy 健康检查
8
+func Healthy(ctx linker.Context) {
9
+	ctx.Success(map[string]string{"keepalive": "true"})
10
+}

+ 43
- 0
cmd/tcp/middleware/auth.go View File

@@ -0,0 +1,43 @@
1
+package middleware
2
+
3
+import (
4
+	"fmt"
5
+	"net/http"
6
+
7
+	"git.links123.net/links123.com/skeleton/config"
8
+	"github.com/dgrijalva/jwt-go"
9
+	"github.com/wpajqz/linker"
10
+)
11
+
12
+// headers
13
+const (
14
+	CtxRequestHeaderUserId        = "user_id"
15
+	CtxRequestHeaderAuthorization = "Authorization"
16
+)
17
+
18
+// Auth empty struct for middleware interface
19
+type Auth struct{}
20
+
21
+// Handle middleware process
22
+func (a *Auth) Handle(ctx linker.Context) linker.Context {
23
+	tk := ctx.GetRequestProperty(CtxRequestHeaderAuthorization)
24
+	if len(tk) < 8 {
25
+		ctx.Error(http.StatusUnauthorized, "Auth failed")
26
+	}
27
+
28
+	token, err := jwt.Parse(tk[7:], func(token *jwt.Token) (interface{}, error) {
29
+		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
30
+			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
31
+		}
32
+
33
+		return []byte(config.C.App.Secret), nil
34
+	})
35
+
36
+	if err != nil || !token.Valid {
37
+		ctx.Error(http.StatusUnauthorized, "Auth failed")
38
+	}
39
+
40
+	ctx.Set(CtxRequestHeaderUserId, int(token.Claims.(jwt.MapClaims)[CtxRequestHeaderUserId].(float64)))
41
+
42
+	return ctx
43
+}

+ 18
- 0
cmd/tcp/router/router.go View File

@@ -0,0 +1,18 @@
1
+package router
2
+
3
+import (
4
+	"git.links123.net/links123.com/skeleton/cmd/tcp/middleware"
5
+	"github.com/wpajqz/linker"
6
+)
7
+
8
+// golbal tcp router
9
+var r *linker.Router
10
+
11
+// BuildRouter build linker roter
12
+func BuildRouter() *linker.Router {
13
+	r = linker.NewRouter()
14
+	r.Use(&middleware.Auth{})
15
+	registerV1Router()
16
+
17
+	return r
18
+}

+ 17
- 0
cmd/tcp/router/v1.go View File

@@ -0,0 +1,17 @@
1
+package router
2
+
3
+import (
4
+	"git.links123.net/links123.com/skeleton/cmd/tcp/handler"
5
+	"github.com/wpajqz/linker"
6
+)
7
+
8
+func registerV1Router() {
9
+	r.NSRouter("/v1",
10
+		r.NSRoute(
11
+			"/",
12
+			linker.HandlerFunc(func(ctx linker.Context) {
13
+				handler.Healthy(ctx)
14
+			}),
15
+		),
16
+	)
17
+}

+ 74
- 0
cmd/tcp/tcp.go View File

@@ -0,0 +1,74 @@
1
+package tcp
2
+
3
+import (
4
+	"os"
5
+	"os/signal"
6
+	"strings"
7
+	"syscall"
8
+	"time"
9
+
10
+	"git.links123.net/links123.com/skeleton/cmd/tcp/router"
11
+	"git.links123.net/links123.com/skeleton/service/store/cache"
12
+	"git.links123.net/links123.com/skeleton/service/store/mysql"
13
+	"github.com/sirupsen/logrus"
14
+	"github.com/spf13/cobra"
15
+	"github.com/wpajqz/linker"
16
+	"github.com/wpajqz/linker/plugins"
17
+)
18
+
19
+// RunCommand cobra subcommand tcp
20
+func RunCommand() *cobra.Command {
21
+	var host, port string
22
+	cmd := &cobra.Command{
23
+		Use:   "tcp",
24
+		Short: "Run the tcp service",
25
+		Run: func(cmd *cobra.Command, args []string) {
26
+			go Start(host, port)
27
+			// 阻塞退出 捕获信号
28
+			signalChan := make(chan os.Signal)
29
+			signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
30
+			logrus.Infof("caught signal %+v, begin garbage collection", <-signalChan)
31
+			Stop()
32
+		},
33
+	}
34
+
35
+	cmd.PersistentFlags().StringVarP(&host, "host", "o", "0.0.0.0", "server hostname")
36
+	cmd.PersistentFlags().StringVarP(&port, "port", "p", "8081", "server port")
37
+
38
+	return cmd
39
+}
40
+
41
+// Start use for cobra or testing
42
+func Start(host, port string) {
43
+	// init db
44
+	mysql.Init()
45
+	// init cache
46
+	cache.Init()
47
+	// init server
48
+	server := linker.NewServer(linker.Config{
49
+		Timeout: 30 * time.Second,
50
+		PluginForPacketSender: []linker.PacketPlugin{
51
+			&plugins.Encryption{},
52
+			&plugins.Debug{Sender: true},
53
+		},
54
+		PluginForPacketReceiver: []linker.PacketPlugin{
55
+			&plugins.Decryption{},
56
+			&plugins.Debug{Sender: false},
57
+		},
58
+	})
59
+	// build router
60
+	r := router.BuildRouter()
61
+	server.BindRouter(r)
62
+	// start server
63
+	err := server.RunTCP("tcp", strings.Join([]string{host, port}, ":"))
64
+	if err != nil {
65
+		panic(err)
66
+	}
67
+}
68
+
69
+// Stop stop the http service graceful
70
+func Stop() {
71
+	// tcp server graceful shutdown missing
72
+	cache.Close()
73
+	mysql.Close()
74
+}

+ 107
- 0
cmd/tcp/tcp_test.go View File

@@ -0,0 +1,107 @@
1
+package tcp
2
+
3
+import (
4
+	"fmt"
5
+	"os"
6
+	"testing"
7
+	"time"
8
+
9
+	"git.links123.net/links123.com/skeleton/config"
10
+	jwt "github.com/dgrijalva/jwt-go"
11
+	"github.com/stretchr/testify/assert"
12
+	"github.com/wpajqz/go-sdk/export"
13
+)
14
+
15
+var client *export.Client
16
+
17
+type (
18
+	ReadyStateCallback    struct{}
19
+	RequestStatusCallback struct {
20
+		Start   func()
21
+		End     func()
22
+		Success func(header, body []byte)
23
+		Error   func(code int, message string)
24
+	}
25
+)
26
+
27
+func (readyStateCallback *ReadyStateCallback) OnOpen() {
28
+	fmt.Println("Open connection")
29
+}
30
+
31
+func (readyStateCallback *ReadyStateCallback) OnClose() {
32
+	fmt.Println("Close connection")
33
+}
34
+
35
+func (readyStateCallback *ReadyStateCallback) OnError(err string) {
36
+	fmt.Println("Error:", err)
37
+}
38
+
39
+func (r RequestStatusCallback) OnStart() {
40
+	if r.Start != nil {
41
+		r.Start()
42
+	}
43
+}
44
+
45
+func (r RequestStatusCallback) OnSuccess(header, body []byte) {
46
+	if r.Success != nil {
47
+		r.Success(header, body)
48
+	}
49
+}
50
+
51
+func (r RequestStatusCallback) OnError(code int, message string) {
52
+	if r.Error != nil {
53
+		r.Error(code, message)
54
+	}
55
+}
56
+
57
+func (r RequestStatusCallback) OnEnd() {
58
+	if r.End != nil {
59
+		r.End()
60
+	}
61
+}
62
+
63
+func genToken(userID int64) string {
64
+	// Create a new token object, specifying signing method and the claims
65
+	// you would like it to contain.
66
+	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
67
+		"user_id": userID,
68
+		"expired": time.Now().Add(time.Hour).Unix(),
69
+	})
70
+
71
+	// Sign and get the complete encoded token as a string using the secret
72
+	tokenString, err := token.SignedString([]byte(config.C.App.Secret))
73
+	if err != nil {
74
+		panic(err)
75
+	}
76
+	return tokenString
77
+}
78
+
79
+func TestHealthy(t *testing.T) {
80
+	err := client.SyncSend("/v1/", nil, &RequestStatusCallback{
81
+		Success: func(header, body []byte) {
82
+			fmt.Print(header)
83
+			assert.Equal(t, "{\"keepalive\":\"true\"}", string(body))
84
+		},
85
+		Error: func(code int, message string) {
86
+			t.Error(code, message)
87
+		},
88
+	})
89
+	if err != nil {
90
+		t.Error(err)
91
+	}
92
+}
93
+
94
+func TestMain(m *testing.M) {
95
+	// start tcp server
96
+	go Start("127.0.0.1", "8081")
97
+	client = export.NewClient("127.0.0.1", 8081, &ReadyStateCallback{})
98
+	for {
99
+		time.Sleep(time.Second)
100
+		if client.GetReadyState() == export.OPEN {
101
+			break
102
+		}
103
+	}
104
+	client.SetRequestProperty("Authorization", "Bearer "+genToken(217))
105
+	// call flag.Parse() here if TestMain uses flags
106
+	os.Exit(m.Run())
107
+}

+ 23
- 0
cmd/version/version.go View File

@@ -0,0 +1,23 @@
1
+package version
2
+
3
+import (
4
+	"fmt"
5
+	"os"
6
+
7
+	"github.com/spf13/cobra"
8
+)
9
+
10
+// RunCommand version command return api version for tracking binary in different server
11
+func RunCommand(apiVersion, gitCommit, built string) *cobra.Command {
12
+	return &cobra.Command{
13
+		Use:     "version",
14
+		Short:   "The version of forum",
15
+		Aliases: []string{"v"},
16
+		Run: func(cmd *cobra.Command, args []string) {
17
+			fmt.Fprintln(os.Stdout, "Server:")
18
+			fmt.Fprintln(os.Stdout, " Api Version:         ", apiVersion)
19
+			fmt.Fprintln(os.Stdout, " Git commit:          ", gitCommit)
20
+			fmt.Fprintln(os.Stdout, " Built:               ", built)
21
+		},
22
+	}
23
+}

+ 91
- 0
config/config.go View File

@@ -0,0 +1,91 @@
1
+package config
2
+
3
+import (
4
+	"io/ioutil"
5
+	"log"
6
+	"path"
7
+	"strings"
8
+
9
+	"github.com/Unknwon/i18n"
10
+	"github.com/gin-gonic/gin"
11
+	"github.com/joho/godotenv"
12
+	"github.com/sirupsen/logrus"
13
+	"github.com/spf13/viper"
14
+)
15
+
16
+// global config
17
+var (
18
+	C appConfig
19
+)
20
+
21
+type appConfig struct {
22
+	App struct {
23
+		Debug  bool   `mapstructure:"debug"`
24
+		Secret string `mapstructure:"secret"`
25
+	} `mapstructure:"app"`
26
+	DB struct {
27
+		Host               string `mapstructure:"host"`
28
+		User               string `mapstructure:"user"`
29
+		Password           string `mapstructure:"password"`
30
+		Name               string `mapstructure:"name"`
31
+		MaxIdleConnections int    `mapstructure:"max_idle_connections"`
32
+		MaxOpenConnections int    `mapstructure:"max_open_connections"`
33
+	} `mapstructure:"db"`
34
+	Redis struct {
35
+		Address  string `mapstructure:"address"`
36
+		Password string `mapstructure:"password"`
37
+		PoolSize int    `mapstructure:"pool_size"`
38
+	} `mapstructure:"redis"`
39
+}
40
+
41
+func init() {
42
+	// 去掉烦人的gin提示,在http模块中会根据需要打开
43
+	gin.SetMode(gin.ReleaseMode)
44
+
45
+	// load .env file for testing
46
+	godotenv.Load()
47
+
48
+	// app
49
+	viper.SetDefault("app.debug", true)
50
+	viper.SetDefault("app.secret", "123456")
51
+
52
+	// db
53
+	viper.SetDefault("db.host", "localhost:3306")
54
+	viper.SetDefault("db.user", "user")
55
+	viper.SetDefault("db.password", "password")
56
+	viper.SetDefault("db.name", "name")
57
+	viper.SetDefault("db.max_idle_connections", 20)
58
+	viper.SetDefault("db.max_open_connections", 50)
59
+
60
+	// redis
61
+	viper.SetDefault("redis.address", "localhost")
62
+	viper.SetDefault("redis.password", "")
63
+	viper.SetDefault("redis.pool_size", 10)
64
+
65
+	// bind env
66
+	viper.SetEnvPrefix("skeleton")
67
+	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
68
+	viper.AutomaticEnv()
69
+
70
+	// unmarshal config to struct
71
+	if err := viper.Unmarshal(&C); err != nil {
72
+		log.Fatalf("viper.Unmarshal error: %v\n", err)
73
+	}
74
+
75
+	// set logrus debug mode
76
+	if C.App.Debug {
77
+		logrus.SetLevel(logrus.DebugLevel)
78
+	}
79
+
80
+	// load language file for i18n
81
+	files, err := ioutil.ReadDir("languages")
82
+	if err == nil {
83
+		for _, file := range files {
84
+			if err := i18n.SetMessage(strings.TrimSuffix(file.Name(), path.Ext(file.Name())), "languages/"+file.Name()); err != nil {
85
+				log.Fatalf("i18n.SetMessage error: %v\n", err)
86
+			}
87
+		}
88
+
89
+		i18n.SetDefaultLang("en-US")
90
+	}
91
+}

+ 31
- 0
docs/docs.go View File

@@ -0,0 +1,31 @@
1
+// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+// This file was generated by swaggo/swag at
3
+// 2018-06-11 01:31:19.492495763 +0800 CST m=+0.184470647
4
+
5
+package docs
6
+
7
+import (
8
+	"github.com/swaggo/swag"
9
+)
10
+
11
+var doc = `{
12
+    "swagger": "2.0",
13
+    "info": {
14
+        "description": "project skeleton for all project from links123.com",
15
+        "title": "project skeleton for all project from links123.com",
16
+        "contact": {},
17
+        "license": {},
18
+        "version": "1.0"
19
+    },
20
+    "host": "127.0.0.1:8080/v1",
21
+    "paths": {}
22
+}`
23
+
24
+type s struct{}
25
+
26
+func (s *s) ReadDoc() string {
27
+	return doc
28
+}
29
+func init() {
30
+	swag.Register(swag.Name, &s{})
31
+}

+ 12
- 0
docs/swagger/swagger.json View File

@@ -0,0 +1,12 @@
1
+{
2
+    "swagger": "2.0",
3
+    "info": {
4
+        "description": "project skeleton for all project from links123.com",
5
+        "title": "project skeleton for all project from links123.com",
6
+        "contact": {},
7
+        "license": {},
8
+        "version": "1.0"
9
+    },
10
+    "host": "127.0.0.1:8080/v1",
11
+    "paths": {}
12
+}

+ 9
- 0
docs/swagger/swagger.yaml View File

@@ -0,0 +1,9 @@
1
+host: 127.0.0.1:8080/v1
2
+info:
3
+  contact: {}
4
+  description: project skeleton for all project from links123.com
5
+  license: {}
6
+  title: project skeleton for all project from links123.com
7
+  version: "1.0"
8
+paths: {}
9
+swagger: "2.0"

+ 30
- 0
go.mod View File

@@ -0,0 +1,30 @@
1
+module git.links123.net/links123.com/skeleton
2
+
3
+require (
4
+	git.links123.net/links123.com/pkg/middleware/auth v0.0.0-20180919101150-037eea5b1493
5
+	git.links123.net/links123.com/pkg/middleware/cors v0.0.0-20180919101150-037eea5b1493
6
+	git.links123.net/links123.com/pkg/request v0.0.0-20180919101150-037eea5b1493
7
+	git.links123.net/links123.com/uc v0.0.0-20180928160433-cf43fb3dd7c5 // indirect
8
+	github.com/0xAX/notificator v0.0.0-20171022182052-88d57ee9043b // indirect
9
+	github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966
10
+	github.com/braintree/manners v0.0.0-20160418043613-82a8879fc5fd
11
+	github.com/codegangsta/envy v0.0.0-20141216192214-4b78388c8ce4 // indirect
12
+	github.com/codegangsta/gin v0.0.0-20171026143024-cafe2ce98974 // indirect
13
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
14
+	github.com/ghodss/yaml v1.0.0 // indirect
15
+	github.com/gin-gonic/gin v1.3.0
16
+	github.com/go-redis/redis v6.14.1+incompatible
17
+	github.com/joho/godotenv v1.2.0
18
+	github.com/mattn/go-shellwords v1.0.3 // indirect
19
+	github.com/sirupsen/logrus v1.0.6
20
+	github.com/spf13/cobra v0.0.3
21
+	github.com/spf13/viper v1.2.0
22
+	github.com/stretchr/testify v1.2.2
23
+	github.com/swaggo/gin-swagger v1.0.0
24
+	github.com/swaggo/swag v1.3.2
25
+	github.com/urfave/cli v1.20.0 // indirect
26
+	github.com/wpajqz/go-sdk v0.0.0-20180819022515-c5611acbd333
27
+	github.com/wpajqz/linker v0.0.0-20180920052826-c21901f38257
28
+	gopkg.in/urfave/cli.v1 v1.20.0 // indirect
29
+	upper.io/db.v3 v3.5.4+incompatible
30
+)

+ 184
- 0
go.sum View File

@@ -0,0 +1,184 @@
1
+git.links123.net/links123.com/pkg v0.0.0-20180730062323-41c11015b7a7 h1:6a3UFovuyG8FpN6rBjrYLe5Rf5yNWQIIEOpx02iOEw8=
2
+git.links123.net/links123.com/pkg v0.0.0-20180730062323-41c11015b7a7/go.mod h1:qTpTu+0bPvaF2g9MGg8yn7aDIZKKk/7OzitnQmC+M68=
3
+git.links123.net/links123.com/pkg v0.0.0-20180919101150-037eea5b1493 h1:Ky4MMh4lqVu6fa15lUhlXBufKVevhFUf2f9Ek0h+VGE=
4
+git.links123.net/links123.com/pkg v0.0.0-20180919101150-037eea5b1493/go.mod h1:qTpTu+0bPvaF2g9MGg8yn7aDIZKKk/7OzitnQmC+M68=
5
+git.links123.net/links123.com/pkg/middleware/auth v0.0.0-20180919101150-037eea5b1493 h1:jKyz2Pfvd9vpPuDwZUDENIP9toZ5WW3YXM6hGWDnzxk=
6
+git.links123.net/links123.com/pkg/middleware/auth v0.0.0-20180919101150-037eea5b1493/go.mod h1:D1WZH6ULNM6Otkb/mqKgqxqPOMXHwG6E85IjiNs4uks=
7
+git.links123.net/links123.com/pkg/middleware/cors v0.0.0-20180919101150-037eea5b1493 h1:JjZ7V+/0Juazyl3vK5VYRTqN6LKrehtMXLMJ8qfiT7g=
8
+git.links123.net/links123.com/pkg/middleware/cors v0.0.0-20180919101150-037eea5b1493/go.mod h1:olQHLIsJHOtHuqIz+RtLojXYGyfAxZ6y5xmZOiJUUxM=
9
+git.links123.net/links123.com/pkg/request v0.0.0-20180919101150-037eea5b1493 h1:PKSbi8Fz+ZuKFeMkswEEi2gbFeMT1M9T4dKs2ubRuuw=
10
+git.links123.net/links123.com/pkg/request v0.0.0-20180919101150-037eea5b1493/go.mod h1:eF0R3hZ3ELW9aTBAv4TU2PDbbguByFOqxKNjldftMg4=
11
+git.links123.net/links123.com/pkg/utils v0.0.0-20180919101150-037eea5b1493 h1:kpAeiPs37LO35my+yZjf6Lrm4MdFvhMoTCU/iiJ9Hdk=
12
+git.links123.net/links123.com/pkg/utils v0.0.0-20180919101150-037eea5b1493/go.mod h1:XnN8VQWIlvU8HRsdrYKH0fe3dQ1dgctqGTd+RnIzXoY=
13
+git.links123.net/links123.com/uc v0.0.0-20180928160433-cf43fb3dd7c5 h1:Sy+ChIDYdzGQJHWk0bJultPHrAjGOqGYdqXA/BjLOiM=
14
+git.links123.net/links123.com/uc v0.0.0-20180928160433-cf43fb3dd7c5/go.mod h1:KDsGY1VC3Htm+gFf2U4pqZ4HSVffrRkxZFz0C/xP4Uk=
15
+github.com/0xAX/notificator v0.0.0-20171022182052-88d57ee9043b h1:Sn+u6zpXFyfm2X7ruh+z6SJiUVyFg8YElh6HIOhrRCA=
16
+github.com/0xAX/notificator v0.0.0-20171022182052-88d57ee9043b/go.mod h1:NtXa9WwQsukMHZpjNakTTz0LArxvGYdPA9CjIcUSZ6s=
17
+github.com/BurntSushi/toml v0.3.0 h1:e1/Ivsx3Z0FVTV0NSOv/aVgbUWyQuzj7DDnFblkRvsY=
18
+github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
19
+github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4=
20
+github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
21
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
22
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
23
+github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 h1:Mp8GNJ/tdTZIEdLdZfykEJaL3mTyEYrSzYNcdoQKpJk=
24
+github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966/go.mod h1:SFtfq0zFPsENI7DpE87QM2hcYu5QQ0fRdCgP+P1Hrqo=
25
+github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20180918114345-ddc87ec2145f h1:4iY9zQViTuwFYEiWs58tio/lDw2emX96jT817Xr3rUg=
26
+github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20180918114345-ddc87ec2145f/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
27
+github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
28
+github.com/braintree/manners v0.0.0-20160418043613-82a8879fc5fd h1:ePesaBzdTmoMQjwqRCLP2jY+jjWMBpwws/LEQdt1fMM=
29
+github.com/braintree/manners v0.0.0-20160418043613-82a8879fc5fd/go.mod h1:TNehV1AhBwtT7Bd+rh8G6MoGDbBLNs/sKdk3nvr4Yzg=
30
+github.com/bu/gin-access-limit v0.0.0-20180526093834-d85581b8e2c4/go.mod h1:yvTzcu7B9xwo2bXcqaWqzyzsWnofVO5jK8KHvzNAKXY=
31
+github.com/codegangsta/envy v0.0.0-20141216192214-4b78388c8ce4 h1:ihrIKrLQzm6Q6NJHBMemvaIGTFxgxQUEkn2AjN0Aulw=
32
+github.com/codegangsta/envy v0.0.0-20141216192214-4b78388c8ce4/go.mod h1:X7wHz0C25Lga6CnJ4WAQNbUQ9P/8eWSNv8qIO71YkSM=
33
+github.com/codegangsta/gin v0.0.0-20171026143024-cafe2ce98974 h1:ysuVNDVE4LIky6I+6JlgAKG+wBNKMpVv3m3neVpvFVw=
34
+github.com/codegangsta/gin v0.0.0-20171026143024-cafe2ce98974/go.mod h1:UBYuwaH3dMw91EZ7tGVaFF6GDj5j46S7zqB9lZPIe58=
35
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
36
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
37
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
38
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
39
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
40
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
41
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
42
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
43
+github.com/gin-contrib/cors v0.0.0-20180912121935-a3af05a9b13e h1:j3eUUIqSQTxePdkqPb27FhbCYGngm/7x6hGjf5dskUk=
44
+github.com/gin-contrib/cors v0.0.0-20180912121935-a3af05a9b13e/go.mod h1:cw+u9IsAkC16e42NtYYVCLsHYXE98nB3M7Dr9mLSeH4=
45
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY=
46
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
47
+github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
48
+github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
49
+github.com/go-openapi/jsonpointer v0.0.0-20180322222829-3a0015ad55fa h1:hr8WVDjg4JKtQptZpzyb196TmruCs7PIsdJz8KAOZp8=
50
+github.com/go-openapi/jsonpointer v0.0.0-20180322222829-3a0015ad55fa/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
51
+github.com/go-openapi/jsonreference v0.0.0-20180322222742-3fb327e6747d h1:k3UQ7Z8yFYq0BNkYykKIheY0HlZBl1Hku+pO9HE9FNU=
52
+github.com/go-openapi/jsonreference v0.0.0-20180322222742-3fb327e6747d/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
53
+github.com/go-openapi/spec v0.0.0-20180801175345-384415f06ee2 h1:D9BfbclVKVcfluusYmw6Z2/O74y41shNFpN5jbbcbSs=
54
+github.com/go-openapi/spec v0.0.0-20180801175345-384415f06ee2/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
55
+github.com/go-openapi/swag v0.0.0-20180715190254-becd2f08beaf h1:7lg/DRYbE2t6UvEipbKopk3GzYhRnv9/+qpUMYNfiAw=
56
+github.com/go-openapi/swag v0.0.0-20180715190254-becd2f08beaf/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
57
+github.com/go-redis/redis v6.14.1+incompatible h1:kSJohAREGMr344uMa8PzuIg5OU6ylCbyDkWkkNOfEik=
58
+github.com/go-redis/redis v6.14.1+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
59
+github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
60
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
61
+github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
62
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
63
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
64
+github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSfgRJKqIzapE78onvvTbdi1rMkU00lZw=
65
+github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
66
+github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
67
+github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
68
+github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
69
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
70
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
71
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
72
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
73
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
74
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
75
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
76
+github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 h1:sHsPfNMAG70QAvKbddQ0uScZCHQoZsT5NykGRCeeeIs=
77
+github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
78
+github.com/joho/godotenv v1.2.0 h1:vGTvz69FzUFp+X4/bAkb0j5BoLC+9bpqTWY8mjhA9pc=
79
+github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
80
+github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
81
+github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
82
+github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
83
+github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
84
+github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
85
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
86
+github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
87
+github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
88
+github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
89
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
90
+github.com/mattn/go-shellwords v1.0.3 h1:K/VxK7SZ+cvuPgFSLKi5QPI9Vr/ipOf4C1gN+ntueUk=
91
+github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
92
+github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KHeTRY+7I=
93
+github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
94
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
95
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
96
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
97
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
98
+github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
99
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
100
+github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
101
+github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
102
+github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
103
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
104
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
105
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
106
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
107
+github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s=
108
+github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
109
+github.com/skip2/go-qrcode v0.0.0-20171229120447-cf5f9fa2f0d8 h1:5C4yAeYifeRO+7z2/H2kxL8tJZE9ZE9LpxK6YUZPByo=
110
+github.com/skip2/go-qrcode v0.0.0-20171229120447-cf5f9fa2f0d8/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
111
+github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf h1:6V1qxN6Usn4jy8unvggSJz/NC790tefw8Zdy6OZS5co=
112
+github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
113
+github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo=
114
+github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
115
+github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
116
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
117
+github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
118
+github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
119
+github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
120
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
121
+github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
122
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
123
+github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=
124
+github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
125
+github.com/spf13/viper v1.2.0 h1:M4Rzxlu+RgU4pyBRKhKaVN1VeYOm8h2jgyXnAseDgCc=
126
+github.com/spf13/viper v1.2.0/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI=
127
+github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
128
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
129
+github.com/swaggo/gin-swagger v1.0.0 h1:k6Nn1jV49u+SNIWt7kejQS/iENZKZVMCNQrKOYatNF8=
130
+github.com/swaggo/gin-swagger v1.0.0/go.mod h1:Mt37wE46iUaTAOv+HSnHbJYssKGqbS25X19lNF4YpBo=
131
+github.com/swaggo/swag v1.3.2 h1:pR137hlBoouh2OWd//4F7xchfCXC1ry6yGFbxEjM9d4=
132
+github.com/swaggo/swag v1.3.2/go.mod h1:hog2WgeMOrQ/LvQ+o1YGTeT+vWVrbi0SiIslBtxKTyM=
133
+github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942 h1:CZORS/4d6i+5FKSAtbRIjlElV2BAFYv/bokcaEVUimQ=
134
+github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
135
+github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
136
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
137
+github.com/wpajqz/go-sdk v0.0.0-20180819022515-c5611acbd333 h1:uIekph2ww/ZvE3w3kC36LdwIjfGj3enaf1SNWEh04oQ=
138
+github.com/wpajqz/go-sdk v0.0.0-20180819022515-c5611acbd333/go.mod h1:8Z5OwaDGrREAqXYMHp9WVhDIkZdeJFfNbUyjYQGRg8U=
139
+github.com/wpajqz/linker v0.0.0-20180818151004-5d64412a1130/go.mod h1:1LpNSex7lqvQi8t5uj9LBLKsvxfm3HK2j6o5Ht3BGmQ=
140
+github.com/wpajqz/linker v0.0.0-20180819092514-365de6cb57f8 h1:LuppfseRirIe/OnBXecBtC6m3gSXnHzlpilEfJI57xo=
141
+github.com/wpajqz/linker v0.0.0-20180819092514-365de6cb57f8/go.mod h1:qDGjG+ES9GK54nkt/8PE3SbGtKyZI0U0XSU7B8hvhqM=
142
+github.com/wpajqz/linker v0.0.0-20180920052826-c21901f38257 h1:i5vHdYSGYZr6fJ2S/MTY8PCvUAZCks5wbZcmBgmNKGc=
143
+github.com/wpajqz/linker v0.0.0-20180920052826-c21901f38257/go.mod h1:qDGjG+ES9GK54nkt/8PE3SbGtKyZI0U0XSU7B8hvhqM=
144
+golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b h1:2b9XGzhjiYsYPnKXoEfL7klWZQIt8IfyRCz62gCqqlQ=
145
+golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
146
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
147
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
148
+golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3 h1:czFLhve3vsQetD6JOJ8NZZvGQIXlnN3/yXxbT6/awxI=
149
+golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
150
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
151
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
152
+golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 h1:BH3eQWeGbwRU2+wxxuuPOdFBmaiBH81O8BugSjHeTFg=
153
+golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
154
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
155
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
156
+golang.org/x/sys v0.0.0-20180918153733-ee1b12c67af4/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
157
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
158
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
159
+google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24=
160
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
161
+gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=
162
+gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
163
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
164
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
165
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
166
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
167
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0=
168
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
169
+gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
170
+gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
171
+gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
172
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
173
+gopkg.in/ini.v1 v1.38.2 h1:dGcbywv4RufeGeiMycPT/plKB5FtmLKLnWKwBiLhUA4=
174
+gopkg.in/ini.v1 v1.38.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
175
+gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU=
176
+gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
177
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
178
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
179
+gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
180
+gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
181
+gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
182
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
183
+upper.io/db.v3 v3.5.4+incompatible h1:IvIK91XGeyFpSO2qcSWeStQ87uZJnkVpn47oa9smytc=
184
+upper.io/db.v3 v3.5.4+incompatible/go.mod h1:FgTdD24eBjJAbPKsQSiHUNgXjOR4Lub3u1UMHSIh82Y=

+ 0
- 0
internal/.gitkeep View File


+ 1
- 0
languages/en-US.ini View File

@@ -0,0 +1 @@
1
+hi = hello, %s

+ 1
- 0
languages/zh-CN.ini View File

@@ -0,0 +1 @@
1
+hi = 你好,%s

+ 29
- 0
main.go View File

@@ -0,0 +1,29 @@
1
+package main
2
+
3
+import (
4
+	"git.links123.net/links123.com/monitor_status/cmd/http"
5
+	"git.links123.net/links123.com/monitor_status/cmd/tcp"
6
+	"git.links123.net/links123.com/monitor_status/cmd/version"
7
+	"github.com/spf13/cobra"
8
+)
9
+
10
+var apiVersion, gitCommit, built string
11
+
12
+// @title project skeleton for all project from links123.com
13
+// @version 1.0
14
+// @description project skeleton for all project from links123.com
15
+// @host 127.0.0.1:8080/v1
16
+func main() {
17
+	rootCmd := &cobra.Command{
18
+		Use:   "skeleton",
19
+		Short: "skeleton api for the project of links123.com's campus",
20
+	}
21
+
22
+	rootCmd.AddCommand(http.RunCommand())
23
+	rootCmd.AddCommand(tcp.RunCommand())
24
+	rootCmd.AddCommand(version.RunCommand(apiVersion, gitCommit, built))
25
+
26
+	if err := rootCmd.Execute(); err != nil {
27
+		panic(err)
28
+	}
29
+}

+ 0
- 0
migrations/.gitkeep View File


+ 6
- 0
service/api/README.md View File

@@ -0,0 +1,6 @@
1
+# 说明
2
+
3
+api 包含
4
+
5
+- 接收外部请求数据的结构体
6
+- 对外部请求进行响应返回的结构体

+ 39
- 0
service/api/common.go View File

@@ -0,0 +1,39 @@
1
+package api
2
+
3
+import (
4
+	"fmt"
5
+)
6
+
7
+// language code
8
+const (
9
+	EnUS = 1
10
+	ZhCN = 2
11
+)
12
+
13
+// CommonParams page and lang info
14
+type CommonParams struct {
15
+	TargetStr string `form:"lang"`
16
+	Target    int
17
+	Page      int `form:"page"`
18
+	Limit     int `form:"limit"`
19
+}
20
+
21
+// Check param check
22
+func (cp *CommonParams) Check() error {
23
+	switch cp.TargetStr {
24
+	case "", "en-US":
25
+		cp.Target = EnUS
26
+	case "zh-CN":
27
+		cp.Target = ZhCN
28
+	default:
29
+		return fmt.Errorf("Unexpected target param: %s", cp.TargetStr)
30
+	}
31
+
32
+	if cp.Limit == 0 {
33
+		cp.Limit = 10
34
+	}
35
+	if cp.Page == 0 {
36
+		cp.Page = 1
37
+	}
38
+	return nil
39
+}

+ 1
- 0
service/service.go View File

@@ -0,0 +1 @@
1
+package service

+ 10
- 0
service/store/cache/auth.go View File

@@ -0,0 +1,10 @@
1
+package cache
2
+
3
+import (
4
+	"git.links123.net/links123.com/pkg/middleware/auth"
5
+)
6
+
7
+// AuthSessionStore 认证存储
8
+func AuthSessionStore() auth.Session {
9
+	return session
10
+}

+ 12
- 0
service/store/cache/auth_test.go View File

@@ -0,0 +1,12 @@
1
+package cache
2
+
3
+import (
4
+	"testing"
5
+)
6
+
7
+func TestAuthSessionStore(t *testing.T) {
8
+	store := AuthSessionStore()
9
+	if store == nil {
10
+		t.Error("init auth session store error")
11
+	}
12
+}

+ 60
- 0
service/store/cache/cache.go View File

@@ -0,0 +1,60 @@
1
+package cache
2
+
3
+import (
4
+	"sync"
5
+	"time"
6
+
7
+	"git.links123.net/links123.com/pkg/middleware/auth"
8
+	"git.links123.net/links123.com/skeleton/config"
9
+	"github.com/go-redis/redis"
10
+	"github.com/sirupsen/logrus"
11
+)
12
+
13
+var (
14
+	client  *redis.Client
15
+	session auth.Session
16
+	once    = &sync.Once{}
17
+)
18
+
19
+// Init 初始化缓存
20
+func Init() {
21
+	once.Do(func() {
22
+		redisConfig := config.C.Redis
23
+
24
+		client = redis.NewClient(&redis.Options{
25
+			Addr:     redisConfig.Address,
26
+			Password: redisConfig.Password,
27
+			PoolSize: redisConfig.PoolSize,
28
+		})
29
+
30
+		for {
31
+			if err := client.Ping().Err(); err != nil {
32
+				logrus.Warn("waiting for redis server start...")
33
+				time.Sleep(3 * time.Second)
34
+				continue
35
+			}
36
+
37
+			logrus.Info("connect to redis successful")
38
+
39
+			break
40
+		}
41
+
42
+		if config.C.App.Debug {
43
+			session = auth.NewDebugSessionStore()
44
+		} else {
45
+			session = auth.NewRedisSessionStore(redisConfig.Address, redisConfig.Password)
46
+		}
47
+	})
48
+}
49
+
50
+// Close 退出时关闭链接
51
+func Close() {
52
+	if client != nil {
53
+		err := client.Close()
54
+		if err != nil {
55
+			logrus.Errorf("close redis connection error: %s", err.Error())
56
+			return
57
+		}
58
+		logrus.Info("redis connection closed")
59
+	}
60
+}

+ 11
- 0
service/store/cache/cache_test.go View File

@@ -0,0 +1,11 @@
1
+package cache
2
+
3
+import (
4
+	"os"
5
+	"testing"
6
+)
7
+
8
+func TestMain(m *testing.M) {
9
+	Init()
10
+	os.Exit(m.Run())
11
+}

+ 69
- 0
service/store/mysql/mysql.go View File

@@ -0,0 +1,69 @@
1
+package mysql
2
+
3
+import (
4
+	"time"
5
+
6
+	"git.links123.net/links123.com/skeleton/config"
7
+	"git.links123.net/links123.com/skeleton/service/api"
8
+	"github.com/sirupsen/logrus"
9
+	"upper.io/db.v3/lib/sqlbuilder"
10
+	"upper.io/db.v3/mysql"
11
+)
12
+
13
+var (
14
+	session sqlbuilder.Database
15
+)
16
+
17
+// Init 初始化数据库
18
+func Init() {
19
+	dbConfig := config.C.DB
20
+	settings := mysql.ConnectionURL{
21
+		Host:     dbConfig.Host,
22
+		Database: dbConfig.Name,
23
+		User:     dbConfig.User,
24
+		Password: dbConfig.Password,
25
+	}
26
+
27
+	var err error
28
+	if session, err = mysql.Open(settings); err != nil {
29
+		logrus.WithField("dsn", settings.String()).Info("connect db failed")
30
+		panic(err)
31
+	}
32
+
33
+	logrus.WithField("dsn", settings.String()).Info("connect db success")
34
+
35
+	session.SetMaxIdleConns(dbConfig.MaxIdleConnections)
36
+	session.SetMaxOpenConns(dbConfig.MaxOpenConnections)
37
+
38
+	for {
39
+		if err := session.Ping(); err != nil {
40
+			logrus.Warn("waiting for mysql server start...")
41
+			time.Sleep(3 * time.Second)
42
+			continue
43
+		}
44
+
45
+		logrus.Info("connect to mysql successful")
46
+
47
+		break
48
+	}
49
+
50
+	if config.C.App.Debug {
51
+		session.SetLogging(true)
52
+	}
53
+}
54
+
55
+// Close 在程序退出时关闭连接
56
+func Close() {
57
+	if session != nil {
58
+		err := session.Close()
59
+		if err != nil {
60
+			logrus.Errorf("error close mysql connection: %s", err.Error())
61
+			return
62
+		}
63
+	}
64
+	logrus.Info("mysql connection close")
65
+}
66
+
67
+func paging(selector sqlbuilder.Selector, cp api.CommonParams) sqlbuilder.Paginator {
68
+	return selector.Paginate(uint(cp.Limit)).Page(uint(cp.Page))
69
+}

+ 66
- 0
vendor/git.links123.net/links123.com/pkg/middleware/auth/auth.go View File

@@ -0,0 +1,66 @@
1
+package auth
2
+
3
+import (
4
+	"fmt"
5
+	"net/http"
6
+
7
+	"github.com/dgrijalva/jwt-go"
8
+	"github.com/gin-gonic/gin"
9
+)
10
+
11
+const (
12
+	CtxRequestHeaderUserId        = "user_id"
13
+	ctxRequestHeaderAuthorization = "Authorization"
14
+	ctxRequestCookieAuthorization = "ak"
15
+	ctxRequestTokenExpired        = "expired"
16
+)
17
+
18
+func Auth(authKey string, session Session) gin.HandlerFunc {
19
+	return func(ctx *gin.Context) {
20
+		var tokenFromCookie, tokenFromHeader string
21
+
22
+		tokenFromCookie, err := ctx.Cookie(ctxRequestCookieAuthorization)
23
+		if err == http.ErrNoCookie {
24
+			tokenFromHeader = ctx.Request.Header.Get(ctxRequestHeaderAuthorization)
25
+		}
26
+
27
+		if tokenFromHeader == "" {
28
+			tokenFromHeader = "Bearer " + tokenFromCookie
29
+		}
30
+
31
+		if len(tokenFromHeader) < 8 {
32
+			ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed"})
33
+			return
34
+		}
35
+
36
+		token, err := jwt.Parse(tokenFromHeader[7:], func(token *jwt.Token) (interface{}, error) {
37
+			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
38
+				return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
39
+			}
40
+
41
+			return []byte(authKey), nil
42
+		})
43
+
44
+		if err != nil || !token.Valid {
45
+			ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed"})
46
+			return
47
+		}
48
+
49
+		if !session.IsExistsJwtToken(token.Raw) {
50
+			ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed, token expired by server"})
51
+			return
52
+		}
53
+
54
+		if mapClaims, ok := token.Claims.(jwt.MapClaims); ok {
55
+			if uid, ok := mapClaims[CtxRequestHeaderUserId].(float64); ok {
56
+				ctx.Set(CtxRequestHeaderUserId, int64(uid))
57
+			} else {
58
+				ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed, mapClaims[CtxRequestHeaderUserId].(float64) error"})
59
+				return
60
+			}
61
+		} else {
62
+			ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed, token.Claims.(jwt.MapClaims) error"})
63
+			return
64
+		}
65
+	}
66
+}

+ 14
- 0
vendor/git.links123.net/links123.com/pkg/middleware/auth/go.mod View File

@@ -0,0 +1,14 @@
1
+module git.links123.net/links123.com/pkg/middleware/auth
2
+
3
+require (
4
+	git.links123.net/links123.com/pkg v0.0.0-20180730062323-41c11015b7a7
5
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
6
+	github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
7
+	github.com/gin-gonic/gin v1.3.0
8
+	github.com/go-redis/redis v6.14.1+incompatible
9
+	github.com/golang/protobuf v1.2.0 // indirect
10
+	github.com/mattn/go-isatty v0.0.4 // indirect
11
+	github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942 // indirect
12
+	gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
13
+	gopkg.in/yaml.v2 v2.2.1 // indirect
14
+)

+ 21
- 0
vendor/git.links123.net/links123.com/pkg/middleware/auth/go.sum View File

@@ -0,0 +1,21 @@
1
+git.links123.net/links123.com/pkg v0.0.0-20180730062323-41c11015b7a7 h1:6a3UFovuyG8FpN6rBjrYLe5Rf5yNWQIIEOpx02iOEw8=
2
+git.links123.net/links123.com/pkg v0.0.0-20180730062323-41c11015b7a7/go.mod h1:qTpTu+0bPvaF2g9MGg8yn7aDIZKKk/7OzitnQmC+M68=
3
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
4
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
5
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY=
6
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
7
+github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
8
+github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
9
+github.com/go-redis/redis v6.14.1+incompatible h1:kSJohAREGMr344uMa8PzuIg5OU6ylCbyDkWkkNOfEik=
10
+github.com/go-redis/redis v6.14.1+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
11
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
12
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
13
+github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
14
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
15
+github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942 h1:CZORS/4d6i+5FKSAtbRIjlElV2BAFYv/bokcaEVUimQ=
16
+github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
17
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
18
+gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
19
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
20
+gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
21
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 44
- 0
vendor/git.links123.net/links123.com/pkg/middleware/auth/optional_auth.go View File

@@ -0,0 +1,44 @@
1
+package auth
2
+
3
+import (
4
+	"net/http"
5
+
6
+	"fmt"
7
+	"github.com/dgrijalva/jwt-go"
8
+	"github.com/gin-gonic/gin"
9
+)
10
+
11
+func OptionalAuth(authKey string) gin.HandlerFunc {
12
+	return func(ctx *gin.Context) {
13
+		var tokenFromCookie, tokenFromHeader string
14
+
15
+		tokenFromCookie, err := ctx.Cookie(ctxRequestCookieAuthorization)
16
+		if err == http.ErrNoCookie {
17
+			tokenFromHeader = ctx.Request.Header.Get(ctxRequestHeaderAuthorization)
18
+		}
19
+
20
+		if tokenFromHeader == "" {
21
+			tokenFromHeader = "Bearer " + tokenFromCookie
22
+		}
23
+
24
+		if len(tokenFromHeader) > 7 {
25
+			token, err := jwt.Parse(tokenFromHeader[7:], func(token *jwt.Token) (interface{}, error) {
26
+				if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
27
+					return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
28
+				}
29
+
30
+				return []byte(authKey), nil
31
+			})
32
+
33
+			if err != nil || !token.Valid {
34
+				return
35
+			}
36
+
37
+			if mapClaims, ok := token.Claims.(jwt.MapClaims); ok {
38
+				if uid, ok := mapClaims[CtxRequestHeaderUserId].(float64); ok {
39
+					ctx.Set(CtxRequestHeaderUserId, int64(uid))
40
+				}
41
+			}
42
+		}
43
+	}
44
+}

+ 12
- 0
vendor/git.links123.net/links123.com/pkg/middleware/auth/session.go View File

@@ -0,0 +1,12 @@
1
+package auth
2
+
3
+type Session interface {
4
+	// StoreJwtToken store jwt token is redis, make it expired for feature
5
+	StoreJwtToken(token string, uid int64, timeout int64) error
6
+
7
+	// IsExistsJwtToken judge whether token is invalid
8
+	IsExistsJwtToken(token string) bool
9
+
10
+	// DeleteJwtToken delete jwt token
11
+	DeleteJwtToken(token string) bool
12
+}

+ 20
- 0
vendor/git.links123.net/links123.com/pkg/middleware/auth/session_debug.go View File

@@ -0,0 +1,20 @@
1
+package auth
2
+
3
+type DebugSessionStore struct{}
4
+
5
+func NewDebugSessionStore() *DebugSessionStore {
6
+	return &DebugSessionStore{}
7
+}
8
+
9
+func (*DebugSessionStore) StoreJwtToken(key string, uid int64, timeout int64) error {
10
+	return nil
11
+}
12
+
13
+func (*DebugSessionStore) IsExistsJwtToken(key string) bool {
14
+	return true
15
+}
16
+
17
+// DeleteJwtToken delete jwt token
18
+func (*DebugSessionStore) DeleteJwtToken(key string) bool {
19
+	return true
20
+}

+ 52
- 0
vendor/git.links123.net/links123.com/pkg/middleware/auth/session_redis.go View File

@@ -0,0 +1,52 @@
1
+package auth
2
+
3
+import (
4
+	"encoding/json"
5
+	"time"
6
+
7
+	"git.links123.net/links123.com/pkg/utils"
8
+	"github.com/go-redis/redis"
9
+)
10
+
11
+type (
12
+	RedisSessionStore struct{ client *redis.Client }
13
+
14
+	item map[string]interface{}
15
+)
16
+
17
+func NewRedisSessionStore(address string, password string) *RedisSessionStore {
18
+	session := &RedisSessionStore{}
19
+	session.client = redis.NewClient(&redis.Options{
20
+		Addr:     address,
21
+		Password: password,
22
+	})
23
+
24
+	if err := session.client.Ping().Err(); err != nil {
25
+		panic(err)
26
+	}
27
+
28
+	return session
29
+}
30
+
31
+func (rss *RedisSessionStore) StoreJwtToken(token string, uid int64, timeout int64) error {
32
+	k := utils.Md5(token)
33
+	v := item{"user_id": uid, "created": time.Now().Unix()}
34
+
35
+	return rss.client.Set(k, v, time.Duration(timeout)*time.Second).Err()
36
+}
37
+
38
+func (rss *RedisSessionStore) IsExistsJwtToken(token string) bool {
39
+	k := utils.Md5(token)
40
+
41
+	return rss.client.Exists(k).Val() == 1
42
+}
43
+
44
+func (rss *RedisSessionStore) DeleteJwtToken(token string) bool {
45
+	k := utils.Md5(token)
46
+
47
+	return rss.client.Del(k).Val() == 1
48
+}
49
+
50
+func (i item) MarshalBinary() (data []byte, err error) {
51
+	return json.Marshal(i)
52
+}

+ 30
- 0
vendor/git.links123.net/links123.com/pkg/middleware/cors/cors.go View File

@@ -0,0 +1,30 @@
1
+package cors
2
+
3
+import (
4
+	"net/http"
5
+	"strings"
6
+
7
+	"github.com/gin-contrib/cors"
8
+	"github.com/gin-gonic/gin"
9
+)
10
+
11
+func Cors() gin.HandlerFunc {
12
+	config := cors.DefaultConfig()
13
+
14
+	config.AddAllowMethods(http.MethodDelete, http.MethodOptions, http.MethodPatch)
15
+	config.AddAllowHeaders("Authorization", "X-Require-Cookie")
16
+	config.AllowCredentials = true
17
+	config.AllowOriginFunc = func(origin string) bool {
18
+		if gin.Mode() == gin.DebugMode {
19
+			return true
20
+		}
21
+
22
+		if strings.Contains(origin, "links123.com") {
23
+			return true
24
+		}
25
+
26
+		return false
27
+	}
28
+
29
+	return cors.New(config)
30
+}

+ 12
- 0
vendor/git.links123.net/links123.com/pkg/middleware/cors/go.mod View File

@@ -0,0 +1,12 @@
1
+module git.links123.net/links123.com/pkg/middleware/cors
2
+
3
+require (
4
+	github.com/gin-contrib/cors v0.0.0-20180912121935-a3af05a9b13e
5
+	github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
6
+	github.com/gin-gonic/gin v1.3.0
7
+	github.com/golang/protobuf v1.2.0 // indirect
8
+	github.com/mattn/go-isatty v0.0.4 // indirect
9
+	github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942 // indirect
10
+	gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
11
+	gopkg.in/yaml.v2 v2.2.1 // indirect
12
+)

+ 17
- 0
vendor/git.links123.net/links123.com/pkg/middleware/cors/go.sum View File

@@ -0,0 +1,17 @@
1
+github.com/gin-contrib/cors v0.0.0-20180912121935-a3af05a9b13e h1:j3eUUIqSQTxePdkqPb27FhbCYGngm/7x6hGjf5dskUk=
2
+github.com/gin-contrib/cors v0.0.0-20180912121935-a3af05a9b13e/go.mod h1:cw+u9IsAkC16e42NtYYVCLsHYXE98nB3M7Dr9mLSeH4=
3
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY=
4
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
5
+github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
6
+github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
7
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
8
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
9
+github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
10
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
11
+github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942 h1:CZORS/4d6i+5FKSAtbRIjlElV2BAFYv/bokcaEVUimQ=
12
+github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
13
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
14
+gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
15
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
16
+gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
17
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 5
- 0
vendor/git.links123.net/links123.com/pkg/request/error.go View File

@@ -0,0 +1,5 @@
1
+package request
2
+
3
+type HTTPError struct {
4
+	Msg string `json:"msg" example:"status bad request"`
5
+}

+ 14
- 0
vendor/git.links123.net/links123.com/pkg/request/go.mod View File

@@ -0,0 +1,14 @@
1
+module git.links123.net/links123.com/pkg/request
2
+
3
+require (
4
+	github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
5
+	github.com/gin-gonic/gin v1.3.0
6
+	github.com/golang/protobuf v1.2.0 // indirect
7
+	github.com/mattn/go-isatty v0.0.4 // indirect
8
+	github.com/sirupsen/logrus v1.0.6
9
+	github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942 // indirect
10
+	golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b // indirect
11
+	golang.org/x/sys v0.0.0-20180918153733-ee1b12c67af4 // indirect
12
+	gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
13
+	gopkg.in/yaml.v2 v2.2.1 // indirect
14
+)

+ 21
- 0
vendor/git.links123.net/links123.com/pkg/request/go.sum View File

@@ -0,0 +1,21 @@
1
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY=
2
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
3
+github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
4
+github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
5
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
6
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
7
+github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
8
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
9
+github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s=
10
+github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
11
+github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942 h1:CZORS/4d6i+5FKSAtbRIjlElV2BAFYv/bokcaEVUimQ=
12
+github.com/ugorji/go/codec v0.0.0-20180831062425-e253f1f20942/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
13
+golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b h1:2b9XGzhjiYsYPnKXoEfL7klWZQIt8IfyRCz62gCqqlQ=
14
+golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
15
+golang.org/x/sys v0.0.0-20180918153733-ee1b12c67af4 h1:h8ij2QOL81JqJ/Vi5Ru+hl4a1yct8+XDGrgBhG0XbuE=
16
+golang.org/x/sys v0.0.0-20180918153733-ee1b12c67af4/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
17
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
18
+gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
19
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
20
+gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
21
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 65
- 0
vendor/git.links123.net/links123.com/pkg/request/request.go View File

@@ -0,0 +1,65 @@
1
+package request
2
+
3
+import (
4
+	"fmt"
5
+	"net/http"
6
+	"runtime"
7
+
8
+	"github.com/gin-gonic/gin"
9
+	"github.com/sirupsen/logrus"
10
+)
11
+
12
+type Checker interface {
13
+	Check() error
14
+}
15
+
16
+func ParseParamFail(ctx *gin.Context, r interface{}, fs ...func() error) bool {
17
+	if r != nil {
18
+		if Fail(ctx, http.StatusBadRequest, ctx.ShouldBind(r)) {
19
+			return true
20
+		}
21
+
22
+		if checker, ok := r.(Checker); ok {
23
+			return Fail(ctx, http.StatusBadRequest, checker.Check())
24
+		}
25
+	}
26
+
27
+	for _, f := range fs {
28
+		if Fail(ctx, http.StatusBadRequest, f()) {
29
+			return true
30
+		}
31
+	}
32
+
33
+	return false
34
+}
35
+
36
+func Fail(ctx *gin.Context, status int, err error) bool {
37
+	if err == nil {
38
+		return false
39
+	}
40
+
41
+	ctx.JSON(status, HTTPError{Msg: err.Error()})
42
+
43
+	if status == http.StatusInternalServerError {
44
+		_, file, line, _ := runtime.Caller(1)
45
+		logrus.WithField("err", err).Errorf("file:%s line:%d", file, line)
46
+	}
47
+
48
+	return true
49
+}
50
+
51
+func Success(ctx *gin.Context, data interface{}) {
52
+	if data == nil {
53
+		ctx.Status(http.StatusNoContent)
54
+		return
55
+	}
56
+
57
+	switch ctx.Request.Method {
58
+	case http.MethodGet, http.MethodHead, http.MethodOptions, http.MethodDelete:
59
+		ctx.JSON(http.StatusOK, data)
60
+	case http.MethodPost, http.MethodPut, http.MethodPatch:
61
+		ctx.JSON(http.StatusCreated, data)
62
+	default:
63
+		ctx.JSON(http.StatusBadRequest, HTTPError{Msg: fmt.Sprintf("unsupported request method %s", ctx.Request.Method)})
64
+	}
65
+}

+ 14
- 0
vendor/git.links123.net/links123.com/pkg/utils/encrypt.go View File

@@ -0,0 +1,14 @@
1
+package utils
2
+
3
+import (
4
+	"crypto/md5"
5
+	"encoding/hex"
6
+)
7
+
8
+func Md5(src string) string {
9
+	h := md5.New()
10
+	h.Write([]byte(src))
11
+	d := h.Sum(nil)
12
+
13
+	return string(hex.EncodeToString(d))
14
+}

+ 1
- 0
vendor/git.links123.net/links123.com/pkg/utils/go.mod View File

@@ -0,0 +1 @@
1
+module git.links123.net/links123.com/pkg/utils

+ 9
- 0
vendor/git.links123.net/links123.com/pkg/utils/time.go View File

@@ -0,0 +1,9 @@
1
+package utils
2
+
3
+import "time"
4
+
5
+const format = "2006-01-02 15:04:05"
6
+
7
+func GetNow() string {
8
+	return time.Now().Format(format)
9
+}

+ 20
- 0
vendor/git.links123.net/links123.com/pkg/utils/unit.go View File

@@ -0,0 +1,20 @@
1
+package utils
2
+
3
+import (
4
+	"encoding/json"
5
+)
6
+
7
+// 去掉struct的空字段
8
+func Struct2Slimming(input interface{}) (interface{}, error) {
9
+	bs, err := json.Marshal(input)
10
+	if err != nil {
11
+		return nil, err
12
+	}
13
+
14
+	var output interface{}
15
+	if err = json.Unmarshal(bs, &output); err != nil {
16
+		return nil, err
17
+	}
18
+
19
+	return output, nil
20
+}

+ 5
- 0
vendor/github.com/PuerkitoBio/purell/.gitignore View File

@@ -0,0 +1,5 @@
1
+*.sublime-*
2
+.DS_Store
3
+*.swp
4
+*.swo
5
+tags

+ 7
- 0
vendor/github.com/PuerkitoBio/purell/.travis.yml View File

@@ -0,0 +1,7 @@
1
+language: go
2
+
3
+go:
4
+    - 1.4
5
+    - 1.5
6
+    - 1.6
7
+    - tip

+ 12
- 0
vendor/github.com/PuerkitoBio/purell/LICENSE View File

@@ -0,0 +1,12 @@
1
+Copyright (c) 2012, Martin Angers
2
+All rights reserved.
3
+
4
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+
8
+* 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.
9
+
10
+* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11
+
12
+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 HOLDER 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.

+ 187
- 0
vendor/github.com/PuerkitoBio/purell/README.md View File

@@ -0,0 +1,187 @@
1
+# Purell
2
+
3
+Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know...
4
+
5
+Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc].
6
+
7
+[![build status](https://secure.travis-ci.org/PuerkitoBio/purell.png)](http://travis-ci.org/PuerkitoBio/purell)
8
+
9
+## Install
10
+
11
+`go get github.com/PuerkitoBio/purell`
12
+
13
+## Changelog
14
+
15
+*    **2016-11-14 (v1.1.0)** : IDN: Conform to RFC 5895: Fold character width (thanks to @beeker1121).
16
+*    **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich).
17
+*    **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]).
18
+*    **v0.2.0** : Add benchmarks, Attempt IDN support.
19
+*    **v0.1.0** : Initial release.
20
+
21
+## Examples
22
+
23
+From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."):
24
+
25
+```go
26
+package purell
27
+
28
+import (
29
+  "fmt"
30
+  "net/url"
31
+)
32
+
33
+func ExampleNormalizeURLString() {
34
+  if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
35
+    FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
36
+    panic(err)
37
+  } else {
38
+    fmt.Print(normalized)
39
+  }
40
+  // Output: http://somewebsite.com:80/Amazing%3F/url/
41
+}
42
+
43
+func ExampleMustNormalizeURLString() {
44
+  normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
45
+    FlagsUnsafeGreedy)
46
+  fmt.Print(normalized)
47
+
48
+  // Output: http://somewebsite.com/Amazing%FA/url
49
+}
50
+
51
+func ExampleNormalizeURL() {
52
+  if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
53
+    panic(err)
54
+  } else {
55
+    normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
56
+    fmt.Print(normalized)
57
+  }
58
+
59
+  // Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
60
+}
61
+```
62
+
63
+## API
64
+
65
+As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags:
66
+
67
+```go
68
+const (
69
+	// Safe normalizations
70
+	FlagLowercaseScheme           NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
71
+	FlagLowercaseHost                                            // http://HOST -> http://host
72
+	FlagUppercaseEscapes                                         // http://host/t%ef -> http://host/t%EF
73
+	FlagDecodeUnnecessaryEscapes                                 // http://host/t%41 -> http://host/tA
74
+	FlagEncodeNecessaryEscapes                                   // http://host/!"#$ -> http://host/%21%22#$
75
+	FlagRemoveDefaultPort                                        // http://host:80 -> http://host
76
+	FlagRemoveEmptyQuerySeparator                                // http://host/path? -> http://host/path
77
+
78
+	// Usually safe normalizations
79
+	FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
80
+	FlagAddTrailingSlash    // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
81
+	FlagRemoveDotSegments   // http://host/path/./a/b/../c -> http://host/path/a/c
82
+
83
+	// Unsafe normalizations
84
+	FlagRemoveDirectoryIndex   // http://host/path/index.html -> http://host/path/
85
+	FlagRemoveFragment         // http://host/path#fragment -> http://host/path
86
+	FlagForceHTTP              // https://host -> http://host
87
+	FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
88
+	FlagRemoveWWW              // http://www.host/ -> http://host/
89
+	FlagAddWWW                 // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
90
+	FlagSortQuery              // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
91
+
92
+	// Normalizations not in the wikipedia article, required to cover tests cases
93
+	// submitted by jehiah
94
+	FlagDecodeDWORDHost           // http://1113982867 -> http://66.102.7.147
95
+	FlagDecodeOctalHost           // http://0102.0146.07.0223 -> http://66.102.7.147
96
+	FlagDecodeHexHost             // http://0x42660793 -> http://66.102.7.147
97
+	FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
98
+	FlagRemoveEmptyPortSeparator  // http://host:/path -> http://host/path
99
+
100
+	// Convenience set of safe normalizations
101
+	FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
102
+
103
+	// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
104
+	// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
105
+
106
+	// Convenience set of usually safe normalizations (includes FlagsSafe)
107
+	FlagsUsuallySafeGreedy    NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
108
+	FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
109
+
110
+	// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
111
+	FlagsUnsafeGreedy    NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
112
+	FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
113
+
114
+	// Convenience set of all available flags
115
+	FlagsAllGreedy    = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
116
+	FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
117
+)
118
+```
119
+
120
+For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set.
121
+
122
+The [full godoc reference is available on gopkgdoc][godoc].
123
+
124
+Some things to note:
125
+
126
+*    `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it.
127
+
128
+*    The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*):
129
+    -    %24 -> $
130
+    -    %26 -> &
131
+    -    %2B-%3B -> +,-./0123456789:;
132
+    -    %3D -> =
133
+    -    %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ
134
+    -    %5F -> _
135
+    -    %61-%7A -> abcdefghijklmnopqrstuvwxyz
136
+    -    %7E -> ~
137
+
138
+
139
+*    When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization).
140
+
141
+*    The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell.
142
+
143
+*    The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object.
144
+
145
+### Safe vs Usually Safe vs Unsafe
146
+
147
+Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between.
148
+
149
+Consider the following URL:
150
+
151
+`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
152
+
153
+Normalizing with the `FlagsSafe` gives:
154
+
155
+`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
156
+
157
+With the `FlagsUsuallySafeGreedy`:
158
+
159
+`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid`
160
+
161
+And with `FlagsUnsafeGreedy`:
162
+
163
+`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3`
164
+
165
+## TODOs
166
+
167
+*    Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`.
168
+
169
+## Thanks / Contributions
170
+
171
+@rogpeppe
172
+@jehiah
173
+@opennota
174
+@pchristopher1275
175
+@zenovich
176
+@beeker1121
177
+
178
+## License
179
+
180
+The [BSD 3-Clause license][bsd].
181
+
182
+[bsd]: http://opensource.org/licenses/BSD-3-Clause
183
+[wiki]: http://en.wikipedia.org/wiki/URL_normalization
184
+[rfc]: http://tools.ietf.org/html/rfc3986#section-6
185
+[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell
186
+[pr5]: https://github.com/PuerkitoBio/purell/pull/5
187
+[iss7]: https://github.com/PuerkitoBio/purell/issues/7

+ 379
- 0
vendor/github.com/PuerkitoBio/purell/purell.go View File

@@ -0,0 +1,379 @@
1
+/*
2
+Package purell offers URL normalization as described on the wikipedia page:
3
+http://en.wikipedia.org/wiki/URL_normalization
4
+*/
5
+package purell
6
+
7
+import (
8
+	"bytes"
9
+	"fmt"
10
+	"net/url"
11
+	"regexp"
12
+	"sort"
13
+	"strconv"
14
+	"strings"
15
+
16
+	"github.com/PuerkitoBio/urlesc"
17
+	"golang.org/x/net/idna"
18
+	"golang.org/x/text/unicode/norm"
19
+	"golang.org/x/text/width"
20
+)
21
+
22
+// A set of normalization flags determines how a URL will
23
+// be normalized.
24
+type NormalizationFlags uint
25
+
26
+const (
27
+	// Safe normalizations
28
+	FlagLowercaseScheme           NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
29
+	FlagLowercaseHost                                            // http://HOST -> http://host
30
+	FlagUppercaseEscapes                                         // http://host/t%ef -> http://host/t%EF
31
+	FlagDecodeUnnecessaryEscapes                                 // http://host/t%41 -> http://host/tA
32
+	FlagEncodeNecessaryEscapes                                   // http://host/!"#$ -> http://host/%21%22#$
33
+	FlagRemoveDefaultPort                                        // http://host:80 -> http://host
34
+	FlagRemoveEmptyQuerySeparator                                // http://host/path? -> http://host/path
35
+
36
+	// Usually safe normalizations
37
+	FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
38
+	FlagAddTrailingSlash    // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
39
+	FlagRemoveDotSegments   // http://host/path/./a/b/../c -> http://host/path/a/c
40
+
41
+	// Unsafe normalizations
42
+	FlagRemoveDirectoryIndex   // http://host/path/index.html -> http://host/path/
43
+	FlagRemoveFragment         // http://host/path#fragment -> http://host/path
44
+	FlagForceHTTP              // https://host -> http://host
45
+	FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
46
+	FlagRemoveWWW              // http://www.host/ -> http://host/
47
+	FlagAddWWW                 // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
48
+	FlagSortQuery              // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
49
+
50
+	// Normalizations not in the wikipedia article, required to cover tests cases
51
+	// submitted by jehiah
52
+	FlagDecodeDWORDHost           // http://1113982867 -> http://66.102.7.147
53
+	FlagDecodeOctalHost           // http://0102.0146.07.0223 -> http://66.102.7.147
54
+	FlagDecodeHexHost             // http://0x42660793 -> http://66.102.7.147
55
+	FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
56
+	FlagRemoveEmptyPortSeparator  // http://host:/path -> http://host/path
57
+
58
+	// Convenience set of safe normalizations
59
+	FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
60
+
61
+	// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
62
+	// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
63
+
64
+	// Convenience set of usually safe normalizations (includes FlagsSafe)
65
+	FlagsUsuallySafeGreedy    NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
66
+	FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
67
+
68
+	// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
69
+	FlagsUnsafeGreedy    NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
70
+	FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
71
+
72
+	// Convenience set of all available flags
73
+	FlagsAllGreedy    = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
74
+	FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
75
+)
76
+
77
+const (
78
+	defaultHttpPort  = ":80"
79
+	defaultHttpsPort = ":443"
80
+)
81
+
82
+// Regular expressions used by the normalizations
83
+var rxPort = regexp.MustCompile(`(:\d+)/?$`)
84
+var rxDirIndex = regexp.MustCompile(`(^|/)((?:default|index)\.\w{1,4})$`)
85
+var rxDupSlashes = regexp.MustCompile(`/{2,}`)
86
+var rxDWORDHost = regexp.MustCompile(`^(\d+)((?:\.+)?(?:\:\d*)?)$`)
87
+var rxOctalHost = regexp.MustCompile(`^(0\d*)\.(0\d*)\.(0\d*)\.(0\d*)((?:\.+)?(?:\:\d*)?)$`)
88
+var rxHexHost = regexp.MustCompile(`^0x([0-9A-Fa-f]+)((?:\.+)?(?:\:\d*)?)$`)
89
+var rxHostDots = regexp.MustCompile(`^(.+?)(:\d+)?$`)
90
+var rxEmptyPort = regexp.MustCompile(`:+$`)
91
+
92
+// Map of flags to implementation function.
93
+// FlagDecodeUnnecessaryEscapes has no action, since it is done automatically
94
+// by parsing the string as an URL. Same for FlagUppercaseEscapes and FlagRemoveEmptyQuerySeparator.
95
+
96
+// Since maps have undefined traversing order, make a slice of ordered keys
97
+var flagsOrder = []NormalizationFlags{
98
+	FlagLowercaseScheme,
99
+	FlagLowercaseHost,
100
+	FlagRemoveDefaultPort,
101
+	FlagRemoveDirectoryIndex,
102
+	FlagRemoveDotSegments,
103
+	FlagRemoveFragment,
104
+	FlagForceHTTP, // Must be after remove default port (because https=443/http=80)
105
+	FlagRemoveDuplicateSlashes,
106
+	FlagRemoveWWW,
107
+	FlagAddWWW,
108
+	FlagSortQuery,
109
+	FlagDecodeDWORDHost,
110
+	FlagDecodeOctalHost,
111
+	FlagDecodeHexHost,
112
+	FlagRemoveUnnecessaryHostDots,
113
+	FlagRemoveEmptyPortSeparator,
114
+	FlagRemoveTrailingSlash, // These two (add/remove trailing slash) must be last
115
+	FlagAddTrailingSlash,
116
+}
117
+
118
+// ... and then the map, where order is unimportant
119
+var flags = map[NormalizationFlags]func(*url.URL){
120
+	FlagLowercaseScheme:           lowercaseScheme,
121
+	FlagLowercaseHost:             lowercaseHost,
122
+	FlagRemoveDefaultPort:         removeDefaultPort,
123
+	FlagRemoveDirectoryIndex:      removeDirectoryIndex,
124
+	FlagRemoveDotSegments:         removeDotSegments,
125
+	FlagRemoveFragment:            removeFragment,
126
+	FlagForceHTTP:                 forceHTTP,
127
+	FlagRemoveDuplicateSlashes:    removeDuplicateSlashes,
128
+	FlagRemoveWWW:                 removeWWW,
129
+	FlagAddWWW:                    addWWW,
130
+	FlagSortQuery:                 sortQuery,
131
+	FlagDecodeDWORDHost:           decodeDWORDHost,
132
+	FlagDecodeOctalHost:           decodeOctalHost,
133
+	FlagDecodeHexHost:             decodeHexHost,
134
+	FlagRemoveUnnecessaryHostDots: removeUnncessaryHostDots,
135
+	FlagRemoveEmptyPortSeparator:  removeEmptyPortSeparator,
136
+	FlagRemoveTrailingSlash:       removeTrailingSlash,
137
+	FlagAddTrailingSlash:          addTrailingSlash,
138
+}
139
+
140
+// MustNormalizeURLString returns the normalized string, and panics if an error occurs.
141
+// It takes an URL string as input, as well as the normalization flags.
142
+func MustNormalizeURLString(u string, f NormalizationFlags) string {
143
+	result, e := NormalizeURLString(u, f)
144
+	if e != nil {
145
+		panic(e)
146
+	}
147
+	return result
148
+}
149
+
150
+// NormalizeURLString returns the normalized string, or an error if it can't be parsed into an URL object.
151
+// It takes an URL string as input, as well as the normalization flags.
152
+func NormalizeURLString(u string, f NormalizationFlags) (string, error) {
153
+	parsed, err := url.Parse(u)
154
+	if err != nil {
155
+		return "", err
156
+	}
157
+
158
+	if f&FlagLowercaseHost == FlagLowercaseHost {
159
+		parsed.Host = strings.ToLower(parsed.Host)
160
+	}
161
+
162
+	// The idna package doesn't fully conform to RFC 5895
163
+	// (https://tools.ietf.org/html/rfc5895), so we do it here.
164
+	// Taken from Go 1.8 cycle source, courtesy of bradfitz.
165
+	// TODO: Remove when (if?) idna package conforms to RFC 5895.
166
+	parsed.Host = width.Fold.String(parsed.Host)
167
+	parsed.Host = norm.NFC.String(parsed.Host)
168
+	if parsed.Host, err = idna.ToASCII(parsed.Host); err != nil {
169
+		return "", err
170
+	}
171
+
172
+	return NormalizeURL(parsed, f), nil
173
+}
174
+
175
+// NormalizeURL returns the normalized string.
176
+// It takes a parsed URL object as input, as well as the normalization flags.
177
+func NormalizeURL(u *url.URL, f NormalizationFlags) string {
178
+	for _, k := range flagsOrder {
179
+		if f&k == k {
180
+			flags[k](u)
181
+		}
182
+	}
183
+	return urlesc.Escape(u)
184
+}
185
+
186
+func lowercaseScheme(u *url.URL) {
187
+	if len(u.Scheme) > 0 {
188
+		u.Scheme = strings.ToLower(u.Scheme)
189
+	}
190
+}
191
+
192
+func lowercaseHost(u *url.URL) {
193
+	if len(u.Host) > 0 {
194
+		u.Host = strings.ToLower(u.Host)
195
+	}
196
+}
197
+
198
+func removeDefaultPort(u *url.URL) {
199
+	if len(u.Host) > 0 {
200
+		scheme := strings.ToLower(u.Scheme)
201
+		u.Host = rxPort.ReplaceAllStringFunc(u.Host, func(val string) string {
202
+			if (scheme == "http" && val == defaultHttpPort) || (scheme == "https" && val == defaultHttpsPort) {
203
+				return ""
204
+			}
205
+			return val
206
+		})
207
+	}
208
+}
209
+
210
+func removeTrailingSlash(u *url.URL) {
211
+	if l := len(u.Path); l > 0 {
212
+		if strings.HasSuffix(u.Path, "/") {
213
+			u.Path = u.Path[:l-1]
214
+		}
215
+	} else if l = len(u.Host); l > 0 {
216
+		if strings.HasSuffix(u.Host, "/") {
217
+			u.Host = u.Host[:l-1]
218
+		}
219
+	}
220
+}
221
+
222
+func addTrailingSlash(u *url.URL) {
223
+	if l := len(u.Path); l > 0 {
224
+		if !strings.HasSuffix(u.Path, "/") {
225
+			u.Path += "/"
226
+		}
227
+	} else if l = len(u.Host); l > 0 {
228
+		if !strings.HasSuffix(u.Host, "/") {
229
+			u.Host += "/"
230
+		}
231
+	}
232
+}
233
+
234
+func removeDotSegments(u *url.URL) {
235
+	if len(u.Path) > 0 {
236
+		var dotFree []string
237
+		var lastIsDot bool
238
+
239
+		sections := strings.Split(u.Path, "/")
240
+		for _, s := range sections {
241
+			if s == ".." {
242
+				if len(dotFree) > 0 {
243
+					dotFree = dotFree[:len(dotFree)-1]
244
+				}
245
+			} else if s != "." {
246
+				dotFree = append(dotFree, s)
247
+			}
248
+			lastIsDot = (s == "." || s == "..")
249
+		}
250
+		// Special case if host does not end with / and new path does not begin with /
251
+		u.Path = strings.Join(dotFree, "/")
252
+		if u.Host != "" && !strings.HasSuffix(u.Host, "/") && !strings.HasPrefix(u.Path, "/") {
253
+			u.Path = "/" + u.Path
254
+		}
255
+		// Special case if the last segment was a dot, make sure the path ends with a slash
256
+		if lastIsDot && !strings.HasSuffix(u.Path, "/") {
257
+			u.Path += "/"
258
+		}
259
+	}
260
+}
261
+
262
+func removeDirectoryIndex(u *url.URL) {
263
+	if len(u.Path) > 0 {
264
+		u.Path = rxDirIndex.ReplaceAllString(u.Path, "$1")
265
+	}
266
+}
267
+
268
+func removeFragment(u *url.URL) {
269
+	u.Fragment = ""
270
+}
271
+
272
+func forceHTTP(u *url.URL) {
273
+	if strings.ToLower(u.Scheme) == "https" {
274
+		u.Scheme = "http"
275
+	}
276
+}
277
+
278
+func removeDuplicateSlashes(u *url.URL) {
279
+	if len(u.Path) > 0 {
280
+		u.Path = rxDupSlashes.ReplaceAllString(u.Path, "/")
281
+	}
282
+}
283
+
284
+func removeWWW(u *url.URL) {
285
+	if len(u.Host) > 0 && strings.HasPrefix(strings.ToLower(u.Host), "www.") {
286
+		u.Host = u.Host[4:]
287
+	}
288
+}
289
+
290
+func addWWW(u *url.URL) {
291
+	if len(u.Host) > 0 && !strings.HasPrefix(strings.ToLower(u.Host), "www.") {
292
+		u.Host = "www." + u.Host
293
+	}
294
+}
295
+
296
+func sortQuery(u *url.URL) {
297
+	q := u.Query()
298
+
299
+	if len(q) > 0 {
300
+		arKeys := make([]string, len(q))
301
+		i := 0
302
+		for k, _ := range q {
303
+			arKeys[i] = k
304
+			i++
305
+		}
306
+		sort.Strings(arKeys)
307
+		buf := new(bytes.Buffer)
308
+		for _, k := range arKeys {
309
+			sort.Strings(q[k])
310
+			for _, v := range q[k] {
311
+				if buf.Len() > 0 {
312
+					buf.WriteRune('&')
313
+				}
314
+				buf.WriteString(fmt.Sprintf("%s=%s", k, urlesc.QueryEscape(v)))
315
+			}
316
+		}
317
+
318
+		// Rebuild the raw query string
319
+		u.RawQuery = buf.String()
320
+	}
321
+}
322
+
323
+func decodeDWORDHost(u *url.URL) {
324
+	if len(u.Host) > 0 {
325
+		if matches := rxDWORDHost.FindStringSubmatch(u.Host); len(matches) > 2 {
326
+			var parts [4]int64
327
+
328
+			dword, _ := strconv.ParseInt(matches[1], 10, 0)
329
+			for i, shift := range []uint{24, 16, 8, 0} {
330
+				parts[i] = dword >> shift & 0xFF
331
+			}
332
+			u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[2])
333
+		}
334
+	}
335
+}
336
+
337
+func decodeOctalHost(u *url.URL) {
338
+	if len(u.Host) > 0 {
339
+		if matches := rxOctalHost.FindStringSubmatch(u.Host); len(matches) > 5 {
340
+			var parts [4]int64
341
+
342
+			for i := 1; i <= 4; i++ {
343
+				parts[i-1], _ = strconv.ParseInt(matches[i], 8, 0)
344
+			}
345
+			u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[5])
346
+		}
347
+	}
348
+}
349
+
350
+func decodeHexHost(u *url.URL) {
351
+	if len(u.Host) > 0 {
352
+		if matches := rxHexHost.FindStringSubmatch(u.Host); len(matches) > 2 {
353
+			// Conversion is safe because of regex validation
354
+			parsed, _ := strconv.ParseInt(matches[1], 16, 0)
355
+			// Set host as DWORD (base 10) encoded host
356
+			u.Host = fmt.Sprintf("%d%s", parsed, matches[2])
357
+			// The rest is the same as decoding a DWORD host
358
+			decodeDWORDHost(u)
359
+		}
360
+	}
361
+}
362
+
363
+func removeUnncessaryHostDots(u *url.URL) {
364
+	if len(u.Host) > 0 {
365
+		if matches := rxHostDots.FindStringSubmatch(u.Host); len(matches) > 1 {
366
+			// Trim the leading and trailing dots
367
+			u.Host = strings.Trim(matches[1], ".")
368
+			if len(matches) > 2 {
369
+				u.Host += matches[2]
370
+			}
371
+		}
372
+	}
373
+}
374
+
375
+func removeEmptyPortSeparator(u *url.URL) {
376
+	if len(u.Host) > 0 {
377
+		u.Host = rxEmptyPort.ReplaceAllString(u.Host, "")
378
+	}
379
+}

+ 15
- 0
vendor/github.com/PuerkitoBio/urlesc/.travis.yml View File

@@ -0,0 +1,15 @@
1
+language: go
2
+
3
+go:
4
+  - 1.4.x
5
+  - 1.5.x
6
+  - 1.6.x
7
+  - 1.7.x
8
+  - 1.8.x
9
+  - tip
10
+
11
+install:
12
+  - go build .
13
+
14
+script:
15
+  - go test -v

+ 27
- 0
vendor/github.com/PuerkitoBio/urlesc/LICENSE View File

@@ -0,0 +1,27 @@
1
+Copyright (c) 2012 The Go Authors. All rights reserved.
2
+
3
+Redistribution and use in source and binary forms, with or without
4
+modification, are permitted provided that the following conditions are
5
+met:
6
+
7
+   * Redistributions of source code must retain the above copyright
8
+notice, this list of conditions and the following disclaimer.
9
+   * Redistributions in binary form must reproduce the above
10
+copyright notice, this list of conditions and the following disclaimer
11
+in the documentation and/or other materials provided with the
12
+distribution.
13
+   * Neither the name of Google Inc. nor the names of its
14
+contributors may be used to endorse or promote products derived from
15
+this software without specific prior written permission.
16
+
17
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 16
- 0
vendor/github.com/PuerkitoBio/urlesc/README.md View File

@@ -0,0 +1,16 @@
1
+urlesc [![Build Status](https://travis-ci.org/PuerkitoBio/urlesc.svg?branch=master)](https://travis-ci.org/PuerkitoBio/urlesc) [![GoDoc](http://godoc.org/github.com/PuerkitoBio/urlesc?status.svg)](http://godoc.org/github.com/PuerkitoBio/urlesc)
2
+======
3
+
4
+Package urlesc implements query escaping as per RFC 3986.
5
+
6
+It contains some parts of the net/url package, modified so as to allow
7
+some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)).
8
+
9
+## Install
10
+
11
+    go get github.com/PuerkitoBio/urlesc
12
+
13
+## License
14
+
15
+Go license (BSD-3-Clause)
16
+

+ 180
- 0
vendor/github.com/PuerkitoBio/urlesc/urlesc.go View File

@@ -0,0 +1,180 @@
1
+// Copyright 2009 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// Package urlesc implements query escaping as per RFC 3986.
6
+// It contains some parts of the net/url package, modified so as to allow
7
+// some reserved characters incorrectly escaped by net/url.
8
+// See https://github.com/golang/go/issues/5684
9
+package urlesc
10
+
11
+import (
12
+	"bytes"
13
+	"net/url"
14
+	"strings"
15
+)
16
+
17
+type encoding int
18
+
19
+const (
20
+	encodePath encoding = 1 + iota
21
+	encodeUserPassword
22
+	encodeQueryComponent
23
+	encodeFragment
24
+)
25
+
26
+// Return true if the specified character should be escaped when
27
+// appearing in a URL string, according to RFC 3986.
28
+func shouldEscape(c byte, mode encoding) bool {
29
+	// §2.3 Unreserved characters (alphanum)
30
+	if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
31
+		return false
32
+	}
33
+
34
+	switch c {
35
+	case '-', '.', '_', '~': // §2.3 Unreserved characters (mark)
36
+		return false
37
+
38
+	// §2.2 Reserved characters (reserved)
39
+	case ':', '/', '?', '#', '[', ']', '@', // gen-delims
40
+		'!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': // sub-delims
41
+		// Different sections of the URL allow a few of
42
+		// the reserved characters to appear unescaped.
43
+		switch mode {
44
+		case encodePath: // §3.3
45
+			// The RFC allows sub-delims and : @.
46
+			// '/', '[' and ']' can be used to assign meaning to individual path
47
+			// segments.  This package only manipulates the path as a whole,
48
+			// so we allow those as well.  That leaves only ? and # to escape.
49
+			return c == '?' || c == '#'
50
+
51
+		case encodeUserPassword: // §3.2.1
52
+			// The RFC allows : and sub-delims in
53
+			// userinfo.  The parsing of userinfo treats ':' as special so we must escape
54
+			// all the gen-delims.
55
+			return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'
56
+
57
+		case encodeQueryComponent: // §3.4
58
+			// The RFC allows / and ?.
59
+			return c != '/' && c != '?'
60
+
61
+		case encodeFragment: // §4.1
62
+			// The RFC text is silent but the grammar allows
63
+			// everything, so escape nothing but #
64
+			return c == '#'
65
+		}
66
+	}
67
+
68
+	// Everything else must be escaped.
69
+	return true
70
+}
71
+
72
+// QueryEscape escapes the string so it can be safely placed
73
+// inside a URL query.
74
+func QueryEscape(s string) string {
75
+	return escape(s, encodeQueryComponent)
76
+}
77
+
78
+func escape(s string, mode encoding) string {
79
+	spaceCount, hexCount := 0, 0
80
+	for i := 0; i < len(s); i++ {
81
+		c := s[i]
82
+		if shouldEscape(c, mode) {
83
+			if c == ' ' && mode == encodeQueryComponent {
84
+				spaceCount++
85
+			} else {
86
+				hexCount++
87
+			}
88
+		}
89
+	}
90
+
91
+	if spaceCount == 0 && hexCount == 0 {
92
+		return s
93
+	}
94
+
95
+	t := make([]byte, len(s)+2*hexCount)
96
+	j := 0
97
+	for i := 0; i < len(s); i++ {
98
+		switch c := s[i]; {
99
+		case c == ' ' && mode == encodeQueryComponent:
100
+			t[j] = '+'
101
+			j++
102
+		case shouldEscape(c, mode):
103
+			t[j] = '%'
104
+			t[j+1] = "0123456789ABCDEF"[c>>4]
105
+			t[j+2] = "0123456789ABCDEF"[c&15]
106
+			j += 3
107
+		default:
108
+			t[j] = s[i]
109
+			j++
110
+		}
111
+	}
112
+	return string(t)
113
+}
114
+
115
+var uiReplacer = strings.NewReplacer(
116
+	"%21", "!",
117
+	"%27", "'",
118
+	"%28", "(",
119
+	"%29", ")",
120
+	"%2A", "*",
121
+)
122
+
123
+// unescapeUserinfo unescapes some characters that need not to be escaped as per RFC3986.
124
+func unescapeUserinfo(s string) string {
125
+	return uiReplacer.Replace(s)
126
+}
127
+
128
+// Escape reassembles the URL into a valid URL string.
129
+// The general form of the result is one of:
130
+//
131
+//	scheme:opaque
132
+//	scheme://userinfo@host/path?query#fragment
133
+//
134
+// If u.Opaque is non-empty, String uses the first form;
135
+// otherwise it uses the second form.
136
+//
137
+// In the second form, the following rules apply:
138
+//	- if u.Scheme is empty, scheme: is omitted.
139
+//	- if u.User is nil, userinfo@ is omitted.
140
+//	- if u.Host is empty, host/ is omitted.
141
+//	- if u.Scheme and u.Host are empty and u.User is nil,
142
+//	   the entire scheme://userinfo@host/ is omitted.
143
+//	- if u.Host is non-empty and u.Path begins with a /,
144
+//	   the form host/path does not add its own /.
145
+//	- if u.RawQuery is empty, ?query is omitted.
146
+//	- if u.Fragment is empty, #fragment is omitted.
147
+func Escape(u *url.URL) string {
148
+	var buf bytes.Buffer
149
+	if u.Scheme != "" {
150
+		buf.WriteString(u.Scheme)
151
+		buf.WriteByte(':')
152
+	}
153
+	if u.Opaque != "" {
154
+		buf.WriteString(u.Opaque)
155
+	} else {
156
+		if u.Scheme != "" || u.Host != "" || u.User != nil {
157
+			buf.WriteString("//")
158
+			if ui := u.User; ui != nil {
159
+				buf.WriteString(unescapeUserinfo(ui.String()))
160
+				buf.WriteByte('@')
161
+			}
162
+			if h := u.Host; h != "" {
163
+				buf.WriteString(h)
164
+			}
165
+		}
166
+		if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
167
+			buf.WriteByte('/')
168
+		}
169
+		buf.WriteString(escape(u.Path, encodePath))
170
+	}
171
+	if u.RawQuery != "" {
172
+		buf.WriteByte('?')
173
+		buf.WriteString(u.RawQuery)
174
+	}
175
+	if u.Fragment != "" {
176
+		buf.WriteByte('#')
177
+		buf.WriteString(escape(u.Fragment, encodeFragment))
178
+	}
179
+	return buf.String()
180
+}

+ 22
- 0
vendor/github.com/Unknwon/i18n/.gitignore View File

@@ -0,0 +1,22 @@
1
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
2
+*.o
3
+*.a
4
+*.so
5
+
6
+# Folders
7
+_obj
8
+_test
9
+
10
+# Architecture specific extensions/prefixes
11
+*.[568vq]
12
+[568vq].out
13
+
14
+*.cgo1.go
15
+*.cgo2.c
16
+_cgo_defun.c
17
+_cgo_gotypes.go
18
+_cgo_export.*
19
+
20
+_testmain.go
21
+
22
+*.exe

+ 191
- 0
vendor/github.com/Unknwon/i18n/LICENSE View File

@@ -0,0 +1,191 @@
1
+Apache License
2
+Version 2.0, January 2004
3
+http://www.apache.org/licenses/
4
+
5
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+1. Definitions.
8
+
9
+"License" shall mean the terms and conditions for use, reproduction, and
10
+distribution as defined by Sections 1 through 9 of this document.
11
+
12
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
13
+owner that is granting the License.
14
+
15
+"Legal Entity" shall mean the union of the acting entity and all other entities
16
+that control, are controlled by, or are under common control with that entity.
17
+For the purposes of this definition, "control" means (i) the power, direct or
18
+indirect, to cause the direction or management of such entity, whether by
19
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20
+outstanding shares, or (iii) beneficial ownership of such entity.
21
+
22
+"You" (or "Your") shall mean an individual or Legal Entity exercising
23
+permissions granted by this License.
24
+
25
+"Source" form shall mean the preferred form for making modifications, including
26
+but not limited to software source code, documentation source, and configuration
27
+files.
28
+
29
+"Object" form shall mean any form resulting from mechanical transformation or
30
+translation of a Source form, including but not limited to compiled object code,
31
+generated documentation, and conversions to other media types.
32
+
33
+"Work" shall mean the work of authorship, whether in Source or Object form, made
34
+available under the License, as indicated by a copyright notice that is included
35
+in or attached to the work (an example is provided in the Appendix below).
36
+
37
+"Derivative Works" shall mean any work, whether in Source or Object form, that
38
+is based on (or derived from) the Work and for which the editorial revisions,
39
+annotations, elaborations, or other modifications represent, as a whole, an
40
+original work of authorship. For the purposes of this License, Derivative Works
41
+shall not include works that remain separable from, or merely link (or bind by
42
+name) to the interfaces of, the Work and Derivative Works thereof.
43
+
44
+"Contribution" shall mean any work of authorship, including the original version
45
+of the Work and any modifications or additions to that Work or Derivative Works
46
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
47
+by the copyright owner or by an individual or Legal Entity authorized to submit
48
+on behalf of the copyright owner. For the purposes of this definition,
49
+"submitted" means any form of electronic, verbal, or written communication sent
50
+to the Licensor or its representatives, including but not limited to
51
+communication on electronic mailing lists, source code control systems, and
52
+issue tracking systems that are managed by, or on behalf of, the Licensor for
53
+the purpose of discussing and improving the Work, but excluding communication
54
+that is conspicuously marked or otherwise designated in writing by the copyright
55
+owner as "Not a Contribution."
56
+
57
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58
+of whom a Contribution has been received by Licensor and subsequently
59
+incorporated within the Work.
60
+
61
+2. Grant of Copyright License.
62
+
63
+Subject to the terms and conditions of this License, each Contributor hereby
64
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65
+irrevocable copyright license to reproduce, prepare Derivative Works of,
66
+publicly display, publicly perform, sublicense, and distribute the Work and such
67
+Derivative Works in Source or Object form.
68
+
69
+3. Grant of Patent License.
70
+
71
+Subject to the terms and conditions of this License, each Contributor hereby
72
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73
+irrevocable (except as stated in this section) patent license to make, have
74
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75
+such license applies only to those patent claims licensable by such Contributor
76
+that are necessarily infringed by their Contribution(s) alone or by combination
77
+of their Contribution(s) with the Work to which such Contribution(s) was
78
+submitted. If You institute patent litigation against any entity (including a
79
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80
+Contribution incorporated within the Work constitutes direct or contributory
81
+patent infringement, then any patent licenses granted to You under this License
82
+for that Work shall terminate as of the date such litigation is filed.
83
+
84
+4. Redistribution.
85
+
86
+You may reproduce and distribute copies of the Work or Derivative Works thereof
87
+in any medium, with or without modifications, and in Source or Object form,
88
+provided that You meet the following conditions:
89
+
90
+You must give any other recipients of the Work or Derivative Works a copy of
91
+this License; and
92
+You must cause any modified files to carry prominent notices stating that You
93
+changed the files; and
94
+You must retain, in the Source form of any Derivative Works that You distribute,
95
+all copyright, patent, trademark, and attribution notices from the Source form
96
+of the Work, excluding those notices that do not pertain to any part of the
97
+Derivative Works; and
98
+If the Work includes a "NOTICE" text file as part of its distribution, then any
99
+Derivative Works that You distribute must include a readable copy of the
100
+attribution notices contained within such NOTICE file, excluding those notices
101
+that do not pertain to any part of the Derivative Works, in at least one of the
102
+following places: within a NOTICE text file distributed as part of the
103
+Derivative Works; within the Source form or documentation, if provided along
104
+with the Derivative Works; or, within a display generated by the Derivative
105
+Works, if and wherever such third-party notices normally appear. The contents of
106
+the NOTICE file are for informational purposes only and do not modify the
107
+License. You may add Your own attribution notices within Derivative Works that
108
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
109
+provided that such additional attribution notices cannot be construed as
110
+modifying the License.
111
+You may add Your own copyright statement to Your modifications and may provide
112
+additional or different license terms and conditions for use, reproduction, or
113
+distribution of Your modifications, or for any such Derivative Works as a whole,
114
+provided Your use, reproduction, and distribution of the Work otherwise complies
115
+with the conditions stated in this License.
116
+
117
+5. Submission of Contributions.
118
+
119
+Unless You explicitly state otherwise, any Contribution intentionally submitted
120
+for inclusion in the Work by You to the Licensor shall be under the terms and
121
+conditions of this License, without any additional terms or conditions.
122
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
123
+any separate license agreement you may have executed with Licensor regarding
124
+such Contributions.
125
+
126
+6. Trademarks.
127
+
128
+This License does not grant permission to use the trade names, trademarks,
129
+service marks, or product names of the Licensor, except as required for
130
+reasonable and customary use in describing the origin of the Work and
131
+reproducing the content of the NOTICE file.
132
+
133
+7. Disclaimer of Warranty.
134
+
135
+Unless required by applicable law or agreed to in writing, Licensor provides the
136
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138
+including, without limitation, any warranties or conditions of TITLE,
139
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140
+solely responsible for determining the appropriateness of using or
141
+redistributing the Work and assume any risks associated with Your exercise of
142
+permissions under this License.
143
+
144
+8. Limitation of Liability.
145
+
146
+In no event and under no legal theory, whether in tort (including negligence),
147
+contract, or otherwise, unless required by applicable law (such as deliberate
148
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
149
+liable to You for damages, including any direct, indirect, special, incidental,
150
+or consequential damages of any character arising as a result of this License or
151
+out of the use or inability to use the Work (including but not limited to
152
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153
+any and all other commercial damages or losses), even if such Contributor has
154
+been advised of the possibility of such damages.
155
+
156
+9. Accepting Warranty or Additional Liability.
157
+
158
+While redistributing the Work or Derivative Works thereof, You may choose to
159
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160
+other liability obligations and/or rights consistent with this License. However,
161
+in accepting such obligations, You may act only on Your own behalf and on Your
162
+sole responsibility, not on behalf of any other Contributor, and only if You
163
+agree to indemnify, defend, and hold each Contributor harmless for any liability
164
+incurred by, or claims asserted against, such Contributor by reason of your
165
+accepting any such warranty or additional liability.
166
+
167
+END OF TERMS AND CONDITIONS
168
+
169
+APPENDIX: How to apply the Apache License to your work
170
+
171
+To apply the Apache License to your work, attach the following boilerplate
172
+notice, with the fields enclosed by brackets "[]" replaced with your own
173
+identifying information. (Don't include the brackets!) The text should be
174
+enclosed in the appropriate comment syntax for the file format. We also
175
+recommend that a file or class name and description of purpose be included on
176
+the same "printed page" as the copyright notice for easier identification within
177
+third-party archives.
178
+
179
+   Copyright [yyyy] [name of copyright owner]
180
+
181
+   Licensed under the Apache License, Version 2.0 (the "License");
182
+   you may not use this file except in compliance with the License.
183
+   You may obtain a copy of the License at
184
+
185
+     http://www.apache.org/licenses/LICENSE-2.0
186
+
187
+   Unless required by applicable law or agreed to in writing, software
188
+   distributed under the License is distributed on an "AS IS" BASIS,
189
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190
+   See the License for the specific language governing permissions and
191
+   limitations under the License.

+ 12
- 0
vendor/github.com/Unknwon/i18n/Makefile View File

@@ -0,0 +1,12 @@
1
+.PHONY: build test bench vet
2
+
3
+build: vet bench
4
+
5
+test:
6
+	go test -v -cover
7
+
8
+bench:
9
+	go test -v -cover -test.bench=. -test.benchmem
10
+
11
+vet:
12
+	go vet

+ 136
- 0
vendor/github.com/Unknwon/i18n/README.md View File

@@ -0,0 +1,136 @@
1
+i18n [![GoDoc](https://godoc.org/github.com/Unknwon/i18n?status.svg)](https://godoc.org/github.com/Unknwon/i18n) [![Sourcegraph](https://sourcegraph.com/github.com/Unknwon/i18n/-/badge.svg)](https://sourcegraph.com/github.com/Unknwon/i18n?badge)
2
+====
3
+
4
+Package i18n is for app Internationalization and Localization.
5
+
6
+## Introduction
7
+
8
+This package provides multiple-language options to improve user experience. Sites like [Go Walker](http://gowalker.org) and [gogs.io](http://gogs.io) are using this module to implement Chinese and English user interfaces.
9
+
10
+You can use following command to install this module:
11
+
12
+    go get github.com/Unknwon/i18n
13
+
14
+## Usage
15
+
16
+First of all, you have to import this package:
17
+
18
+```go
19
+import "github.com/Unknwon/i18n"
20
+```
21
+
22
+The format of locale files is very like INI format configuration file, which is basically key-value pairs. But this module has some improvements. Every language corresponding to a locale file, for example, under `conf/locale` folder of [gogsweb](https://github.com/gogits/gogsweb/tree/master/conf/locale), there are two files called `locale_en-US.ini` and `locale_zh-CN.ini`.
23
+
24
+The name and extensions of locale files can be anything, but we strongly recommend you to follow the style of gogsweb.
25
+
26
+## Minimal example
27
+
28
+Here are two simplest locale file examples:
29
+
30
+File `locale_en-US.ini`:
31
+
32
+```ini
33
+hi = hello, %s
34
+bye = goodbye
35
+```
36
+
37
+File `locale_zh-CN.ini`:
38
+
39
+```ini
40
+hi = 您好,%s
41
+bye = 再见
42
+```
43
+
44
+### Do Translation
45
+
46
+There are two ways to do translation depends on which way is the best fit for your application or framework.
47
+
48
+Directly use package function to translate:
49
+
50
+```go
51
+i18n.Tr("en-US", "hi", "Unknwon")
52
+i18n.Tr("en-US", "bye")
53
+```
54
+
55
+Or create a struct and embed it:
56
+
57
+```go
58
+type MyController struct{
59
+    // ...other fields
60
+    i18n.Locale
61
+}
62
+
63
+//...
64
+
65
+func ... {
66
+    c := &MyController{
67
+        Locale: i18n.Locale{"en-US"},
68
+    }
69
+    _ = c.Tr("hi", "Unknwon")
70
+    _ = c.Tr("bye")
71
+}
72
+```
73
+
74
+Code above will produce correspondingly:
75
+
76
+- English `en-US`:`hello, Unknwon`, `goodbye`
77
+- Chinese `zh-CN`:`您好,Unknwon`, `再见`
78
+
79
+## Section
80
+
81
+For different pages, one key may map to different values. Therefore, i18n module also uses the section feature of INI format configuration to achieve section.
82
+
83
+For example, the key name is `about`, and we want to show `About` in the home page and `About Us` in about page. Then you can do following:
84
+
85
+Content in locale file:
86
+
87
+```ini
88
+about = About
89
+
90
+[about]
91
+about = About Us
92
+```
93
+
94
+Get `about` in home page:
95
+
96
+```go
97
+i18n.Tr("en-US", "about")
98
+```
99
+
100
+Get `about` in about page:
101
+
102
+```go
103
+i18n.Tr("en-US", "about.about")
104
+```
105
+
106
+### Ambiguity
107
+
108
+Because dot `.` is sign of section in both [INI parser](https://github.com/go-ini/ini) and locale files, so when your key name contains `.` will cause ambiguity. At this point, you just need to add one more `.` in front of the key.
109
+
110
+For example, the key name is `about.`, then we can use:
111
+
112
+```go
113
+i18n.Tr("en-US", ".about.")
114
+```
115
+
116
+to get expect result.
117
+
118
+## Helper tool
119
+
120
+Module i18n provides a command line helper tool beei18n for simplify steps of your development. You can install it as follows:
121
+
122
+	go get github.com/Unknwon/i18n/ui18n
123
+
124
+### Sync locale files
125
+
126
+Command `sync` allows you use a exist local file as the template to create or sync other locale files:
127
+
128
+	ui18n sync srouce_file.ini other1.ini other2.ini
129
+
130
+This command can operate 1 or more files in one command.
131
+
132
+## More information
133
+
134
+- The first locale you load to the module is considered as **default locale**.
135
+- When matching non-default locale and didn't find the string, i18n will have a second try on default locale.
136
+- If i18n still cannot find string in the default locale, raw string will be returned. For instance, when the string is `hi` and it does not exist in locale file, simply return `hi` as output.

+ 231
- 0
vendor/github.com/Unknwon/i18n/i18n.go View File

@@ -0,0 +1,231 @@
1
+// Copyright 2013 Unknwon
2
+//
3
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
4
+// not use this file except in compliance with the License. You may obtain
5
+// a copy of the License at
6
+//
7
+//     http://www.apache.org/licenses/LICENSE-2.0
8
+//
9
+// Unless required by applicable law or agreed to in writing, software
10
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+// License for the specific language governing permissions and limitations
13
+// under the License.
14
+
15
+// Package i18n is for app Internationalization and Localization.
16
+package i18n
17
+
18
+import (
19
+	"errors"
20
+	"fmt"
21
+	"reflect"
22
+	"strings"
23
+
24
+	"gopkg.in/ini.v1"
25
+)
26
+
27
+var (
28
+	ErrLangAlreadyExist = errors.New("Lang already exists")
29
+
30
+	locales = &localeStore{store: make(map[string]*locale)}
31
+)
32
+
33
+type locale struct {
34
+	id       int
35
+	lang     string
36
+	langDesc string
37
+	message  *ini.File
38
+}
39
+
40
+type localeStore struct {
41
+	langs       []string
42
+	langDescs   []string
43
+	store       map[string]*locale
44
+	defaultLang string
45
+}
46
+
47
+// Get target language string
48
+func (d *localeStore) Get(lang, section, format string) (string, bool) {
49
+	if locale, ok := d.store[lang]; ok {
50
+		if key, err := locale.message.Section(section).GetKey(format); err == nil {
51
+			return key.Value(), true
52
+		}
53
+	}
54
+
55
+	if len(d.defaultLang) > 0 && lang != d.defaultLang {
56
+		return d.Get(d.defaultLang, section, format)
57
+	}
58
+
59
+	return "", false
60
+}
61
+
62
+func (d *localeStore) Add(lc *locale) bool {
63
+	if _, ok := d.store[lc.lang]; ok {
64
+		return false
65
+	}
66
+
67
+	lc.id = len(d.langs)
68
+	d.langs = append(d.langs, lc.lang)
69
+	d.langDescs = append(d.langDescs, lc.langDesc)
70
+	d.store[lc.lang] = lc
71
+
72
+	return true
73
+}
74
+
75
+func (d *localeStore) Reload(langs ...string) (err error) {
76
+	if len(langs) == 0 {
77
+		for _, lc := range d.store {
78
+			if err = lc.message.Reload(); err != nil {
79
+				return err
80
+			}
81
+		}
82
+	} else {
83
+		for _, lang := range langs {
84
+			if lc, ok := d.store[lang]; ok {
85
+				if err = lc.message.Reload(); err != nil {
86
+					return err
87
+				}
88
+			}
89
+		}
90
+	}
91
+	return nil
92
+}
93
+
94
+// SetDefaultLang sets default language which is a indicator that
95
+// when target language is not found, try find in default language again.
96
+func SetDefaultLang(lang string) {
97
+	locales.defaultLang = lang
98
+}
99
+
100
+// ReloadLangs reloads locale files.
101
+func ReloadLangs(langs ...string) error {
102
+	return locales.Reload(langs...)
103
+}
104
+
105
+// Count returns number of languages that are registered.
106
+func Count() int {
107
+	return len(locales.langs)
108
+}
109
+
110
+// ListLangs returns list of all locale languages.
111
+func ListLangs() []string {
112
+	langs := make([]string, len(locales.langs))
113
+	copy(langs, locales.langs)
114
+	return langs
115
+}
116
+
117
+func ListLangDescs() []string {
118
+	langDescs := make([]string, len(locales.langDescs))
119
+	copy(langDescs, locales.langDescs)
120
+	return langDescs
121
+}
122
+
123
+// IsExist returns true if given language locale exists.
124
+func IsExist(lang string) bool {
125
+	_, ok := locales.store[lang]
126
+	return ok
127
+}
128
+
129
+// IndexLang returns index of language locale,
130
+// it returns -1 if locale not exists.
131
+func IndexLang(lang string) int {
132
+	if lc, ok := locales.store[lang]; ok {
133
+		return lc.id
134
+	}
135
+	return -1
136
+}
137
+
138
+// GetLangByIndex return language by given index.
139
+func GetLangByIndex(index int) string {
140
+	if index < 0 || index >= len(locales.langs) {
141
+		return ""
142
+	}
143
+	return locales.langs[index]
144
+}
145
+
146
+func GetDescriptionByIndex(index int) string {
147
+	if index < 0 || index >= len(locales.langDescs) {
148
+		return ""
149
+	}
150
+
151
+	return locales.langDescs[index]
152
+}
153
+
154
+func GetDescriptionByLang(lang string) string {
155
+	return GetDescriptionByIndex(IndexLang(lang))
156
+}
157
+
158
+func SetMessageWithDesc(lang, langDesc string, localeFile interface{}, otherLocaleFiles ...interface{}) error {
159
+	message, err := ini.LoadSources(ini.LoadOptions{
160
+		IgnoreInlineComment:         true,
161
+		UnescapeValueCommentSymbols: true,
162
+	}, localeFile, otherLocaleFiles...)
163
+	if err == nil {
164
+		message.BlockMode = false
165
+		lc := new(locale)
166
+		lc.lang = lang
167
+		lc.langDesc = langDesc
168
+		lc.message = message
169
+
170
+		if locales.Add(lc) == false {
171
+			return ErrLangAlreadyExist
172
+		}
173
+	}
174
+	return err
175
+}
176
+
177
+// SetMessage sets the message file for localization.
178
+func SetMessage(lang string, localeFile interface{}, otherLocaleFiles ...interface{}) error {
179
+	return SetMessageWithDesc(lang, lang, localeFile, otherLocaleFiles...)
180
+}
181
+
182
+// Locale represents the information of localization.
183
+type Locale struct {
184
+	Lang string
185
+}
186
+
187
+// Tr translates content to target language.
188
+func (l Locale) Tr(format string, args ...interface{}) string {
189
+	return Tr(l.Lang, format, args...)
190
+}
191
+
192
+// Index returns lang index of LangStore.
193
+func (l Locale) Index() int {
194
+	return IndexLang(l.Lang)
195
+}
196
+
197
+// Tr translates content to target language.
198
+func Tr(lang, format string, args ...interface{}) string {
199
+	var section string
200
+
201
+	idx := strings.IndexByte(format, '.')
202
+	if idx > 0 {
203
+		section = format[:idx]
204
+		format = format[idx+1:]
205
+	}
206
+
207
+	value, ok := locales.Get(lang, section, format)
208
+	if ok {
209
+		format = value
210
+	}
211
+
212
+	if len(args) > 0 {
213
+		params := make([]interface{}, 0, len(args))
214
+		for _, arg := range args {
215
+			if arg == nil {
216
+				continue
217
+			}
218
+
219
+			val := reflect.ValueOf(arg)
220
+			if val.Kind() == reflect.Slice {
221
+				for i := 0; i < val.Len(); i++ {
222
+					params = append(params, val.Index(i).Interface())
223
+				}
224
+			} else {
225
+				params = append(params, arg)
226
+			}
227
+		}
228
+		return fmt.Sprintf(format, params...)
229
+	}
230
+	return format
231
+}

+ 19
- 0
vendor/github.com/braintree/manners/LICENSE View File

@@ -0,0 +1,19 @@
1
+Copyright (c) 2014 Braintree, a division of PayPal, Inc.
2
+
3
+Permission is hereby granted, free of charge, to any person obtaining a copy
4
+of this software and associated documentation files (the "Software"), to deal
5
+in the Software without restriction, including without limitation the rights
6
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+copies of the Software, and to permit persons to whom the Software is
8
+furnished to do so, subject to the following conditions:
9
+
10
+The above copyright notice and this permission notice shall be included in
11
+all copies or substantial portions of the Software.
12
+
13
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+THE SOFTWARE.

+ 36
- 0
vendor/github.com/braintree/manners/README.md View File

@@ -0,0 +1,36 @@
1
+# Manners
2
+
3
+A *polite* webserver for Go.
4
+
5
+Manners allows you to shut your Go webserver down gracefully, without dropping any requests. It can act as a drop-in replacement for the standard library's http.ListenAndServe function:
6
+
7
+```go
8
+func main() {
9
+  handler := MyHTTPHandler()
10
+  manners.ListenAndServe(":7000", handler)
11
+}
12
+```
13
+
14
+Then, when you want to shut the server down:
15
+
16
+```go
17
+manners.Close()
18
+```
19
+
20
+(Note that this does not block until all the requests are finished. Rather, the call to manners.ListenAndServe will stop blocking when all the requests are finished.)
21
+
22
+Manners ensures that all requests are served by incrementing a WaitGroup when a request comes in and decrementing it when the request finishes.
23
+
24
+If your request handler spawns Goroutines that are not guaranteed to finish with the request, you can ensure they are also completed with the `StartRoutine` and `FinishRoutine` functions on the server.
25
+
26
+### Known Issues
27
+
28
+Manners does not correctly shut down long-lived keepalive connections when issued a shutdown command. Clients on an idle keepalive connection may see a connection reset error rather than a close. See https://github.com/braintree/manners/issues/13 for details.
29
+
30
+### Compatability
31
+
32
+Manners 0.3.0 and above uses standard library functionality introduced in Go 1.3.
33
+
34
+### Installation
35
+
36
+`go get github.com/braintree/manners`

+ 7
- 0
vendor/github.com/braintree/manners/interfaces.go View File

@@ -0,0 +1,7 @@
1
+package manners
2
+
3
+type waitGroup interface {
4
+	Add(int)
5
+	Done()
6
+	Wait()
7
+}

+ 292
- 0
vendor/github.com/braintree/manners/server.go View File

@@ -0,0 +1,292 @@
1
+/*
2
+Package manners provides a wrapper for a standard net/http server that
3
+ensures all active HTTP client have completed their current request
4
+before the server shuts down.
5
+
6
+It can be used a drop-in replacement for the standard http package,
7
+or can wrap a pre-configured Server.
8
+
9
+eg.
10
+
11
+	http.Handle("/hello", func(w http.ResponseWriter, r *http.Request) {
12
+	  w.Write([]byte("Hello\n"))
13
+	})
14
+
15
+	log.Fatal(manners.ListenAndServe(":8080", nil))
16
+
17
+or for a customized server:
18
+
19
+	s := manners.NewWithServer(&http.Server{
20
+		Addr:           ":8080",
21
+		Handler:        myHandler,
22
+		ReadTimeout:    10 * time.Second,
23
+		WriteTimeout:   10 * time.Second,
24
+		MaxHeaderBytes: 1 << 20,
25
+	})
26
+	log.Fatal(s.ListenAndServe())
27
+
28
+The server will shut down cleanly when the Close() method is called:
29
+
30
+	go func() {
31
+		sigchan := make(chan os.Signal, 1)
32
+		signal.Notify(sigchan, os.Interrupt, os.Kill)
33
+		<-sigchan
34
+		log.Info("Shutting down...")
35
+		manners.Close()
36
+	}()
37
+
38
+	http.Handle("/hello", myHandler)
39
+	log.Fatal(manners.ListenAndServe(":8080", nil))
40
+*/
41
+package manners
42
+
43
+import (
44
+	"crypto/tls"
45
+	"net"
46
+	"net/http"
47
+	"sync"
48
+	"sync/atomic"
49
+)
50
+
51
+// A GracefulServer maintains a WaitGroup that counts how many in-flight
52
+// requests the server is handling. When it receives a shutdown signal,
53
+// it stops accepting new requests but does not actually shut down until
54
+// all in-flight requests terminate.
55
+//
56
+// GracefulServer embeds the underlying net/http.Server making its non-override
57
+// methods and properties avaiable.
58
+//
59
+// It must be initialized by calling NewWithServer.
60
+type GracefulServer struct {
61
+	*http.Server
62
+
63
+	shutdown         chan bool
64
+	shutdownFinished chan bool
65
+	wg               waitGroup
66
+	routinesCount    int
67
+
68
+	lcsmu       sync.RWMutex
69
+	connections map[net.Conn]bool
70
+
71
+	up chan net.Listener // Only used by test code.
72
+}
73
+
74
+// NewServer creates a new GracefulServer.
75
+func NewServer() *GracefulServer {
76
+	return NewWithServer(new(http.Server))
77
+}
78
+
79
+// NewWithServer wraps an existing http.Server object and returns a
80
+// GracefulServer that supports all of the original Server operations.
81
+func NewWithServer(s *http.Server) *GracefulServer {
82
+	return &GracefulServer{
83
+		Server:           s,
84
+		shutdown:         make(chan bool),
85
+		shutdownFinished: make(chan bool, 1),
86
+		wg:               new(sync.WaitGroup),
87
+		routinesCount:    0,
88
+		connections:      make(map[net.Conn]bool),
89
+	}
90
+}
91
+
92
+// Close stops the server from accepting new requets and begins shutting down.
93
+// It returns true if it's the first time Close is called.
94
+func (s *GracefulServer) Close() bool {
95
+	return <-s.shutdown
96
+}
97
+
98
+// BlockingClose is similar to Close, except that it blocks until the last
99
+// connection has been closed.
100
+func (s *GracefulServer) BlockingClose() bool {
101
+	result := s.Close()
102
+	<-s.shutdownFinished
103
+	return result
104
+}
105
+
106
+// ListenAndServe provides a graceful equivalent of net/http.Serve.ListenAndServe.
107
+func (s *GracefulServer) ListenAndServe() error {
108
+	addr := s.Addr
109
+	if addr == "" {
110
+		addr = ":http"
111
+	}
112
+	listener, err := net.Listen("tcp", addr)
113
+	if err != nil {
114
+		return err
115
+	}
116
+
117
+	return s.Serve(listener)
118
+}
119
+
120
+// ListenAndServeTLS provides a graceful equivalent of net/http.Serve.ListenAndServeTLS.
121
+func (s *GracefulServer) ListenAndServeTLS(certFile, keyFile string) error {
122
+	// direct lift from net/http/server.go
123
+	addr := s.Addr
124
+	if addr == "" {
125
+		addr = ":https"
126
+	}
127
+	config := &tls.Config{}
128
+	if s.TLSConfig != nil {
129
+		*config = *s.TLSConfig
130
+	}
131
+	if config.NextProtos == nil {
132
+		config.NextProtos = []string{"http/1.1"}
133
+	}
134
+
135
+	var err error
136
+	config.Certificates = make([]tls.Certificate, 1)
137
+	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
138
+	if err != nil {
139
+		return err
140
+	}
141
+
142
+	ln, err := net.Listen("tcp", addr)
143
+	if err != nil {
144
+		return err
145
+	}
146
+
147
+	return s.Serve(tls.NewListener(ln, config))
148
+}
149
+
150
+// Serve provides a graceful equivalent net/http.Server.Serve.
151
+func (s *GracefulServer) Serve(listener net.Listener) error {
152
+	// Wrap the server HTTP handler into graceful one, that will close kept
153
+	// alive connections if a new request is received after shutdown.
154
+	gracefulHandler := newGracefulHandler(s.Server.Handler)
155
+	s.Server.Handler = gracefulHandler
156
+
157
+	// Start a goroutine that waits for a shutdown signal and will stop the
158
+	// listener when it receives the signal. That in turn will result in
159
+	// unblocking of the http.Serve call.
160
+	go func() {
161
+		s.shutdown <- true
162
+		close(s.shutdown)
163
+		gracefulHandler.Close()
164
+		s.Server.SetKeepAlivesEnabled(false)
165
+		listener.Close()
166
+	}()
167
+
168
+	originalConnState := s.Server.ConnState
169
+
170
+	// s.ConnState is invoked by the net/http.Server every time a connection
171
+	// changes state. It keeps track of each connection's state over time,
172
+	// enabling manners to handle persisted connections correctly.
173
+	s.ConnState = func(conn net.Conn, newState http.ConnState) {
174
+		s.lcsmu.RLock()
175
+		protected := s.connections[conn]
176
+		s.lcsmu.RUnlock()
177
+
178
+		switch newState {
179
+
180
+		case http.StateNew:
181
+			// New connection -> StateNew
182
+			protected = true
183
+			s.StartRoutine()
184
+
185
+		case http.StateActive:
186
+			// (StateNew, StateIdle) -> StateActive
187
+			if gracefulHandler.IsClosed() {
188
+				conn.Close()
189
+				break
190
+			}
191
+
192
+			if !protected {
193
+				protected = true
194
+				s.StartRoutine()
195
+			}
196
+
197
+		default:
198
+			// (StateNew, StateActive) -> (StateIdle, StateClosed, StateHiJacked)
199
+			if protected {
200
+				s.FinishRoutine()
201
+				protected = false
202
+			}
203
+		}
204
+
205
+		s.lcsmu.Lock()
206
+		if newState == http.StateClosed || newState == http.StateHijacked {
207
+			delete(s.connections, conn)
208
+		} else {
209
+			s.connections[conn] = protected
210
+		}
211
+		s.lcsmu.Unlock()
212
+
213
+		if originalConnState != nil {
214
+			originalConnState(conn, newState)
215
+		}
216
+	}
217
+
218
+	// A hook to allow the server to notify others when it is ready to receive
219
+	// requests; only used by tests.
220
+	if s.up != nil {
221
+		s.up <- listener
222
+	}
223
+
224
+	err := s.Server.Serve(listener)
225
+	// An error returned on shutdown is not worth reporting.
226
+	if err != nil && gracefulHandler.IsClosed() {
227
+		err = nil
228
+	}
229
+
230
+	// Wait for pending requests to complete regardless the Serve result.
231
+	s.wg.Wait()
232
+	s.shutdownFinished <- true
233
+	return err
234
+}
235
+
236
+// StartRoutine increments the server's WaitGroup. Use this if a web request
237
+// starts more goroutines and these goroutines are not guaranteed to finish
238
+// before the request.
239
+func (s *GracefulServer) StartRoutine() {
240
+	s.lcsmu.Lock()
241
+	defer s.lcsmu.Unlock()
242
+	s.wg.Add(1)
243
+	s.routinesCount++
244
+}
245
+
246
+// FinishRoutine decrements the server's WaitGroup. Use this to complement
247
+// StartRoutine().
248
+func (s *GracefulServer) FinishRoutine() {
249
+	s.lcsmu.Lock()
250
+	defer s.lcsmu.Unlock()
251
+	s.wg.Done()
252
+	s.routinesCount--
253
+}
254
+
255
+// RoutinesCount returns the number of currently running routines
256
+func (s *GracefulServer) RoutinesCount() int {
257
+	s.lcsmu.RLock()
258
+	defer s.lcsmu.RUnlock()
259
+	return s.routinesCount
260
+}
261
+
262
+// gracefulHandler is used by GracefulServer to prevent calling ServeHTTP on
263
+// to be closed kept-alive connections during the server shutdown.
264
+type gracefulHandler struct {
265
+	closed  int32 // accessed atomically.
266
+	wrapped http.Handler
267
+}
268
+
269
+func newGracefulHandler(wrapped http.Handler) *gracefulHandler {
270
+	return &gracefulHandler{
271
+		wrapped: wrapped,
272
+	}
273
+}
274
+
275
+func (gh *gracefulHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
276
+	if atomic.LoadInt32(&gh.closed) == 0 {
277
+		gh.wrapped.ServeHTTP(w, r)
278
+		return
279
+	}
280
+	r.Body.Close()
281
+	// Server is shutting down at this moment, and the connection that this
282
+	// handler is being called on is about to be closed. So we do not need to
283
+	// actually execute the handler logic.
284
+}
285
+
286
+func (gh *gracefulHandler) Close() {
287
+	atomic.StoreInt32(&gh.closed, 1)
288
+}
289
+
290
+func (gh *gracefulHandler) IsClosed() bool {
291
+	return atomic.LoadInt32(&gh.closed) == 1
292
+}

+ 47
- 0
vendor/github.com/braintree/manners/static.go View File

@@ -0,0 +1,47 @@
1
+package manners
2
+
3
+import (
4
+	"net"
5
+	"net/http"
6
+	"sync"
7
+)
8
+
9
+var (
10
+	defaultServer     *GracefulServer
11
+	defaultServerLock = &sync.Mutex{}
12
+)
13
+
14
+func init() {
15
+	defaultServerLock.Lock()
16
+}
17
+
18
+// ListenAndServe provides a graceful version of the function provided by the
19
+// net/http package. Call Close() to stop the server.
20
+func ListenAndServe(addr string, handler http.Handler) error {
21
+	defaultServer = NewWithServer(&http.Server{Addr: addr, Handler: handler})
22
+	defaultServerLock.Unlock()
23
+	return defaultServer.ListenAndServe()
24
+}
25
+
26
+// ListenAndServeTLS provides a graceful version of the function provided by the
27
+// net/http package. Call Close() to stop the server.
28
+func ListenAndServeTLS(addr string, certFile string, keyFile string, handler http.Handler) error {
29
+	defaultServer = NewWithServer(&http.Server{Addr: addr, Handler: handler})
30
+	defaultServerLock.Unlock()
31
+	return defaultServer.ListenAndServeTLS(certFile, keyFile)
32
+}
33
+
34
+// Serve provides a graceful version of the function provided by the net/http
35
+// package. Call Close() to stop the server.
36
+func Serve(l net.Listener, handler http.Handler) error {
37
+	defaultServer = NewWithServer(&http.Server{Handler: handler})
38
+	defaultServerLock.Unlock()
39
+	return defaultServer.Serve(l)
40
+}
41
+
42
+// Shuts down the default server used by ListenAndServe, ListenAndServeTLS and
43
+// Serve. It returns true if it's the first time Close is called.
44
+func Close() bool {
45
+	defaultServerLock.Lock()
46
+	return defaultServer.Close()
47
+}

+ 15
- 0
vendor/github.com/davecgh/go-spew/LICENSE View File

@@ -0,0 +1,15 @@
1
+ISC License
2
+
3
+Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
4
+
5
+Permission to use, copy, modify, and/or distribute this software for any
6
+purpose with or without fee is hereby granted, provided that the above
7
+copyright notice and this permission notice appear in all copies.
8
+
9
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ 145
- 0
vendor/github.com/davecgh/go-spew/spew/bypass.go View File

@@ -0,0 +1,145 @@
1
+// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
2
+//
3
+// Permission to use, copy, modify, and distribute this software for any
4
+// purpose with or without fee is hereby granted, provided that the above
5
+// copyright notice and this permission notice appear in all copies.
6
+//
7
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
+
15
+// NOTE: Due to the following build constraints, this file will only be compiled
16
+// when the code is not running on Google App Engine, compiled by GopherJS, and
17
+// "-tags safe" is not added to the go build command line.  The "disableunsafe"
18
+// tag is deprecated and thus should not be used.
19
+// Go versions prior to 1.4 are disabled because they use a different layout
20
+// for interfaces which make the implementation of unsafeReflectValue more complex.
21
+// +build !js,!appengine,!safe,!disableunsafe,go1.4
22
+
23
+package spew
24
+
25
+import (
26
+	"reflect"
27
+	"unsafe"
28
+)
29
+
30
+const (
31
+	// UnsafeDisabled is a build-time constant which specifies whether or
32
+	// not access to the unsafe package is available.
33
+	UnsafeDisabled = false
34
+
35
+	// ptrSize is the size of a pointer on the current arch.
36
+	ptrSize = unsafe.Sizeof((*byte)(nil))
37
+)
38
+
39
+type flag uintptr
40
+
41
+var (
42
+	// flagRO indicates whether the value field of a reflect.Value
43
+	// is read-only.
44
+	flagRO flag
45
+
46
+	// flagAddr indicates whether the address of the reflect.Value's
47
+	// value may be taken.
48
+	flagAddr flag
49
+)
50
+
51
+// flagKindMask holds the bits that make up the kind
52
+// part of the flags field. In all the supported versions,
53
+// it is in the lower 5 bits.
54
+const flagKindMask = flag(0x1f)
55
+
56
+// Different versions of Go have used different
57
+// bit layouts for the flags type. This table
58
+// records the known combinations.
59
+var okFlags = []struct {
60
+	ro, addr flag
61
+}{{
62
+	// From Go 1.4 to 1.5
63
+	ro:   1 << 5,
64
+	addr: 1 << 7,
65
+}, {
66
+	// Up to Go tip.
67
+	ro:   1<<5 | 1<<6,
68
+	addr: 1 << 8,
69
+}}
70
+
71
+var flagValOffset = func() uintptr {
72
+	field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
73
+	if !ok {
74
+		panic("reflect.Value has no flag field")
75
+	}
76
+	return field.Offset
77
+}()
78
+
79
+// flagField returns a pointer to the flag field of a reflect.Value.
80
+func flagField(v *reflect.Value) *flag {
81
+	return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
82
+}
83
+
84
+// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
85
+// the typical safety restrictions preventing access to unaddressable and
86
+// unexported data.  It works by digging the raw pointer to the underlying
87
+// value out of the protected value and generating a new unprotected (unsafe)
88
+// reflect.Value to it.
89
+//
90
+// This allows us to check for implementations of the Stringer and error
91
+// interfaces to be used for pretty printing ordinarily unaddressable and
92
+// inaccessible values such as unexported struct fields.
93
+func unsafeReflectValue(v reflect.Value) reflect.Value {
94
+	if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
95
+		return v
96
+	}
97
+	flagFieldPtr := flagField(&v)
98
+	*flagFieldPtr &^= flagRO
99
+	*flagFieldPtr |= flagAddr
100
+	return v
101
+}
102
+
103
+// Sanity checks against future reflect package changes
104
+// to the type or semantics of the Value.flag field.
105
+func init() {
106
+	field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
107
+	if !ok {
108
+		panic("reflect.Value has no flag field")
109
+	}
110
+	if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
111
+		panic("reflect.Value flag field has changed kind")
112
+	}
113
+	type t0 int
114
+	var t struct {
115
+		A t0
116
+		// t0 will have flagEmbedRO set.
117
+		t0
118
+		// a will have flagStickyRO set
119
+		a t0
120
+	}
121
+	vA := reflect.ValueOf(t).FieldByName("A")
122
+	va := reflect.ValueOf(t).FieldByName("a")
123
+	vt0 := reflect.ValueOf(t).FieldByName("t0")
124
+
125
+	// Infer flagRO from the difference between the flags
126
+	// for the (otherwise identical) fields in t.
127
+	flagPublic := *flagField(&vA)
128
+	flagWithRO := *flagField(&va) | *flagField(&vt0)
129
+	flagRO = flagPublic ^ flagWithRO
130
+
131
+	// Infer flagAddr from the difference between a value
132
+	// taken from a pointer and not.
133
+	vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
134
+	flagNoPtr := *flagField(&vA)
135
+	flagPtr := *flagField(&vPtrA)
136
+	flagAddr = flagNoPtr ^ flagPtr
137
+
138
+	// Check that the inferred flags tally with one of the known versions.
139
+	for _, f := range okFlags {
140
+		if flagRO == f.ro && flagAddr == f.addr {
141
+			return
142
+		}
143
+	}
144
+	panic("reflect.Value read-only flag has changed semantics")
145
+}

+ 38
- 0
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go View File

@@ -0,0 +1,38 @@
1
+// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
2
+//
3
+// Permission to use, copy, modify, and distribute this software for any
4
+// purpose with or without fee is hereby granted, provided that the above
5
+// copyright notice and this permission notice appear in all copies.
6
+//
7
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
+
15
+// NOTE: Due to the following build constraints, this file will only be compiled
16
+// when the code is running on Google App Engine, compiled by GopherJS, or
17
+// "-tags safe" is added to the go build command line.  The "disableunsafe"
18
+// tag is deprecated and thus should not be used.
19
+// +build js appengine safe disableunsafe !go1.4
20
+
21
+package spew
22
+
23
+import "reflect"
24
+
25
+const (
26
+	// UnsafeDisabled is a build-time constant which specifies whether or
27
+	// not access to the unsafe package is available.
28
+	UnsafeDisabled = true
29
+)
30
+
31
+// unsafeReflectValue typically converts the passed reflect.Value into a one
32
+// that bypasses the typical safety restrictions preventing access to
33
+// unaddressable and unexported data.  However, doing this relies on access to
34
+// the unsafe package.  This is a stub version which simply returns the passed
35
+// reflect.Value when the unsafe package is not available.
36
+func unsafeReflectValue(v reflect.Value) reflect.Value {
37
+	return v
38
+}

+ 341
- 0
vendor/github.com/davecgh/go-spew/spew/common.go View File

@@ -0,0 +1,341 @@
1
+/*
2
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+package spew
18
+
19
+import (
20
+	"bytes"
21
+	"fmt"
22
+	"io"
23
+	"reflect"
24
+	"sort"
25
+	"strconv"
26
+)
27
+
28
+// Some constants in the form of bytes to avoid string overhead.  This mirrors
29
+// the technique used in the fmt package.
30
+var (
31
+	panicBytes            = []byte("(PANIC=")
32
+	plusBytes             = []byte("+")
33
+	iBytes                = []byte("i")
34
+	trueBytes             = []byte("true")
35
+	falseBytes            = []byte("false")
36
+	interfaceBytes        = []byte("(interface {})")
37
+	commaNewlineBytes     = []byte(",\n")
38
+	newlineBytes          = []byte("\n")
39
+	openBraceBytes        = []byte("{")
40
+	openBraceNewlineBytes = []byte("{\n")
41
+	closeBraceBytes       = []byte("}")
42
+	asteriskBytes         = []byte("*")
43
+	colonBytes            = []byte(":")
44
+	colonSpaceBytes       = []byte(": ")
45
+	openParenBytes        = []byte("(")
46
+	closeParenBytes       = []byte(")")
47
+	spaceBytes            = []byte(" ")
48
+	pointerChainBytes     = []byte("->")
49
+	nilAngleBytes         = []byte("<nil>")
50
+	maxNewlineBytes       = []byte("<max depth reached>\n")
51
+	maxShortBytes         = []byte("<max>")
52
+	circularBytes         = []byte("<already shown>")
53
+	circularShortBytes    = []byte("<shown>")
54
+	invalidAngleBytes     = []byte("<invalid>")
55
+	openBracketBytes      = []byte("[")
56
+	closeBracketBytes     = []byte("]")
57
+	percentBytes          = []byte("%")
58
+	precisionBytes        = []byte(".")
59
+	openAngleBytes        = []byte("<")
60
+	closeAngleBytes       = []byte(">")
61
+	openMapBytes          = []byte("map[")
62
+	closeMapBytes         = []byte("]")
63
+	lenEqualsBytes        = []byte("len=")
64
+	capEqualsBytes        = []byte("cap=")
65
+)
66
+
67
+// hexDigits is used to map a decimal value to a hex digit.
68
+var hexDigits = "0123456789abcdef"
69
+
70
+// catchPanic handles any panics that might occur during the handleMethods
71
+// calls.
72
+func catchPanic(w io.Writer, v reflect.Value) {
73
+	if err := recover(); err != nil {
74
+		w.Write(panicBytes)
75
+		fmt.Fprintf(w, "%v", err)
76
+		w.Write(closeParenBytes)
77
+	}
78
+}
79
+
80
+// handleMethods attempts to call the Error and String methods on the underlying
81
+// type the passed reflect.Value represents and outputes the result to Writer w.
82
+//
83
+// It handles panics in any called methods by catching and displaying the error
84
+// as the formatted value.
85
+func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
86
+	// We need an interface to check if the type implements the error or
87
+	// Stringer interface.  However, the reflect package won't give us an
88
+	// interface on certain things like unexported struct fields in order
89
+	// to enforce visibility rules.  We use unsafe, when it's available,
90
+	// to bypass these restrictions since this package does not mutate the
91
+	// values.
92
+	if !v.CanInterface() {
93
+		if UnsafeDisabled {
94
+			return false
95
+		}
96
+
97
+		v = unsafeReflectValue(v)
98
+	}
99
+
100
+	// Choose whether or not to do error and Stringer interface lookups against
101
+	// the base type or a pointer to the base type depending on settings.
102
+	// Technically calling one of these methods with a pointer receiver can
103
+	// mutate the value, however, types which choose to satisify an error or
104
+	// Stringer interface with a pointer receiver should not be mutating their
105
+	// state inside these interface methods.
106
+	if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
107
+		v = unsafeReflectValue(v)
108
+	}
109
+	if v.CanAddr() {
110
+		v = v.Addr()
111
+	}
112
+
113
+	// Is it an error or Stringer?
114
+	switch iface := v.Interface().(type) {
115
+	case error:
116
+		defer catchPanic(w, v)
117
+		if cs.ContinueOnMethod {
118
+			w.Write(openParenBytes)
119
+			w.Write([]byte(iface.Error()))
120
+			w.Write(closeParenBytes)
121
+			w.Write(spaceBytes)
122
+			return false
123
+		}
124
+
125
+		w.Write([]byte(iface.Error()))
126
+		return true
127
+
128
+	case fmt.Stringer:
129
+		defer catchPanic(w, v)
130
+		if cs.ContinueOnMethod {
131
+			w.Write(openParenBytes)
132
+			w.Write([]byte(iface.String()))
133
+			w.Write(closeParenBytes)
134
+			w.Write(spaceBytes)
135
+			return false
136
+		}
137
+		w.Write([]byte(iface.String()))
138
+		return true
139
+	}
140
+	return false
141
+}
142
+
143
+// printBool outputs a boolean value as true or false to Writer w.
144
+func printBool(w io.Writer, val bool) {
145
+	if val {
146
+		w.Write(trueBytes)
147
+	} else {
148
+		w.Write(falseBytes)
149
+	}
150
+}
151
+
152
+// printInt outputs a signed integer value to Writer w.
153
+func printInt(w io.Writer, val int64, base int) {
154
+	w.Write([]byte(strconv.FormatInt(val, base)))
155
+}
156
+
157
+// printUint outputs an unsigned integer value to Writer w.
158
+func printUint(w io.Writer, val uint64, base int) {
159
+	w.Write([]byte(strconv.FormatUint(val, base)))
160
+}
161
+
162
+// printFloat outputs a floating point value using the specified precision,
163
+// which is expected to be 32 or 64bit, to Writer w.
164
+func printFloat(w io.Writer, val float64, precision int) {
165
+	w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
166
+}
167
+
168
+// printComplex outputs a complex value using the specified float precision
169
+// for the real and imaginary parts to Writer w.
170
+func printComplex(w io.Writer, c complex128, floatPrecision int) {
171
+	r := real(c)
172
+	w.Write(openParenBytes)
173
+	w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
174
+	i := imag(c)
175
+	if i >= 0 {
176
+		w.Write(plusBytes)
177
+	}
178
+	w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
179
+	w.Write(iBytes)
180
+	w.Write(closeParenBytes)
181
+}
182
+
183
+// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
184
+// prefix to Writer w.
185
+func printHexPtr(w io.Writer, p uintptr) {
186
+	// Null pointer.
187
+	num := uint64(p)
188
+	if num == 0 {
189
+		w.Write(nilAngleBytes)
190
+		return
191
+	}
192
+
193
+	// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
194
+	buf := make([]byte, 18)
195
+
196
+	// It's simpler to construct the hex string right to left.
197
+	base := uint64(16)
198
+	i := len(buf) - 1
199
+	for num >= base {
200
+		buf[i] = hexDigits[num%base]
201
+		num /= base
202
+		i--
203
+	}
204
+	buf[i] = hexDigits[num]
205
+
206
+	// Add '0x' prefix.
207
+	i--
208
+	buf[i] = 'x'
209
+	i--
210
+	buf[i] = '0'
211
+
212
+	// Strip unused leading bytes.
213
+	buf = buf[i:]
214
+	w.Write(buf)
215
+}
216
+
217
+// valuesSorter implements sort.Interface to allow a slice of reflect.Value
218
+// elements to be sorted.
219
+type valuesSorter struct {
220
+	values  []reflect.Value
221
+	strings []string // either nil or same len and values
222
+	cs      *ConfigState
223
+}
224
+
225
+// newValuesSorter initializes a valuesSorter instance, which holds a set of
226
+// surrogate keys on which the data should be sorted.  It uses flags in
227
+// ConfigState to decide if and how to populate those surrogate keys.
228
+func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
229
+	vs := &valuesSorter{values: values, cs: cs}
230
+	if canSortSimply(vs.values[0].Kind()) {
231
+		return vs
232
+	}
233
+	if !cs.DisableMethods {
234
+		vs.strings = make([]string, len(values))
235
+		for i := range vs.values {
236
+			b := bytes.Buffer{}
237
+			if !handleMethods(cs, &b, vs.values[i]) {
238
+				vs.strings = nil
239
+				break
240
+			}
241
+			vs.strings[i] = b.String()
242
+		}
243
+	}
244
+	if vs.strings == nil && cs.SpewKeys {
245
+		vs.strings = make([]string, len(values))
246
+		for i := range vs.values {
247
+			vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
248
+		}
249
+	}
250
+	return vs
251
+}
252
+
253
+// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
254
+// directly, or whether it should be considered for sorting by surrogate keys
255
+// (if the ConfigState allows it).
256
+func canSortSimply(kind reflect.Kind) bool {
257
+	// This switch parallels valueSortLess, except for the default case.
258
+	switch kind {
259
+	case reflect.Bool:
260
+		return true
261
+	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
262
+		return true
263
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
264
+		return true
265
+	case reflect.Float32, reflect.Float64:
266
+		return true
267
+	case reflect.String:
268
+		return true
269
+	case reflect.Uintptr:
270
+		return true
271
+	case reflect.Array:
272
+		return true
273
+	}
274
+	return false
275
+}
276
+
277
+// Len returns the number of values in the slice.  It is part of the
278
+// sort.Interface implementation.
279
+func (s *valuesSorter) Len() int {
280
+	return len(s.values)
281
+}
282
+
283
+// Swap swaps the values at the passed indices.  It is part of the
284
+// sort.Interface implementation.
285
+func (s *valuesSorter) Swap(i, j int) {
286
+	s.values[i], s.values[j] = s.values[j], s.values[i]
287
+	if s.strings != nil {
288
+		s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
289
+	}
290
+}
291
+
292
+// valueSortLess returns whether the first value should sort before the second
293
+// value.  It is used by valueSorter.Less as part of the sort.Interface
294
+// implementation.
295
+func valueSortLess(a, b reflect.Value) bool {
296
+	switch a.Kind() {
297
+	case reflect.Bool:
298
+		return !a.Bool() && b.Bool()
299
+	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
300
+		return a.Int() < b.Int()
301
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
302
+		return a.Uint() < b.Uint()
303
+	case reflect.Float32, reflect.Float64:
304
+		return a.Float() < b.Float()
305
+	case reflect.String:
306
+		return a.String() < b.String()
307
+	case reflect.Uintptr:
308
+		return a.Uint() < b.Uint()
309
+	case reflect.Array:
310
+		// Compare the contents of both arrays.
311
+		l := a.Len()
312
+		for i := 0; i < l; i++ {
313
+			av := a.Index(i)
314
+			bv := b.Index(i)
315
+			if av.Interface() == bv.Interface() {
316
+				continue
317
+			}
318
+			return valueSortLess(av, bv)
319
+		}
320
+	}
321
+	return a.String() < b.String()
322
+}
323
+
324
+// Less returns whether the value at index i should sort before the
325
+// value at index j.  It is part of the sort.Interface implementation.
326
+func (s *valuesSorter) Less(i, j int) bool {
327
+	if s.strings == nil {
328
+		return valueSortLess(s.values[i], s.values[j])
329
+	}
330
+	return s.strings[i] < s.strings[j]
331
+}
332
+
333
+// sortValues is a sort function that handles both native types and any type that
334
+// can be converted to error or Stringer.  Other inputs are sorted according to
335
+// their Value.String() value to ensure display stability.
336
+func sortValues(values []reflect.Value, cs *ConfigState) {
337
+	if len(values) == 0 {
338
+		return
339
+	}
340
+	sort.Sort(newValuesSorter(values, cs))
341
+}

+ 306
- 0
vendor/github.com/davecgh/go-spew/spew/config.go View File

@@ -0,0 +1,306 @@
1
+/*
2
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+package spew
18
+
19
+import (
20
+	"bytes"
21
+	"fmt"
22
+	"io"
23
+	"os"
24
+)
25
+
26
+// ConfigState houses the configuration options used by spew to format and
27
+// display values.  There is a global instance, Config, that is used to control
28
+// all top-level Formatter and Dump functionality.  Each ConfigState instance
29
+// provides methods equivalent to the top-level functions.
30
+//
31
+// The zero value for ConfigState provides no indentation.  You would typically
32
+// want to set it to a space or a tab.
33
+//
34
+// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
35
+// with default settings.  See the documentation of NewDefaultConfig for default
36
+// values.
37
+type ConfigState struct {
38
+	// Indent specifies the string to use for each indentation level.  The
39
+	// global config instance that all top-level functions use set this to a
40
+	// single space by default.  If you would like more indentation, you might
41
+	// set this to a tab with "\t" or perhaps two spaces with "  ".
42
+	Indent string
43
+
44
+	// MaxDepth controls the maximum number of levels to descend into nested
45
+	// data structures.  The default, 0, means there is no limit.
46
+	//
47
+	// NOTE: Circular data structures are properly detected, so it is not
48
+	// necessary to set this value unless you specifically want to limit deeply
49
+	// nested data structures.
50
+	MaxDepth int
51
+
52
+	// DisableMethods specifies whether or not error and Stringer interfaces are
53
+	// invoked for types that implement them.
54
+	DisableMethods bool
55
+
56
+	// DisablePointerMethods specifies whether or not to check for and invoke
57
+	// error and Stringer interfaces on types which only accept a pointer
58
+	// receiver when the current type is not a pointer.
59
+	//
60
+	// NOTE: This might be an unsafe action since calling one of these methods
61
+	// with a pointer receiver could technically mutate the value, however,
62
+	// in practice, types which choose to satisify an error or Stringer
63
+	// interface with a pointer receiver should not be mutating their state
64
+	// inside these interface methods.  As a result, this option relies on
65
+	// access to the unsafe package, so it will not have any effect when
66
+	// running in environments without access to the unsafe package such as
67
+	// Google App Engine or with the "safe" build tag specified.
68
+	DisablePointerMethods bool
69
+
70
+	// DisablePointerAddresses specifies whether to disable the printing of
71
+	// pointer addresses. This is useful when diffing data structures in tests.
72
+	DisablePointerAddresses bool
73
+
74
+	// DisableCapacities specifies whether to disable the printing of capacities
75
+	// for arrays, slices, maps and channels. This is useful when diffing
76
+	// data structures in tests.
77
+	DisableCapacities bool
78
+
79
+	// ContinueOnMethod specifies whether or not recursion should continue once
80
+	// a custom error or Stringer interface is invoked.  The default, false,
81
+	// means it will print the results of invoking the custom error or Stringer
82
+	// interface and return immediately instead of continuing to recurse into
83
+	// the internals of the data type.
84
+	//
85
+	// NOTE: This flag does not have any effect if method invocation is disabled
86
+	// via the DisableMethods or DisablePointerMethods options.
87
+	ContinueOnMethod bool
88
+
89
+	// SortKeys specifies map keys should be sorted before being printed. Use
90
+	// this to have a more deterministic, diffable output.  Note that only
91
+	// native types (bool, int, uint, floats, uintptr and string) and types
92
+	// that support the error or Stringer interfaces (if methods are
93
+	// enabled) are supported, with other types sorted according to the
94
+	// reflect.Value.String() output which guarantees display stability.
95
+	SortKeys bool
96
+
97
+	// SpewKeys specifies that, as a last resort attempt, map keys should
98
+	// be spewed to strings and sorted by those strings.  This is only
99
+	// considered if SortKeys is true.
100
+	SpewKeys bool
101
+}
102
+
103
+// Config is the active configuration of the top-level functions.
104
+// The configuration can be changed by modifying the contents of spew.Config.
105
+var Config = ConfigState{Indent: " "}
106
+
107
+// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
108
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
109
+// the formatted string as a value that satisfies error.  See NewFormatter
110
+// for formatting details.
111
+//
112
+// This function is shorthand for the following syntax:
113
+//
114
+//	fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
115
+func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
116
+	return fmt.Errorf(format, c.convertArgs(a)...)
117
+}
118
+
119
+// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
120
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
121
+// the number of bytes written and any write error encountered.  See
122
+// NewFormatter for formatting details.
123
+//
124
+// This function is shorthand for the following syntax:
125
+//
126
+//	fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
127
+func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
128
+	return fmt.Fprint(w, c.convertArgs(a)...)
129
+}
130
+
131
+// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
132
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
133
+// the number of bytes written and any write error encountered.  See
134
+// NewFormatter for formatting details.
135
+//
136
+// This function is shorthand for the following syntax:
137
+//
138
+//	fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
139
+func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
140
+	return fmt.Fprintf(w, format, c.convertArgs(a)...)
141
+}
142
+
143
+// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
144
+// passed with a Formatter interface returned by c.NewFormatter.  See
145
+// NewFormatter for formatting details.
146
+//
147
+// This function is shorthand for the following syntax:
148
+//
149
+//	fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
150
+func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
151
+	return fmt.Fprintln(w, c.convertArgs(a)...)
152
+}
153
+
154
+// Print is a wrapper for fmt.Print that treats each argument as if it were
155
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
156
+// the number of bytes written and any write error encountered.  See
157
+// NewFormatter for formatting details.
158
+//
159
+// This function is shorthand for the following syntax:
160
+//
161
+//	fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
162
+func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
163
+	return fmt.Print(c.convertArgs(a)...)
164
+}
165
+
166
+// Printf is a wrapper for fmt.Printf that treats each argument as if it were
167
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
168
+// the number of bytes written and any write error encountered.  See
169
+// NewFormatter for formatting details.
170
+//
171
+// This function is shorthand for the following syntax:
172
+//
173
+//	fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
174
+func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
175
+	return fmt.Printf(format, c.convertArgs(a)...)
176
+}
177
+
178
+// Println is a wrapper for fmt.Println that treats each argument as if it were
179
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
180
+// the number of bytes written and any write error encountered.  See
181
+// NewFormatter for formatting details.
182
+//
183
+// This function is shorthand for the following syntax:
184
+//
185
+//	fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
186
+func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
187
+	return fmt.Println(c.convertArgs(a)...)
188
+}
189
+
190
+// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
191
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
192
+// the resulting string.  See NewFormatter for formatting details.
193
+//
194
+// This function is shorthand for the following syntax:
195
+//
196
+//	fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
197
+func (c *ConfigState) Sprint(a ...interface{}) string {
198
+	return fmt.Sprint(c.convertArgs(a)...)
199
+}
200
+
201
+// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
202
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
203
+// the resulting string.  See NewFormatter for formatting details.
204
+//
205
+// This function is shorthand for the following syntax:
206
+//
207
+//	fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
208
+func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
209
+	return fmt.Sprintf(format, c.convertArgs(a)...)
210
+}
211
+
212
+// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
213
+// were passed with a Formatter interface returned by c.NewFormatter.  It
214
+// returns the resulting string.  See NewFormatter for formatting details.
215
+//
216
+// This function is shorthand for the following syntax:
217
+//
218
+//	fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
219
+func (c *ConfigState) Sprintln(a ...interface{}) string {
220
+	return fmt.Sprintln(c.convertArgs(a)...)
221
+}
222
+
223
+/*
224
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
225
+interface.  As a result, it integrates cleanly with standard fmt package
226
+printing functions.  The formatter is useful for inline printing of smaller data
227
+types similar to the standard %v format specifier.
228
+
229
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
230
+addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
231
+combinations.  Any other verbs such as %x and %q will be sent to the the
232
+standard fmt package for formatting.  In addition, the custom formatter ignores
233
+the width and precision arguments (however they will still work on the format
234
+specifiers not handled by the custom formatter).
235
+
236
+Typically this function shouldn't be called directly.  It is much easier to make
237
+use of the custom formatter by calling one of the convenience functions such as
238
+c.Printf, c.Println, or c.Printf.
239
+*/
240
+func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
241
+	return newFormatter(c, v)
242
+}
243
+
244
+// Fdump formats and displays the passed arguments to io.Writer w.  It formats
245
+// exactly the same as Dump.
246
+func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
247
+	fdump(c, w, a...)
248
+}
249
+
250
+/*
251
+Dump displays the passed parameters to standard out with newlines, customizable
252
+indentation, and additional debug information such as complete types and all
253
+pointer addresses used to indirect to the final value.  It provides the
254
+following features over the built-in printing facilities provided by the fmt
255
+package:
256
+
257
+	* Pointers are dereferenced and followed
258
+	* Circular data structures are detected and handled properly
259
+	* Custom Stringer/error interfaces are optionally invoked, including
260
+	  on unexported types
261
+	* Custom types which only implement the Stringer/error interfaces via
262
+	  a pointer receiver are optionally invoked when passing non-pointer
263
+	  variables
264
+	* Byte arrays and slices are dumped like the hexdump -C command which
265
+	  includes offsets, byte values in hex, and ASCII output
266
+
267
+The configuration options are controlled by modifying the public members
268
+of c.  See ConfigState for options documentation.
269
+
270
+See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
271
+get the formatted result as a string.
272
+*/
273
+func (c *ConfigState) Dump(a ...interface{}) {
274
+	fdump(c, os.Stdout, a...)
275
+}
276
+
277
+// Sdump returns a string with the passed arguments formatted exactly the same
278
+// as Dump.
279
+func (c *ConfigState) Sdump(a ...interface{}) string {
280
+	var buf bytes.Buffer
281
+	fdump(c, &buf, a...)
282
+	return buf.String()
283
+}
284
+
285
+// convertArgs accepts a slice of arguments and returns a slice of the same
286
+// length with each argument converted to a spew Formatter interface using
287
+// the ConfigState associated with s.
288
+func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
289
+	formatters = make([]interface{}, len(args))
290
+	for index, arg := range args {
291
+		formatters[index] = newFormatter(c, arg)
292
+	}
293
+	return formatters
294
+}
295
+
296
+// NewDefaultConfig returns a ConfigState with the following default settings.
297
+//
298
+// 	Indent: " "
299
+// 	MaxDepth: 0
300
+// 	DisableMethods: false
301
+// 	DisablePointerMethods: false
302
+// 	ContinueOnMethod: false
303
+// 	SortKeys: false
304
+func NewDefaultConfig() *ConfigState {
305
+	return &ConfigState{Indent: " "}
306
+}

+ 211
- 0
vendor/github.com/davecgh/go-spew/spew/doc.go View File

@@ -0,0 +1,211 @@
1
+/*
2
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+/*
18
+Package spew implements a deep pretty printer for Go data structures to aid in
19
+debugging.
20
+
21
+A quick overview of the additional features spew provides over the built-in
22
+printing facilities for Go data types are as follows:
23
+
24
+	* Pointers are dereferenced and followed
25
+	* Circular data structures are detected and handled properly
26
+	* Custom Stringer/error interfaces are optionally invoked, including
27
+	  on unexported types
28
+	* Custom types which only implement the Stringer/error interfaces via
29
+	  a pointer receiver are optionally invoked when passing non-pointer
30
+	  variables
31
+	* Byte arrays and slices are dumped like the hexdump -C command which
32
+	  includes offsets, byte values in hex, and ASCII output (only when using
33
+	  Dump style)
34
+
35
+There are two different approaches spew allows for dumping Go data structures:
36
+
37
+	* Dump style which prints with newlines, customizable indentation,
38
+	  and additional debug information such as types and all pointer addresses
39
+	  used to indirect to the final value
40
+	* A custom Formatter interface that integrates cleanly with the standard fmt
41
+	  package and replaces %v, %+v, %#v, and %#+v to provide inline printing
42
+	  similar to the default %v while providing the additional functionality
43
+	  outlined above and passing unsupported format verbs such as %x and %q
44
+	  along to fmt
45
+
46
+Quick Start
47
+
48
+This section demonstrates how to quickly get started with spew.  See the
49
+sections below for further details on formatting and configuration options.
50
+
51
+To dump a variable with full newlines, indentation, type, and pointer
52
+information use Dump, Fdump, or Sdump:
53
+	spew.Dump(myVar1, myVar2, ...)
54
+	spew.Fdump(someWriter, myVar1, myVar2, ...)
55
+	str := spew.Sdump(myVar1, myVar2, ...)
56
+
57
+Alternatively, if you would prefer to use format strings with a compacted inline
58
+printing style, use the convenience wrappers Printf, Fprintf, etc with
59
+%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
60
+%#+v (adds types and pointer addresses):
61
+	spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
62
+	spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
63
+	spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
64
+	spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
65
+
66
+Configuration Options
67
+
68
+Configuration of spew is handled by fields in the ConfigState type.  For
69
+convenience, all of the top-level functions use a global state available
70
+via the spew.Config global.
71
+
72
+It is also possible to create a ConfigState instance that provides methods
73
+equivalent to the top-level functions.  This allows concurrent configuration
74
+options.  See the ConfigState documentation for more details.
75
+
76
+The following configuration options are available:
77
+	* Indent
78
+		String to use for each indentation level for Dump functions.
79
+		It is a single space by default.  A popular alternative is "\t".
80
+
81
+	* MaxDepth
82
+		Maximum number of levels to descend into nested data structures.
83
+		There is no limit by default.
84
+
85
+	* DisableMethods
86
+		Disables invocation of error and Stringer interface methods.
87
+		Method invocation is enabled by default.
88
+
89
+	* DisablePointerMethods
90
+		Disables invocation of error and Stringer interface methods on types
91
+		which only accept pointer receivers from non-pointer variables.
92
+		Pointer method invocation is enabled by default.
93
+
94
+	* DisablePointerAddresses
95
+		DisablePointerAddresses specifies whether to disable the printing of
96
+		pointer addresses. This is useful when diffing data structures in tests.
97
+
98
+	* DisableCapacities
99
+		DisableCapacities specifies whether to disable the printing of
100
+		capacities for arrays, slices, maps and channels. This is useful when
101
+		diffing data structures in tests.
102
+
103
+	* ContinueOnMethod
104
+		Enables recursion into types after invoking error and Stringer interface
105
+		methods. Recursion after method invocation is disabled by default.
106
+
107
+	* SortKeys
108
+		Specifies map keys should be sorted before being printed. Use
109
+		this to have a more deterministic, diffable output.  Note that
110
+		only native types (bool, int, uint, floats, uintptr and string)
111
+		and types which implement error or Stringer interfaces are
112
+		supported with other types sorted according to the
113
+		reflect.Value.String() output which guarantees display
114
+		stability.  Natural map order is used by default.
115
+
116
+	* SpewKeys
117
+		Specifies that, as a last resort attempt, map keys should be
118
+		spewed to strings and sorted by those strings.  This is only
119
+		considered if SortKeys is true.
120
+
121
+Dump Usage
122
+
123
+Simply call spew.Dump with a list of variables you want to dump:
124
+
125
+	spew.Dump(myVar1, myVar2, ...)
126
+
127
+You may also call spew.Fdump if you would prefer to output to an arbitrary
128
+io.Writer.  For example, to dump to standard error:
129
+
130
+	spew.Fdump(os.Stderr, myVar1, myVar2, ...)
131
+
132
+A third option is to call spew.Sdump to get the formatted output as a string:
133
+
134
+	str := spew.Sdump(myVar1, myVar2, ...)
135
+
136
+Sample Dump Output
137
+
138
+See the Dump example for details on the setup of the types and variables being
139
+shown here.
140
+
141
+	(main.Foo) {
142
+	 unexportedField: (*main.Bar)(0xf84002e210)({
143
+	  flag: (main.Flag) flagTwo,
144
+	  data: (uintptr) <nil>
145
+	 }),
146
+	 ExportedField: (map[interface {}]interface {}) (len=1) {
147
+	  (string) (len=3) "one": (bool) true
148
+	 }
149
+	}
150
+
151
+Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
152
+command as shown.
153
+	([]uint8) (len=32 cap=32) {
154
+	 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |
155
+	 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!"#$%&'()*+,-./0|
156
+	 00000020  31 32                                             |12|
157
+	}
158
+
159
+Custom Formatter
160
+
161
+Spew provides a custom formatter that implements the fmt.Formatter interface
162
+so that it integrates cleanly with standard fmt package printing functions. The
163
+formatter is useful for inline printing of smaller data types similar to the
164
+standard %v format specifier.
165
+
166
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
167
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
168
+combinations.  Any other verbs such as %x and %q will be sent to the the
169
+standard fmt package for formatting.  In addition, the custom formatter ignores
170
+the width and precision arguments (however they will still work on the format
171
+specifiers not handled by the custom formatter).
172
+
173
+Custom Formatter Usage
174
+
175
+The simplest way to make use of the spew custom formatter is to call one of the
176
+convenience functions such as spew.Printf, spew.Println, or spew.Printf.  The
177
+functions have syntax you are most likely already familiar with:
178
+
179
+	spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
180
+	spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
181
+	spew.Println(myVar, myVar2)
182
+	spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
183
+	spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
184
+
185
+See the Index for the full list convenience functions.
186
+
187
+Sample Formatter Output
188
+
189
+Double pointer to a uint8:
190
+	  %v: <**>5
191
+	 %+v: <**>(0xf8400420d0->0xf8400420c8)5
192
+	 %#v: (**uint8)5
193
+	%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
194
+
195
+Pointer to circular struct with a uint8 field and a pointer to itself:
196
+	  %v: <*>{1 <*><shown>}
197
+	 %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
198
+	 %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
199
+	%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
200
+
201
+See the Printf example for details on the setup of variables being shown
202
+here.
203
+
204
+Errors
205
+
206
+Since it is possible for custom Stringer/error interfaces to panic, spew
207
+detects them and handles them internally by printing the panic information
208
+inline with the output.  Since spew is intended to provide deep pretty printing
209
+capabilities on structures, it intentionally does not return any errors.
210
+*/
211
+package spew

+ 509
- 0
vendor/github.com/davecgh/go-spew/spew/dump.go View File

@@ -0,0 +1,509 @@
1
+/*
2
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+package spew
18
+
19
+import (
20
+	"bytes"
21
+	"encoding/hex"
22
+	"fmt"
23
+	"io"
24
+	"os"
25
+	"reflect"
26
+	"regexp"
27
+	"strconv"
28
+	"strings"
29
+)
30
+
31
+var (
32
+	// uint8Type is a reflect.Type representing a uint8.  It is used to
33
+	// convert cgo types to uint8 slices for hexdumping.
34
+	uint8Type = reflect.TypeOf(uint8(0))
35
+
36
+	// cCharRE is a regular expression that matches a cgo char.
37
+	// It is used to detect character arrays to hexdump them.
38
+	cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
39
+
40
+	// cUnsignedCharRE is a regular expression that matches a cgo unsigned
41
+	// char.  It is used to detect unsigned character arrays to hexdump
42
+	// them.
43
+	cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
44
+
45
+	// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
46
+	// It is used to detect uint8_t arrays to hexdump them.
47
+	cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
48
+)
49
+
50
+// dumpState contains information about the state of a dump operation.
51
+type dumpState struct {
52
+	w                io.Writer
53
+	depth            int
54
+	pointers         map[uintptr]int
55
+	ignoreNextType   bool
56
+	ignoreNextIndent bool
57
+	cs               *ConfigState
58
+}
59
+
60
+// indent performs indentation according to the depth level and cs.Indent
61
+// option.
62
+func (d *dumpState) indent() {
63
+	if d.ignoreNextIndent {
64
+		d.ignoreNextIndent = false
65
+		return
66
+	}
67
+	d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
68
+}
69
+
70
+// unpackValue returns values inside of non-nil interfaces when possible.
71
+// This is useful for data types like structs, arrays, slices, and maps which
72
+// can contain varying types packed inside an interface.
73
+func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
74
+	if v.Kind() == reflect.Interface && !v.IsNil() {
75
+		v = v.Elem()
76
+	}
77
+	return v
78
+}
79
+
80
+// dumpPtr handles formatting of pointers by indirecting them as necessary.
81
+func (d *dumpState) dumpPtr(v reflect.Value) {
82
+	// Remove pointers at or below the current depth from map used to detect
83
+	// circular refs.
84
+	for k, depth := range d.pointers {
85
+		if depth >= d.depth {
86
+			delete(d.pointers, k)
87
+		}
88
+	}
89
+
90
+	// Keep list of all dereferenced pointers to show later.
91
+	pointerChain := make([]uintptr, 0)
92
+
93
+	// Figure out how many levels of indirection there are by dereferencing
94
+	// pointers and unpacking interfaces down the chain while detecting circular
95
+	// references.
96
+	nilFound := false
97
+	cycleFound := false
98
+	indirects := 0
99
+	ve := v
100
+	for ve.Kind() == reflect.Ptr {
101
+		if ve.IsNil() {
102
+			nilFound = true
103
+			break
104
+		}
105
+		indirects++
106
+		addr := ve.Pointer()
107
+		pointerChain = append(pointerChain, addr)
108
+		if pd, ok := d.pointers[addr]; ok && pd < d.depth {
109
+			cycleFound = true
110
+			indirects--
111
+			break
112
+		}
113
+		d.pointers[addr] = d.depth
114
+
115
+		ve = ve.Elem()
116
+		if ve.Kind() == reflect.Interface {
117
+			if ve.IsNil() {
118
+				nilFound = true
119
+				break
120
+			}
121
+			ve = ve.Elem()
122
+		}
123
+	}
124
+
125
+	// Display type information.
126
+	d.w.Write(openParenBytes)
127
+	d.w.Write(bytes.Repeat(asteriskBytes, indirects))
128
+	d.w.Write([]byte(ve.Type().String()))
129
+	d.w.Write(closeParenBytes)
130
+
131
+	// Display pointer information.
132
+	if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
133
+		d.w.Write(openParenBytes)
134
+		for i, addr := range pointerChain {
135
+			if i > 0 {
136
+				d.w.Write(pointerChainBytes)
137
+			}
138
+			printHexPtr(d.w, addr)
139
+		}
140
+		d.w.Write(closeParenBytes)
141
+	}
142
+
143
+	// Display dereferenced value.
144
+	d.w.Write(openParenBytes)
145
+	switch {
146
+	case nilFound:
147
+		d.w.Write(nilAngleBytes)
148
+
149
+	case cycleFound:
150
+		d.w.Write(circularBytes)
151
+
152
+	default:
153
+		d.ignoreNextType = true
154
+		d.dump(ve)
155
+	}
156
+	d.w.Write(closeParenBytes)
157
+}
158
+
159
+// dumpSlice handles formatting of arrays and slices.  Byte (uint8 under
160
+// reflection) arrays and slices are dumped in hexdump -C fashion.
161
+func (d *dumpState) dumpSlice(v reflect.Value) {
162
+	// Determine whether this type should be hex dumped or not.  Also,
163
+	// for types which should be hexdumped, try to use the underlying data
164
+	// first, then fall back to trying to convert them to a uint8 slice.
165
+	var buf []uint8
166
+	doConvert := false
167
+	doHexDump := false
168
+	numEntries := v.Len()
169
+	if numEntries > 0 {
170
+		vt := v.Index(0).Type()
171
+		vts := vt.String()
172
+		switch {
173
+		// C types that need to be converted.
174
+		case cCharRE.MatchString(vts):
175
+			fallthrough
176
+		case cUnsignedCharRE.MatchString(vts):
177
+			fallthrough
178
+		case cUint8tCharRE.MatchString(vts):
179
+			doConvert = true
180
+
181
+		// Try to use existing uint8 slices and fall back to converting
182
+		// and copying if that fails.
183
+		case vt.Kind() == reflect.Uint8:
184
+			// We need an addressable interface to convert the type
185
+			// to a byte slice.  However, the reflect package won't
186
+			// give us an interface on certain things like
187
+			// unexported struct fields in order to enforce
188
+			// visibility rules.  We use unsafe, when available, to
189
+			// bypass these restrictions since this package does not
190
+			// mutate the values.
191
+			vs := v
192
+			if !vs.CanInterface() || !vs.CanAddr() {
193
+				vs = unsafeReflectValue(vs)
194
+			}
195
+			if !UnsafeDisabled {
196
+				vs = vs.Slice(0, numEntries)
197
+
198
+				// Use the existing uint8 slice if it can be
199
+				// type asserted.
200
+				iface := vs.Interface()
201
+				if slice, ok := iface.([]uint8); ok {
202
+					buf = slice
203
+					doHexDump = true
204
+					break
205
+				}
206
+			}
207
+
208
+			// The underlying data needs to be converted if it can't
209
+			// be type asserted to a uint8 slice.
210
+			doConvert = true
211
+		}
212
+
213
+		// Copy and convert the underlying type if needed.
214
+		if doConvert && vt.ConvertibleTo(uint8Type) {
215
+			// Convert and copy each element into a uint8 byte
216
+			// slice.
217
+			buf = make([]uint8, numEntries)
218
+			for i := 0; i < numEntries; i++ {
219
+				vv := v.Index(i)
220
+				buf[i] = uint8(vv.Convert(uint8Type).Uint())
221
+			}
222
+			doHexDump = true
223
+		}
224
+	}
225
+
226
+	// Hexdump the entire slice as needed.
227
+	if doHexDump {
228
+		indent := strings.Repeat(d.cs.Indent, d.depth)
229
+		str := indent + hex.Dump(buf)
230
+		str = strings.Replace(str, "\n", "\n"+indent, -1)
231
+		str = strings.TrimRight(str, d.cs.Indent)
232
+		d.w.Write([]byte(str))
233
+		return
234
+	}
235
+
236
+	// Recursively call dump for each item.
237
+	for i := 0; i < numEntries; i++ {
238
+		d.dump(d.unpackValue(v.Index(i)))
239
+		if i < (numEntries - 1) {
240
+			d.w.Write(commaNewlineBytes)
241
+		} else {
242
+			d.w.Write(newlineBytes)
243
+		}
244
+	}
245
+}
246
+
247
+// dump is the main workhorse for dumping a value.  It uses the passed reflect
248
+// value to figure out what kind of object we are dealing with and formats it
249
+// appropriately.  It is a recursive function, however circular data structures
250
+// are detected and handled properly.
251
+func (d *dumpState) dump(v reflect.Value) {
252
+	// Handle invalid reflect values immediately.
253
+	kind := v.Kind()
254
+	if kind == reflect.Invalid {
255
+		d.w.Write(invalidAngleBytes)
256
+		return
257
+	}
258
+
259
+	// Handle pointers specially.
260
+	if kind == reflect.Ptr {
261
+		d.indent()
262
+		d.dumpPtr(v)
263
+		return
264
+	}
265
+
266
+	// Print type information unless already handled elsewhere.
267
+	if !d.ignoreNextType {
268
+		d.indent()
269
+		d.w.Write(openParenBytes)
270
+		d.w.Write([]byte(v.Type().String()))
271
+		d.w.Write(closeParenBytes)
272
+		d.w.Write(spaceBytes)
273
+	}
274
+	d.ignoreNextType = false
275
+
276
+	// Display length and capacity if the built-in len and cap functions
277
+	// work with the value's kind and the len/cap itself is non-zero.
278
+	valueLen, valueCap := 0, 0
279
+	switch v.Kind() {
280
+	case reflect.Array, reflect.Slice, reflect.Chan:
281
+		valueLen, valueCap = v.Len(), v.Cap()
282
+	case reflect.Map, reflect.String:
283
+		valueLen = v.Len()
284
+	}
285
+	if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
286
+		d.w.Write(openParenBytes)
287
+		if valueLen != 0 {
288
+			d.w.Write(lenEqualsBytes)
289
+			printInt(d.w, int64(valueLen), 10)
290
+		}
291
+		if !d.cs.DisableCapacities && valueCap != 0 {
292
+			if valueLen != 0 {
293
+				d.w.Write(spaceBytes)
294
+			}
295
+			d.w.Write(capEqualsBytes)
296
+			printInt(d.w, int64(valueCap), 10)
297
+		}
298
+		d.w.Write(closeParenBytes)
299
+		d.w.Write(spaceBytes)
300
+	}
301
+
302
+	// Call Stringer/error interfaces if they exist and the handle methods flag
303
+	// is enabled
304
+	if !d.cs.DisableMethods {
305
+		if (kind != reflect.Invalid) && (kind != reflect.Interface) {
306
+			if handled := handleMethods(d.cs, d.w, v); handled {
307
+				return
308
+			}
309
+		}
310
+	}
311
+
312
+	switch kind {
313
+	case reflect.Invalid:
314
+		// Do nothing.  We should never get here since invalid has already
315
+		// been handled above.
316
+
317
+	case reflect.Bool:
318
+		printBool(d.w, v.Bool())
319
+
320
+	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
321
+		printInt(d.w, v.Int(), 10)
322
+
323
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
324
+		printUint(d.w, v.Uint(), 10)
325
+
326
+	case reflect.Float32:
327
+		printFloat(d.w, v.Float(), 32)
328
+
329
+	case reflect.Float64:
330
+		printFloat(d.w, v.Float(), 64)
331
+
332
+	case reflect.Complex64:
333
+		printComplex(d.w, v.Complex(), 32)
334
+
335
+	case reflect.Complex128:
336
+		printComplex(d.w, v.Complex(), 64)
337
+
338
+	case reflect.Slice:
339
+		if v.IsNil() {
340
+			d.w.Write(nilAngleBytes)
341
+			break
342
+		}
343
+		fallthrough
344
+
345
+	case reflect.Array:
346
+		d.w.Write(openBraceNewlineBytes)
347
+		d.depth++
348
+		if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
349
+			d.indent()
350
+			d.w.Write(maxNewlineBytes)
351
+		} else {
352
+			d.dumpSlice(v)
353
+		}
354
+		d.depth--
355
+		d.indent()
356
+		d.w.Write(closeBraceBytes)
357
+
358
+	case reflect.String:
359
+		d.w.Write([]byte(strconv.Quote(v.String())))
360
+
361
+	case reflect.Interface:
362
+		// The only time we should get here is for nil interfaces due to
363
+		// unpackValue calls.
364
+		if v.IsNil() {
365
+			d.w.Write(nilAngleBytes)
366
+		}
367
+
368
+	case reflect.Ptr:
369
+		// Do nothing.  We should never get here since pointers have already
370
+		// been handled above.
371
+
372
+	case reflect.Map:
373
+		// nil maps should be indicated as different than empty maps
374
+		if v.IsNil() {
375
+			d.w.Write(nilAngleBytes)
376
+			break
377
+		}
378
+
379
+		d.w.Write(openBraceNewlineBytes)
380
+		d.depth++
381
+		if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
382
+			d.indent()
383
+			d.w.Write(maxNewlineBytes)
384
+		} else {
385
+			numEntries := v.Len()
386
+			keys := v.MapKeys()
387
+			if d.cs.SortKeys {
388
+				sortValues(keys, d.cs)
389
+			}
390
+			for i, key := range keys {
391
+				d.dump(d.unpackValue(key))
392
+				d.w.Write(colonSpaceBytes)
393
+				d.ignoreNextIndent = true
394
+				d.dump(d.unpackValue(v.MapIndex(key)))
395
+				if i < (numEntries - 1) {
396
+					d.w.Write(commaNewlineBytes)
397
+				} else {
398
+					d.w.Write(newlineBytes)
399
+				}
400
+			}
401
+		}
402
+		d.depth--
403
+		d.indent()
404
+		d.w.Write(closeBraceBytes)
405
+
406
+	case reflect.Struct:
407
+		d.w.Write(openBraceNewlineBytes)
408
+		d.depth++
409
+		if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
410
+			d.indent()
411
+			d.w.Write(maxNewlineBytes)
412
+		} else {
413
+			vt := v.Type()
414
+			numFields := v.NumField()
415
+			for i := 0; i < numFields; i++ {
416
+				d.indent()
417
+				vtf := vt.Field(i)
418
+				d.w.Write([]byte(vtf.Name))
419
+				d.w.Write(colonSpaceBytes)
420
+				d.ignoreNextIndent = true
421
+				d.dump(d.unpackValue(v.Field(i)))
422
+				if i < (numFields - 1) {
423
+					d.w.Write(commaNewlineBytes)
424
+				} else {
425
+					d.w.Write(newlineBytes)
426
+				}
427
+			}
428
+		}
429
+		d.depth--
430
+		d.indent()
431
+		d.w.Write(closeBraceBytes)
432
+
433
+	case reflect.Uintptr:
434
+		printHexPtr(d.w, uintptr(v.Uint()))
435
+
436
+	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
437
+		printHexPtr(d.w, v.Pointer())
438
+
439
+	// There were not any other types at the time this code was written, but
440
+	// fall back to letting the default fmt package handle it in case any new
441
+	// types are added.
442
+	default:
443
+		if v.CanInterface() {
444
+			fmt.Fprintf(d.w, "%v", v.Interface())
445
+		} else {
446
+			fmt.Fprintf(d.w, "%v", v.String())
447
+		}
448
+	}
449
+}
450
+
451
+// fdump is a helper function to consolidate the logic from the various public
452
+// methods which take varying writers and config states.
453
+func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
454
+	for _, arg := range a {
455
+		if arg == nil {
456
+			w.Write(interfaceBytes)
457
+			w.Write(spaceBytes)
458
+			w.Write(nilAngleBytes)
459
+			w.Write(newlineBytes)
460
+			continue
461
+		}
462
+
463
+		d := dumpState{w: w, cs: cs}
464
+		d.pointers = make(map[uintptr]int)
465
+		d.dump(reflect.ValueOf(arg))
466
+		d.w.Write(newlineBytes)
467
+	}
468
+}
469
+
470
+// Fdump formats and displays the passed arguments to io.Writer w.  It formats
471
+// exactly the same as Dump.
472
+func Fdump(w io.Writer, a ...interface{}) {
473
+	fdump(&Config, w, a...)
474
+}
475
+
476
+// Sdump returns a string with the passed arguments formatted exactly the same
477
+// as Dump.
478
+func Sdump(a ...interface{}) string {
479
+	var buf bytes.Buffer
480
+	fdump(&Config, &buf, a...)
481
+	return buf.String()
482
+}
483
+
484
+/*
485
+Dump displays the passed parameters to standard out with newlines, customizable
486
+indentation, and additional debug information such as complete types and all
487
+pointer addresses used to indirect to the final value.  It provides the
488
+following features over the built-in printing facilities provided by the fmt
489
+package:
490
+
491
+	* Pointers are dereferenced and followed
492
+	* Circular data structures are detected and handled properly
493
+	* Custom Stringer/error interfaces are optionally invoked, including
494
+	  on unexported types
495
+	* Custom types which only implement the Stringer/error interfaces via
496
+	  a pointer receiver are optionally invoked when passing non-pointer
497
+	  variables
498
+	* Byte arrays and slices are dumped like the hexdump -C command which
499
+	  includes offsets, byte values in hex, and ASCII output
500
+
501
+The configuration options are controlled by an exported package global,
502
+spew.Config.  See ConfigState for options documentation.
503
+
504
+See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
505
+get the formatted result as a string.
506
+*/
507
+func Dump(a ...interface{}) {
508
+	fdump(&Config, os.Stdout, a...)
509
+}

+ 419
- 0
vendor/github.com/davecgh/go-spew/spew/format.go View File

@@ -0,0 +1,419 @@
1
+/*
2
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+package spew
18
+
19
+import (
20
+	"bytes"
21
+	"fmt"
22
+	"reflect"
23
+	"strconv"
24
+	"strings"
25
+)
26
+
27
+// supportedFlags is a list of all the character flags supported by fmt package.
28
+const supportedFlags = "0-+# "
29
+
30
+// formatState implements the fmt.Formatter interface and contains information
31
+// about the state of a formatting operation.  The NewFormatter function can
32
+// be used to get a new Formatter which can be used directly as arguments
33
+// in standard fmt package printing calls.
34
+type formatState struct {
35
+	value          interface{}
36
+	fs             fmt.State
37
+	depth          int
38
+	pointers       map[uintptr]int
39
+	ignoreNextType bool
40
+	cs             *ConfigState
41
+}
42
+
43
+// buildDefaultFormat recreates the original format string without precision
44
+// and width information to pass in to fmt.Sprintf in the case of an
45
+// unrecognized type.  Unless new types are added to the language, this
46
+// function won't ever be called.
47
+func (f *formatState) buildDefaultFormat() (format string) {
48
+	buf := bytes.NewBuffer(percentBytes)
49
+
50
+	for _, flag := range supportedFlags {
51
+		if f.fs.Flag(int(flag)) {
52
+			buf.WriteRune(flag)
53
+		}
54
+	}
55
+
56
+	buf.WriteRune('v')
57
+
58
+	format = buf.String()
59
+	return format
60
+}
61
+
62
+// constructOrigFormat recreates the original format string including precision
63
+// and width information to pass along to the standard fmt package.  This allows
64
+// automatic deferral of all format strings this package doesn't support.
65
+func (f *formatState) constructOrigFormat(verb rune) (format string) {
66
+	buf := bytes.NewBuffer(percentBytes)
67
+
68
+	for _, flag := range supportedFlags {
69
+		if f.fs.Flag(int(flag)) {
70
+			buf.WriteRune(flag)
71
+		}
72
+	}
73
+
74
+	if width, ok := f.fs.Width(); ok {
75
+		buf.WriteString(strconv.Itoa(width))
76
+	}
77
+
78
+	if precision, ok := f.fs.Precision(); ok {
79
+		buf.Write(precisionBytes)
80
+		buf.WriteString(strconv.Itoa(precision))
81
+	}
82
+
83
+	buf.WriteRune(verb)
84
+
85
+	format = buf.String()
86
+	return format
87
+}
88
+
89
+// unpackValue returns values inside of non-nil interfaces when possible and
90
+// ensures that types for values which have been unpacked from an interface
91
+// are displayed when the show types flag is also set.
92
+// This is useful for data types like structs, arrays, slices, and maps which
93
+// can contain varying types packed inside an interface.
94
+func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
95
+	if v.Kind() == reflect.Interface {
96
+		f.ignoreNextType = false
97
+		if !v.IsNil() {
98
+			v = v.Elem()
99
+		}
100
+	}
101
+	return v
102
+}
103
+
104
+// formatPtr handles formatting of pointers by indirecting them as necessary.
105
+func (f *formatState) formatPtr(v reflect.Value) {
106
+	// Display nil if top level pointer is nil.
107
+	showTypes := f.fs.Flag('#')
108
+	if v.IsNil() && (!showTypes || f.ignoreNextType) {
109
+		f.fs.Write(nilAngleBytes)
110
+		return
111
+	}
112
+
113
+	// Remove pointers at or below the current depth from map used to detect
114
+	// circular refs.
115
+	for k, depth := range f.pointers {
116
+		if depth >= f.depth {
117
+			delete(f.pointers, k)
118
+		}
119
+	}
120
+
121
+	// Keep list of all dereferenced pointers to possibly show later.
122
+	pointerChain := make([]uintptr, 0)
123
+
124
+	// Figure out how many levels of indirection there are by derferencing
125
+	// pointers and unpacking interfaces down the chain while detecting circular
126
+	// references.
127
+	nilFound := false
128
+	cycleFound := false
129
+	indirects := 0
130
+	ve := v
131
+	for ve.Kind() == reflect.Ptr {
132
+		if ve.IsNil() {
133
+			nilFound = true
134
+			break
135
+		}
136
+		indirects++
137
+		addr := ve.Pointer()
138
+		pointerChain = append(pointerChain, addr)
139
+		if pd, ok := f.pointers[addr]; ok && pd < f.depth {
140
+			cycleFound = true
141
+			indirects--
142
+			break
143
+		}
144
+		f.pointers[addr] = f.depth
145
+
146
+		ve = ve.Elem()
147
+		if ve.Kind() == reflect.Interface {
148
+			if ve.IsNil() {
149
+				nilFound = true
150
+				break
151
+			}
152
+			ve = ve.Elem()
153
+		}
154
+	}
155
+
156
+	// Display type or indirection level depending on flags.
157
+	if showTypes && !f.ignoreNextType {
158
+		f.fs.Write(openParenBytes)
159
+		f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
160
+		f.fs.Write([]byte(ve.Type().String()))
161
+		f.fs.Write(closeParenBytes)
162
+	} else {
163
+		if nilFound || cycleFound {
164
+			indirects += strings.Count(ve.Type().String(), "*")
165
+		}
166
+		f.fs.Write(openAngleBytes)
167
+		f.fs.Write([]byte(strings.Repeat("*", indirects)))
168
+		f.fs.Write(closeAngleBytes)
169
+	}
170
+
171
+	// Display pointer information depending on flags.
172
+	if f.fs.Flag('+') && (len(pointerChain) > 0) {
173
+		f.fs.Write(openParenBytes)
174
+		for i, addr := range pointerChain {
175
+			if i > 0 {
176
+				f.fs.Write(pointerChainBytes)
177
+			}
178
+			printHexPtr(f.fs, addr)
179
+		}
180
+		f.fs.Write(closeParenBytes)
181
+	}
182
+
183
+	// Display dereferenced value.
184
+	switch {
185
+	case nilFound:
186
+		f.fs.Write(nilAngleBytes)
187
+
188
+	case cycleFound:
189
+		f.fs.Write(circularShortBytes)
190
+
191
+	default:
192
+		f.ignoreNextType = true
193
+		f.format(ve)
194
+	}
195
+}
196
+
197
+// format is the main workhorse for providing the Formatter interface.  It
198
+// uses the passed reflect value to figure out what kind of object we are
199
+// dealing with and formats it appropriately.  It is a recursive function,
200
+// however circular data structures are detected and handled properly.
201
+func (f *formatState) format(v reflect.Value) {
202
+	// Handle invalid reflect values immediately.
203
+	kind := v.Kind()
204
+	if kind == reflect.Invalid {
205
+		f.fs.Write(invalidAngleBytes)
206
+		return
207
+	}
208
+
209
+	// Handle pointers specially.
210
+	if kind == reflect.Ptr {
211
+		f.formatPtr(v)
212
+		return
213
+	}
214
+
215
+	// Print type information unless already handled elsewhere.
216
+	if !f.ignoreNextType && f.fs.Flag('#') {
217
+		f.fs.Write(openParenBytes)
218
+		f.fs.Write([]byte(v.Type().String()))
219
+		f.fs.Write(closeParenBytes)
220
+	}
221
+	f.ignoreNextType = false
222
+
223
+	// Call Stringer/error interfaces if they exist and the handle methods
224
+	// flag is enabled.
225
+	if !f.cs.DisableMethods {
226
+		if (kind != reflect.Invalid) && (kind != reflect.Interface) {
227
+			if handled := handleMethods(f.cs, f.fs, v); handled {
228
+				return
229
+			}
230
+		}
231
+	}
232
+
233
+	switch kind {
234
+	case reflect.Invalid:
235
+		// Do nothing.  We should never get here since invalid has already
236
+		// been handled above.
237
+
238
+	case reflect.Bool:
239
+		printBool(f.fs, v.Bool())
240
+
241
+	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
242
+		printInt(f.fs, v.Int(), 10)
243
+
244
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
245
+		printUint(f.fs, v.Uint(), 10)
246
+
247
+	case reflect.Float32:
248
+		printFloat(f.fs, v.Float(), 32)
249
+
250
+	case reflect.Float64:
251
+		printFloat(f.fs, v.Float(), 64)
252
+
253
+	case reflect.Complex64:
254
+		printComplex(f.fs, v.Complex(), 32)
255
+
256
+	case reflect.Complex128:
257
+		printComplex(f.fs, v.Complex(), 64)
258
+
259
+	case reflect.Slice:
260
+		if v.IsNil() {
261
+			f.fs.Write(nilAngleBytes)
262
+			break
263
+		}
264
+		fallthrough
265
+
266
+	case reflect.Array:
267
+		f.fs.Write(openBracketBytes)
268
+		f.depth++
269
+		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
270
+			f.fs.Write(maxShortBytes)
271
+		} else {
272
+			numEntries := v.Len()
273
+			for i := 0; i < numEntries; i++ {
274
+				if i > 0 {
275
+					f.fs.Write(spaceBytes)
276
+				}
277
+				f.ignoreNextType = true
278
+				f.format(f.unpackValue(v.Index(i)))
279
+			}
280
+		}
281
+		f.depth--
282
+		f.fs.Write(closeBracketBytes)
283
+
284
+	case reflect.String:
285
+		f.fs.Write([]byte(v.String()))
286
+
287
+	case reflect.Interface:
288
+		// The only time we should get here is for nil interfaces due to
289
+		// unpackValue calls.
290
+		if v.IsNil() {
291
+			f.fs.Write(nilAngleBytes)
292
+		}
293
+
294
+	case reflect.Ptr:
295
+		// Do nothing.  We should never get here since pointers have already
296
+		// been handled above.
297
+
298
+	case reflect.Map:
299
+		// nil maps should be indicated as different than empty maps
300
+		if v.IsNil() {
301
+			f.fs.Write(nilAngleBytes)
302
+			break
303
+		}
304
+
305
+		f.fs.Write(openMapBytes)
306
+		f.depth++
307
+		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
308
+			f.fs.Write(maxShortBytes)
309
+		} else {
310
+			keys := v.MapKeys()
311
+			if f.cs.SortKeys {
312
+				sortValues(keys, f.cs)
313
+			}
314
+			for i, key := range keys {
315
+				if i > 0 {
316
+					f.fs.Write(spaceBytes)
317
+				}
318
+				f.ignoreNextType = true
319
+				f.format(f.unpackValue(key))
320
+				f.fs.Write(colonBytes)
321
+				f.ignoreNextType = true
322
+				f.format(f.unpackValue(v.MapIndex(key)))
323
+			}
324
+		}
325
+		f.depth--
326
+		f.fs.Write(closeMapBytes)
327
+
328
+	case reflect.Struct:
329
+		numFields := v.NumField()
330
+		f.fs.Write(openBraceBytes)
331
+		f.depth++
332
+		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
333
+			f.fs.Write(maxShortBytes)
334
+		} else {
335
+			vt := v.Type()
336
+			for i := 0; i < numFields; i++ {
337
+				if i > 0 {
338
+					f.fs.Write(spaceBytes)
339
+				}
340
+				vtf := vt.Field(i)
341
+				if f.fs.Flag('+') || f.fs.Flag('#') {
342
+					f.fs.Write([]byte(vtf.Name))
343
+					f.fs.Write(colonBytes)
344
+				}
345
+				f.format(f.unpackValue(v.Field(i)))
346
+			}
347
+		}
348
+		f.depth--
349
+		f.fs.Write(closeBraceBytes)
350
+
351
+	case reflect.Uintptr:
352
+		printHexPtr(f.fs, uintptr(v.Uint()))
353
+
354
+	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
355
+		printHexPtr(f.fs, v.Pointer())
356
+
357
+	// There were not any other types at the time this code was written, but
358
+	// fall back to letting the default fmt package handle it if any get added.
359
+	default:
360
+		format := f.buildDefaultFormat()
361
+		if v.CanInterface() {
362
+			fmt.Fprintf(f.fs, format, v.Interface())
363
+		} else {
364
+			fmt.Fprintf(f.fs, format, v.String())
365
+		}
366
+	}
367
+}
368
+
369
+// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
370
+// details.
371
+func (f *formatState) Format(fs fmt.State, verb rune) {
372
+	f.fs = fs
373
+
374
+	// Use standard formatting for verbs that are not v.
375
+	if verb != 'v' {
376
+		format := f.constructOrigFormat(verb)
377
+		fmt.Fprintf(fs, format, f.value)
378
+		return
379
+	}
380
+
381
+	if f.value == nil {
382
+		if fs.Flag('#') {
383
+			fs.Write(interfaceBytes)
384
+		}
385
+		fs.Write(nilAngleBytes)
386
+		return
387
+	}
388
+
389
+	f.format(reflect.ValueOf(f.value))
390
+}
391
+
392
+// newFormatter is a helper function to consolidate the logic from the various
393
+// public methods which take varying config states.
394
+func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
395
+	fs := &formatState{value: v, cs: cs}
396
+	fs.pointers = make(map[uintptr]int)
397
+	return fs
398
+}
399
+
400
+/*
401
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
402
+interface.  As a result, it integrates cleanly with standard fmt package
403
+printing functions.  The formatter is useful for inline printing of smaller data
404
+types similar to the standard %v format specifier.
405
+
406
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
407
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
408
+combinations.  Any other verbs such as %x and %q will be sent to the the
409
+standard fmt package for formatting.  In addition, the custom formatter ignores
410
+the width and precision arguments (however they will still work on the format
411
+specifiers not handled by the custom formatter).
412
+
413
+Typically this function shouldn't be called directly.  It is much easier to make
414
+use of the custom formatter by calling one of the convenience functions such as
415
+Printf, Println, or Fprintf.
416
+*/
417
+func NewFormatter(v interface{}) fmt.Formatter {
418
+	return newFormatter(&Config, v)
419
+}

+ 148
- 0
vendor/github.com/davecgh/go-spew/spew/spew.go View File

@@ -0,0 +1,148 @@
1
+/*
2
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+package spew
18
+
19
+import (
20
+	"fmt"
21
+	"io"
22
+)
23
+
24
+// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
25
+// passed with a default Formatter interface returned by NewFormatter.  It
26
+// returns the formatted string as a value that satisfies error.  See
27
+// NewFormatter for formatting details.
28
+//
29
+// This function is shorthand for the following syntax:
30
+//
31
+//	fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
32
+func Errorf(format string, a ...interface{}) (err error) {
33
+	return fmt.Errorf(format, convertArgs(a)...)
34
+}
35
+
36
+// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
37
+// passed with a default Formatter interface returned by NewFormatter.  It
38
+// returns the number of bytes written and any write error encountered.  See
39
+// NewFormatter for formatting details.
40
+//
41
+// This function is shorthand for the following syntax:
42
+//
43
+//	fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
44
+func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
45
+	return fmt.Fprint(w, convertArgs(a)...)
46
+}
47
+
48
+// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
49
+// passed with a default Formatter interface returned by NewFormatter.  It
50
+// returns the number of bytes written and any write error encountered.  See
51
+// NewFormatter for formatting details.
52
+//
53
+// This function is shorthand for the following syntax:
54
+//
55
+//	fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
56
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
57
+	return fmt.Fprintf(w, format, convertArgs(a)...)
58
+}
59
+
60
+// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
61
+// passed with a default Formatter interface returned by NewFormatter.  See
62
+// NewFormatter for formatting details.
63
+//
64
+// This function is shorthand for the following syntax:
65
+//
66
+//	fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
67
+func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
68
+	return fmt.Fprintln(w, convertArgs(a)...)
69
+}
70
+
71
+// Print is a wrapper for fmt.Print that treats each argument as if it were
72
+// passed with a default Formatter interface returned by NewFormatter.  It
73
+// returns the number of bytes written and any write error encountered.  See
74
+// NewFormatter for formatting details.
75
+//
76
+// This function is shorthand for the following syntax:
77
+//
78
+//	fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
79
+func Print(a ...interface{}) (n int, err error) {
80
+	return fmt.Print(convertArgs(a)...)
81
+}
82
+
83
+// Printf is a wrapper for fmt.Printf that treats each argument as if it were
84
+// passed with a default Formatter interface returned by NewFormatter.  It
85
+// returns the number of bytes written and any write error encountered.  See
86
+// NewFormatter for formatting details.
87
+//
88
+// This function is shorthand for the following syntax:
89
+//
90
+//	fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
91
+func Printf(format string, a ...interface{}) (n int, err error) {
92
+	return fmt.Printf(format, convertArgs(a)...)
93
+}
94
+
95
+// Println is a wrapper for fmt.Println that treats each argument as if it were
96
+// passed with a default Formatter interface returned by NewFormatter.  It
97
+// returns the number of bytes written and any write error encountered.  See
98
+// NewFormatter for formatting details.
99
+//
100
+// This function is shorthand for the following syntax:
101
+//
102
+//	fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
103
+func Println(a ...interface{}) (n int, err error) {
104
+	return fmt.Println(convertArgs(a)...)
105
+}
106
+
107
+// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
108
+// passed with a default Formatter interface returned by NewFormatter.  It
109
+// returns the resulting string.  See NewFormatter for formatting details.
110
+//
111
+// This function is shorthand for the following syntax:
112
+//
113
+//	fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
114
+func Sprint(a ...interface{}) string {
115
+	return fmt.Sprint(convertArgs(a)...)
116
+}
117
+
118
+// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
119
+// passed with a default Formatter interface returned by NewFormatter.  It
120
+// returns the resulting string.  See NewFormatter for formatting details.
121
+//
122
+// This function is shorthand for the following syntax:
123
+//
124
+//	fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
125
+func Sprintf(format string, a ...interface{}) string {
126
+	return fmt.Sprintf(format, convertArgs(a)...)
127
+}
128
+
129
+// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
130
+// were passed with a default Formatter interface returned by NewFormatter.  It
131
+// returns the resulting string.  See NewFormatter for formatting details.
132
+//
133
+// This function is shorthand for the following syntax:
134
+//
135
+//	fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
136
+func Sprintln(a ...interface{}) string {
137
+	return fmt.Sprintln(convertArgs(a)...)
138
+}
139
+
140
+// convertArgs accepts a slice of arguments and returns a slice of the same
141
+// length with each argument converted to a default spew Formatter interface.
142
+func convertArgs(args []interface{}) (formatters []interface{}) {
143
+	formatters = make([]interface{}, len(args))
144
+	for index, arg := range args {
145
+		formatters[index] = NewFormatter(arg)
146
+	}
147
+	return formatters
148
+}

+ 4
- 0
vendor/github.com/dgrijalva/jwt-go/.gitignore View File

@@ -0,0 +1,4 @@
1
+.DS_Store
2
+bin
3
+
4
+

+ 13
- 0
vendor/github.com/dgrijalva/jwt-go/.travis.yml View File

@@ -0,0 +1,13 @@
1
+language: go
2
+
3
+script:
4
+    - go vet ./...
5
+    - go test -v ./...
6
+
7
+go:
8
+  - 1.3
9
+  - 1.4
10
+  - 1.5
11
+  - 1.6
12
+  - 1.7
13
+  - tip

+ 8
- 0
vendor/github.com/dgrijalva/jwt-go/LICENSE View File

@@ -0,0 +1,8 @@
1
+Copyright (c) 2012 Dave Grijalva
2
+
3
+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:
4
+
5
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+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.
8
+

+ 97
- 0
vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md View File

@@ -0,0 +1,97 @@
1
+## Migration Guide from v2 -> v3
2
+
3
+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.
4
+
5
+### `Token.Claims` is now an interface type
6
+
7
+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`.
8
+
9
+`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.
10
+
11
+The old example for parsing a token looked like this..
12
+
13
+```go
14
+	if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
15
+		fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
16
+	}
17
+```
18
+
19
+is now directly mapped to...
20
+
21
+```go
22
+	if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
23
+		claims := token.Claims.(jwt.MapClaims)
24
+		fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
25
+	}
26
+```
27
+
28
+`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.
29
+
30
+```go
31
+	type MyCustomClaims struct {
32
+		User string
33
+		*StandardClaims
34
+	}
35
+	
36
+	if token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, keyLookupFunc); err == nil {
37
+		claims := token.Claims.(*MyCustomClaims)
38
+		fmt.Printf("Token for user %v expires %v", claims.User, claims.StandardClaims.ExpiresAt)
39
+	}
40
+```
41
+
42
+### `ParseFromRequest` has been moved
43
+
44
+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`.
45
+
46
+`Extractors` do the work of picking the token string out of a request.  The interface is simple and composable.
47
+
48
+This simple parsing example:
49
+
50
+```go
51
+	if token, err := jwt.ParseFromRequest(tokenString, req, keyLookupFunc); err == nil {
52
+		fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
53
+	}
54
+```
55
+
56
+is directly mapped to:
57
+
58
+```go
59
+	if token, err := request.ParseFromRequest(req, request.OAuth2Extractor, keyLookupFunc); err == nil {
60
+		claims := token.Claims.(jwt.MapClaims)
61
+		fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
62
+	}
63
+```
64
+
65
+There are several concrete `Extractor` types provided for your convenience:
66
+
67
+* `HeaderExtractor` will search a list of headers until one contains content.
68
+* `ArgumentExtractor` will search a list of keys in request query and form arguments until one contains content.
69
+* `MultiExtractor` will try a list of `Extractors` in order until one returns content.
70
+* `AuthorizationHeaderExtractor` will look in the `Authorization` header for a `Bearer` token.
71
+* `OAuth2Extractor` searches the places an OAuth2 token would be specified (per the spec): `Authorization` header and `access_token` argument
72
+* `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
73
+
74
+
75
+### RSA signing methods no longer accept `[]byte` keys
76
+
77
+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.
78
+
79
+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.
80
+
81
+```go 
82
+	func keyLookupFunc(*Token) (interface{}, error) {
83
+		// Don't forget to validate the alg is what you expect:
84
+		if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
85
+			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
86
+		}
87
+		
88
+		// Look up key 
89
+		key, err := lookupPublicKey(token.Header["kid"])
90
+		if err != nil {
91
+			return nil, err
92
+		}
93
+		
94
+		// Unpack key from PEM encoded PKCS8
95
+		return jwt.ParseRSAPublicKeyFromPEM(key)
96
+	}
97
+```

+ 100
- 0
vendor/github.com/dgrijalva/jwt-go/README.md View File

@@ -0,0 +1,100 @@
1
+# jwt-go
2
+
3
+[![Build Status](https://travis-ci.org/dgrijalva/jwt-go.svg?branch=master)](https://travis-ci.org/dgrijalva/jwt-go)
4
+[![GoDoc](https://godoc.org/github.com/dgrijalva/jwt-go?status.svg)](https://godoc.org/github.com/dgrijalva/jwt-go)
5
+
6
+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)
7
+
8
+**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. 
9
+
10
+**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.
11
+
12
+**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.
13
+
14
+## What the heck is a JWT?
15
+
16
+JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens.
17
+
18
+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.
19
+
20
+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.
21
+
22
+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.
23
+
24
+## What's in the box?
25
+
26
+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.
27
+
28
+## Examples
29
+
30
+See [the project documentation](https://godoc.org/github.com/dgrijalva/jwt-go) for examples of usage:
31
+
32
+* [Simple example of parsing and validating a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac)
33
+* [Simple example of building and signing a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-New--Hmac)
34
+* [Directory of Examples](https://godoc.org/github.com/dgrijalva/jwt-go#pkg-examples)
35
+
36
+## Extensions
37
+
38
+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`.  
39
+
40
+Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go
41
+
42
+## Compliance
43
+
44
+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:
45
+
46
+* 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.
47
+
48
+## Project Status & Versioning
49
+
50
+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).
51
+
52
+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).
53
+
54
+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.
55
+
56
+**BREAKING CHANGES:*** 
57
+* 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.
58
+
59
+## Usage Tips
60
+
61
+### Signing vs Encryption
62
+
63
+A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data:
64
+
65
+* The author of the token was in the possession of the signing secret
66
+* The data has not been modified since it was signed
67
+
68
+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.
69
+
70
+### Choosing a Signing Method
71
+
72
+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.
73
+
74
+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.
75
+
76
+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.
77
+
78
+### Signing Methods and Key Types
79
+
80
+Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones:
81
+
82
+* The [HMAC signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation
83
+* 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
84
+* 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
85
+
86
+### JWT and OAuth
87
+
88
+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.
89
+
90
+Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
91
+
92
+* 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.
93
+* 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.
94
+* 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.
95
+
96
+## More
97
+
98
+Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
99
+
100
+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
- 0
vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md View File

@@ -0,0 +1,118 @@
1
+## `jwt-go` Version History
2
+
3
+#### 3.2.0
4
+
5
+* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
6
+* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate
7
+* 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.
8
+* Deprecated `ParseFromRequestWithClaims` to simplify API in the future.
9
+
10
+#### 3.1.0
11
+
12
+* Improvements to `jwt` command line tool
13
+* Added `SkipClaimsValidation` option to `Parser`
14
+* Documentation updates
15
+
16
+#### 3.0.0
17
+
18
+* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
19
+	* 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.
20
+	* `ParseFromRequest` has been moved to `request` subpackage and usage has changed
21
+	* 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.
22
+* Other Additions and Changes
23
+	* Added `Claims` interface type to allow users to decode the claims into a custom type
24
+	* 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.
25
+	* Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage
26
+	* Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims`
27
+	* Added new interface type `Extractor`, which is used for extracting JWT strings from http requests.  Used with `ParseFromRequest` and `ParseFromRequestWithClaims`.
28
+	* Added several new, more specific, validation errors to error type bitmask
29
+	* Moved examples from README to executable example files
30
+	* Signing method registry is now thread safe
31
+	* 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)
32
+
33
+#### 2.7.0
34
+
35
+This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes.
36
+
37
+* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying
38
+* Error text for expired tokens includes how long it's been expired
39
+* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM`
40
+* Documentation updates
41
+
42
+#### 2.6.0
43
+
44
+* Exposed inner error within ValidationError
45
+* Fixed validation errors when using UseJSONNumber flag
46
+* Added several unit tests
47
+
48
+#### 2.5.0
49
+
50
+* Added support for signing method none.  You shouldn't use this.  The API tries to make this clear.
51
+* Updated/fixed some documentation
52
+* Added more helpful error message when trying to parse tokens that begin with `BEARER `
53
+
54
+#### 2.4.0
55
+
56
+* Added new type, Parser, to allow for configuration of various parsing parameters
57
+	* You can now specify a list of valid signing methods.  Anything outside this set will be rejected.
58
+	* You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON
59
+* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go)
60
+* Fixed some bugs with ECDSA parsing
61
+
62
+#### 2.3.0
63
+
64
+* Added support for ECDSA signing methods
65
+* Added support for RSA PSS signing methods (requires go v1.4)
66
+
67
+#### 2.2.0
68
+
69
+* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`.  Result will now be the parsed token and an error, instead of a panic.
70
+
71
+#### 2.1.0
72
+
73
+Backwards compatible API change that was missed in 2.0.0.
74
+
75
+* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte`
76
+
77
+#### 2.0.0
78
+
79
+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.
80
+
81
+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`.
82
+
83
+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`.
84
+
85
+* **Compatibility Breaking Changes**
86
+	* `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct`
87
+	* `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct`
88
+	* `KeyFunc` now returns `interface{}` instead of `[]byte`
89
+	* `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key
90
+	* `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key
91
+* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`.  Specific sizes are now just instances of this type.
92
+    * Added public package global `SigningMethodHS256`
93
+    * Added public package global `SigningMethodHS384`
94
+    * Added public package global `SigningMethodHS512`
95
+* Renamed type `SigningMethodRS256` to `SigningMethodRSA`.  Specific sizes are now just instances of this type.
96
+    * Added public package global `SigningMethodRS256`
97
+    * Added public package global `SigningMethodRS384`
98
+    * Added public package global `SigningMethodRS512`
99
+* Moved sample private key for HMAC tests from an inline value to a file on disk.  Value is unchanged.
100
+* Refactored the RSA implementation to be easier to read
101
+* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM`
102
+
103
+#### 1.0.2
104
+
105
+* Fixed bug in parsing public keys from certificates
106
+* Added more tests around the parsing of keys for RS256
107
+* Code refactoring in RS256 implementation.  No functional changes
108
+
109
+#### 1.0.1
110
+
111
+* Fixed panic if RS256 signing method was passed an invalid key
112
+
113
+#### 1.0.0
114
+
115
+* First versioned release
116
+* API stabilized
117
+* Supports creating, signing, parsing, and validating JWT tokens
118
+* Supports RS256 and HS256 signing methods

+ 134
- 0
vendor/github.com/dgrijalva/jwt-go/claims.go View File

@@ -0,0 +1,134 @@
1
+package jwt
2
+
3
+import (
4
+	"crypto/subtle"
5
+	"fmt"
6
+	"time"
7
+)
8
+
9
+// For a type to be a Claims object, it must just have a Valid method that determines
10
+// if the token is invalid for any supported reason
11
+type Claims interface {
12
+	Valid() error
13
+}
14
+
15
+// Structured version of Claims Section, as referenced at
16
+// https://tools.ietf.org/html/rfc7519#section-4.1
17
+// See examples for how to use this with your own claim types
18
+type StandardClaims struct {
19
+	Audience  string `json:"aud,omitempty"`
20
+	ExpiresAt int64  `json:"exp,omitempty"`
21
+	Id        string `json:"jti,omitempty"`
22
+	IssuedAt  int64  `json:"iat,omitempty"`
23
+	Issuer    string `json:"iss,omitempty"`
24
+	NotBefore int64  `json:"nbf,omitempty"`
25
+	Subject   string `json:"sub,omitempty"`
26
+}
27
+
28
+// Validates time based claims "exp, iat, nbf".
29
+// There is no accounting for clock skew.
30
+// As well, if any of the above claims are not in the token, it will still
31
+// be considered a valid claim.
32
+func (c StandardClaims) Valid() error {
33
+	vErr := new(ValidationError)
34
+	now := TimeFunc().Unix()
35
+
36
+	// The claims below are optional, by default, so if they are set to the
37
+	// default value in Go, let's not fail the verification for them.
38
+	if c.VerifyExpiresAt(now, false) == false {
39
+		delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0))
40
+		vErr.Inner = fmt.Errorf("token is expired by %v", delta)
41
+		vErr.Errors |= ValidationErrorExpired
42
+	}
43
+
44
+	if c.VerifyIssuedAt(now, false) == false {
45
+		vErr.Inner = fmt.Errorf("Token used before issued")
46
+		vErr.Errors |= ValidationErrorIssuedAt
47
+	}
48
+
49
+	if c.VerifyNotBefore(now, false) == false {
50
+		vErr.Inner = fmt.Errorf("token is not valid yet")
51
+		vErr.Errors |= ValidationErrorNotValidYet
52
+	}
53
+
54
+	if vErr.valid() {
55
+		return nil
56
+	}
57
+
58
+	return vErr
59
+}
60
+
61
+// Compares the aud claim against cmp.
62
+// If required is false, this method will return true if the value matches or is unset
63
+func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
64
+	return verifyAud(c.Audience, cmp, req)
65
+}
66
+
67
+// Compares the exp claim against cmp.
68
+// If required is false, this method will return true if the value matches or is unset
69
+func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
70
+	return verifyExp(c.ExpiresAt, cmp, req)
71
+}
72
+
73
+// Compares the iat claim against cmp.
74
+// If required is false, this method will return true if the value matches or is unset
75
+func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
76
+	return verifyIat(c.IssuedAt, cmp, req)
77
+}
78
+
79
+// Compares the iss claim against cmp.
80
+// If required is false, this method will return true if the value matches or is unset
81
+func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
82
+	return verifyIss(c.Issuer, cmp, req)
83
+}
84
+
85
+// Compares the nbf claim against cmp.
86
+// If required is false, this method will return true if the value matches or is unset
87
+func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
88
+	return verifyNbf(c.NotBefore, cmp, req)
89
+}
90
+
91
+// ----- helpers
92
+
93
+func verifyAud(aud string, cmp string, required bool) bool {
94
+	if aud == "" {
95
+		return !required
96
+	}
97
+	if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 {
98
+		return true
99
+	} else {
100
+		return false
101
+	}
102
+}
103
+
104
+func verifyExp(exp int64, now int64, required bool) bool {
105
+	if exp == 0 {
106
+		return !required
107
+	}
108
+	return now <= exp
109
+}
110
+
111
+func verifyIat(iat int64, now int64, required bool) bool {
112
+	if iat == 0 {
113
+		return !required
114
+	}
115
+	return now >= iat
116
+}
117
+
118
+func verifyIss(iss string, cmp string, required bool) bool {
119
+	if iss == "" {
120
+		return !required
121
+	}
122
+	if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 {
123
+		return true
124
+	} else {
125
+		return false
126
+	}
127
+}
128
+
129
+func verifyNbf(nbf int64, now int64, required bool) bool {
130
+	if nbf == 0 {
131
+		return !required
132
+	}
133
+	return now >= nbf
134
+}

+ 4
- 0
vendor/github.com/dgrijalva/jwt-go/doc.go View File

@@ -0,0 +1,4 @@
1
+// Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html
2
+//
3
+// See README.md for more info.
4
+package jwt

+ 148
- 0
vendor/github.com/dgrijalva/jwt-go/ecdsa.go View File

@@ -0,0 +1,148 @@
1
+package jwt
2
+
3
+import (
4
+	"crypto"
5
+	"crypto/ecdsa"
6
+	"crypto/rand"
7
+	"errors"
8
+	"math/big"
9
+)
10
+
11
+var (
12
+	// Sadly this is missing from crypto/ecdsa compared to crypto/rsa
13
+	ErrECDSAVerification = errors.New("crypto/ecdsa: verification error")
14
+)
15
+
16
+// Implements the ECDSA family of signing methods signing methods
17
+// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
18
+type SigningMethodECDSA struct {
19
+	Name      string
20
+	Hash      crypto.Hash
21
+	KeySize   int
22
+	CurveBits int
23
+}
24
+
25
+// Specific instances for EC256 and company
26
+var (
27
+	SigningMethodES256 *SigningMethodECDSA
28
+	SigningMethodES384 *SigningMethodECDSA
29
+	SigningMethodES512 *SigningMethodECDSA
30
+)
31
+
32
+func init() {
33
+	// ES256
34
+	SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256}
35
+	RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod {
36
+		return SigningMethodES256
37
+	})
38
+
39
+	// ES384
40
+	SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384}
41
+	RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod {
42
+		return SigningMethodES384
43
+	})
44
+
45
+	// ES512
46
+	SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521}
47
+	RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod {
48
+		return SigningMethodES512
49
+	})
50
+}
51
+
52
+func (m *SigningMethodECDSA) Alg() string {
53
+	return m.Name
54
+}
55
+
56
+// Implements the Verify method from SigningMethod
57
+// For this verify method, key must be an ecdsa.PublicKey struct
58
+func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error {
59
+	var err error
60
+
61
+	// Decode the signature
62
+	var sig []byte
63
+	if sig, err = DecodeSegment(signature); err != nil {
64
+		return err
65
+	}
66
+
67
+	// Get the key
68
+	var ecdsaKey *ecdsa.PublicKey
69
+	switch k := key.(type) {
70
+	case *ecdsa.PublicKey:
71
+		ecdsaKey = k
72
+	default:
73
+		return ErrInvalidKeyType
74
+	}
75
+
76
+	if len(sig) != 2*m.KeySize {
77
+		return ErrECDSAVerification
78
+	}
79
+
80
+	r := big.NewInt(0).SetBytes(sig[:m.KeySize])
81
+	s := big.NewInt(0).SetBytes(sig[m.KeySize:])
82
+
83
+	// Create hasher
84
+	if !m.Hash.Available() {
85
+		return ErrHashUnavailable
86
+	}
87
+	hasher := m.Hash.New()
88
+	hasher.Write([]byte(signingString))
89
+
90
+	// Verify the signature
91
+	if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus == true {
92
+		return nil
93
+	} else {
94
+		return ErrECDSAVerification
95
+	}
96
+}
97
+
98
+// Implements the Sign method from SigningMethod
99
+// For this signing method, key must be an ecdsa.PrivateKey struct
100
+func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
101
+	// Get the key
102
+	var ecdsaKey *ecdsa.PrivateKey
103
+	switch k := key.(type) {
104
+	case *ecdsa.PrivateKey:
105
+		ecdsaKey = k
106
+	default:
107
+		return "", ErrInvalidKeyType
108
+	}
109
+
110
+	// Create the hasher
111
+	if !m.Hash.Available() {
112
+		return "", ErrHashUnavailable
113
+	}
114
+
115
+	hasher := m.Hash.New()
116
+	hasher.Write([]byte(signingString))
117
+
118
+	// Sign the string and return r, s
119
+	if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil {
120
+		curveBits := ecdsaKey.Curve.Params().BitSize
121
+
122
+		if m.CurveBits != curveBits {
123
+			return "", ErrInvalidKey
124
+		}
125
+
126
+		keyBytes := curveBits / 8
127
+		if curveBits%8 > 0 {
128
+			keyBytes += 1
129
+		}
130
+
131
+		// We serialize the outpus (r and s) into big-endian byte arrays and pad
132
+		// them with zeros on the left to make sure the sizes work out. Both arrays
133
+		// must be keyBytes long, and the output must be 2*keyBytes long.
134
+		rBytes := r.Bytes()
135
+		rBytesPadded := make([]byte, keyBytes)
136
+		copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
137
+
138
+		sBytes := s.Bytes()
139
+		sBytesPadded := make([]byte, keyBytes)
140
+		copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
141
+
142
+		out := append(rBytesPadded, sBytesPadded...)
143
+
144
+		return EncodeSegment(out), nil
145
+	} else {
146
+		return "", err
147
+	}
148
+}

+ 67
- 0
vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go View File

@@ -0,0 +1,67 @@
1
+package jwt
2
+
3
+import (
4
+	"crypto/ecdsa"
5
+	"crypto/x509"
6
+	"encoding/pem"
7
+	"errors"
8
+)
9
+
10
+var (
11
+	ErrNotECPublicKey  = errors.New("Key is not a valid ECDSA public key")
12
+	ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private key")
13
+)
14
+
15
+// Parse PEM encoded Elliptic Curve Private Key Structure
16
+func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
17
+	var err error
18
+
19
+	// Parse PEM block
20
+	var block *pem.Block
21
+	if block, _ = pem.Decode(key); block == nil {
22
+		return nil, ErrKeyMustBePEMEncoded
23
+	}
24
+
25
+	// Parse the key
26
+	var parsedKey interface{}
27
+	if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
28
+		return nil, err
29
+	}
30
+
31
+	var pkey *ecdsa.PrivateKey
32
+	var ok bool
33
+	if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
34
+		return nil, ErrNotECPrivateKey
35
+	}
36
+
37
+	return pkey, nil
38
+}
39
+
40
+// Parse PEM encoded PKCS1 or PKCS8 public key
41
+func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
42
+	var err error
43
+
44
+	// Parse PEM block
45
+	var block *pem.Block
46
+	if block, _ = pem.Decode(key); block == nil {
47
+		return nil, ErrKeyMustBePEMEncoded
48
+	}
49
+
50
+	// Parse the key
51
+	var parsedKey interface{}
52
+	if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
53
+		if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
54
+			parsedKey = cert.PublicKey
55
+		} else {
56
+			return nil, err
57
+		}
58
+	}
59
+
60
+	var pkey *ecdsa.PublicKey
61
+	var ok bool
62
+	if pkey, ok = parsedKey.(*ecdsa.PublicKey); !ok {
63
+		return nil, ErrNotECPublicKey
64
+	}
65
+
66
+	return pkey, nil
67
+}

+ 59
- 0
vendor/github.com/dgrijalva/jwt-go/errors.go View File

@@ -0,0 +1,59 @@
1
+package jwt
2
+
3
+import (
4
+	"errors"
5
+)
6
+
7
+// Error constants
8
+var (
9
+	ErrInvalidKey      = errors.New("key is invalid")
10
+	ErrInvalidKeyType  = errors.New("key is of invalid type")
11
+	ErrHashUnavailable = errors.New("the requested hash function is unavailable")
12
+)
13
+
14
+// The errors that might occur when parsing and validating a token
15
+const (
16
+	ValidationErrorMalformed        uint32 = 1 << iota // Token is malformed
17
+	ValidationErrorUnverifiable                        // Token could not be verified because of signing problems
18
+	ValidationErrorSignatureInvalid                    // Signature validation failed
19
+
20
+	// Standard Claim validation errors
21
+	ValidationErrorAudience      // AUD validation failed
22
+	ValidationErrorExpired       // EXP validation failed
23
+	ValidationErrorIssuedAt      // IAT validation failed
24
+	ValidationErrorIssuer        // ISS validation failed
25
+	ValidationErrorNotValidYet   // NBF validation failed
26
+	ValidationErrorId            // JTI validation failed
27
+	ValidationErrorClaimsInvalid // Generic claims validation error
28
+)
29
+
30
+// Helper for constructing a ValidationError with a string error message
31
+func NewValidationError(errorText string, errorFlags uint32) *ValidationError {
32
+	return &ValidationError{
33
+		text:   errorText,
34
+		Errors: errorFlags,
35
+	}
36
+}
37
+
38
+// The error from Parse if token is not valid
39
+type ValidationError struct {
40
+	Inner  error  // stores the error returned by external dependencies, i.e.: KeyFunc
41
+	Errors uint32 // bitfield.  see ValidationError... constants
42
+	text   string // errors that do not have a valid error just have text
43
+}
44
+
45
+// Validation error is an error type
46
+func (e ValidationError) Error() string {
47
+	if e.Inner != nil {
48
+		return e.Inner.Error()
49
+	} else if e.text != "" {
50
+		return e.text
51
+	} else {
52
+		return "token is invalid"
53
+	}
54
+}
55
+
56
+// No errors
57
+func (e *ValidationError) valid() bool {
58
+	return e.Errors == 0
59
+}

+ 95
- 0
vendor/github.com/dgrijalva/jwt-go/hmac.go View File

@@ -0,0 +1,95 @@
1
+package jwt
2
+
3
+import (
4
+	"crypto"
5
+	"crypto/hmac"
6
+	"errors"
7
+)
8
+
9
+// Implements the HMAC-SHA family of signing methods signing methods
10
+// Expects key type of []byte for both signing and validation
11
+type SigningMethodHMAC struct {
12
+	Name string
13
+	Hash crypto.Hash
14
+}
15
+
16
+// Specific instances for HS256 and company
17
+var (
18
+	SigningMethodHS256  *SigningMethodHMAC
19
+	SigningMethodHS384  *SigningMethodHMAC
20
+	SigningMethodHS512  *SigningMethodHMAC
21
+	ErrSignatureInvalid = errors.New("signature is invalid")
22
+)
23
+
24
+func init() {
25
+	// HS256
26
+	SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256}
27
+	RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod {
28
+		return SigningMethodHS256
29
+	})
30
+
31
+	// HS384
32
+	SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384}
33
+	RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod {
34
+		return SigningMethodHS384
35
+	})
36
+
37
+	// HS512
38
+	SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512}
39
+	RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod {
40
+		return SigningMethodHS512
41
+	})
42
+}
43
+
44
+func (m *SigningMethodHMAC) Alg() string {
45
+	return m.Name
46
+}
47
+
48
+// Verify the signature of HSXXX tokens.  Returns nil if the signature is valid.
49
+func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error {
50
+	// Verify the key is the right type
51
+	keyBytes, ok := key.([]byte)
52
+	if !ok {
53
+		return ErrInvalidKeyType
54
+	}
55
+
56
+	// Decode signature, for comparison
57
+	sig, err := DecodeSegment(signature)
58
+	if err != nil {
59
+		return err
60
+	}
61
+
62
+	// Can we use the specified hashing method?
63
+	if !m.Hash.Available() {
64
+		return ErrHashUnavailable
65
+	}
66
+
67
+	// This signing method is symmetric, so we validate the signature
68
+	// by reproducing the signature from the signing string and key, then
69
+	// comparing that against the provided signature.
70
+	hasher := hmac.New(m.Hash.New, keyBytes)
71
+	hasher.Write([]byte(signingString))
72
+	if !hmac.Equal(sig, hasher.Sum(nil)) {
73
+		return ErrSignatureInvalid
74
+	}
75
+
76
+	// No validation errors.  Signature is good.
77
+	return nil
78
+}
79
+
80
+// Implements the Sign method from SigningMethod for this signing method.
81
+// Key must be []byte
82
+func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
83
+	if keyBytes, ok := key.([]byte); ok {
84
+		if !m.Hash.Available() {
85
+			return "", ErrHashUnavailable
86
+		}
87
+
88
+		hasher := hmac.New(m.Hash.New, keyBytes)
89
+		hasher.Write([]byte(signingString))
90
+
91
+		return EncodeSegment(hasher.Sum(nil)), nil
92
+	}
93
+
94
+	return "", ErrInvalidKeyType
95
+}

+ 94
- 0
vendor/github.com/dgrijalva/jwt-go/map_claims.go View File

@@ -0,0 +1,94 @@
1
+package jwt
2
+
3
+import (
4
+	"encoding/json"
5
+	"errors"
6
+	// "fmt"
7
+)
8
+
9
+// Claims type that uses the map[string]interface{} for JSON decoding
10
+// This is the default claims type if you don't supply one
11
+type MapClaims map[string]interface{}
12
+
13
+// Compares the aud claim against cmp.
14
+// If required is false, this method will return true if the value matches or is unset
15
+func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
16
+	aud, _ := m["aud"].(string)
17
+	return verifyAud(aud, cmp, req)
18
+}
19
+
20
+// Compares the exp claim against cmp.
21
+// If required is false, this method will return true if the value matches or is unset
22
+func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
23
+	switch exp := m["exp"].(type) {
24
+	case float64:
25
+		return verifyExp(int64(exp), cmp, req)
26
+	case json.Number:
27
+		v, _ := exp.Int64()
28
+		return verifyExp(v, cmp, req)
29
+	}
30
+	return req == false
31
+}
32
+
33
+// Compares the iat claim against cmp.
34
+// If required is false, this method will return true if the value matches or is unset
35
+func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
36
+	switch iat := m["iat"].(type) {
37
+	case float64:
38
+		return verifyIat(int64(iat), cmp, req)
39
+	case json.Number:
40
+		v, _ := iat.Int64()
41
+		return verifyIat(v, cmp, req)
42
+	}
43
+	return req == false
44
+}
45
+
46
+// Compares the iss claim against cmp.
47
+// If required is false, this method will return true if the value matches or is unset
48
+func (m MapClaims) VerifyIssuer(cmp string, req bool) bool {
49
+	iss, _ := m["iss"].(string)
50
+	return verifyIss(iss, cmp, req)
51
+}
52
+
53
+// Compares the nbf claim against cmp.
54
+// If required is false, this method will return true if the value matches or is unset
55
+func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
56
+	switch nbf := m["nbf"].(type) {
57
+	case float64:
58
+		return verifyNbf(int64(nbf), cmp, req)
59
+	case json.Number:
60
+		v, _ := nbf.Int64()
61
+		return verifyNbf(v, cmp, req)
62
+	}
63
+	return req == false
64
+}
65
+
66
+// Validates time based claims "exp, iat, nbf".
67
+// There is no accounting for clock skew.
68
+// As well, if any of the above claims are not in the token, it will still
69
+// be considered a valid claim.
70
+func (m MapClaims) Valid() error {
71
+	vErr := new(ValidationError)
72
+	now := TimeFunc().Unix()
73
+
74
+	if m.VerifyExpiresAt(now, false) == false {
75
+		vErr.Inner = errors.New("Token is expired")
76
+		vErr.Errors |= ValidationErrorExpired
77
+	}
78
+
79
+	if m.VerifyIssuedAt(now, false) == false {
80
+		vErr.Inner = errors.New("Token used before issued")
81
+		vErr.Errors |= ValidationErrorIssuedAt
82
+	}
83
+
84
+	if m.VerifyNotBefore(now, false) == false {
85
+		vErr.Inner = errors.New("Token is not valid yet")
86
+		vErr.Errors |= ValidationErrorNotValidYet
87
+	}
88
+
89
+	if vErr.valid() {
90
+		return nil
91
+	}
92
+
93
+	return vErr
94
+}

+ 52
- 0
vendor/github.com/dgrijalva/jwt-go/none.go View File

@@ -0,0 +1,52 @@
1
+package jwt
2
+
3
+// Implements the none signing method.  This is required by the spec
4
+// but you probably should never use it.
5
+var SigningMethodNone *signingMethodNone
6
+
7
+const UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing method allowed"
8
+
9
+var NoneSignatureTypeDisallowedError error
10
+
11
+type signingMethodNone struct{}
12
+type unsafeNoneMagicConstant string
13
+
14
+func init() {
15
+	SigningMethodNone = &signingMethodNone{}
16
+	NoneSignatureTypeDisallowedError = NewValidationError("'none' signature type is not allowed", ValidationErrorSignatureInvalid)
17
+
18
+	RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod {
19
+		return SigningMethodNone
20
+	})
21
+}
22
+
23
+func (m *signingMethodNone) Alg() string {
24
+	return "none"
25
+}
26
+
27
+// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key
28
+func (m *signingMethodNone) Verify(signingString, signature string, key interface{}) (err error) {
29
+	// Key must be UnsafeAllowNoneSignatureType to prevent accidentally
30
+	// accepting 'none' signing method
31
+	if _, ok := key.(unsafeNoneMagicConstant); !ok {
32
+		return NoneSignatureTypeDisallowedError
33
+	}
34
+	// If signing method is none, signature must be an empty string
35
+	if signature != "" {
36
+		return NewValidationError(
37
+			"'none' signing method with non-empty signature",
38
+			ValidationErrorSignatureInvalid,
39
+		)
40
+	}
41
+
42
+	// Accept 'none' signing method.
43
+	return nil
44
+}
45
+
46
+// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key
47
+func (m *signingMethodNone) Sign(signingString string, key interface{}) (string, error) {
48
+	if _, ok := key.(unsafeNoneMagicConstant); ok {
49
+		return "", nil
50
+	}
51
+	return "", NoneSignatureTypeDisallowedError
52
+}

+ 148
- 0
vendor/github.com/dgrijalva/jwt-go/parser.go View File

@@ -0,0 +1,148 @@
1
+package jwt
2
+
3
+import (
4
+	"bytes"
5
+	"encoding/json"
6
+	"fmt"
7
+	"strings"
8
+)
9
+
10
+type Parser struct {
11
+	ValidMethods         []string // If populated, only these methods will be considered valid
12
+	UseJSONNumber        bool     // Use JSON Number format in JSON decoder
13
+	SkipClaimsValidation bool     // Skip claims validation during token parsing
14
+}
15
+
16
+// Parse, validate, and return a token.
17
+// keyFunc will receive the parsed token and should return the key for validating.
18
+// If everything is kosher, err will be nil
19
+func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
20
+	return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
21
+}
22
+
23
+func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
24
+	token, parts, err := p.ParseUnverified(tokenString, claims)
25
+	if err != nil {
26
+		return token, err
27
+	}
28
+
29
+	// Verify signing method is in the required set
30
+	if p.ValidMethods != nil {
31
+		var signingMethodValid = false
32
+		var alg = token.Method.Alg()
33
+		for _, m := range p.ValidMethods {
34
+			if m == alg {
35
+				signingMethodValid = true
36
+				break
37
+			}
38
+		}
39
+		if !signingMethodValid {
40
+			// signing method is not in the listed set
41
+			return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
42
+		}
43
+	}
44
+
45
+	// Lookup key
46
+	var key interface{}
47
+	if keyFunc == nil {
48
+		// keyFunc was not provided.  short circuiting validation
49
+		return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
50
+	}
51
+	if key, err = keyFunc(token); err != nil {
52
+		// keyFunc returned an error
53
+		if ve, ok := err.(*ValidationError); ok {
54
+			return token, ve
55
+		}
56
+		return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
57
+	}
58
+
59
+	vErr := &ValidationError{}
60
+
61
+	// Validate Claims
62
+	if !p.SkipClaimsValidation {
63
+		if err := token.Claims.Valid(); err != nil {
64
+
65
+			// If the Claims Valid returned an error, check if it is a validation error,
66
+			// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
67
+			if e, ok := err.(*ValidationError); !ok {
68
+				vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
69
+			} else {
70
+				vErr = e
71
+			}
72
+		}
73
+	}
74
+
75
+	// Perform validation
76
+	token.Signature = parts[2]
77
+	if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
78
+		vErr.Inner = err
79
+		vErr.Errors |= ValidationErrorSignatureInvalid
80
+	}
81
+
82
+	if vErr.valid() {
83
+		token.Valid = true
84
+		return token, nil
85
+	}
86
+
87
+	return token, vErr
88
+}
89
+
90
+// WARNING: Don't use this method unless you know what you're doing
91
+//
92
+// This method parses the token but doesn't validate the signature. It's only
93
+// ever useful in cases where you know the signature is valid (because it has
94
+// been checked previously in the stack) and you want to extract values from
95
+// it.
96
+func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
97
+	parts = strings.Split(tokenString, ".")
98
+	if len(parts) != 3 {
99
+		return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
100
+	}
101
+
102
+	token = &Token{Raw: tokenString}
103
+
104
+	// parse Header
105
+	var headerBytes []byte
106
+	if headerBytes, err = DecodeSegment(parts[0]); err != nil {
107
+		if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
108
+			return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
109
+		}
110
+		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
111
+	}
112
+	if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
113
+		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
114
+	}
115
+
116
+	// parse Claims
117
+	var claimBytes []byte
118
+	token.Claims = claims
119
+
120
+	if claimBytes, err = DecodeSegment(parts[1]); err != nil {
121
+		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
122
+	}
123
+	dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
124
+	if p.UseJSONNumber {
125
+		dec.UseNumber()
126
+	}
127
+	// JSON Decode.  Special case for map type to avoid weird pointer behavior
128
+	if c, ok := token.Claims.(MapClaims); ok {
129
+		err = dec.Decode(&c)
130
+	} else {
131
+		err = dec.Decode(&claims)
132
+	}
133
+	// Handle decode error
134
+	if err != nil {
135
+		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
136
+	}
137
+
138
+	// Lookup signature method
139
+	if method, ok := token.Header["alg"].(string); ok {
140
+		if token.Method = GetSigningMethod(method); token.Method == nil {
141
+			return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
142
+		}
143
+	} else {
144
+		return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
145
+	}
146
+
147
+	return token, parts, nil
148
+}

+ 101
- 0
vendor/github.com/dgrijalva/jwt-go/rsa.go View File

@@ -0,0 +1,101 @@
1
+package jwt
2
+
3
+import (
4
+	"crypto"
5
+	"crypto/rand"
6
+	"crypto/rsa"
7
+)
8
+
9
+// Implements the RSA family of signing methods signing methods
10
+// Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation
11
+type SigningMethodRSA struct {
12
+	Name string
13
+	Hash crypto.Hash
14
+}
15
+
16
+// Specific instances for RS256 and company
17
+var (
18
+	SigningMethodRS256 *SigningMethodRSA
19
+	SigningMethodRS384 *SigningMethodRSA
20
+	SigningMethodRS512 *SigningMethodRSA
21
+)
22
+
23
+func init() {
24
+	// RS256
25
+	SigningMethodRS256 = &SigningMethodRSA{"RS256", crypto.SHA256}
26
+	RegisterSigningMethod(SigningMethodRS256.Alg(), func() SigningMethod {
27
+		return SigningMethodRS256
28
+	})
29
+
30
+	// RS384
31
+	SigningMethodRS384 = &SigningMethodRSA{"RS384", crypto.SHA384}
32
+	RegisterSigningMethod(SigningMethodRS384.Alg(), func() SigningMethod {
33
+		return SigningMethodRS384
34
+	})
35
+
36
+	// RS512
37
+	SigningMethodRS512 = &SigningMethodRSA{"RS512", crypto.SHA512}
38
+	RegisterSigningMethod(SigningMethodRS512.Alg(), func() SigningMethod {
39
+		return SigningMethodRS512
40
+	})
41
+}
42
+
43
+func (m *SigningMethodRSA) Alg() string {
44
+	return m.Name
45
+}
46
+
47
+// Implements the Verify method from SigningMethod
48
+// For this signing method, must be an *rsa.PublicKey structure.
49
+func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error {
50
+	var err error
51
+
52
+	// Decode the signature
53
+	var sig []byte
54
+	if sig, err = DecodeSegment(signature); err != nil {
55
+		return err
56
+	}
57
+
58
+	var rsaKey *rsa.PublicKey
59
+	var ok bool
60
+
61
+	if rsaKey, ok = key.(*rsa.PublicKey); !ok {
62
+		return ErrInvalidKeyType
63
+	}
64
+
65
+	// Create hasher
66
+	if !m.Hash.Available() {
67
+		return ErrHashUnavailable
68
+	}
69
+	hasher := m.Hash.New()
70
+	hasher.Write([]byte(signingString))
71
+
72
+	// Verify the signature
73
+	return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig)
74
+}
75
+
76
+// Implements the Sign method from SigningMethod
77
+// For this signing method, must be an *rsa.PrivateKey structure.
78
+func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) {
79
+	var rsaKey *rsa.PrivateKey
80
+	var ok bool
81
+
82
+	// Validate type of key
83
+	if rsaKey, ok = key.(*rsa.PrivateKey); !ok {
84
+		return "", ErrInvalidKey
85
+	}
86
+
87
+	// Create the hasher
88
+	if !m.Hash.Available() {
89
+		return "", ErrHashUnavailable
90
+	}
91
+
92
+	hasher := m.Hash.New()
93
+	hasher.Write([]byte(signingString))
94
+
95
+	// Sign the string and return the encoded bytes
96
+	if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil {
97
+		return EncodeSegment(sigBytes), nil
98
+	} else {
99
+		return "", err
100
+	}
101
+}

+ 126
- 0
vendor/github.com/dgrijalva/jwt-go/rsa_pss.go View File

@@ -0,0 +1,126 @@
1
+// +build go1.4
2
+
3
+package jwt
4
+
5
+import (
6
+	"crypto"
7
+	"crypto/rand"
8
+	"crypto/rsa"
9
+)
10
+
11
+// Implements the RSAPSS family of signing methods signing methods
12
+type SigningMethodRSAPSS struct {
13
+	*SigningMethodRSA
14
+	Options *rsa.PSSOptions
15
+}
16
+
17
+// Specific instances for RS/PS and company
18
+var (
19
+	SigningMethodPS256 *SigningMethodRSAPSS
20
+	SigningMethodPS384 *SigningMethodRSAPSS
21
+	SigningMethodPS512 *SigningMethodRSAPSS
22
+)
23
+
24
+func init() {
25
+	// PS256
26
+	SigningMethodPS256 = &SigningMethodRSAPSS{
27
+		&SigningMethodRSA{
28
+			Name: "PS256",
29
+			Hash: crypto.SHA256,
30
+		},
31
+		&rsa.PSSOptions{
32
+			SaltLength: rsa.PSSSaltLengthAuto,
33
+			Hash:       crypto.SHA256,
34
+		},
35
+	}
36
+	RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod {
37
+		return SigningMethodPS256
38
+	})
39
+
40
+	// PS384
41
+	SigningMethodPS384 = &SigningMethodRSAPSS{
42
+		&SigningMethodRSA{
43
+			Name: "PS384",
44
+			Hash: crypto.SHA384,
45
+		},
46
+		&rsa.PSSOptions{
47
+			SaltLength: rsa.PSSSaltLengthAuto,
48
+			Hash:       crypto.SHA384,
49
+		},
50
+	}
51
+	RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod {
52
+		return SigningMethodPS384
53
+	})
54
+
55
+	// PS512
56
+	SigningMethodPS512 = &SigningMethodRSAPSS{
57
+		&SigningMethodRSA{
58
+			Name: "PS512",
59
+			Hash: crypto.SHA512,
60
+		},
61
+		&rsa.PSSOptions{
62
+			SaltLength: rsa.PSSSaltLengthAuto,
63
+			Hash:       crypto.SHA512,
64
+		},
65
+	}
66
+	RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod {
67
+		return SigningMethodPS512
68
+	})
69
+}
70
+
71
+// Implements the Verify method from SigningMethod
72
+// For this verify method, key must be an rsa.PublicKey struct
73
+func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error {
74
+	var err error
75
+
76
+	// Decode the signature
77
+	var sig []byte
78
+	if sig, err = DecodeSegment(signature); err != nil {
79
+		return err
80
+	}
81
+
82
+	var rsaKey *rsa.PublicKey
83
+	switch k := key.(type) {
84
+	case *rsa.PublicKey:
85
+		rsaKey = k
86
+	default:
87
+		return ErrInvalidKey
88
+	}
89
+
90
+	// Create hasher
91
+	if !m.Hash.Available() {
92
+		return ErrHashUnavailable
93
+	}
94
+	hasher := m.Hash.New()
95
+	hasher.Write([]byte(signingString))
96
+
97
+	return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, m.Options)
98
+}
99
+
100
+// Implements the Sign method from SigningMethod
101
+// For this signing method, key must be an rsa.PrivateKey struct
102
+func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) {
103
+	var rsaKey *rsa.PrivateKey
104
+
105
+	switch k := key.(type) {
106
+	case *rsa.PrivateKey:
107
+		rsaKey = k
108
+	default:
109
+		return "", ErrInvalidKeyType
110
+	}
111
+
112
+	// Create the hasher
113
+	if !m.Hash.Available() {
114
+		return "", ErrHashUnavailable
115
+	}
116
+
117
+	hasher := m.Hash.New()
118
+	hasher.Write([]byte(signingString))
119
+
120
+	// Sign the string and return the encoded bytes
121
+	if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil {
122
+		return EncodeSegment(sigBytes), nil
123
+	} else {
124
+		return "", err
125
+	}
126
+}

+ 101
- 0
vendor/github.com/dgrijalva/jwt-go/rsa_utils.go View File

@@ -0,0 +1,101 @@
1
+package jwt
2
+
3
+import (
4
+	"crypto/rsa"
5
+	"crypto/x509"
6
+	"encoding/pem"
7
+	"errors"
8
+)
9
+
10
+var (
11
+	ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key")
12
+	ErrNotRSAPrivateKey    = errors.New("Key is not a valid RSA private key")
13
+	ErrNotRSAPublicKey     = errors.New("Key is not a valid RSA public key")
14
+)
15
+
16
+// Parse PEM encoded PKCS1 or PKCS8 private key
17
+func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
18
+	var err error
19
+
20
+	// Parse PEM block
21
+	var block *pem.Block
22
+	if block, _ = pem.Decode(key); block == nil {
23
+		return nil, ErrKeyMustBePEMEncoded
24
+	}
25
+
26
+	var parsedKey interface{}
27
+	if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
28
+		if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
29
+			return nil, err
30
+		}
31
+	}
32
+
33
+	var pkey *rsa.PrivateKey
34
+	var ok bool
35
+	if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
36
+		return nil, ErrNotRSAPrivateKey
37
+	}
38
+
39
+	return pkey, nil
40
+}
41
+
42
+// Parse PEM encoded PKCS1 or PKCS8 private key protected with password
43
+func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
44
+	var err error
45
+
46
+	// Parse PEM block
47
+	var block *pem.Block
48
+	if block, _ = pem.Decode(key); block == nil {
49
+		return nil, ErrKeyMustBePEMEncoded
50
+	}
51
+
52
+	var parsedKey interface{}
53
+
54
+	var blockDecrypted []byte
55
+	if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
56
+		return nil, err
57
+	}
58
+
59
+	if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil {
60
+		if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil {
61
+			return nil, err
62
+		}
63
+	}
64
+
65
+	var pkey *rsa.PrivateKey
66
+	var ok bool
67
+	if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
68
+		return nil, ErrNotRSAPrivateKey
69
+	}
70
+
71
+	return pkey, nil
72
+}
73
+
74
+// Parse PEM encoded PKCS1 or PKCS8 public key
75
+func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
76
+	var err error
77
+
78
+	// Parse PEM block
79
+	var block *pem.Block
80
+	if block, _ = pem.Decode(key); block == nil {
81
+		return nil, ErrKeyMustBePEMEncoded
82
+	}
83
+
84
+	// Parse the key
85
+	var parsedKey interface{}
86
+	if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
87
+		if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
88
+			parsedKey = cert.PublicKey
89
+		} else {
90
+			return nil, err
91
+		}
92
+	}
93
+
94
+	var pkey *rsa.PublicKey
95
+	var ok bool
96
+	if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
97
+		return nil, ErrNotRSAPublicKey
98
+	}
99
+
100
+	return pkey, nil
101
+}

+ 0
- 0
vendor/github.com/dgrijalva/jwt-go/signing_method.go View File


Some files were not shown because too many files changed in this diff