replace zxq.co/ripple/hanayo

This commit is contained in:
Alicia
2019-02-23 13:29:15 +00:00
commit c3d206c173
5871 changed files with 1353715 additions and 0 deletions

2
vendor/github.com/gin-gonic/contrib/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
*/Godeps/*
!*/Godeps/Godeps.json

18
vendor/github.com/gin-gonic/contrib/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,18 @@
language: go
go:
- 1.6.x
- 1.7.x
- 1.8.x
- tip
services:
- memcache
- redis-server
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/acc2c57482e94b44f557
on_success: change
on_failure: always
on_start: false

39
vendor/github.com/gin-gonic/contrib/README.md generated vendored Normal file
View File

@@ -0,0 +1,39 @@
# gin-gonic/contrib
[![Build Status](https://travis-ci.org/gin-gonic/contrib.svg)](https://travis-ci.org/gin-gonic/contrib)
Here you'll find middleware ready to use with [Gin Framework](https://github.com/gin-gonic/gin). Submit your pull request, either with the package in a folder, or by adding a link to this `README.md`.
If adding a package directly, don't forget to create a `README.md` inside with author name.
If adding a link to your own repository, please follow this example:
```
+ nameOfMiddleware (https://github.com/yourusername/yourrepo)
```
Each author is responsible of maintaining his own code, although if you submit as a package, you allow the community to fix it. You can also submit a pull request to fix an existing package.
## List of external middleware
+ [RestGate](https://github.com/pjebs/restgate) - Secure authentication for REST API endpoints
+ [staticbin](https://github.com/olebedev/staticbin) - middleware/handler for serving static files from binary data
+ [gin-cors](https://github.com/gin-contrib/cors) - Official CORS gin's middleware
+ [gin-csrf](https://github.com/utrack/gin-csrf) - CSRF protection
+ [gin-health](https://github.com/utrack/gin-health) - middleware that simplifies stat reporting via [gocraft/health](https://github.com/gocraft/health)
+ [gin-merry](https://github.com/utrack/gin-merry) - middleware for pretty-printing [merry](https://github.com/ansel1/merry) errors with context
+ [gin-revision](https://github.com/appleboy/gin-revision-middleware) - Revision middleware for Gin framework
+ [gin-jwt](https://github.com/appleboy/gin-jwt) - JWT Middleware for Gin Framework
+ [gin-sessions](https://github.com/kimiazhu/ginweb-contrib/tree/master/sessions) - session middleware based on mongodb and mysql
+ [gin-location](https://github.com/drone/gin-location) - middleware for exposing the server's hostname and scheme
+ [gin-nice-recovery](https://github.com/ekyoung/gin-nice-recovery) - panic recovery middleware that let's you build a nicer user experience
+ [gin-limit](https://github.com/aviddiviner/gin-limit) - limits simultaneous requests; can help with high traffic load
+ [ez-gin-template](https://github.com/michelloworld/ez-gin-template) - easy template wrap for gin
+ [gin-hydra](https://github.com/janekolszak/gin-hydra) - [Hydra](https://github.com/ory-am/hydra) middleware for Gin
+ [gin-glog](https://github.com/zalando/gin-glog) - meant as drop-in replacement for Gin's default logger
+ [gin-gomonitor](https://github.com/zalando/gin-gomonitor) - for exposing metrics with Go-Monitor
+ [gin-oauth2](https://github.com/zalando/gin-oauth2) - for working with OAuth2
+ [static](https://github.com/hyperboloide/static) An alternative static assets handler for the gin framework.
+ [xss-mw](https://github.com/dvwright/xss-mw) - XssMw is a middleware designed to "auto remove XSS" from user submitted input
+ [gin-helmet](https://github.com/danielkov/gin-helmet) - Collection of simple security middleware.
+ [gin-jwt-session](https://github.com/ScottHuangZL/gin-jwt-session) - middleware to provide JWT/Session/Flashes, easy to use while also provide options for adjust if necessary. Provide sample too.
+ [gin-template](https://github.com/foolin/gin-template) - Easy and simple to use html/template for gin framework.

View File

@@ -0,0 +1,22 @@
{
"ImportPath": "github.com/gin-gonic/contrib/cache",
"GoVersion": "go1.3",
"Deps": [
{
"ImportPath": "github.com/bradfitz/gomemcache/memcache",
"Rev": "72a68649ba712ee7c4b5b4a943a626bcd7d90eb8"
},
{
"ImportPath": "github.com/garyburd/redigo/redis",
"Rev": "535138d7bcd717d6531c701ef5933d98b1866257"
},
{
"ImportPath": "github.com/gin-gonic/gin",
"Rev": "ac0ad2fed865d40a0adc1ac3ccaadc3acff5db4b"
},
{
"ImportPath": "github.com/robfig/go-cache",
"Rev": "9fc39e0dbf62c034ec4e45e6120fc69433a3ec51"
}
]
}

5
vendor/github.com/gin-gonic/contrib/cache/README.md generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# cache
## EOL-warning
**This package has been abandoned on 2016-12-07. Please use [gin-contrib/cache](https://github.com/gin-contrib/cache) instead.**

153
vendor/github.com/gin-gonic/contrib/cache/cache.go generated vendored Normal file
View File

@@ -0,0 +1,153 @@
package cache
import (
"bytes"
"crypto/sha1"
"errors"
"github.com/gin-gonic/gin"
"io"
"net/http"
"net/url"
"time"
)
const (
DEFAULT = time.Duration(0)
FOREVER = time.Duration(-1)
CACHE_MIDDLEWARE_KEY = "gincontrib.cache"
)
var (
PageCachePrefix = "gincontrib.page.cache"
ErrCacheMiss = errors.New("cache: key not found.")
ErrNotStored = errors.New("cache: not stored.")
ErrNotSupport = errors.New("cache: not support.")
)
type CacheStore interface {
Get(key string, value interface{}) error
Set(key string, value interface{}, expire time.Duration) error
Add(key string, value interface{}, expire time.Duration) error
Replace(key string, data interface{}, expire time.Duration) error
Delete(key string) error
Increment(key string, data uint64) (uint64, error)
Decrement(key string, data uint64) (uint64, error)
Flush() error
}
type responseCache struct {
status int
header http.Header
data []byte
}
type cachedWriter struct {
gin.ResponseWriter
status int
written bool
store CacheStore
expire time.Duration
key string
}
func urlEscape(prefix string, u string) string {
key := url.QueryEscape(u)
if len(key) > 200 {
h := sha1.New()
io.WriteString(h, u)
key = string(h.Sum(nil))
}
var buffer bytes.Buffer
buffer.WriteString(prefix)
buffer.WriteString(":")
buffer.WriteString(key)
return buffer.String()
}
func newCachedWriter(store CacheStore, expire time.Duration, writer gin.ResponseWriter, key string) *cachedWriter {
return &cachedWriter{writer, 0, false, store, expire, key}
}
func (w *cachedWriter) WriteHeader(code int) {
w.status = code
w.written = true
w.ResponseWriter.WriteHeader(code)
}
func (w *cachedWriter) Status() int {
return w.status
}
func (w *cachedWriter) Written() bool {
return w.written
}
func (w *cachedWriter) Write(data []byte) (int, error) {
ret, err := w.ResponseWriter.Write(data)
if err == nil {
//cache response
store := w.store
val := responseCache{
w.status,
w.Header(),
data,
}
err = store.Set(w.key, val, w.expire)
if err != nil {
// need logger
}
}
return ret, err
}
// Cache Middleware
func Cache(store *CacheStore) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set(CACHE_MIDDLEWARE_KEY, store)
c.Next()
}
}
func SiteCache(store CacheStore, expire time.Duration) gin.HandlerFunc {
return func(c *gin.Context) {
var cache responseCache
url := c.Request.URL
key := urlEscape(PageCachePrefix, url.RequestURI())
if err := store.Get(key, &cache); err != nil {
c.Next()
} else {
c.Writer.WriteHeader(cache.status)
for k, vals := range cache.header {
for _, v := range vals {
c.Writer.Header().Add(k, v)
}
}
c.Writer.Write(cache.data)
}
}
}
// Cache Decorator
func CachePage(store CacheStore, expire time.Duration, handle gin.HandlerFunc) gin.HandlerFunc {
return func(c *gin.Context) {
var cache responseCache
url := c.Request.URL
key := urlEscape(PageCachePrefix, url.RequestURI())
if err := store.Get(key, &cache); err != nil {
// replace writer
writer := newCachedWriter(store, expire, c.Writer, key)
c.Writer = writer
handle(c)
} else {
c.Writer.WriteHeader(cache.status)
for k, vals := range cache.header {
for _, v := range vals {
c.Writer.Header().Add(k, v)
}
}
c.Writer.Write(cache.data)
}
}
}

202
vendor/github.com/gin-gonic/contrib/cache/cache_test.go generated vendored Normal file
View File

@@ -0,0 +1,202 @@
package cache
import (
"math"
"testing"
"time"
)
type cacheFactory func(*testing.T, time.Duration) CacheStore
// Test typical cache interactions
func typicalGetSet(t *testing.T, newCache cacheFactory) {
var err error
cache := newCache(t, time.Hour)
value := "foo"
if err = cache.Set("value", value, DEFAULT); err != nil {
t.Errorf("Error setting a value: %s", err)
}
value = ""
err = cache.Get("value", &value)
if err != nil {
t.Errorf("Error getting a value: %s", err)
}
if value != "foo" {
t.Errorf("Expected to get foo back, got %s", value)
}
}
// Test the increment-decrement cases
func incrDecr(t *testing.T, newCache cacheFactory) {
var err error
cache := newCache(t, time.Hour)
// Normal increment / decrement operation.
if err = cache.Set("int", 10, DEFAULT); err != nil {
t.Errorf("Error setting int: %s", err)
}
newValue, err := cache.Increment("int", 50)
if err != nil {
t.Errorf("Error incrementing int: %s", err)
}
if newValue != 60 {
t.Errorf("Expected 60, was %d", newValue)
}
if newValue, err = cache.Decrement("int", 50); err != nil {
t.Errorf("Error decrementing: %s", err)
}
if newValue != 10 {
t.Errorf("Expected 10, was %d", newValue)
}
// Increment wraparound
newValue, err = cache.Increment("int", math.MaxUint64-5)
if err != nil {
t.Errorf("Error wrapping around: %s", err)
}
if newValue != 4 {
t.Errorf("Expected wraparound 4, got %d", newValue)
}
// Decrement capped at 0
newValue, err = cache.Decrement("int", 25)
if err != nil {
t.Errorf("Error decrementing below 0: %s", err)
}
if newValue != 0 {
t.Errorf("Expected capped at 0, got %d", newValue)
}
}
func expiration(t *testing.T, newCache cacheFactory) {
// memcached does not support expiration times less than 1 second.
var err error
cache := newCache(t, time.Second)
// Test Set w/ DEFAULT
value := 10
cache.Set("int", value, DEFAULT)
time.Sleep(2 * time.Second)
err = cache.Get("int", &value)
if err != ErrCacheMiss {
t.Errorf("Expected CacheMiss, but got: %s", err)
}
// Test Set w/ short time
cache.Set("int", value, time.Second)
time.Sleep(2 * time.Second)
err = cache.Get("int", &value)
if err != ErrCacheMiss {
t.Errorf("Expected CacheMiss, but got: %s", err)
}
// Test Set w/ longer time.
cache.Set("int", value, time.Hour)
time.Sleep(2 * time.Second)
err = cache.Get("int", &value)
if err != nil {
t.Errorf("Expected to get the value, but got: %s", err)
}
// Test Set w/ forever.
cache.Set("int", value, FOREVER)
time.Sleep(2 * time.Second)
err = cache.Get("int", &value)
if err != nil {
t.Errorf("Expected to get the value, but got: %s", err)
}
}
func emptyCache(t *testing.T, newCache cacheFactory) {
var err error
cache := newCache(t, time.Hour)
err = cache.Get("notexist", 0)
if err == nil {
t.Errorf("Error expected for non-existent key")
}
if err != ErrCacheMiss {
t.Errorf("Expected ErrCacheMiss for non-existent key: %s", err)
}
err = cache.Delete("notexist")
if err != ErrCacheMiss {
t.Errorf("Expected ErrCacheMiss for non-existent key: %s", err)
}
_, err = cache.Increment("notexist", 1)
if err != ErrCacheMiss {
t.Errorf("Expected cache miss incrementing non-existent key: %s", err)
}
_, err = cache.Decrement("notexist", 1)
if err != ErrCacheMiss {
t.Errorf("Expected cache miss decrementing non-existent key: %s", err)
}
}
func testReplace(t *testing.T, newCache cacheFactory) {
var err error
cache := newCache(t, time.Hour)
// Replace in an empty cache.
if err = cache.Replace("notexist", 1, FOREVER); err != ErrNotStored {
t.Errorf("Replace in empty cache: expected ErrNotStored, got: %s", err)
}
// Set a value of 1, and replace it with 2
if err = cache.Set("int", 1, time.Second); err != nil {
t.Errorf("Unexpected error: %s", err)
}
if err = cache.Replace("int", 2, time.Second); err != nil {
t.Errorf("Unexpected error: %s", err)
}
var i int
if err = cache.Get("int", &i); err != nil {
t.Errorf("Unexpected error getting a replaced item: %s", err)
}
if i != 2 {
t.Errorf("Expected 2, got %d", i)
}
// Wait for it to expire and replace with 3 (unsuccessfully).
time.Sleep(2 * time.Second)
if err = cache.Replace("int", 3, time.Second); err != ErrNotStored {
t.Errorf("Expected ErrNotStored, got: %s", err)
}
if err = cache.Get("int", &i); err != ErrCacheMiss {
t.Errorf("Expected cache miss, got: %s", err)
}
}
func testAdd(t *testing.T, newCache cacheFactory) {
var err error
cache := newCache(t, time.Hour)
// Add to an empty cache.
if err = cache.Add("int", 1, time.Second); err != nil {
t.Errorf("Unexpected error adding to empty cache: %s", err)
}
// Try to add again. (fail)
if err = cache.Add("int", 2, time.Second); err != ErrNotStored {
t.Errorf("Expected ErrNotStored adding dupe to cache: %s", err)
}
// Wait for it to expire, and add again.
time.Sleep(2 * time.Second)
if err = cache.Add("int", 3, time.Second); err != nil {
t.Errorf("Unexpected error adding to cache: %s", err)
}
// Get and verify the value.
var i int
if err = cache.Get("int", &i); err != nil {
t.Errorf("Unexpected error: %s", err)
}
if i != 3 {
t.Errorf("Expected 3, got: %d", i)
}
}

View File

@@ -0,0 +1,25 @@
package main
import (
"fmt"
"github.com/gin-gonic/contrib/cache"
"github.com/gin-gonic/gin"
"time"
)
func main() {
r := gin.Default()
store := cache.NewInMemoryStore(time.Second)
// Cached Page
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
r.GET("/cache_ping", cache.CachePage(store, time.Minute, func(c *gin.Context) {
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
}))
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}

78
vendor/github.com/gin-gonic/contrib/cache/inmemory.go generated vendored Normal file
View File

@@ -0,0 +1,78 @@
package cache
import (
"github.com/robfig/go-cache"
"reflect"
"time"
)
type InMemoryStore struct {
cache.Cache
}
func NewInMemoryStore(defaultExpiration time.Duration) *InMemoryStore {
return &InMemoryStore{*cache.New(defaultExpiration, time.Minute)}
}
func (c *InMemoryStore) Get(key string, value interface{}) error {
val, found := c.Cache.Get(key)
if !found {
return ErrCacheMiss
}
v := reflect.ValueOf(value)
if v.Type().Kind() == reflect.Ptr && v.Elem().CanSet() {
v.Elem().Set(reflect.ValueOf(val))
return nil
}
return ErrNotStored
}
func (c *InMemoryStore) Set(key string, value interface{}, expires time.Duration) error {
// NOTE: go-cache understands the values of DEFAULT and FOREVER
c.Cache.Set(key, value, expires)
return nil
}
func (c *InMemoryStore) Add(key string, value interface{}, expires time.Duration) error {
err := c.Cache.Add(key, value, expires)
if err == cache.ErrKeyExists {
return ErrNotStored
}
return err
}
func (c *InMemoryStore) Replace(key string, value interface{}, expires time.Duration) error {
if err := c.Cache.Replace(key, value, expires); err != nil {
return ErrNotStored
}
return nil
}
func (c *InMemoryStore) Delete(key string) error {
if found := c.Cache.Delete(key); !found {
return ErrCacheMiss
}
return nil
}
func (c *InMemoryStore) Increment(key string, n uint64) (uint64, error) {
newValue, err := c.Cache.Increment(key, n)
if err == cache.ErrCacheMiss {
return 0, ErrCacheMiss
}
return newValue, err
}
func (c *InMemoryStore) Decrement(key string, n uint64) (uint64, error) {
newValue, err := c.Cache.Decrement(key, n)
if err == cache.ErrCacheMiss {
return 0, ErrCacheMiss
}
return newValue, err
}
func (c *InMemoryStore) Flush() error {
c.Cache.Flush()
return nil
}

View File

@@ -0,0 +1,35 @@
package cache
import (
"testing"
"time"
)
var newInMemoryStore = func(_ *testing.T, defaultExpiration time.Duration) CacheStore {
return NewInMemoryStore(defaultExpiration)
}
// Test typical cache interactions
func TestInMemoryCache_TypicalGetSet(t *testing.T) {
typicalGetSet(t, newInMemoryStore)
}
func TestInMemoryCache_IncrDecr(t *testing.T) {
incrDecr(t, newInMemoryStore)
}
func TestInMemoryCache_Expiration(t *testing.T) {
expiration(t, newInMemoryStore)
}
func TestInMemoryCache_EmptyCache(t *testing.T) {
emptyCache(t, newInMemoryStore)
}
func TestInMemoryCache_Replace(t *testing.T) {
testReplace(t, newInMemoryStore)
}
func TestInMemoryCache_Add(t *testing.T) {
testAdd(t, newInMemoryStore)
}

87
vendor/github.com/gin-gonic/contrib/cache/memcached.go generated vendored Normal file
View File

@@ -0,0 +1,87 @@
package cache
import (
"github.com/bradfitz/gomemcache/memcache"
"time"
)
type MemcachedStore struct {
*memcache.Client
defaultExpiration time.Duration
}
func NewMemcachedStore(hostList []string, defaultExpiration time.Duration) *MemcachedStore {
return &MemcachedStore{memcache.New(hostList...), defaultExpiration}
}
func (c *MemcachedStore) Set(key string, value interface{}, expires time.Duration) error {
return c.invoke((*memcache.Client).Set, key, value, expires)
}
func (c *MemcachedStore) Add(key string, value interface{}, expires time.Duration) error {
return c.invoke((*memcache.Client).Add, key, value, expires)
}
func (c *MemcachedStore) Replace(key string, value interface{}, expires time.Duration) error {
return c.invoke((*memcache.Client).Replace, key, value, expires)
}
func (c *MemcachedStore) Get(key string, value interface{}) error {
item, err := c.Client.Get(key)
if err != nil {
return convertMemcacheError(err)
}
return deserialize(item.Value, value)
}
func (c *MemcachedStore) Delete(key string) error {
return convertMemcacheError(c.Client.Delete(key))
}
func (c *MemcachedStore) Increment(key string, delta uint64) (uint64, error) {
newValue, err := c.Client.Increment(key, delta)
return newValue, convertMemcacheError(err)
}
func (c *MemcachedStore) Decrement(key string, delta uint64) (uint64, error) {
newValue, err := c.Client.Decrement(key, delta)
return newValue, convertMemcacheError(err)
}
func (c *MemcachedStore) Flush() error {
return ErrNotSupport
}
func (c *MemcachedStore) invoke(storeFn func(*memcache.Client, *memcache.Item) error,
key string, value interface{}, expire time.Duration) error {
switch expire {
case DEFAULT:
expire = c.defaultExpiration
case FOREVER:
expire = time.Duration(0)
}
b, err := serialize(value)
if err != nil {
return err
}
return convertMemcacheError(storeFn(c.Client, &memcache.Item{
Key: key,
Value: b,
Expiration: int32(expire / time.Second),
}))
}
func convertMemcacheError(err error) error {
switch err {
case nil:
return nil
case memcache.ErrCacheMiss:
return ErrCacheMiss
case memcache.ErrNotStored:
return ErrNotStored
}
return err
}

View File

@@ -0,0 +1,46 @@
package cache
import (
"net"
"testing"
"time"
)
// These tests require memcached running on localhost:11211 (the default)
const testServer = "localhost:11211"
var newMemcachedStore = func(t *testing.T, defaultExpiration time.Duration) CacheStore {
c, err := net.Dial("tcp", testServer)
if err == nil {
c.Write([]byte("flush_all\r\n"))
c.Close()
return NewMemcachedStore([]string{testServer}, defaultExpiration)
}
t.Errorf("couldn't connect to memcached on %s", testServer)
t.FailNow()
panic("")
}
func TestMemcachedCache_TypicalGetSet(t *testing.T) {
typicalGetSet(t, newMemcachedStore)
}
func TestMemcachedCache_IncrDecr(t *testing.T) {
incrDecr(t, newMemcachedStore)
}
func TestMemcachedCache_Expiration(t *testing.T) {
expiration(t, newMemcachedStore)
}
func TestMemcachedCache_EmptyCache(t *testing.T) {
emptyCache(t, newMemcachedStore)
}
func TestMemcachedCache_Replace(t *testing.T) {
testReplace(t, newMemcachedStore)
}
func TestMemcachedCache_Add(t *testing.T) {
testAdd(t, newMemcachedStore)
}

181
vendor/github.com/gin-gonic/contrib/cache/redis.go generated vendored Normal file
View File

@@ -0,0 +1,181 @@
package cache
import (
"github.com/garyburd/redigo/redis"
"time"
)
// Wraps the Redis client to meet the Cache interface.
type RedisStore struct {
pool *redis.Pool
defaultExpiration time.Duration
}
// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCache(host string, password string, defaultExpiration time.Duration) *RedisStore {
var pool = &redis.Pool{
MaxIdle: 5,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
// the redis protocol should probably be made sett-able
c, err := redis.Dial("tcp", host)
if err != nil {
return nil, err
}
if len(password) > 0 {
if _, err := c.Do("AUTH", password); err != nil {
c.Close()
return nil, err
}
} else {
// check with PING
if _, err := c.Do("PING"); err != nil {
c.Close()
return nil, err
}
}
return c, err
},
// custom connection test method
TestOnBorrow: func(c redis.Conn, t time.Time) error {
if _, err := c.Do("PING"); err != nil {
return err
}
return nil
},
}
return &RedisStore{pool, defaultExpiration}
}
func (c *RedisStore) Set(key string, value interface{}, expires time.Duration) error {
return c.invoke(c.pool.Get().Do, key, value, expires)
}
func (c *RedisStore) Add(key string, value interface{}, expires time.Duration) error {
conn := c.pool.Get()
if exists(conn, key) {
return ErrNotStored
}
return c.invoke(conn.Do, key, value, expires)
}
func (c *RedisStore) Replace(key string, value interface{}, expires time.Duration) error {
conn := c.pool.Get()
if !exists(conn, key) {
return ErrNotStored
}
err := c.invoke(conn.Do, key, value, expires)
if value == nil {
return ErrNotStored
} else {
return err
}
}
func (c *RedisStore) Get(key string, ptrValue interface{}) error {
conn := c.pool.Get()
defer conn.Close()
raw, err := conn.Do("GET", key)
if raw == nil {
return ErrCacheMiss
}
item, err := redis.Bytes(raw, err)
if err != nil {
return err
}
return deserialize(item, ptrValue)
}
func exists(conn redis.Conn, key string) bool {
retval, _ := redis.Bool(conn.Do("EXISTS", key))
return retval
}
func (c *RedisStore) Delete(key string) error {
conn := c.pool.Get()
defer conn.Close()
if !exists(conn, key) {
return ErrCacheMiss
}
_, err := conn.Do("DEL", key)
return err
}
func (c *RedisStore) Increment(key string, delta uint64) (uint64, error) {
conn := c.pool.Get()
defer conn.Close()
// Check for existance *before* increment as per the cache contract.
// redis will auto create the key, and we don't want that. Since we need to do increment
// ourselves instead of natively via INCRBY (redis doesn't support wrapping), we get the value
// and do the exists check this way to minimize calls to Redis
val, err := conn.Do("GET", key)
if val == nil {
return 0, ErrCacheMiss
}
if err == nil {
currentVal, err := redis.Int64(val, nil)
if err != nil {
return 0, err
}
var sum int64 = currentVal + int64(delta)
_, err = conn.Do("SET", key, sum)
if err != nil {
return 0, err
}
return uint64(sum), nil
} else {
return 0, err
}
}
func (c *RedisStore) Decrement(key string, delta uint64) (newValue uint64, err error) {
conn := c.pool.Get()
defer conn.Close()
// Check for existance *before* increment as per the cache contract.
// redis will auto create the key, and we don't want that, hence the exists call
if !exists(conn, key) {
return 0, ErrCacheMiss
}
// Decrement contract says you can only go to 0
// so we go fetch the value and if the delta is greater than the amount,
// 0 out the value
currentVal, err := redis.Int64(conn.Do("GET", key))
if err == nil && delta > uint64(currentVal) {
tempint, err := redis.Int64(conn.Do("DECRBY", key, currentVal))
return uint64(tempint), err
}
tempint, err := redis.Int64(conn.Do("DECRBY", key, delta))
return uint64(tempint), err
}
func (c *RedisStore) Flush() error {
conn := c.pool.Get()
defer conn.Close()
_, err := conn.Do("FLUSHALL")
return err
}
func (c *RedisStore) invoke(f func(string, ...interface{}) (interface{}, error),
key string, value interface{}, expires time.Duration) error {
switch expires {
case DEFAULT:
expires = c.defaultExpiration
case FOREVER:
expires = time.Duration(0)
}
b, err := serialize(value)
if err != nil {
return err
}
conn := c.pool.Get()
defer conn.Close()
if expires > 0 {
_, err := f("SETEX", key, int32(expires/time.Second), b)
return err
} else {
_, err := f("SET", key, b)
return err
}
}

View File

@@ -0,0 +1,48 @@
package cache
import (
"net"
"testing"
"time"
)
// These tests require redis server running on localhost:6379 (the default)
const redisTestServer = "localhost:6379"
var newRedisStore = func(t *testing.T, defaultExpiration time.Duration) CacheStore {
c, err := net.Dial("tcp", redisTestServer)
if err == nil {
c.Write([]byte("flush_all\r\n"))
c.Close()
redisCache := NewRedisCache(redisTestServer, "", defaultExpiration)
redisCache.Flush()
return redisCache
}
t.Errorf("couldn't connect to redis on %s", redisTestServer)
t.FailNow()
panic("")
}
func TestRedisCache_TypicalGetSet(t *testing.T) {
typicalGetSet(t, newRedisStore)
}
func TestRedisCache_IncrDecr(t *testing.T) {
incrDecr(t, newRedisStore)
}
func TestRedisCache_Expiration(t *testing.T) {
expiration(t, newRedisStore)
}
func TestRedisCache_EmptyCache(t *testing.T) {
emptyCache(t, newRedisStore)
}
func TestRedisCache_Replace(t *testing.T) {
testReplace(t, newRedisStore)
}
func TestRedisCache_Add(t *testing.T) {
testAdd(t, newRedisStore)
}

View File

@@ -0,0 +1,66 @@
package cache
import (
"bytes"
"encoding/gob"
"reflect"
"strconv"
)
func serialize(value interface{}) ([]byte, error) {
if bytes, ok := value.([]byte); ok {
return bytes, nil
}
switch v := reflect.ValueOf(value); v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return []byte(strconv.FormatInt(v.Int(), 10)), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return []byte(strconv.FormatUint(v.Uint(), 10)), nil
}
var b bytes.Buffer
encoder := gob.NewEncoder(&b)
if err := encoder.Encode(value); err != nil {
return nil, err
}
return b.Bytes(), nil
}
func deserialize(byt []byte, ptr interface{}) (err error) {
if bytes, ok := ptr.(*[]byte); ok {
*bytes = byt
return nil
}
if v := reflect.ValueOf(ptr); v.Kind() == reflect.Ptr {
switch p := v.Elem(); p.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
var i int64
i, err = strconv.ParseInt(string(byt), 10, 64)
if err != nil {
return err
} else {
p.SetInt(i)
}
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
var i uint64
i, err = strconv.ParseUint(string(byt), 10, 64)
if err != nil {
return err
} else {
p.SetUint(i)
}
return nil
}
}
b := bytes.NewBuffer(byt)
decoder := gob.NewDecoder(b)
if err = decoder.Decode(ptr); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,53 @@
package commonlog
import (
"bytes"
"io"
"strconv"
"sync"
"time"
"github.com/gin-gonic/gin"
)
// Instances a Logger middleware that will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
func New() gin.HandlerFunc {
return NewWithWriter(gin.DefaultWriter)
}
// Instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func NewWithWriter(out io.Writer) gin.HandlerFunc {
pool := &sync.Pool{
New: func() interface{} {
buf := new(bytes.Buffer)
return buf
},
}
return func(c *gin.Context) {
// Process request
c.Next()
//127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
w := pool.Get().(*bytes.Buffer)
w.Reset()
w.WriteString(c.ClientIP())
w.WriteString(" - - ")
w.WriteString(time.Now().Format("[02/Jan/2006:15:04:05 -0700] "))
w.WriteString("\"")
w.WriteString(c.Request.Method)
w.WriteString(" ")
w.WriteString(c.Request.URL.Path)
w.WriteString(" ")
w.WriteString(c.Request.Proto)
w.WriteString("\" ")
w.WriteString(strconv.Itoa(c.Writer.Status()))
w.WriteString(" ")
w.WriteString(strconv.Itoa(c.Writer.Size()))
w.WriteString("\n")
w.WriteTo(out)
pool.Put(w)
}
}

5
vendor/github.com/gin-gonic/contrib/cors/README.md generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# cors
## EOL-warning
**This package has been abandoned on 2016-12-07. Please use [gin-contrib/cors](https://github.com/gin-contrib/cors) instead.**

109
vendor/github.com/gin-gonic/contrib/cors/config.go generated vendored Normal file
View File

@@ -0,0 +1,109 @@
package cors
import (
"net/http"
"strconv"
"strings"
"time"
)
type settings struct {
allowAllOrigins bool
allowedOriginFunc func(string) bool
allowedOrigins []string
allowedMethods []string
allowedHeaders []string
exposedHeaders []string
normalHeaders http.Header
preflightHeaders http.Header
}
func newSettings(c Config) *settings {
if err := c.Validate(); err != nil {
panic(err.Error())
}
return &settings{
allowedOriginFunc: c.AllowOriginFunc,
allowAllOrigins: c.AllowAllOrigins,
allowedOrigins: c.AllowedOrigins,
allowedMethods: distinct(c.AllowedMethods),
allowedHeaders: distinct(c.AllowedHeaders),
normalHeaders: generateNormalHeaders(c),
preflightHeaders: generatePreflightHeaders(c),
}
}
func (c *settings) validateOrigin(origin string) (string, bool) {
if c.allowAllOrigins {
return "*", true
}
if c.allowedOriginFunc != nil {
return origin, c.allowedOriginFunc(origin)
}
for _, value := range c.allowedOrigins {
if value == origin {
return origin, true
}
}
return "", false
}
func (c *settings) validateMethod(method string) bool {
// TODO!!!
return true
}
func (c *settings) validateHeader(header string) bool {
// TODO!!!
return true
}
func generateNormalHeaders(c Config) http.Header {
headers := make(http.Header)
if c.AllowCredentials {
headers.Set("Access-Control-Allow-Credentials", "true")
}
if len(c.ExposedHeaders) > 0 {
headers.Set("Access-Control-Expose-Headers", strings.Join(c.ExposedHeaders, ", "))
}
return headers
}
func generatePreflightHeaders(c Config) http.Header {
headers := make(http.Header)
if c.AllowCredentials {
headers.Set("Access-Control-Allow-Credentials", "true")
}
if len(c.AllowedMethods) > 0 {
headers.Set("Access-Control-Allow-Methods", strings.Join(c.AllowedMethods, ", "))
}
if len(c.AllowedHeaders) > 0 {
headers.Set("Access-Control-Allow-Headers", strings.Join(c.AllowedHeaders, ", "))
}
if c.MaxAge > time.Duration(0) {
headers.Set("Access-Control-Max-Age", strconv.FormatInt(int64(c.MaxAge/time.Second), 10))
}
return headers
}
func distinct(s []string) []string {
m := map[string]bool{}
for _, v := range s {
if _, seen := m[v]; !seen {
s[len(m)] = v
m[v] = true
}
}
return s[:len(m)]
}
func parse(content string) []string {
if len(content) == 0 {
return nil
}
parts := strings.Split(content, ",")
for i := 0; i < len(parts); i++ {
parts[i] = strings.TrimSpace(parts[i])
}
return parts
}

145
vendor/github.com/gin-gonic/contrib/cors/cors.go generated vendored Normal file
View File

@@ -0,0 +1,145 @@
package cors
import (
"errors"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
)
type Config struct {
AbortOnError bool
AllowAllOrigins bool
// AllowedOrigins is a list of origins a cross-domain request can be executed from.
// If the special "*" value is present in the list, all origins will be allowed.
// Default value is ["*"]
AllowedOrigins []string
// AllowOriginFunc is a custom function to validate the origin. It take the origin
// as argument and returns true if allowed or false otherwise. If this option is
// set, the content of AllowedOrigins is ignored.
AllowOriginFunc func(origin string) bool
// AllowedMethods is a list of methods the client is allowed to use with
// cross-domain requests. Default value is simple methods (GET and POST)
AllowedMethods []string
// AllowedHeaders is list of non simple headers the client is allowed to use with
// cross-domain requests.
// If the special "*" value is present in the list, all headers will be allowed.
// Default value is [] but "Origin" is always appended to the list.
AllowedHeaders []string
// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
// API specification
ExposedHeaders []string
// AllowCredentials indicates whether the request can include user credentials like
// cookies, HTTP authentication or client side SSL certificates.
AllowCredentials bool
// MaxAge indicates how long (in seconds) the results of a preflight request
// can be cached
MaxAge time.Duration
}
func (c *Config) AddAllowedMethods(methods ...string) {
c.AllowedMethods = append(c.AllowedMethods, methods...)
}
func (c *Config) AddAllowedHeaders(headers ...string) {
c.AllowedHeaders = append(c.AllowedHeaders, headers...)
}
func (c *Config) AddExposedHeaders(headers ...string) {
c.ExposedHeaders = append(c.ExposedHeaders, headers...)
}
func (c Config) Validate() error {
if c.AllowAllOrigins && (c.AllowOriginFunc != nil || len(c.AllowedOrigins) > 0) {
return errors.New("conflict settings: all origins are allowed. AllowOriginFunc or AllowedOrigins is not needed")
}
if !c.AllowAllOrigins && c.AllowOriginFunc == nil && len(c.AllowedOrigins) == 0 {
return errors.New("conflict settings: all origins disabled")
}
if c.AllowOriginFunc != nil && len(c.AllowedOrigins) > 0 {
return errors.New("conflict settings: if a allow origin func is provided, AllowedOrigins is not needed")
}
for _, origin := range c.AllowedOrigins {
if !strings.HasPrefix(origin, "http://") && !strings.HasPrefix(origin, "https://") {
return errors.New("bad origin: origins must include http:// or https://")
}
}
return nil
}
var defaultConfig = Config{
AbortOnError: false,
AllowAllOrigins: true,
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "HEAD"},
AllowedHeaders: []string{"Content-Type"},
//ExposedHeaders: "",
AllowCredentials: false,
MaxAge: 12 * time.Hour,
}
func DefaultConfig() Config {
cp := defaultConfig
return cp
}
func Default() gin.HandlerFunc {
return New(defaultConfig)
}
func New(config Config) gin.HandlerFunc {
s := newSettings(config)
// Algorithm based in http://www.html5rocks.com/static/images/cors_server_flowchart.png
return func(c *gin.Context) {
origin := c.Request.Header.Get("Origin")
if len(origin) == 0 {
return
}
origin, valid := s.validateOrigin(origin)
if valid {
if c.Request.Method == "OPTIONS" {
valid = handlePreflight(c, s)
} else {
valid = handleNormal(c, s)
}
}
if !valid {
if config.AbortOnError {
c.AbortWithStatus(http.StatusForbidden)
}
return
}
c.Header("Access-Control-Allow-Origin", origin)
}
}
func handlePreflight(c *gin.Context, s *settings) bool {
c.AbortWithStatus(200)
if !s.validateMethod(c.Request.Header.Get("Access-Control-Request-Method")) {
return false
}
if !s.validateHeader(c.Request.Header.Get("Access-Control-Request-Header")) {
return false
}
for key, value := range s.preflightHeaders {
c.Writer.Header()[key] = value
}
return true
}
func handleNormal(c *gin.Context, s *settings) bool {
for key, value := range s.normalHeaders {
c.Writer.Header()[key] = value
}
return true
}

104
vendor/github.com/gin-gonic/contrib/cors/cors_test.go generated vendored Normal file
View File

@@ -0,0 +1,104 @@
package cors
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
req, _ := http.NewRequest(method, path, nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
return w
}
func TestBadConfig(t *testing.T) {
assert.Panics(t, func() { New(Config{}) })
assert.Panics(t, func() {
New(Config{
AllowAllOrigins: true,
AllowedOrigins: []string{"http://google.com"},
})
})
assert.Panics(t, func() {
New(Config{
AllowAllOrigins: true,
AllowOriginFunc: func(origin string) bool { return false },
})
})
assert.Panics(t, func() {
New(Config{
AllowedOrigins: []string{"http://google.com"},
AllowOriginFunc: func(origin string) bool { return false },
})
})
assert.Panics(t, func() {
New(Config{
AllowedOrigins: []string{"google.com"},
})
})
}
func TestDeny0(t *testing.T) {
called := false
router := gin.Default()
router.Use(New(Config{
AllowedOrigins: []string{"http://example.com"},
}))
router.GET("/", func(c *gin.Context) {
called = true
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/", nil)
req.Header.Set("Origin", "https://example.com")
router.ServeHTTP(w, req)
assert.True(t, called)
assert.NotContains(t, w.Header(), "Access-Control")
}
func TestDenyAbortOnError(t *testing.T) {
called := false
router := gin.Default()
router.Use(New(Config{
AbortOnError: true,
AllowedOrigins: []string{"http://example.com"},
}))
router.GET("/", func(c *gin.Context) {
called = true
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/", nil)
req.Header.Set("Origin", "https://example.com")
router.ServeHTTP(w, req)
assert.False(t, called)
assert.NotContains(t, w.Header(), "Access-Control")
}
func TestDeny2(t *testing.T) {
}
func TestDeny3(t *testing.T) {
}
func TestPasses0(t *testing.T) {
}
func TestPasses1(t *testing.T) {
}
func TestPasses2(t *testing.T) {
}

27
vendor/github.com/gin-gonic/contrib/expvar/README.md generated vendored Normal file
View File

@@ -0,0 +1,27 @@
# expvar for gin
## EOL-warning
**This package has been abandoned on 2016-12-15. Please use [gin-contrib/expvar](https://github.com/gin-contrib/expvar) instead.**
```go
package main
import "github.com/gin-gonic/gin"
import "github.com/gin-gonic/contrib/expvar"
func main() {
router := gin.Default()
router.GET("/debug/vars", expvar.Handler())
router.Run(":8080")
}
```
Request: `http://localhost:8080/debug/vars`
```json
{
"cmdline": ["/var/folders/zg/q__7tncn7kxc34pc3j0_v7rc0000gn/T/go-build115008999/command-line-arguments/_obj/exe/main"],
"memstats": {"Alloc":406968,"TotalAlloc":3025088,"Sys":3999992,"Lookups":15,"Mallocs":10405,"Frees":9228,"HeapAlloc":406968,"HeapSys":1916928,"HeapIdle":1097728,"HeapInuse":819200,"HeapReleased":0,"HeapObjects":1177,"StackInuse":180224,"StackSys":180224,"MSpanInuse":7904,"MSpanSys":16384,"MCacheInuse":1200,"MCacheSys":16384,"BuckHashSys":1441424,"GCSys":137622,"OtherSys":291026,"NextGC":578160,"LastGC":1432428478423798618,"PauseTotalNs":4326675,"PauseNs":[105780,76617,91326,115727,195752,249831,554025,485129,344607,416552,400537,424639,463089,403064,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"PauseEnd":[1432428359211210066,1432428359211415512,1432428359211821428,1432428359212452447,1432428359212906768,1432428359214282772,1432428381213398837,1432428383977712300,1432428452748952359,1432428470574839824,1432428472452814302,1432428474379491025,1432428476329036668,1432428478423798444,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"NumGC":14,"EnableGC":true,"DebugGC":false,"BySize":[{"Size":0,"Mallocs":0,"Frees":0},{"Size":8,"Mallocs":258,"Frees":237},{"Size":16,"Mallocs":4125,"Frees":3670},{"Size":32,"Mallocs":765,"Frees":652},{"Size":48,"Mallocs":495,"Frees":367},{"Size":64,"Mallocs":305,"Frees":274},{"Size":80,"Mallocs":37,"Frees":24},{"Size":96,"Mallocs":32,"Frees":25},{"Size":112,"Mallocs":713,"Frees":569},{"Size":128,"Mallocs":283,"Frees":259},{"Size":144,"Mallocs":91,"Frees":85},{"Size":160,"Mallocs":139,"Frees":112},{"Size":176,"Mallocs":349,"Frees":315},{"Size":192,"Mallocs":0,"Frees":0},{"Size":208,"Mallocs":223,"Frees":196},{"Size":224,"Mallocs":2,"Frees":2},{"Size":240,"Mallocs":86,"Frees":80},{"Size":256,"Mallocs":21,"Frees":18},{"Size":288,"Mallocs":130,"Frees":104},{"Size":320,"Mallocs":19,"Frees":15},{"Size":352,"Mallocs":278,"Frees":259},{"Size":384,"Mallocs":5,"Frees":5},{"Size":416,"Mallocs":17,"Frees":10},{"Size":448,"Mallocs":0,"Frees":0},{"Size":480,"Mallocs":2,"Frees":1},{"Size":512,"Mallocs":16,"Frees":12},{"Size":576,"Mallocs":92,"Frees":83},{"Size":640,"Mallocs":12,"Frees":7},{"Size":704,"Mallocs":2,"Frees":2},{"Size":768,"Mallocs":0,"Frees":0},{"Size":896,"Mallocs":15,"Frees":12},{"Size":1024,"Mallocs":10,"Frees":8},{"Size":1152,"Mallocs":88,"Frees":82},{"Size":1280,"Mallocs":7,"Frees":6},{"Size":1408,"Mallocs":2,"Frees":1},{"Size":1536,"Mallocs":0,"Frees":0},{"Size":1664,"Mallocs":9,"Frees":4},{"Size":2048,"Mallocs":10,"Frees":9},{"Size":2304,"Mallocs":88,"Frees":82},{"Size":2560,"Mallocs":6,"Frees":5},{"Size":2816,"Mallocs":2,"Frees":1},{"Size":3072,"Mallocs":1,"Frees":1},{"Size":3328,"Mallocs":4,"Frees":1},{"Size":4096,"Mallocs":172,"Frees":167},{"Size":4608,"Mallocs":93,"Frees":81},{"Size":5376,"Mallocs":7,"Frees":0},{"Size":6144,"Mallocs":87,"Frees":81},{"Size":6400,"Mallocs":0,"Frees":0},{"Size":6656,"Mallocs":1,"Frees":0},{"Size":6912,"Mallocs":0,"Frees":0},{"Size":8192,"Mallocs":6,"Frees":6},{"Size":8448,"Mallocs":0,"Frees":0},{"Size":8704,"Mallocs":1,"Frees":1},{"Size":9472,"Mallocs":0,"Frees":0},{"Size":10496,"Mallocs":0,"Frees":0},{"Size":12288,"Mallocs":1,"Frees":1},{"Size":13568,"Mallocs":0,"Frees":0},{"Size":14080,"Mallocs":0,"Frees":0},{"Size":16384,"Mallocs":0,"Frees":0},{"Size":16640,"Mallocs":0,"Frees":0},{"Size":17664,"Mallocs":1,"Frees":0}]}
}
```

26
vendor/github.com/gin-gonic/contrib/expvar/expvar.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
package expvar
import (
"expvar"
"fmt"
"github.com/gin-gonic/gin"
)
func Handler() gin.HandlerFunc {
return func(c *gin.Context) {
w := c.Writer
c.Header("Content-Type", "application/json; charset=utf-8")
w.Write([]byte("{\n"))
first := true
expvar.Do(func(kv expvar.KeyValue) {
if !first {
w.Write([]byte(",\n"))
}
first = false
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
})
w.Write([]byte("\n}\n"))
c.AbortWithStatus(200)
}
}

View File

@@ -0,0 +1,10 @@
{
"ImportPath": "github.com/gin-gonic/contrib/ginrus",
"GoVersion": "go1.3",
"Deps": [
{
"ImportPath": "github.com/gin-gonic/gin",
"Rev": "ac0ad2fed865d40a0adc1ac3ccaadc3acff5db4b"
}
]
}

View File

@@ -0,0 +1,38 @@
package main
import (
"fmt"
"os"
"time"
"github.com/gin-gonic/contrib/ginrus"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
func main() {
r := gin.New()
// Add a ginrus middleware, which:
// - Logs all requests, like a combined access and error log.
// - Logs to stdout.
// - RFC3339 with UTC time format.
r.Use(ginrus.Ginrus(logrus.StandardLogger(), time.RFC3339, true))
// Add similar middleware, but:
// - Only logs requests with errors, like an error log.
// - Logs to stderr instead of stdout.
// - Local time zone instead of UTC.
logger := logrus.New()
logger.Level = logrus.ErrorLevel
logger.Out = os.Stderr
r.Use(ginrus.Ginrus(logger, time.RFC3339, false))
// Example ping request.
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}

55
vendor/github.com/gin-gonic/contrib/ginrus/ginrus.go generated vendored Normal file
View File

@@ -0,0 +1,55 @@
// Package ginrus provides log handling using logrus package.
//
// Based on github.com/stephenmuss/ginerus but adds more options.
package ginrus
import (
"time"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
type loggerEntryWithFields interface {
WithFields(fields logrus.Fields) *logrus.Entry
}
// Ginrus returns a gin.HandlerFunc (middleware) that logs requests using logrus.
//
// Requests with errors are logged using logrus.Error().
// Requests without errors are logged using logrus.Info().
//
// It receives:
// 1. A time package format string (e.g. time.RFC3339).
// 2. A boolean stating whether to use UTC time zone or local.
func Ginrus(logger loggerEntryWithFields, timeFormat string, utc bool) gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
// some evil middlewares modify this values
path := c.Request.URL.Path
c.Next()
end := time.Now()
latency := end.Sub(start)
if utc {
end = end.UTC()
}
entry := logger.WithFields(logrus.Fields{
"status": c.Writer.Status(),
"method": c.Request.Method,
"path": path,
"ip": c.ClientIP(),
"latency": latency,
"user-agent": c.Request.UserAgent(),
"time": end.Format(timeFormat),
})
if len(c.Errors) > 0 {
// Append error field if this is an erroneous request.
entry.Error(c.Errors.String())
} else {
entry.Info()
}
}
}

View File

@@ -0,0 +1,10 @@
{
"ImportPath": "github.com/gin-gonic/contrib/gzip",
"GoVersion": "go1.3",
"Deps": [
{
"ImportPath": "github.com/gin-gonic/gin",
"Rev": "ac0ad2fed865d40a0adc1ac3ccaadc3acff5db4b"
}
]
}

5
vendor/github.com/gin-gonic/contrib/gzip/README.md generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# gzip
## EOL-warning
**This package has been abandoned on 2016-12-07. Please use [gin-contrib/gzip](https://github.com/gin-contrib/gzip) instead.**

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"github.com/gin-gonic/contrib/gzip"
"github.com/gin-gonic/gin"
"time"
)
func main() {
r := gin.Default()
r.Use(gzip.Gzip(gzip.DefaultCompression))
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}

68
vendor/github.com/gin-gonic/contrib/gzip/gzip.go generated vendored Normal file
View File

@@ -0,0 +1,68 @@
package gzip
import (
"compress/gzip"
"net/http"
"path/filepath"
"strings"
"github.com/gin-gonic/gin"
)
const (
BestCompression = gzip.BestCompression
BestSpeed = gzip.BestSpeed
DefaultCompression = gzip.DefaultCompression
NoCompression = gzip.NoCompression
)
func Gzip(level int) gin.HandlerFunc {
return func(c *gin.Context) {
if !shouldCompress(c.Request) {
return
}
gz, err := gzip.NewWriterLevel(c.Writer, level)
if err != nil {
return
}
c.Header("Content-Encoding", "gzip")
c.Header("Vary", "Accept-Encoding")
c.Writer = &gzipWriter{c.Writer, gz}
defer func() {
c.Header("Content-Length", "0")
gz.Close()
}()
c.Next()
}
}
type gzipWriter struct {
gin.ResponseWriter
writer *gzip.Writer
}
func (g *gzipWriter) WriteString(s string) (int, error) {
return g.writer.Write([]byte(s))
}
func (g *gzipWriter) Write(data []byte) (int, error) {
return g.writer.Write(data)
}
func shouldCompress(req *http.Request) bool {
if !strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") {
return false
}
extension := filepath.Ext(req.URL.Path)
if len(extension) < 4 { // fast path
return true
}
switch extension {
case ".png", ".gif", ".jpeg", ".jpg":
return false
default:
return true
}
}

81
vendor/github.com/gin-gonic/contrib/gzip/gzip_test.go generated vendored Normal file
View File

@@ -0,0 +1,81 @@
package gzip
import (
"compress/gzip"
"io/ioutil"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
const (
testResponse = "Gzip Test Response "
)
func newServer() *gin.Engine {
router := gin.Default()
router.Use(Gzip(DefaultCompression))
router.GET("/", func(c *gin.Context) {
c.Header("Content-Length", strconv.Itoa(len(testResponse)))
c.String(200, testResponse)
})
return router
}
func TestGzip(t *testing.T) {
req, _ := http.NewRequest("GET", "/", nil)
req.Header.Add("Accept-Encoding", "gzip")
w := httptest.NewRecorder()
r := newServer()
r.ServeHTTP(w, req)
assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Header().Get("Content-Encoding"), "gzip")
assert.Equal(t, w.Header().Get("Vary"), "Accept-Encoding")
assert.Equal(t, w.Header().Get("Content-Length"), "0")
assert.NotEqual(t, w.Body.Len(), 19)
gr, err := gzip.NewReader(w.Body)
assert.NoError(t, err)
defer gr.Close()
body, _ := ioutil.ReadAll(gr)
assert.Equal(t, string(body), testResponse)
}
func TestGzipPNG(t *testing.T) {
req, _ := http.NewRequest("GET", "/image.png", nil)
req.Header.Add("Accept-Encoding", "gzip")
router := gin.New()
router.Use(Gzip(DefaultCompression))
router.GET("/image.png", func(c *gin.Context) {
c.String(200, "this is a PNG!")
})
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Header().Get("Content-Encoding"), "")
assert.Equal(t, w.Header().Get("Vary"), "")
assert.Equal(t, w.Body.String(), "this is a PNG!")
}
func TestNoGzip(t *testing.T) {
req, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
r := newServer()
r.ServeHTTP(w, req)
assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Header().Get("Content-Encoding"), "")
assert.Equal(t, w.Header().Get("Content-Length"), "19")
assert.Equal(t, w.Body.String(), testResponse)
}

View File

@@ -0,0 +1,22 @@
{
"ImportPath": "github.com/gin-gonic/contrib/jwt",
"GoVersion": "go1.3",
"Deps": [
{
"ImportPath": "github.com/dgrijalva/jwt-go",
"Rev": "5ca80149b9d3f8b863af0e2bb6742e608603bd99"
},
{
"ImportPath": "github.com/gin-gonic/gin",
"Rev": "ac0ad2fed865d40a0adc1ac3ccaadc3acff5db4b"
},
{
"ImportPath": "github.com/jacobsa/oglematchers",
"Rev": "3ecefc49db07722beca986d9bb71ddd026b133f0"
},
{
"ImportPath": "github.com/smartystreets/goconvey/convey",
"Rev": "958443eebb772fc6c1dcc2a44cdc6a59e1b3ff0d"
}
]
}

83
vendor/github.com/gin-gonic/contrib/jwt/README.md generated vendored Normal file
View File

@@ -0,0 +1,83 @@
JWT middleware for go gonic.
JSON Web Token (JWT) more information: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html
EDIT: Below is the test for [christopherL91/Go-API](https://github.com/christopherL91/Go-API)
```go
package jwt_test
import (
"encoding/json"
. "github.com/smartystreets/goconvey/convey"
"io/ioutil"
"net/http"
"strings"
"testing"
)
type User struct {
Username string `json:"username"`
Password string `json:"password"`
}
type Response struct {
Token string `json:"token"`
}
func createNewsUser(username, password string) *User {
return &User{username, password}
}
func TestLogin(t *testing.T) {
Convey("Should be able to login", t, func() {
user := createNewsUser("jonas", "1234")
jsondata, _ := json.Marshal(user)
post_data := strings.NewReader(string(jsondata))
req, _ := http.NewRequest("POST", "http://localhost:3000/api/login", post_data)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, _ := client.Do(req)
So(res.StatusCode, ShouldEqual, 200)
Convey("Should be able to parse body", func() {
body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
So(err, ShouldBeNil)
Convey("Should be able to get json back", func() {
responseData := new(Response)
err := json.Unmarshal(body, responseData)
So(err, ShouldBeNil)
Convey("Should be able to be authorized", func() {
token := responseData.Token
req, _ := http.NewRequest("GET", "http://localhost:3000/api/auth/testAuth", nil)
req.Header.Set("Authorization", "Bearer "+token)
client = &http.Client{}
res, _ := client.Do(req)
So(res.StatusCode, ShouldEqual, 200)
})
})
})
})
Convey("Should not be able to login with false credentials", t, func() {
user := createNewsUser("jnwfkjnkfneknvjwenv", "wenknfkwnfknfknkfjnwkfenw")
jsondata, _ := json.Marshal(user)
post_data := strings.NewReader(string(jsondata))
req, _ := http.NewRequest("POST", "http://localhost:3000/api/login", post_data)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, _ := client.Do(req)
So(res.StatusCode, ShouldEqual, 401)
})
Convey("Should not be able to authorize with false credentials", t, func() {
token := ""
req, _ := http.NewRequest("GET", "http://localhost:3000/api/auth/testAuth", nil)
req.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
res, _ := client.Do(req)
So(res.StatusCode, ShouldEqual, 401)
})
}
```

View File

@@ -0,0 +1,49 @@
package main
import (
"time"
jwt_lib "github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/contrib/jwt"
"github.com/gin-gonic/gin"
)
var (
mysupersecretpassword = "unicornsAreAwesome"
)
func main() {
r := gin.Default()
public := r.Group("/api")
public.GET("/", func(c *gin.Context) {
// Create the token
token := jwt_lib.New(jwt_lib.GetSigningMethod("HS256"))
// Set some claims
token.Claims = jwt_lib.MapClaims{
"Id": "Christopher",
"exp": time.Now().Add(time.Hour * 1).Unix(),
}
// Sign and get the complete encoded token as a string
tokenString, err := token.SignedString([]byte(mysupersecretpassword))
if err != nil {
c.JSON(500, gin.H{"message": "Could not generate token"})
}
c.JSON(200, gin.H{"token": tokenString})
})
private := r.Group("/api/private")
private.Use(jwt.Auth(mysupersecretpassword))
/*
Set this header in your request to get here.
Authorization: Bearer `token`
*/
private.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Hello from private"})
})
r.Run("localhost:8080")
}

20
vendor/github.com/gin-gonic/contrib/jwt/jwt.go generated vendored Normal file
View File

@@ -0,0 +1,20 @@
package jwt
import (
jwt_lib "github.com/dgrijalva/jwt-go"
"github.com/dgrijalva/jwt-go/request"
"github.com/gin-gonic/gin"
)
func Auth(secret string) gin.HandlerFunc {
return func(c *gin.Context) {
_, err := request.ParseFromRequest(c.Request, request.OAuth2Extractor, func(token *jwt_lib.Token) (interface{}, error) {
b := ([]byte(secret))
return b, nil
})
if err != nil {
c.AbortWithError(401, err)
}
}
}

View File

@@ -0,0 +1,29 @@
package newrelic
import (
"time"
"github.com/gin-gonic/gin"
metrics "github.com/yvasiyarov/go-metrics"
"github.com/yvasiyarov/gorelic"
)
var agent *gorelic.Agent
func NewRelic(license string, appname string, verbose bool) gin.HandlerFunc {
agent = gorelic.NewAgent()
agent.NewrelicLicense = license
agent.HTTPTimer = metrics.NewTimer()
agent.CollectHTTPStat = true
agent.Verbose = verbose
agent.NewrelicName = appname
agent.Run()
return func(c *gin.Context) {
startTime := time.Now()
c.Next()
agent.HTTPTimer.UpdateSince(startTime)
}
}

View File

@@ -0,0 +1,86 @@
## EOL-warning
**This package has been abandoned on 2016-12-13. Please use [gin-contrib/multitemplate](https://github.com/gin-contrib/multitemplate) instead.**
This is a custom HTML render to support multi templates, ie. more than one `*template.Template`.
#Simple example
```go
package main
import (
"html/template"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/contrib/renders/multitemplate"
)
func main() {
router := gin.Default()
router.HTMLRender = createMyRender()
router.GET("/", func(c *gin.Context) {
c.HTML(200, "index", data)
})
router.Run(":8080")
}
func createMyRender() multitemplate.Render {
r := multitemplate.New()
r.AddFromFiles("index", "base.html", "base.html")
r.AddFromFiles("article", "base.html", "article.html")
r.AddFromFiles("login", "base.html", "login.html")
r.AddFromFiles("dashboard", "base.html", "dashboard.html")
return r
}
```
##Advanced example
[https://elithrar.github.io/article/approximating-html-template-inheritance/](https://elithrar.github.io/article/approximating-html-template-inheritance/)
```go
package main
import (
"html/template"
"path/filepath"
"github.com/gin-gonic/contrib/renders/multitemplate"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.HTMLRender = loadTemplates("./templates")
router.GET("/", func(c *gin.Context) {
c.HTML(200, "index.tmpl", gin.H{
"title": "Welcome!",
})
})
router.Run(":8080")
}
func loadTemplates(templatesDir string) multitemplate.Render {
r := multitemplate.New()
layouts, err := filepath.Glob(templatesDir + "layouts/*.tmpl")
if err != nil {
panic(err.Error())
}
includes, err := filepath.Glob(templatesDir + "includes/*.tmpl")
if err != nil {
panic(err.Error())
}
// Generate our templates map from our layouts/ and includes/ directories
for _, layout := range layouts {
files := append(includes, layout)
r.Add(filepath.Base(layout), template.Must(template.ParseFiles(files...)))
}
return r
}
```

View File

@@ -0,0 +1,50 @@
package multitemplate
import (
"html/template"
"github.com/gin-gonic/gin/render"
)
type Render map[string]*template.Template
var _ render.HTMLRender = Render{}
func New() Render {
return make(Render)
}
func (r Render) Add(name string, tmpl *template.Template) {
if tmpl == nil {
panic("template can not be nil")
}
if len(name) == 0 {
panic("template name cannot be empty")
}
r[name] = tmpl
}
func (r Render) AddFromFiles(name string, files ...string) *template.Template {
tmpl := template.Must(template.ParseFiles(files...))
r.Add(name, tmpl)
return tmpl
}
func (r Render) AddFromGlob(name, glob string) *template.Template {
tmpl := template.Must(template.ParseGlob(glob))
r.Add(name, tmpl)
return tmpl
}
func (r *Render) AddFromString(name, templateString string) *template.Template {
tmpl := template.Must(template.New("").Parse(templateString))
r.Add(name, tmpl)
return tmpl
}
func (r Render) Instance(name string, data interface{}) render.Render {
return render.HTML{
Template: r[name],
Data: data,
}
}

46
vendor/github.com/gin-gonic/contrib/rest/rest.go generated vendored Normal file
View File

@@ -0,0 +1,46 @@
package rest
import (
"github.com/gin-gonic/gin"
)
// All of the methods are the same type as HandlerFunc
// if you don't want to support any methods of CRUD, then don't implement it
type CreateSupported interface {
CreateHandler(*gin.Context)
}
type ListSupported interface {
ListHandler(*gin.Context)
}
type TakeSupported interface {
TakeHandler(*gin.Context)
}
type UpdateSupported interface {
UpdateHandler(*gin.Context)
}
type DeleteSupported interface {
DeleteHandler(*gin.Context)
}
// It defines
// POST: /path
// GET: /path
// PUT: /path/:id
// POST: /path/:id
func CRUD(group *gin.RouterGroup, path string, resource interface{}) {
if resource, ok := resource.(CreateSupported); ok {
group.POST(path, resource.CreateHandler)
}
if resource, ok := resource.(ListSupported); ok {
group.GET(path, resource.ListHandler)
}
if resource, ok := resource.(TakeSupported); ok {
group.GET(path+"/:id", resource.TakeHandler)
}
if resource, ok := resource.(UpdateSupported); ok {
group.PUT(path+"/:id", resource.UpdateHandler)
}
if resource, ok := resource.(DeleteSupported); ok {
group.DELETE(path+"/:id", resource.DeleteHandler)
}
}

View File

@@ -0,0 +1,10 @@
{
"ImportPath": "github.com/gin-gonic/contrib/secure",
"GoVersion": "go1.3",
"Deps": [
{
"ImportPath": "github.com/gin-gonic/gin",
"Rev": "ac0ad2fed865d40a0adc1ac3ccaadc3acff5db4b"
}
]
}

View File

@@ -0,0 +1,32 @@
package main
import (
"fmt"
"github.com/gin-gonic/contrib/secure"
"github.com/gin-gonic/gin"
"time"
)
func main() {
r := gin.Default()
r.Use(secure.Secure(secure.Options{
AllowedHosts: []string{"example.com", "ssl.example.com"},
SSLRedirect: true,
SSLHost: "ssl.example.com",
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
STSSeconds: 315360000,
STSIncludeSubdomains: true,
FrameDeny: true,
ContentTypeNosniff: true,
BrowserXssFilter: true,
ContentSecurityPolicy: "default-src 'self'",
}))
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong "+fmt.Sprint(time.Now().Unix()))
})
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}

179
vendor/github.com/gin-gonic/contrib/secure/secure.go generated vendored Normal file
View File

@@ -0,0 +1,179 @@
package secure
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
const (
stsHeader = "Strict-Transport-Security"
stsSubdomainString = "; includeSubdomains"
frameOptionsHeader = "X-Frame-Options"
frameOptionsValue = "DENY"
contentTypeHeader = "X-Content-Type-Options"
contentTypeValue = "nosniff"
xssProtectionHeader = "X-XSS-Protection"
xssProtectionValue = "1; mode=block"
cspHeader = "Content-Security-Policy"
)
func defaultBadHostHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Bad Host", http.StatusInternalServerError)
}
// Options is a struct for specifying configuration options for the secure.Secure middleware.
type Options struct {
// AllowedHosts is a list of fully qualified domain names that are allowed. Default is empty list, which allows any and all host names.
AllowedHosts []string
// If SSLRedirect is set to true, then only allow https requests. Default is false.
SSLRedirect bool
// If SSLTemporaryRedirect is true, the a 302 will be used while redirecting. Default is false (301).
SSLTemporaryRedirect bool
// SSLHost is the host name that is used to redirect http requests to https. Default is "", which indicates to use the same host.
SSLHost string
// SSLProxyHeaders is set of header keys with associated values that would indicate a valid https request. Useful when using Nginx: `map[string]string{"X-Forwarded-Proto": "https"}`. Default is blank map.
SSLProxyHeaders map[string]string
// STSSeconds is the max-age of the Strict-Transport-Security header. Default is 0, which would NOT include the header.
STSSeconds int64
// If STSIncludeSubdomains is set to true, the `includeSubdomains` will be appended to the Strict-Transport-Security header. Default is false.
STSIncludeSubdomains bool
// If FrameDeny is set to true, adds the X-Frame-Options header with the value of `DENY`. Default is false.
FrameDeny bool
// CustomFrameOptionsValue allows the X-Frame-Options header value to be set with a custom value. This overrides the FrameDeny option.
CustomFrameOptionsValue string
// If ContentTypeNosniff is true, adds the X-Content-Type-Options header with the value `nosniff`. Default is false.
ContentTypeNosniff bool
// If BrowserXssFilter is true, adds the X-XSS-Protection header with the value `1; mode=block`. Default is false.
BrowserXssFilter bool
// ContentSecurityPolicy allows the Content-Security-Policy header value to be set with a custom value. Default is "".
ContentSecurityPolicy string
// When developing, the AllowedHosts, SSL, and STS options can cause some unwanted effects. Usually testing happens on http, not https, and on localhost, not your production domain... so set this to true for dev environment.
// If you would like your development environment to mimic production with complete Host blocking, SSL redirects, and STS headers, leave this as false. Default if false.
IsDevelopment bool
// Handlers for when an error occurs (ie bad host).
BadHostHandler http.Handler
}
// Secure is a middleware that helps setup a few basic security features. A single secure.Options struct can be
// provided to configure which features should be enabled, and the ability to override a few of the default values.
type secure struct {
// Customize Secure with an Options struct.
opt Options
}
// Constructs a new Secure instance with supplied options.
func New(options Options) *secure {
if options.BadHostHandler == nil {
options.BadHostHandler = http.HandlerFunc(defaultBadHostHandler)
}
return &secure{
opt: options,
}
}
func (s *secure) process(w http.ResponseWriter, r *http.Request) error {
// Allowed hosts check.
if len(s.opt.AllowedHosts) > 0 && !s.opt.IsDevelopment {
isGoodHost := false
for _, allowedHost := range s.opt.AllowedHosts {
if strings.EqualFold(allowedHost, r.Host) {
isGoodHost = true
break
}
}
if !isGoodHost {
s.opt.BadHostHandler.ServeHTTP(w, r)
return fmt.Errorf("Bad host name: %s", r.Host)
}
}
// SSL check.
if s.opt.SSLRedirect && s.opt.IsDevelopment == false {
isSSL := false
if strings.EqualFold(r.URL.Scheme, "https") || r.TLS != nil {
isSSL = true
} else {
for k, v := range s.opt.SSLProxyHeaders {
if r.Header.Get(k) == v {
isSSL = true
break
}
}
}
if isSSL == false {
url := r.URL
url.Scheme = "https"
url.Host = r.Host
if len(s.opt.SSLHost) > 0 {
url.Host = s.opt.SSLHost
}
status := http.StatusMovedPermanently
if s.opt.SSLTemporaryRedirect {
status = http.StatusTemporaryRedirect
}
http.Redirect(w, r, url.String(), status)
return fmt.Errorf("Redirecting to HTTPS")
}
}
// Strict Transport Security header.
if s.opt.STSSeconds != 0 && !s.opt.IsDevelopment {
stsSub := ""
if s.opt.STSIncludeSubdomains {
stsSub = stsSubdomainString
}
w.Header().Add(stsHeader, fmt.Sprintf("max-age=%d%s", s.opt.STSSeconds, stsSub))
}
// Frame Options header.
if len(s.opt.CustomFrameOptionsValue) > 0 {
w.Header().Add(frameOptionsHeader, s.opt.CustomFrameOptionsValue)
} else if s.opt.FrameDeny {
w.Header().Add(frameOptionsHeader, frameOptionsValue)
}
// Content Type Options header.
if s.opt.ContentTypeNosniff {
w.Header().Add(contentTypeHeader, contentTypeValue)
}
// XSS Protection header.
if s.opt.BrowserXssFilter {
w.Header().Add(xssProtectionHeader, xssProtectionValue)
}
// Content Security Policy header.
if len(s.opt.ContentSecurityPolicy) > 0 {
w.Header().Add(cspHeader, s.opt.ContentSecurityPolicy)
}
return nil
}
func Secure(options Options) gin.HandlerFunc {
s := New(options)
return func(c *gin.Context) {
err := s.process(c.Writer, c.Request)
if err != nil {
if c.Writer.Written() {
c.AbortWithStatus(c.Writer.Status())
} else {
c.AbortWithError(http.StatusInternalServerError, err)
}
}
}
}

View File

@@ -0,0 +1,470 @@
package secure
import (
"github.com/gin-gonic/gin"
"net/http"
"net/http/httptest"
"reflect"
"testing"
)
const (
testResponse = "bar"
)
func newServer(options Options) *gin.Engine {
r := gin.Default()
r.Use(Secure(options))
r.GET("/foo", func(c *gin.Context) {
c.String(200, testResponse)
})
return r
}
func TestNoConfig(t *testing.T) {
s := newServer(Options{
// Intentionally left blank.
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Body.String(), "bar")
}
func TestNoAllowHosts(t *testing.T) {
s := newServer(Options{
AllowedHosts: []string{},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Body.String(), `bar`)
}
func TestGoodSingleAllowHosts(t *testing.T) {
s := newServer(Options{
AllowedHosts: []string{"www.example.com"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Body.String(), `bar`)
}
func TestBadSingleAllowHosts(t *testing.T) {
s := newServer(Options{
AllowedHosts: []string{"sub.example.com"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusInternalServerError)
}
func TestGoodMultipleAllowHosts(t *testing.T) {
s := newServer(Options{
AllowedHosts: []string{"www.example.com", "sub.example.com"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "sub.example.com"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Body.String(), `bar`)
}
func TestBadMultipleAllowHosts(t *testing.T) {
s := newServer(Options{
AllowedHosts: []string{"www.example.com", "sub.example.com"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www3.example.com"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusInternalServerError)
}
func TestAllowHostsInDevMode(t *testing.T) {
s := newServer(Options{
AllowedHosts: []string{"www.example.com", "sub.example.com"},
IsDevelopment: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www3.example.com"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
}
func TestBadHostHandler(t *testing.T) {
badHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "BadHost", http.StatusInternalServerError)
})
s := newServer(Options{
AllowedHosts: []string{"www.example.com", "sub.example.com"},
BadHostHandler: badHandler,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www3.example.com"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusInternalServerError)
// http.Error outputs a new line character with the response.
expect(t, res.Body.String(), "BadHost\n")
}
func TestSSL(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "https"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
}
func TestSSLInDevMode(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
IsDevelopment: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "http"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
}
func TestBasicSSL(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "http"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusMovedPermanently)
expect(t, res.Header().Get("Location"), "https://www.example.com/foo")
}
func TestBasicSSLWithHost(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
SSLHost: "secure.example.com",
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "http"
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusMovedPermanently)
expect(t, res.Header().Get("Location"), "https://secure.example.com/foo")
}
func TestBadProxySSL(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "http"
req.Header.Add("X-Forwarded-Proto", "https")
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusMovedPermanently)
expect(t, res.Header().Get("Location"), "https://www.example.com/foo")
}
func TestCustomProxySSL(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "http"
req.Header.Add("X-Forwarded-Proto", "https")
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
}
func TestCustomProxySSLInDevMode(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
IsDevelopment: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "http"
req.Header.Add("X-Forwarded-Proto", "http")
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
}
func TestCustomProxyAndHostSSL(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
SSLHost: "secure.example.com",
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "http"
req.Header.Add("X-Forwarded-Proto", "https")
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
}
func TestCustomBadProxyAndHostSSL(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "superman"},
SSLHost: "secure.example.com",
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "http"
req.Header.Add("X-Forwarded-Proto", "https")
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusMovedPermanently)
expect(t, res.Header().Get("Location"), "https://secure.example.com/foo")
}
func TestCustomBadProxyAndHostSSLWithTempRedirect(t *testing.T) {
s := newServer(Options{
SSLRedirect: true,
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "superman"},
SSLHost: "secure.example.com",
SSLTemporaryRedirect: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
req.Host = "www.example.com"
req.URL.Scheme = "http"
req.Header.Add("X-Forwarded-Proto", "https")
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusTemporaryRedirect)
expect(t, res.Header().Get("Location"), "https://secure.example.com/foo")
}
func TestStsHeader(t *testing.T) {
s := newServer(Options{
STSSeconds: 315360000,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("Strict-Transport-Security"), "max-age=315360000")
}
func TestStsHeaderInDevMode(t *testing.T) {
s := newServer(Options{
STSSeconds: 315360000,
IsDevelopment: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("Strict-Transport-Security"), "")
}
func TestStsHeaderWithSubdomain(t *testing.T) {
s := newServer(Options{
STSSeconds: 315360000,
STSIncludeSubdomains: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("Strict-Transport-Security"), "max-age=315360000; includeSubdomains")
}
func TestFrameDeny(t *testing.T) {
s := newServer(Options{
FrameDeny: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("X-Frame-Options"), "DENY")
}
func TestCustomFrameValue(t *testing.T) {
s := newServer(Options{
CustomFrameOptionsValue: "SAMEORIGIN",
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("X-Frame-Options"), "SAMEORIGIN")
}
func TestCustomFrameValueWithDeny(t *testing.T) {
s := newServer(Options{
FrameDeny: true,
CustomFrameOptionsValue: "SAMEORIGIN",
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("X-Frame-Options"), "SAMEORIGIN")
}
func TestContentNosniff(t *testing.T) {
s := newServer(Options{
ContentTypeNosniff: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("X-Content-Type-Options"), "nosniff")
}
func TestXSSProtection(t *testing.T) {
s := newServer(Options{
BrowserXssFilter: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("X-XSS-Protection"), "1; mode=block")
}
func TestCsp(t *testing.T) {
s := newServer(Options{
ContentSecurityPolicy: "default-src 'self'",
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("Content-Security-Policy"), "default-src 'self'")
}
func TestInlineSecure(t *testing.T) {
s := newServer(Options{
FrameDeny: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foo", nil)
s.ServeHTTP(res, req)
expect(t, res.Code, http.StatusOK)
expect(t, res.Header().Get("X-Frame-Options"), "DENY")
}
/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Errorf("Expected [%v] (type %v) - Got [%v] (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}

29
vendor/github.com/gin-gonic/contrib/sentry/README.md generated vendored Normal file
View File

@@ -0,0 +1,29 @@
# sentry
Middleware to integrate with [sentry](https://getsentry.com/) crash reporting. Middleware version of `raven.RecoveryHandler()`.
## EOL-warning
**This package has been abandoned on 2017-01-13. Please use [gin-contrib/sentry](https://github.com/gin-contrib/sentry) instead.**
## Example
```go
package main
import (
"github.com/getsentry/raven-go"
"github.com/gin-gonic/contrib/sentry"
"github.com/gin-gonic/gin"
)
func init() {
raven.SetDSN("https://<key>:<secret>@app.getsentry.com/<project>")
}
func main() {
r := gin.Default()
r.Use(sentry.Recovery(raven.DefaultClient, false))
// ...
r.Run(":8080")
}
```

44
vendor/github.com/gin-gonic/contrib/sentry/recovery.go generated vendored Normal file
View File

@@ -0,0 +1,44 @@
package sentry
import (
"errors"
"fmt"
"net/http"
"runtime/debug"
"github.com/getsentry/raven-go"
"github.com/gin-gonic/gin"
)
func Recovery(client *raven.Client, onlyCrashes bool) gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
flags := map[string]string{
"endpoint": c.Request.RequestURI,
}
if rval := recover(); rval != nil {
debug.PrintStack()
rvalStr := fmt.Sprint(rval)
packet := raven.NewPacket(rvalStr,
raven.NewException(errors.New(rvalStr), raven.NewStacktrace(2, 3, nil)),
raven.NewHttp(c.Request))
client.Capture(packet, flags)
c.AbortWithStatus(http.StatusInternalServerError)
}
if !onlyCrashes {
for _, item := range c.Errors {
packet := raven.NewPacket(item.Error(),
&raven.Message{
Message: item.Error(),
Params: []interface{}{item.Meta},
},
raven.NewHttp(c.Request))
client.Capture(packet, flags)
}
}
}()
c.Next()
}
}

View File

@@ -0,0 +1,18 @@
{
"ImportPath": "github.com/gin-gonic/contrib/sessions",
"GoVersion": "go1.3",
"Deps": [
{
"ImportPath": "github.com/boj/redistore",
"Rev": "0cd55584b172cefd31c4cb84e2904585d898c7b2"
},
{
"ImportPath": "github.com/gin-gonic/gin",
"Rev": "ac0ad2fed865d40a0adc1ac3ccaadc3acff5db4b"
},
{
"ImportPath": "github.com/gorilla/sessions",
"Rev": "f61c3ec2cf65d69e7efedfd4d060fe128882c951"
}
]
}

75
vendor/github.com/gin-gonic/contrib/sessions/README.md generated vendored Normal file
View File

@@ -0,0 +1,75 @@
# sessions
Gin middleware for session management with multi-backend support (currently cookie, Redis).
## EOL-warning
**This package has been abandoned on 2016-12-07. Please use [gin-contrib/sessions](https://github.com/gin-contrib/sessions) instead.**
## Examples
#### cookie-based
```go
package main
import (
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
store := sessions.NewCookieStore([]byte("secret"))
r.Use(sessions.Sessions("mysession", store))
r.GET("/incr", func(c *gin.Context) {
session := sessions.Default(c)
var count int
v := session.Get("count")
if v == nil {
count = 0
} else {
count = v.(int)
count += 1
}
session.Set("count", count)
session.Save()
c.JSON(200, gin.H{"count": count})
})
r.Run(":8000")
}
```
#### Redis
```go
package main
import (
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
store, _ := sessions.NewRedisStore(10, "tcp", "localhost:6379", "", []byte("secret"))
r.Use(sessions.Sessions("session", store))
r.GET("/incr", func(c *gin.Context) {
session := sessions.Default(c)
var count int
v := session.Get("count")
if v == nil {
count = 0
} else {
count = v.(int)
count += 1
}
session.Set("count", count)
session.Save()
c.JSON(200, gin.H{"count": count})
})
r.Run(":8000")
}
```

36
vendor/github.com/gin-gonic/contrib/sessions/cookie.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
package sessions
import (
"github.com/gorilla/sessions"
)
type CookieStore interface {
Store
}
// Keys are defined in pairs to allow key rotation, but the common case is to set a single
// authentication key and optionally an encryption key.
//
// The first key in a pair is used for authentication and the second for encryption. The
// encryption key can be set to nil or omitted in the last pair, but the authentication key
// is required in all pairs.
//
// It is recommended to use an authentication key with 32 or 64 bytes. The encryption key,
// if set, must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 modes.
func NewCookieStore(keyPairs ...[]byte) CookieStore {
return &cookieStore{sessions.NewCookieStore(keyPairs...)}
}
type cookieStore struct {
*sessions.CookieStore
}
func (c *cookieStore) Options(options Options) {
c.CookieStore.Options = &sessions.Options{
Path: options.Path,
Domain: options.Domain,
MaxAge: options.MaxAge,
Secure: options.Secure,
HttpOnly: options.HttpOnly,
}
}

View File

@@ -0,0 +1,30 @@
package sessions
import (
"testing"
)
var newCookieStore = func(_ *testing.T) Store {
store := NewCookieStore([]byte("secret"))
return store
}
func TestCookie_SessionGetSet(t *testing.T) {
sessionGetSet(t, newCookieStore)
}
func TestCookie_SessionDeleteKey(t *testing.T) {
sessionDeleteKey(t, newCookieStore)
}
func TestCookie_SessionFlashes(t *testing.T) {
sessionFlashes(t, newCookieStore)
}
func TestCookie_SessionClear(t *testing.T) {
sessionClear(t, newCookieStore)
}
func TestCookie_SessionOptions(t *testing.T) {
sessionOptions(t, newCookieStore)
}

View File

@@ -0,0 +1,28 @@
package main
import (
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
store := sessions.NewCookieStore([]byte("secret"))
r.Use(sessions.Sessions("mysession", store))
r.GET("/incr", func(c *gin.Context) {
session := sessions.Default(c)
var count int
v := session.Get("count")
if v == nil {
count = 0
} else {
count = v.(int)
count += 1
}
session.Set("count", count)
session.Save()
c.JSON(200, gin.H{"count": count})
})
r.Run(":8000")
}

View File

@@ -0,0 +1,28 @@
package main
import (
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
store, _ := sessions.NewRedisStore(10, "tcp", "localhost:6379", "", []byte("secret"))
r.Use(sessions.Sessions("mysession", store))
r.GET("/incr", func(c *gin.Context) {
session := sessions.Default(c)
var count int
v := session.Get("count")
if v == nil {
count = 0
} else {
count = v.(int)
count += 1
}
session.Set("count", count)
session.Save()
c.JSON(200, gin.H{"count": count})
})
r.Run(":8000")
}

45
vendor/github.com/gin-gonic/contrib/sessions/redis.go generated vendored Normal file
View File

@@ -0,0 +1,45 @@
package sessions
import (
"github.com/boj/redistore"
"github.com/gorilla/sessions"
)
type RedisStore interface {
Store
}
// size: maximum number of idle connections.
// network: tcp or udp
// address: host:port
// password: redis-password
// Keys are defined in pairs to allow key rotation, but the common case is to set a single
// authentication key and optionally an encryption key.
//
// The first key in a pair is used for authentication and the second for encryption. The
// encryption key can be set to nil or omitted in the last pair, but the authentication key
// is required in all pairs.
//
// It is recommended to use an authentication key with 32 or 64 bytes. The encryption key,
// if set, must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 modes.
func NewRedisStore(size int, network, address, password string, keyPairs ...[]byte) (RedisStore, error) {
store, err := redistore.NewRediStore(size, network, address, password, keyPairs...)
if err != nil {
return nil, err
}
return &redisStore{store}, nil
}
type redisStore struct {
*redistore.RediStore
}
func (c *redisStore) Options(options Options) {
c.RediStore.Options = &sessions.Options{
Path: options.Path,
Domain: options.Domain,
MaxAge: options.MaxAge,
Secure: options.Secure,
HttpOnly: options.HttpOnly,
}
}

View File

@@ -0,0 +1,35 @@
package sessions
import (
"testing"
)
const redisTestServer = "localhost:6379"
var newRedisStore = func(_ *testing.T) Store {
store, err := NewRedisStore(10, "tcp", redisTestServer, "", []byte("secret"))
if err != nil {
panic(err)
}
return store
}
func TestRedis_SessionGetSet(t *testing.T) {
sessionGetSet(t, newRedisStore)
}
func TestRedis_SessionDeleteKey(t *testing.T) {
sessionDeleteKey(t, newRedisStore)
}
func TestRedis_SessionFlashes(t *testing.T) {
sessionFlashes(t, newRedisStore)
}
func TestRedis_SessionClear(t *testing.T) {
sessionClear(t, newRedisStore)
}
func TestRedis_SessionOptions(t *testing.T) {
sessionOptions(t, newRedisStore)
}

View File

@@ -0,0 +1,147 @@
package sessions
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gorilla/context"
"github.com/gorilla/sessions"
)
const (
DefaultKey = "github.com/gin-gonic/contrib/sessions"
errorFormat = "[sessions] ERROR! %s\n"
)
type Store interface {
sessions.Store
Options(Options)
}
// Options stores configuration for a session or session store.
// Fields are a subset of http.Cookie fields.
type Options struct {
Path string
Domain string
// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'.
// MaxAge>0 means Max-Age attribute present and given in seconds.
MaxAge int
Secure bool
HttpOnly bool
}
// Wraps thinly gorilla-session methods.
// Session stores the values and optional configuration for a session.
type Session interface {
// Get returns the session value associated to the given key.
Get(key interface{}) interface{}
// Set sets the session value associated to the given key.
Set(key interface{}, val interface{})
// Delete removes the session value associated to the given key.
Delete(key interface{})
// Clear deletes all values in the session.
Clear()
// AddFlash adds a flash message to the session.
// A single variadic argument is accepted, and it is optional: it defines the flash key.
// If not defined "_flash" is used by default.
AddFlash(value interface{}, vars ...string)
// Flashes returns a slice of flash messages from the session.
// A single variadic argument is accepted, and it is optional: it defines the flash key.
// If not defined "_flash" is used by default.
Flashes(vars ...string) []interface{}
// Options sets confuguration for a session.
Options(Options)
// Save saves all sessions used during the current request.
Save() error
}
func Sessions(name string, store Store) gin.HandlerFunc {
return func(c *gin.Context) {
s := &session{name, c.Request, store, nil, false, c.Writer}
c.Set(DefaultKey, s)
defer context.Clear(c.Request)
c.Next()
}
}
type session struct {
name string
request *http.Request
store Store
session *sessions.Session
written bool
writer http.ResponseWriter
}
func (s *session) Get(key interface{}) interface{} {
return s.Session().Values[key]
}
func (s *session) Set(key interface{}, val interface{}) {
s.Session().Values[key] = val
s.written = true
}
func (s *session) Delete(key interface{}) {
delete(s.Session().Values, key)
s.written = true
}
func (s *session) Clear() {
for key := range s.Session().Values {
s.Delete(key)
}
}
func (s *session) AddFlash(value interface{}, vars ...string) {
s.Session().AddFlash(value, vars...)
s.written = true
}
func (s *session) Flashes(vars ...string) []interface{} {
s.written = true
return s.Session().Flashes(vars...)
}
func (s *session) Options(options Options) {
s.Session().Options = &sessions.Options{
Path: options.Path,
Domain: options.Domain,
MaxAge: options.MaxAge,
Secure: options.Secure,
HttpOnly: options.HttpOnly,
}
}
func (s *session) Save() error {
if s.Written() {
e := s.Session().Save(s.request, s.writer)
if e == nil {
s.written = false
}
return e
}
return nil
}
func (s *session) Session() *sessions.Session {
if s.session == nil {
var err error
s.session, err = s.store.Get(s.request, s.name)
if err != nil {
log.Printf(errorFormat, err)
}
}
return s.session
}
func (s *session) Written() bool {
return s.written
}
// shortcut to get session
func Default(c *gin.Context) Session {
return c.MustGet(DefaultKey).(Session)
}

View File

@@ -0,0 +1,219 @@
package sessions
import (
"github.com/gin-gonic/gin"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
type storeFactory func(*testing.T) Store
const sessionName = "mysession"
const ok = "ok"
func sessionGetSet(t *testing.T, newStore storeFactory) {
r := gin.Default()
r.Use(Sessions(sessionName, newStore(t)))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Save()
c.String(200, ok)
})
r.GET("/get", func(c *gin.Context) {
session := Default(c)
if session.Get("key") != ok {
t.Error("Session writing failed")
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/get", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
}
func sessionDeleteKey(t *testing.T, newStore storeFactory) {
r := gin.Default()
r.Use(Sessions(sessionName, newStore(t)))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Save()
c.String(200, ok)
})
r.GET("/delete", func(c *gin.Context) {
session := Default(c)
session.Delete("key")
session.Save()
c.String(200, ok)
})
r.GET("/get", func(c *gin.Context) {
session := Default(c)
if session.Get("key") != nil {
t.Error("Session deleting failed")
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/delete", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
res3 := httptest.NewRecorder()
req3, _ := http.NewRequest("GET", "/get", nil)
req3.Header.Set("Cookie", res2.Header().Get("Set-Cookie"))
r.ServeHTTP(res3, req3)
}
func sessionFlashes(t *testing.T, newStore storeFactory) {
r := gin.Default()
store := newStore(t)
store.Options(Options{
Domain: "localhost",
})
r.Use(Sessions(sessionName, store))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
session.AddFlash(ok)
session.Save()
c.String(200, ok)
})
r.GET("/flash", func(c *gin.Context) {
session := Default(c)
l := len(session.Flashes())
if l != 1 {
t.Error("Flashes count does not equal 1. Equals ", l)
}
session.Save()
c.String(200, ok)
})
r.GET("/check", func(c *gin.Context) {
session := Default(c)
l := len(session.Flashes())
if l != 0 {
t.Error("flashes count is not 0 after reading. Equals ", l)
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/flash", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
res3 := httptest.NewRecorder()
req3, _ := http.NewRequest("GET", "/check", nil)
req3.Header.Set("Cookie", res2.Header().Get("Set-Cookie"))
r.ServeHTTP(res3, req3)
}
func sessionClear(t *testing.T, newStore storeFactory) {
data := map[string]string{
"key": "val",
"foo": "bar",
}
r := gin.Default()
store := newStore(t)
r.Use(Sessions(sessionName, store))
r.GET("/set", func(c *gin.Context) {
session := Default(c)
for k, v := range data {
session.Set(k, v)
}
session.Clear()
session.Save()
c.String(200, ok)
})
r.GET("/check", func(c *gin.Context) {
session := Default(c)
for k, v := range data {
if session.Get(k) == v {
t.Fatal("Session clear failed")
}
}
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/set", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/check", nil)
req2.Header.Set("Cookie", res1.Header().Get("Set-Cookie"))
r.ServeHTTP(res2, req2)
}
func sessionOptions(t *testing.T, newStore storeFactory) {
r := gin.Default()
store := newStore(t)
store.Options(Options{
Domain: "localhost",
})
r.Use(Sessions(sessionName, store))
r.GET("/domain", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Options(Options{
Path: "/foo/bar/bat",
})
session.Save()
c.String(200, ok)
})
r.GET("/path", func(c *gin.Context) {
session := Default(c)
session.Set("key", ok)
session.Save()
c.String(200, ok)
})
res1 := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/domain", nil)
r.ServeHTTP(res1, req1)
res2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/path", nil)
r.ServeHTTP(res2, req2)
s := strings.Split(res1.Header().Get("Set-Cookie"), ";")
if s[1] != " Path=/foo/bar/bat" {
t.Error("Error writing path with options:", s[1])
}
s = strings.Split(res2.Header().Get("Set-Cookie"), ";")
if s[1] != " Domain=localhost" {
t.Error("Error writing domain with options:", s[1])
}
}

5
vendor/github.com/gin-gonic/contrib/static/README.md generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# static
## EOL-warning
**This package has been abandoned on 2016-12-13. Please use [gin-contrib/static](https://github.com/gin-contrib/static) instead.**

View File

@@ -0,0 +1,121 @@
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"os"
"strings"
)
func bindata_read(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
}
var buf bytes.Buffer
_, err = io.Copy(&buf, gz)
gz.Close()
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
}
return buf.Bytes(), nil
}
func data_index_html() ([]byte, error) {
return bindata_read([]byte{
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0x44, 0xce,
0xbd, 0xae, 0xc2, 0x30, 0x0c, 0x05, 0xe0, 0xbd, 0x4f, 0xe1, 0x9b, 0xbd,
0xaa, 0xba, 0xdd, 0x21, 0xcd, 0xc2, 0xef, 0x06, 0x43, 0x19, 0x18, 0x5d,
0x62, 0x35, 0x41, 0x4e, 0x22, 0x15, 0x4b, 0x88, 0xb7, 0x27, 0x21, 0x45,
0x4c, 0x39, 0xb1, 0xf5, 0x1d, 0x59, 0xff, 0x6d, 0x4f, 0x9b, 0xf1, 0x7a,
0xde, 0x81, 0x93, 0xc0, 0xa6, 0xd1, 0xe5, 0x01, 0xc6, 0x38, 0x0f, 0xea,
0x8e, 0xca, 0x34, 0x00, 0xda, 0x11, 0xda, 0x12, 0x72, 0x0c, 0x24, 0x08,
0x37, 0x87, 0xcb, 0x83, 0x64, 0x50, 0x97, 0x71, 0xdf, 0xfe, 0x2b, 0xe8,
0xd6, 0xa5, 0x78, 0x61, 0x32, 0x73, 0x6a, 0x27, 0x1f, 0x2d, 0x0a, 0xea,
0xae, 0x4e, 0x4a, 0x47, 0xf7, 0x2d, 0xd1, 0x53, 0xb2, 0xaf, 0x15, 0xb8,
0xde, 0x1c, 0x89, 0x39, 0xc1, 0xc1, 0x47, 0xf8, 0x39, 0x08, 0xde, 0x5a,
0xa6, 0x27, 0x2e, 0x94, 0x5d, 0x5f, 0x7d, 0x65, 0xf9, 0xff, 0x39, 0xf3,
0x1d, 0x00, 0x00, 0xff, 0xff, 0x51, 0x69, 0x85, 0x27, 0xb7, 0x00, 0x00,
0x00,
},
"data/index.html",
)
}
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok {
return f()
}
return nil, fmt.Errorf("Asset %s not found", name)
}
// AssetNames returns the names of the assets.
func AssetNames() []string {
names := make([]string, 0, len(_bindata))
for name := range _bindata {
names = append(names, name)
}
return names
}
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() ([]byte, error){
"data/index.html": data_index_html,
}
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
func AssetDir(name string) ([]string, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(cannonicalName, "/")
node := _bintree
for _, p := range pathList {
node = node.Children[p]
if node == nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
}
if node.Func != nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
rv := make([]string, 0, len(node.Children))
for name := range node.Children {
rv = append(rv, name)
}
return rv, nil
}
type _bintree_t struct {
Func func() ([]byte, error)
Children map[string]*_bintree_t
}
var _bintree = &_bintree_t{nil, map[string]*_bintree_t{
"data": &_bintree_t{nil, map[string]*_bintree_t{
"index.html": &_bintree_t{data_index_html, map[string]*_bintree_t{}},
}},
}}
// AssetInfo returns file info of given path
func AssetInfo(path string) (os.FileInfo, error) {
return os.Stat(path)
}

View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>go-bindata</title>
</head>
<body>
<h1>Hello Gin go-bindata middleware</h1>
</body>
</html>

View File

@@ -0,0 +1,51 @@
package main
import (
"net/http"
"strings"
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/gin-gonic/contrib/static"
"github.com/gin-gonic/gin"
)
type binaryFileSystem struct {
fs http.FileSystem
}
func (b *binaryFileSystem) Open(name string) (http.File, error) {
return b.fs.Open(name)
}
func (b *binaryFileSystem) Exists(prefix string, filepath string) bool {
if p := strings.TrimPrefix(filepath, prefix); len(p) < len(filepath) {
if _, err := b.fs.Open(p); err != nil {
return false
}
return true
}
return false
}
func BinaryFileSystem(root string) *binaryFileSystem {
fs := &assetfs.AssetFS{Asset, AssetDir, AssetInfo, root}
return &binaryFileSystem{
fs,
}
}
// Usage
// $ go-bindata data/
// $ go build && ./bindata
//
func main() {
r := gin.Default()
r.Use(static.Serve("/static", BinaryFileSystem("data")))
r.GET("/ping", func(c *gin.Context) {
c.String(200, "test")
})
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}

View File

@@ -0,0 +1,22 @@
package main
import (
"github.com/gin-gonic/contrib/static"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// if Allow DirectoryIndex
//r.Use(static.Serve("/", static.LocalFile("/tmp", true)))
// set prefix
//r.Use(static.Serve("/static", static.LocalFile("/tmp", true)))
r.Use(static.Serve("/", static.LocalFile("/tmp", false)))
r.GET("/ping", func(c *gin.Context) {
c.String(200, "test")
})
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}

62
vendor/github.com/gin-gonic/contrib/static/static.go generated vendored Normal file
View File

@@ -0,0 +1,62 @@
package static
import (
"net/http"
"os"
"path"
"strings"
"github.com/gin-gonic/gin"
)
type ServeFileSystem interface {
http.FileSystem
Exists(prefix string, path string) bool
}
type localFileSystem struct {
http.FileSystem
root string
indexes bool
}
func LocalFile(root string, indexes bool) *localFileSystem {
return &localFileSystem{
FileSystem: gin.Dir(root, indexes),
root: root,
indexes: indexes,
}
}
func (l *localFileSystem) Exists(prefix string, filepath string) bool {
if p := strings.TrimPrefix(filepath, prefix); len(p) < len(filepath) {
name := path.Join(l.root, p)
stats, err := os.Stat(name)
if err != nil {
return false
}
if !l.indexes && stats.IsDir() {
return false
}
return true
}
return false
}
func ServeRoot(urlPrefix, root string) gin.HandlerFunc {
return Serve(urlPrefix, LocalFile(root, false))
}
// Static returns a middleware handler that serves static files in the given directory.
func Serve(urlPrefix string, fs ServeFileSystem) gin.HandlerFunc {
fileserver := http.FileServer(fs)
if urlPrefix != "" {
fileserver = http.StripPrefix(urlPrefix, fileserver)
}
return func(c *gin.Context) {
if fs.Exists(urlPrefix, c.Request.URL.Path) {
fileserver.ServeHTTP(c.Writer, c.Request)
c.Abort()
}
}
}

View File

@@ -0,0 +1,86 @@
package static
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
req, _ := http.NewRequest(method, path, nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
return w
}
func TestEmptyDirectory(t *testing.T) {
// SETUP file
testRoot, _ := os.Getwd()
f, err := ioutil.TempFile(testRoot, "")
if err != nil {
t.Error(err)
}
defer os.Remove(f.Name())
f.WriteString("Gin Web Framework")
f.Close()
dir, filename := filepath.Split(f.Name())
router := gin.New()
router.Use(ServeRoot("/", dir))
router.GET("/", func(c *gin.Context) {
c.String(200, "index")
})
router.GET("/a", func(c *gin.Context) {
c.String(200, "a")
})
router.GET("/"+filename, func(c *gin.Context) {
c.String(200, "this is not printed")
})
w := performRequest(router, "GET", "/")
assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Body.String(), "index")
w = performRequest(router, "GET", "/"+filename)
assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Body.String(), "Gin Web Framework")
w = performRequest(router, "GET", "/"+filename+"a")
assert.Equal(t, w.Code, 404)
w = performRequest(router, "GET", "/a")
assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Body.String(), "a")
router2 := gin.New()
router2.Use(ServeRoot("/static", dir))
router2.GET("/"+filename, func(c *gin.Context) {
c.String(200, "this is printed")
})
w = performRequest(router2, "GET", "/")
assert.Equal(t, w.Code, 404)
w = performRequest(router2, "GET", "/static")
assert.Equal(t, w.Code, 404)
router2.GET("/static", func(c *gin.Context) {
c.String(200, "index")
})
w = performRequest(router2, "GET", "/static")
assert.Equal(t, w.Code, 200)
w = performRequest(router2, "GET", "/"+filename)
assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Body.String(), "this is printed")
w = performRequest(router2, "GET", "/static/"+filename)
assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Body.String(), "Gin Web Framework")
}

4
vendor/github.com/gin-gonic/gin/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,4 @@
vendor/*
!vendor/vendor.json
coverage.out
count.out

31
vendor/github.com/gin-gonic/gin/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,31 @@
language: go
sudo: false
go:
- 1.6.x
- 1.7.x
- 1.8.x
- master
git:
depth: 3
install:
- make install
script:
- make vet
- make fmt-check
- make embedmd
- make misspell-check
- make test
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/7f95bf605c4d356372f4
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false

227
vendor/github.com/gin-gonic/gin/AUTHORS.md generated vendored Normal file
View File

@@ -0,0 +1,227 @@
List of all the awesome people working to make Gin the best Web Framework in Go.
## gin 0.x series authors
**Maintainer:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho)
People and companies, who have contributed, in alphabetical order.
**@858806258 (杰哥)**
- Fix typo in example
**@achedeuzot (Klemen Sever)**
- Fix newline debug printing
**@adammck (Adam Mckaig)**
- Add MIT license
**@AlexanderChen1989 (Alexander)**
- Typos in README
**@alexanderdidenko (Aleksandr Didenko)**
- Add support multipart/form-data
**@alexandernyquist (Alexander Nyquist)**
- Using template.Must to fix multiple return issue
- ★ Added support for OPTIONS verb
- ★ Setting response headers before calling WriteHeader
- Improved documentation for model binding
- ★ Added Content.Redirect()
- ★ Added tons of Unit tests
**@austinheap (Austin Heap)**
- Added travis CI integration
**@andredublin (Andre Dublin)**
- Fix typo in comment
**@bredov (Ludwig Valda Vasquez)**
- Fix html templating in debug mode
**@bluele (Jun Kimura)**
- Fixes code examples in README
**@chad-russell**
- ★ Support for serializing gin.H into XML
**@dickeyxxx (Jeff Dickey)**
- Typos in README
- Add example about serving static files
**@donileo (Adonis)**
- Add NoMethod handler
**@dutchcoders (DutchCoders)**
- ★ Fix security bug that allows client to spoof ip
- Fix typo. r.HTMLTemplates -> SetHTMLTemplate
**@el3ctro- (Joshua Loper)**
- Fix typo in example
**@ethankan (Ethan Kan)**
- Unsigned integers in binding
**(Evgeny Persienko)**
- Validate sub structures
**@frankbille (Frank Bille)**
- Add support for HTTP Realm Auth
**@fmd (Fareed Dudhia)**
- Fix typo. SetHTTPTemplate -> SetHTMLTemplate
**@ironiridis (Christopher Harrington)**
- Remove old reference
**@jammie-stackhouse (Jamie Stackhouse)**
- Add more shortcuts for router methods
**@jasonrhansen**
- Fix spelling and grammar errors in documentation
**@JasonSoft (Jason Lee)**
- Fix typo in comment
**@joiggama (Ignacio Galindo)**
- Add utf-8 charset header on renders
**@julienschmidt (Julien Schmidt)**
- gofmt the code examples
**@kelcecil (Kel Cecil)**
- Fix readme typo
**@kyledinh (Kyle Dinh)**
- Adds RunTLS()
**@LinusU (Linus Unnebäck)**
- Small fixes in README
**@loongmxbt (Saint Asky)**
- Fix typo in example
**@lucas-clemente (Lucas Clemente)**
- ★ work around path.Join removing trailing slashes from routes
**@mattn (Yasuhiro Matsumoto)**
- Improve color logger
**@mdigger (Dmitry Sedykh)**
- Fixes Form binding when content-type is x-www-form-urlencoded
- No repeat call c.Writer.Status() in gin.Logger
- Fixes Content-Type for json render
**@mirzac (Mirza Ceric)**
- Fix debug printing
**@mopemope (Yutaka Matsubara)**
- ★ Adds Godep support (Dependencies Manager)
- Fix variadic parameter in the flexible render API
- Fix Corrupted plain render
- Add Pluggable View Renderer Example
**@msemenistyi (Mykyta Semenistyi)**
- update Readme.md. Add code to String method
**@msoedov (Sasha Myasoedov)**
- ★ Adds tons of unit tests.
**@ngerakines (Nick Gerakines)**
- ★ Improves API, c.GET() doesn't panic
- Adds MustGet() method
**@r8k (Rajiv Kilaparti)**
- Fix Port usage in README.
**@rayrod2030 (Ray Rodriguez)**
- Fix typo in example
**@rns**
- Fix typo in example
**@RobAWilkinson (Robert Wilkinson)**
- Add example of forms and params
**@rogierlommers (Rogier Lommers)**
- Add updated static serve example
**@se77en (Damon Zhao)**
- Improve color logging
**@silasb (Silas Baronda)**
- Fixing quotes in README
**@SkuliOskarsson (Skuli Oskarsson)**
- Fixes some texts in README II
**@slimmy (Jimmy Pettersson)**
- Added messages for required bindings
**@smira (Andrey Smirnov)**
- Add support for ignored/unexported fields in binding
**@superalsrk (SRK.Lyu)**
- Update httprouter godeps
**@tebeka (Miki Tebeka)**
- Use net/http constants instead of numeric values
**@techjanitor**
- Update context.go reserved IPs
**@yosssi (Keiji Yoshida)**
- Fix link in README
**@yuyabee**
- Fixed README

298
vendor/github.com/gin-gonic/gin/BENCHMARKS.md generated vendored Normal file
View File

@@ -0,0 +1,298 @@
**Machine:** intel i7 ivy bridge quad-core. 8GB RAM.
**Date:** June 4th, 2015
[https://github.com/gin-gonic/go-http-routing-benchmark](https://github.com/gin-gonic/go-http-routing-benchmark)
```
BenchmarkAce_Param 5000000 372 ns/op 32 B/op 1 allocs/op
BenchmarkBear_Param 1000000 1165 ns/op 424 B/op 5 allocs/op
BenchmarkBeego_Param 1000000 2440 ns/op 720 B/op 10 allocs/op
BenchmarkBone_Param 1000000 1067 ns/op 384 B/op 3 allocs/op
BenchmarkDenco_Param 5000000 240 ns/op 32 B/op 1 allocs/op
BenchmarkEcho_Param 10000000 130 ns/op 0 B/op 0 allocs/op
BenchmarkGin_Param 10000000 133 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_Param 1000000 1826 ns/op 656 B/op 9 allocs/op
BenchmarkGoji_Param 2000000 957 ns/op 336 B/op 2 allocs/op
BenchmarkGoJsonRest_Param 1000000 2021 ns/op 657 B/op 14 allocs/op
BenchmarkGoRestful_Param 200000 8825 ns/op 2496 B/op 31 allocs/op
BenchmarkGorillaMux_Param 500000 3340 ns/op 784 B/op 9 allocs/op
BenchmarkHttpRouter_Param 10000000 152 ns/op 32 B/op 1 allocs/op
BenchmarkHttpTreeMux_Param 2000000 717 ns/op 336 B/op 2 allocs/op
BenchmarkKocha_Param 3000000 423 ns/op 56 B/op 3 allocs/op
BenchmarkMacaron_Param 1000000 3410 ns/op 1104 B/op 11 allocs/op
BenchmarkMartini_Param 200000 7101 ns/op 1152 B/op 12 allocs/op
BenchmarkPat_Param 1000000 2040 ns/op 656 B/op 14 allocs/op
BenchmarkPossum_Param 1000000 2048 ns/op 624 B/op 7 allocs/op
BenchmarkR2router_Param 1000000 1144 ns/op 432 B/op 6 allocs/op
BenchmarkRevel_Param 200000 6725 ns/op 1672 B/op 28 allocs/op
BenchmarkRivet_Param 1000000 1121 ns/op 464 B/op 5 allocs/op
BenchmarkTango_Param 1000000 1479 ns/op 256 B/op 10 allocs/op
BenchmarkTigerTonic_Param 1000000 3393 ns/op 992 B/op 19 allocs/op
BenchmarkTraffic_Param 300000 5525 ns/op 1984 B/op 23 allocs/op
BenchmarkVulcan_Param 2000000 924 ns/op 98 B/op 3 allocs/op
BenchmarkZeus_Param 1000000 1084 ns/op 368 B/op 3 allocs/op
BenchmarkAce_Param5 3000000 614 ns/op 160 B/op 1 allocs/op
BenchmarkBear_Param5 1000000 1617 ns/op 469 B/op 5 allocs/op
BenchmarkBeego_Param5 1000000 3373 ns/op 992 B/op 13 allocs/op
BenchmarkBone_Param5 1000000 1478 ns/op 432 B/op 3 allocs/op
BenchmarkDenco_Param5 3000000 570 ns/op 160 B/op 1 allocs/op
BenchmarkEcho_Param5 5000000 256 ns/op 0 B/op 0 allocs/op
BenchmarkGin_Param5 10000000 222 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_Param5 1000000 2789 ns/op 928 B/op 12 allocs/op
BenchmarkGoji_Param5 1000000 1287 ns/op 336 B/op 2 allocs/op
BenchmarkGoJsonRest_Param5 1000000 3670 ns/op 1105 B/op 17 allocs/op
BenchmarkGoRestful_Param5 200000 10756 ns/op 2672 B/op 31 allocs/op
BenchmarkGorillaMux_Param5 300000 5543 ns/op 912 B/op 9 allocs/op
BenchmarkHttpRouter_Param5 5000000 403 ns/op 160 B/op 1 allocs/op
BenchmarkHttpTreeMux_Param5 1000000 1089 ns/op 336 B/op 2 allocs/op
BenchmarkKocha_Param5 1000000 1682 ns/op 440 B/op 10 allocs/op
BenchmarkMacaron_Param5 300000 4596 ns/op 1376 B/op 14 allocs/op
BenchmarkMartini_Param5 100000 15703 ns/op 1280 B/op 12 allocs/op
BenchmarkPat_Param5 300000 5320 ns/op 1008 B/op 42 allocs/op
BenchmarkPossum_Param5 1000000 2155 ns/op 624 B/op 7 allocs/op
BenchmarkR2router_Param5 1000000 1559 ns/op 432 B/op 6 allocs/op
BenchmarkRevel_Param5 200000 8184 ns/op 2024 B/op 35 allocs/op
BenchmarkRivet_Param5 1000000 1914 ns/op 528 B/op 9 allocs/op
BenchmarkTango_Param5 1000000 3280 ns/op 944 B/op 18 allocs/op
BenchmarkTigerTonic_Param5 200000 11638 ns/op 2519 B/op 53 allocs/op
BenchmarkTraffic_Param5 200000 8941 ns/op 2280 B/op 31 allocs/op
BenchmarkVulcan_Param5 1000000 1279 ns/op 98 B/op 3 allocs/op
BenchmarkZeus_Param5 1000000 1574 ns/op 416 B/op 3 allocs/op
BenchmarkAce_Param20 1000000 1528 ns/op 640 B/op 1 allocs/op
BenchmarkBear_Param20 300000 4906 ns/op 1633 B/op 5 allocs/op
BenchmarkBeego_Param20 200000 10529 ns/op 3868 B/op 17 allocs/op
BenchmarkBone_Param20 300000 7362 ns/op 2539 B/op 5 allocs/op
BenchmarkDenco_Param20 1000000 1884 ns/op 640 B/op 1 allocs/op
BenchmarkEcho_Param20 2000000 689 ns/op 0 B/op 0 allocs/op
BenchmarkGin_Param20 3000000 545 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_Param20 200000 9437 ns/op 3804 B/op 16 allocs/op
BenchmarkGoji_Param20 500000 3987 ns/op 1246 B/op 2 allocs/op
BenchmarkGoJsonRest_Param20 100000 12799 ns/op 4492 B/op 21 allocs/op
BenchmarkGoRestful_Param20 100000 19451 ns/op 5244 B/op 33 allocs/op
BenchmarkGorillaMux_Param20 100000 12456 ns/op 3275 B/op 11 allocs/op
BenchmarkHttpRouter_Param20 1000000 1333 ns/op 640 B/op 1 allocs/op
BenchmarkHttpTreeMux_Param20 300000 6490 ns/op 2187 B/op 4 allocs/op
BenchmarkKocha_Param20 300000 5335 ns/op 1808 B/op 27 allocs/op
BenchmarkMacaron_Param20 200000 11325 ns/op 4252 B/op 18 allocs/op
BenchmarkMartini_Param20 20000 64419 ns/op 3644 B/op 14 allocs/op
BenchmarkPat_Param20 50000 24672 ns/op 4888 B/op 151 allocs/op
BenchmarkPossum_Param20 1000000 2085 ns/op 624 B/op 7 allocs/op
BenchmarkR2router_Param20 300000 6809 ns/op 2283 B/op 8 allocs/op
BenchmarkRevel_Param20 100000 16600 ns/op 5551 B/op 54 allocs/op
BenchmarkRivet_Param20 200000 8428 ns/op 2620 B/op 26 allocs/op
BenchmarkTango_Param20 100000 16302 ns/op 8224 B/op 48 allocs/op
BenchmarkTigerTonic_Param20 30000 46828 ns/op 10538 B/op 178 allocs/op
BenchmarkTraffic_Param20 50000 28871 ns/op 7998 B/op 66 allocs/op
BenchmarkVulcan_Param20 1000000 2267 ns/op 98 B/op 3 allocs/op
BenchmarkZeus_Param20 300000 6828 ns/op 2507 B/op 5 allocs/op
BenchmarkAce_ParamWrite 3000000 502 ns/op 40 B/op 2 allocs/op
BenchmarkBear_ParamWrite 1000000 1303 ns/op 424 B/op 5 allocs/op
BenchmarkBeego_ParamWrite 1000000 2489 ns/op 728 B/op 11 allocs/op
BenchmarkBone_ParamWrite 1000000 1181 ns/op 384 B/op 3 allocs/op
BenchmarkDenco_ParamWrite 5000000 315 ns/op 32 B/op 1 allocs/op
BenchmarkEcho_ParamWrite 10000000 237 ns/op 8 B/op 1 allocs/op
BenchmarkGin_ParamWrite 5000000 336 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_ParamWrite 1000000 2079 ns/op 664 B/op 10 allocs/op
BenchmarkGoji_ParamWrite 1000000 1092 ns/op 336 B/op 2 allocs/op
BenchmarkGoJsonRest_ParamWrite 1000000 3329 ns/op 1136 B/op 19 allocs/op
BenchmarkGoRestful_ParamWrite 200000 9273 ns/op 2504 B/op 32 allocs/op
BenchmarkGorillaMux_ParamWrite 500000 3919 ns/op 792 B/op 10 allocs/op
BenchmarkHttpRouter_ParamWrite 10000000 223 ns/op 32 B/op 1 allocs/op
BenchmarkHttpTreeMux_ParamWrite 2000000 788 ns/op 336 B/op 2 allocs/op
BenchmarkKocha_ParamWrite 3000000 549 ns/op 56 B/op 3 allocs/op
BenchmarkMacaron_ParamWrite 500000 4558 ns/op 1216 B/op 16 allocs/op
BenchmarkMartini_ParamWrite 200000 8850 ns/op 1256 B/op 16 allocs/op
BenchmarkPat_ParamWrite 500000 3679 ns/op 1088 B/op 19 allocs/op
BenchmarkPossum_ParamWrite 1000000 2114 ns/op 624 B/op 7 allocs/op
BenchmarkR2router_ParamWrite 1000000 1320 ns/op 432 B/op 6 allocs/op
BenchmarkRevel_ParamWrite 200000 8048 ns/op 2128 B/op 33 allocs/op
BenchmarkRivet_ParamWrite 1000000 1393 ns/op 472 B/op 6 allocs/op
BenchmarkTango_ParamWrite 2000000 819 ns/op 136 B/op 5 allocs/op
BenchmarkTigerTonic_ParamWrite 300000 5860 ns/op 1440 B/op 25 allocs/op
BenchmarkTraffic_ParamWrite 200000 7429 ns/op 2400 B/op 27 allocs/op
BenchmarkVulcan_ParamWrite 2000000 972 ns/op 98 B/op 3 allocs/op
BenchmarkZeus_ParamWrite 1000000 1226 ns/op 368 B/op 3 allocs/op
BenchmarkAce_GithubStatic 5000000 294 ns/op 0 B/op 0 allocs/op
BenchmarkBear_GithubStatic 3000000 575 ns/op 88 B/op 3 allocs/op
BenchmarkBeego_GithubStatic 1000000 1561 ns/op 368 B/op 7 allocs/op
BenchmarkBone_GithubStatic 200000 12301 ns/op 2880 B/op 60 allocs/op
BenchmarkDenco_GithubStatic 20000000 74.6 ns/op 0 B/op 0 allocs/op
BenchmarkEcho_GithubStatic 10000000 176 ns/op 0 B/op 0 allocs/op
BenchmarkGin_GithubStatic 10000000 159 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GithubStatic 1000000 1116 ns/op 304 B/op 6 allocs/op
BenchmarkGoji_GithubStatic 5000000 413 ns/op 0 B/op 0 allocs/op
BenchmarkGoRestful_GithubStatic 30000 55200 ns/op 3520 B/op 36 allocs/op
BenchmarkGoJsonRest_GithubStatic 1000000 1504 ns/op 337 B/op 12 allocs/op
BenchmarkGorillaMux_GithubStatic 100000 23620 ns/op 464 B/op 8 allocs/op
BenchmarkHttpRouter_GithubStatic 20000000 78.3 ns/op 0 B/op 0 allocs/op
BenchmarkHttpTreeMux_GithubStatic 20000000 84.9 ns/op 0 B/op 0 allocs/op
BenchmarkKocha_GithubStatic 20000000 111 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_GithubStatic 1000000 2686 ns/op 752 B/op 8 allocs/op
BenchmarkMartini_GithubStatic 100000 22244 ns/op 832 B/op 11 allocs/op
BenchmarkPat_GithubStatic 100000 13278 ns/op 3648 B/op 76 allocs/op
BenchmarkPossum_GithubStatic 1000000 1429 ns/op 480 B/op 4 allocs/op
BenchmarkR2router_GithubStatic 2000000 726 ns/op 144 B/op 5 allocs/op
BenchmarkRevel_GithubStatic 300000 6271 ns/op 1288 B/op 25 allocs/op
BenchmarkRivet_GithubStatic 3000000 474 ns/op 112 B/op 2 allocs/op
BenchmarkTango_GithubStatic 1000000 1842 ns/op 256 B/op 10 allocs/op
BenchmarkTigerTonic_GithubStatic 5000000 361 ns/op 48 B/op 1 allocs/op
BenchmarkTraffic_GithubStatic 30000 47197 ns/op 18920 B/op 149 allocs/op
BenchmarkVulcan_GithubStatic 1000000 1415 ns/op 98 B/op 3 allocs/op
BenchmarkZeus_GithubStatic 1000000 2522 ns/op 512 B/op 11 allocs/op
BenchmarkAce_GithubParam 3000000 578 ns/op 96 B/op 1 allocs/op
BenchmarkBear_GithubParam 1000000 1592 ns/op 464 B/op 5 allocs/op
BenchmarkBeego_GithubParam 1000000 2891 ns/op 784 B/op 11 allocs/op
BenchmarkBone_GithubParam 300000 6440 ns/op 1456 B/op 16 allocs/op
BenchmarkDenco_GithubParam 3000000 514 ns/op 128 B/op 1 allocs/op
BenchmarkEcho_GithubParam 5000000 292 ns/op 0 B/op 0 allocs/op
BenchmarkGin_GithubParam 10000000 242 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GithubParam 1000000 2343 ns/op 720 B/op 10 allocs/op
BenchmarkGoji_GithubParam 1000000 1566 ns/op 336 B/op 2 allocs/op
BenchmarkGoJsonRest_GithubParam 1000000 2828 ns/op 721 B/op 15 allocs/op
BenchmarkGoRestful_GithubParam 10000 177711 ns/op 2816 B/op 35 allocs/op
BenchmarkGorillaMux_GithubParam 100000 13591 ns/op 816 B/op 9 allocs/op
BenchmarkHttpRouter_GithubParam 5000000 352 ns/op 96 B/op 1 allocs/op
BenchmarkHttpTreeMux_GithubParam 2000000 973 ns/op 336 B/op 2 allocs/op
BenchmarkKocha_GithubParam 2000000 889 ns/op 128 B/op 5 allocs/op
BenchmarkMacaron_GithubParam 500000 4047 ns/op 1168 B/op 12 allocs/op
BenchmarkMartini_GithubParam 50000 28982 ns/op 1184 B/op 12 allocs/op
BenchmarkPat_GithubParam 200000 8747 ns/op 2480 B/op 56 allocs/op
BenchmarkPossum_GithubParam 1000000 2158 ns/op 624 B/op 7 allocs/op
BenchmarkR2router_GithubParam 1000000 1352 ns/op 432 B/op 6 allocs/op
BenchmarkRevel_GithubParam 200000 7673 ns/op 1784 B/op 30 allocs/op
BenchmarkRivet_GithubParam 1000000 1573 ns/op 480 B/op 6 allocs/op
BenchmarkTango_GithubParam 1000000 2418 ns/op 480 B/op 13 allocs/op
BenchmarkTigerTonic_GithubParam 300000 6048 ns/op 1440 B/op 28 allocs/op
BenchmarkTraffic_GithubParam 100000 20143 ns/op 6024 B/op 55 allocs/op
BenchmarkVulcan_GithubParam 1000000 2224 ns/op 98 B/op 3 allocs/op
BenchmarkZeus_GithubParam 500000 4156 ns/op 1312 B/op 12 allocs/op
BenchmarkAce_GithubAll 10000 109482 ns/op 13792 B/op 167 allocs/op
BenchmarkBear_GithubAll 10000 287490 ns/op 79952 B/op 943 allocs/op
BenchmarkBeego_GithubAll 3000 562184 ns/op 146272 B/op 2092 allocs/op
BenchmarkBone_GithubAll 500 2578716 ns/op 648016 B/op 8119 allocs/op
BenchmarkDenco_GithubAll 20000 94955 ns/op 20224 B/op 167 allocs/op
BenchmarkEcho_GithubAll 30000 58705 ns/op 0 B/op 0 allocs/op
BenchmarkGin_GithubAll 30000 50991 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GithubAll 5000 449648 ns/op 133280 B/op 1889 allocs/op
BenchmarkGoji_GithubAll 2000 689748 ns/op 56113 B/op 334 allocs/op
BenchmarkGoJsonRest_GithubAll 5000 537769 ns/op 135995 B/op 2940 allocs/op
BenchmarkGoRestful_GithubAll 100 18410628 ns/op 797236 B/op 7725 allocs/op
BenchmarkGorillaMux_GithubAll 200 8036360 ns/op 153137 B/op 1791 allocs/op
BenchmarkHttpRouter_GithubAll 20000 63506 ns/op 13792 B/op 167 allocs/op
BenchmarkHttpTreeMux_GithubAll 10000 165927 ns/op 56112 B/op 334 allocs/op
BenchmarkKocha_GithubAll 10000 171362 ns/op 23304 B/op 843 allocs/op
BenchmarkMacaron_GithubAll 2000 817008 ns/op 224960 B/op 2315 allocs/op
BenchmarkMartini_GithubAll 100 12609209 ns/op 237952 B/op 2686 allocs/op
BenchmarkPat_GithubAll 300 4830398 ns/op 1504101 B/op 32222 allocs/op
BenchmarkPossum_GithubAll 10000 301716 ns/op 97440 B/op 812 allocs/op
BenchmarkR2router_GithubAll 10000 270691 ns/op 77328 B/op 1182 allocs/op
BenchmarkRevel_GithubAll 1000 1491919 ns/op 345553 B/op 5918 allocs/op
BenchmarkRivet_GithubAll 10000 283860 ns/op 84272 B/op 1079 allocs/op
BenchmarkTango_GithubAll 5000 473821 ns/op 87078 B/op 2470 allocs/op
BenchmarkTigerTonic_GithubAll 2000 1120131 ns/op 241088 B/op 6052 allocs/op
BenchmarkTraffic_GithubAll 200 8708979 ns/op 2664762 B/op 22390 allocs/op
BenchmarkVulcan_GithubAll 5000 353392 ns/op 19894 B/op 609 allocs/op
BenchmarkZeus_GithubAll 2000 944234 ns/op 300688 B/op 2648 allocs/op
BenchmarkAce_GPlusStatic 5000000 251 ns/op 0 B/op 0 allocs/op
BenchmarkBear_GPlusStatic 3000000 415 ns/op 72 B/op 3 allocs/op
BenchmarkBeego_GPlusStatic 1000000 1416 ns/op 352 B/op 7 allocs/op
BenchmarkBone_GPlusStatic 10000000 192 ns/op 32 B/op 1 allocs/op
BenchmarkDenco_GPlusStatic 30000000 47.6 ns/op 0 B/op 0 allocs/op
BenchmarkEcho_GPlusStatic 10000000 131 ns/op 0 B/op 0 allocs/op
BenchmarkGin_GPlusStatic 10000000 131 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GPlusStatic 1000000 1035 ns/op 288 B/op 6 allocs/op
BenchmarkGoji_GPlusStatic 5000000 304 ns/op 0 B/op 0 allocs/op
BenchmarkGoJsonRest_GPlusStatic 1000000 1286 ns/op 337 B/op 12 allocs/op
BenchmarkGoRestful_GPlusStatic 200000 9649 ns/op 2160 B/op 30 allocs/op
BenchmarkGorillaMux_GPlusStatic 1000000 2346 ns/op 464 B/op 8 allocs/op
BenchmarkHttpRouter_GPlusStatic 30000000 42.7 ns/op 0 B/op 0 allocs/op
BenchmarkHttpTreeMux_GPlusStatic 30000000 49.5 ns/op 0 B/op 0 allocs/op
BenchmarkKocha_GPlusStatic 20000000 74.8 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_GPlusStatic 1000000 2520 ns/op 736 B/op 8 allocs/op
BenchmarkMartini_GPlusStatic 300000 5310 ns/op 832 B/op 11 allocs/op
BenchmarkPat_GPlusStatic 5000000 398 ns/op 96 B/op 2 allocs/op
BenchmarkPossum_GPlusStatic 1000000 1434 ns/op 480 B/op 4 allocs/op
BenchmarkR2router_GPlusStatic 2000000 646 ns/op 144 B/op 5 allocs/op
BenchmarkRevel_GPlusStatic 300000 6172 ns/op 1272 B/op 25 allocs/op
BenchmarkRivet_GPlusStatic 3000000 444 ns/op 112 B/op 2 allocs/op
BenchmarkTango_GPlusStatic 1000000 1400 ns/op 208 B/op 10 allocs/op
BenchmarkTigerTonic_GPlusStatic 10000000 213 ns/op 32 B/op 1 allocs/op
BenchmarkTraffic_GPlusStatic 1000000 3091 ns/op 1208 B/op 16 allocs/op
BenchmarkVulcan_GPlusStatic 2000000 863 ns/op 98 B/op 3 allocs/op
BenchmarkZeus_GPlusStatic 10000000 237 ns/op 16 B/op 1 allocs/op
BenchmarkAce_GPlusParam 3000000 435 ns/op 64 B/op 1 allocs/op
BenchmarkBear_GPlusParam 1000000 1205 ns/op 448 B/op 5 allocs/op
BenchmarkBeego_GPlusParam 1000000 2494 ns/op 720 B/op 10 allocs/op
BenchmarkBone_GPlusParam 1000000 1126 ns/op 384 B/op 3 allocs/op
BenchmarkDenco_GPlusParam 5000000 325 ns/op 64 B/op 1 allocs/op
BenchmarkEcho_GPlusParam 10000000 168 ns/op 0 B/op 0 allocs/op
BenchmarkGin_GPlusParam 10000000 170 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GPlusParam 1000000 1895 ns/op 656 B/op 9 allocs/op
BenchmarkGoji_GPlusParam 1000000 1071 ns/op 336 B/op 2 allocs/op
BenchmarkGoJsonRest_GPlusParam 1000000 2282 ns/op 657 B/op 14 allocs/op
BenchmarkGoRestful_GPlusParam 100000 19400 ns/op 2560 B/op 33 allocs/op
BenchmarkGorillaMux_GPlusParam 500000 5001 ns/op 784 B/op 9 allocs/op
BenchmarkHttpRouter_GPlusParam 10000000 240 ns/op 64 B/op 1 allocs/op
BenchmarkHttpTreeMux_GPlusParam 2000000 797 ns/op 336 B/op 2 allocs/op
BenchmarkKocha_GPlusParam 3000000 505 ns/op 56 B/op 3 allocs/op
BenchmarkMacaron_GPlusParam 1000000 3668 ns/op 1104 B/op 11 allocs/op
BenchmarkMartini_GPlusParam 200000 10672 ns/op 1152 B/op 12 allocs/op
BenchmarkPat_GPlusParam 1000000 2376 ns/op 704 B/op 14 allocs/op
BenchmarkPossum_GPlusParam 1000000 2090 ns/op 624 B/op 7 allocs/op
BenchmarkR2router_GPlusParam 1000000 1233 ns/op 432 B/op 6 allocs/op
BenchmarkRevel_GPlusParam 200000 6778 ns/op 1704 B/op 28 allocs/op
BenchmarkRivet_GPlusParam 1000000 1279 ns/op 464 B/op 5 allocs/op
BenchmarkTango_GPlusParam 1000000 1981 ns/op 272 B/op 10 allocs/op
BenchmarkTigerTonic_GPlusParam 500000 3893 ns/op 1064 B/op 19 allocs/op
BenchmarkTraffic_GPlusParam 200000 6585 ns/op 2000 B/op 23 allocs/op
BenchmarkVulcan_GPlusParam 1000000 1233 ns/op 98 B/op 3 allocs/op
BenchmarkZeus_GPlusParam 1000000 1350 ns/op 368 B/op 3 allocs/op
BenchmarkAce_GPlus2Params 3000000 512 ns/op 64 B/op 1 allocs/op
BenchmarkBear_GPlus2Params 1000000 1564 ns/op 464 B/op 5 allocs/op
BenchmarkBeego_GPlus2Params 1000000 3043 ns/op 784 B/op 11 allocs/op
BenchmarkBone_GPlus2Params 1000000 3152 ns/op 736 B/op 7 allocs/op
BenchmarkDenco_GPlus2Params 3000000 431 ns/op 64 B/op 1 allocs/op
BenchmarkEcho_GPlus2Params 5000000 247 ns/op 0 B/op 0 allocs/op
BenchmarkGin_GPlus2Params 10000000 219 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GPlus2Params 1000000 2363 ns/op 720 B/op 10 allocs/op
BenchmarkGoji_GPlus2Params 1000000 1540 ns/op 336 B/op 2 allocs/op
BenchmarkGoJsonRest_GPlus2Params 1000000 2872 ns/op 721 B/op 15 allocs/op
BenchmarkGoRestful_GPlus2Params 100000 23030 ns/op 2720 B/op 35 allocs/op
BenchmarkGorillaMux_GPlus2Params 200000 10516 ns/op 816 B/op 9 allocs/op
BenchmarkHttpRouter_GPlus2Params 5000000 273 ns/op 64 B/op 1 allocs/op
BenchmarkHttpTreeMux_GPlus2Params 2000000 939 ns/op 336 B/op 2 allocs/op
BenchmarkKocha_GPlus2Params 2000000 844 ns/op 128 B/op 5 allocs/op
BenchmarkMacaron_GPlus2Params 500000 3914 ns/op 1168 B/op 12 allocs/op
BenchmarkMartini_GPlus2Params 50000 35759 ns/op 1280 B/op 16 allocs/op
BenchmarkPat_GPlus2Params 200000 7089 ns/op 2304 B/op 41 allocs/op
BenchmarkPossum_GPlus2Params 1000000 2093 ns/op 624 B/op 7 allocs/op
BenchmarkR2router_GPlus2Params 1000000 1320 ns/op 432 B/op 6 allocs/op
BenchmarkRevel_GPlus2Params 200000 7351 ns/op 1800 B/op 30 allocs/op
BenchmarkRivet_GPlus2Params 1000000 1485 ns/op 480 B/op 6 allocs/op
BenchmarkTango_GPlus2Params 1000000 2111 ns/op 448 B/op 12 allocs/op
BenchmarkTigerTonic_GPlus2Params 300000 6271 ns/op 1528 B/op 28 allocs/op
BenchmarkTraffic_GPlus2Params 100000 14886 ns/op 3312 B/op 34 allocs/op
BenchmarkVulcan_GPlus2Params 1000000 1883 ns/op 98 B/op 3 allocs/op
BenchmarkZeus_GPlus2Params 1000000 2686 ns/op 784 B/op 6 allocs/op
BenchmarkAce_GPlusAll 300000 5912 ns/op 640 B/op 11 allocs/op
BenchmarkBear_GPlusAll 100000 16448 ns/op 5072 B/op 61 allocs/op
BenchmarkBeego_GPlusAll 50000 32916 ns/op 8976 B/op 129 allocs/op
BenchmarkBone_GPlusAll 50000 25836 ns/op 6992 B/op 76 allocs/op
BenchmarkDenco_GPlusAll 500000 4462 ns/op 672 B/op 11 allocs/op
BenchmarkEcho_GPlusAll 500000 2806 ns/op 0 B/op 0 allocs/op
BenchmarkGin_GPlusAll 500000 2579 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GPlusAll 50000 25223 ns/op 8144 B/op 116 allocs/op
BenchmarkGoji_GPlusAll 100000 14237 ns/op 3696 B/op 22 allocs/op
BenchmarkGoJsonRest_GPlusAll 50000 29227 ns/op 8221 B/op 183 allocs/op
BenchmarkGoRestful_GPlusAll 10000 203144 ns/op 36064 B/op 441 allocs/op
BenchmarkGorillaMux_GPlusAll 20000 80906 ns/op 9712 B/op 115 allocs/op
BenchmarkHttpRouter_GPlusAll 500000 3040 ns/op 640 B/op 11 allocs/op
BenchmarkHttpTreeMux_GPlusAll 200000 9627 ns/op 3696 B/op 22 allocs/op
BenchmarkKocha_GPlusAll 200000 8108 ns/op 976 B/op 43 allocs/op
BenchmarkMacaron_GPlusAll 30000 48083 ns/op 13968 B/op 142 allocs/op
BenchmarkMartini_GPlusAll 10000 196978 ns/op 15072 B/op 178 allocs/op
BenchmarkPat_GPlusAll 30000 58865 ns/op 16880 B/op 343 allocs/op
BenchmarkPossum_GPlusAll 100000 19685 ns/op 6240 B/op 52 allocs/op
BenchmarkR2router_GPlusAll 100000 16251 ns/op 5040 B/op 76 allocs/op
BenchmarkRevel_GPlusAll 20000 93489 ns/op 21656 B/op 368 allocs/op
BenchmarkRivet_GPlusAll 100000 16907 ns/op 5408 B/op 64 allocs/op
```

191
vendor/github.com/gin-gonic/gin/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,191 @@
# CHANGELOG
### Gin 1.2
- [NEW] Switch from godeps to govendor
- [NEW] Add support for Let's Encrypt via gin-gonic/autotls
- [NEW] Improve README examples and add extra at examples folder
- [NEW] Improved support with App Engine
- [NEW] Add custom template delimiters, see #860
- [NEW] Add Template Func Maps, see #962
- [NEW] Add \*context.Handler(), see #928
- [NEW] Add \*context.GetRawData()
- [NEW] Add \*context.GetHeader() (request)
- [NEW] Add \*context.AbortWithStatusJSON() (JSON content type)
- [NEW] Add \*context.Keys type cast helpers
- [NEW] Add \*context.ShouldBindWith()
- [NEW] Add \*context.MustBindWith()
- [NEW] Add \*engine.SetFuncMap()
- [DEPRECATE] On next release: \*context.BindWith(), see #855
- [FIX] Refactor render
- [FIX] Reworked tests
- [FIX] logger now supports cygwin
- [FIX] Use X-Forwarded-For before X-Real-Ip
- [FIX] time.Time binding (#904)
### Gin 1.1.4
- [NEW] Support google appengine for IsTerminal func
### Gin 1.1.3
- [FIX] Reverted Logger: skip ANSI color commands
### Gin 1.1
- [NEW] Implement QueryArray and PostArray methods
- [NEW] Refactor GetQuery and GetPostForm
- [NEW] Add contribution guide
- [FIX] Corrected typos in README
- [FIX] Removed additional Iota
- [FIX] Changed imports to gopkg instead of github in README (#733)
- [FIX] Logger: skip ANSI color commands if output is not a tty
### Gin 1.0rc2 (...)
- [PERFORMANCE] Fast path for writing Content-Type.
- [PERFORMANCE] Much faster 404 routing
- [PERFORMANCE] Allocation optimizations
- [PERFORMANCE] Faster root tree lookup
- [PERFORMANCE] Zero overhead, String() and JSON() rendering.
- [PERFORMANCE] Faster ClientIP parsing
- [PERFORMANCE] Much faster SSE implementation
- [NEW] Benchmarks suite
- [NEW] Bind validation can be disabled and replaced with custom validators.
- [NEW] More flexible HTML render
- [NEW] Multipart and PostForm bindings
- [NEW] Adds method to return all the registered routes
- [NEW] Context.HandlerName() returns the main handler's name
- [NEW] Adds Error.IsType() helper
- [FIX] Binding multipart form
- [FIX] Integration tests
- [FIX] Crash when binding non struct object in Context.
- [FIX] RunTLS() implementation
- [FIX] Logger() unit tests
- [FIX] Adds SetHTMLTemplate() warning
- [FIX] Context.IsAborted()
- [FIX] More unit tests
- [FIX] JSON, XML, HTML renders accept custom content-types
- [FIX] gin.AbortIndex is unexported
- [FIX] Better approach to avoid directory listing in StaticFS()
- [FIX] Context.ClientIP() always returns the IP with trimmed spaces.
- [FIX] Better warning when running in debug mode.
- [FIX] Google App Engine integration. debugPrint does not use os.Stdout
- [FIX] Fixes integer overflow in error type
- [FIX] Error implements the json.Marshaller interface
- [FIX] MIT license in every file
### Gin 1.0rc1 (May 22, 2015)
- [PERFORMANCE] Zero allocation router
- [PERFORMANCE] Faster JSON, XML and text rendering
- [PERFORMANCE] Custom hand optimized HttpRouter for Gin
- [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations
- [NEW] Built-in support for golang.org/x/net/context
- [NEW] Any(path, handler). Create a route that matches any path
- [NEW] Refactored rendering pipeline (faster and static typeded)
- [NEW] Refactored errors API
- [NEW] IndentedJSON() prints pretty JSON
- [NEW] Added gin.DefaultWriter
- [NEW] UNIX socket support
- [NEW] RouterGroup.BasePath is exposed
- [NEW] JSON validation using go-validate-yourself (very powerful options)
- [NEW] Completed suite of unit tests
- [NEW] HTTP streaming with c.Stream()
- [NEW] StaticFile() creates a router for serving just one file.
- [NEW] StaticFS() has an option to disable directory listing.
- [NEW] StaticFS() for serving static files through virtual filesystems
- [NEW] Server-Sent Events native support
- [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler
- [NEW] Added LoggerWithWriter() middleware
- [NEW] Added RecoveryWithWriter() middleware
- [NEW] Added DefaultPostFormValue()
- [NEW] Added DefaultFormValue()
- [NEW] Added DefaultParamValue()
- [FIX] BasicAuth() when using custom realm
- [FIX] Bug when serving static files in nested routing group
- [FIX] Redirect using built-in http.Redirect()
- [FIX] Logger when printing the requested path
- [FIX] Documentation typos
- [FIX] Context.Engine renamed to Context.engine
- [FIX] Better debugging messages
- [FIX] ErrorLogger
- [FIX] Debug HTTP render
- [FIX] Refactored binding and render modules
- [FIX] Refactored Context initialization
- [FIX] Refactored BasicAuth()
- [FIX] NoMethod/NoRoute handlers
- [FIX] Hijacking http
- [FIX] Better support for Google App Engine (using log instead of fmt)
### Gin 0.6 (Mar 9, 2015)
- [NEW] Support multipart/form-data
- [NEW] NoMethod handler
- [NEW] Validate sub structures
- [NEW] Support for HTTP Realm Auth
- [FIX] Unsigned integers in binding
- [FIX] Improve color logger
### Gin 0.5 (Feb 7, 2015)
- [NEW] Content Negotiation
- [FIX] Solved security bug that allow a client to spoof ip
- [FIX] Fix unexported/ignored fields in binding
### Gin 0.4 (Aug 21, 2014)
- [NEW] Development mode
- [NEW] Unit tests
- [NEW] Add Content.Redirect()
- [FIX] Deferring WriteHeader()
- [FIX] Improved documentation for model binding
### Gin 0.3 (Jul 18, 2014)
- [PERFORMANCE] Normal log and error log are printed in the same call.
- [PERFORMANCE] Improve performance of NoRouter()
- [PERFORMANCE] Improve context's memory locality, reduce CPU cache faults.
- [NEW] Flexible rendering API
- [NEW] Add Context.File()
- [NEW] Add shorcut RunTLS() for http.ListenAndServeTLS
- [FIX] Rename NotFound404() to NoRoute()
- [FIX] Errors in context are purged
- [FIX] Adds HEAD method in Static file serving
- [FIX] Refactors Static() file serving
- [FIX] Using keyed initialization to fix app-engine integration
- [FIX] Can't unmarshal JSON array, #63
- [FIX] Renaming Context.Req to Context.Request
- [FIX] Check application/x-www-form-urlencoded when parsing form
### Gin 0.2b (Jul 08, 2014)
- [PERFORMANCE] Using sync.Pool to allocatio/gc overhead
- [NEW] Travis CI integration
- [NEW] Completely new logger
- [NEW] New API for serving static files. gin.Static()
- [NEW] gin.H() can be serialized into XML
- [NEW] Typed errors. Errors can be typed. Internet/external/custom.
- [NEW] Support for Godeps
- [NEW] Travis/Godocs badges in README
- [NEW] New Bind() and BindWith() methods for parsing request body.
- [NEW] Add Content.Copy()
- [NEW] Add context.LastError()
- [NEW] Add shorcut for OPTIONS HTTP method
- [FIX] Tons of README fixes
- [FIX] Header is written before body
- [FIX] BasicAuth() and changes API a little bit
- [FIX] Recovery() middleware only prints panics
- [FIX] Context.Get() does not panic anymore. Use MustGet() instead.
- [FIX] Multiple http.WriteHeader() in NotFound handlers
- [FIX] Engine.Run() panics if http server can't be setted up
- [FIX] Crash when route path doesn't start with '/'
- [FIX] Do not update header when status code is negative
- [FIX] Setting response headers before calling WriteHeader in context.String()
- [FIX] Add MIT license
- [FIX] Changes behaviour of ErrorLogger() and Logger()

21
vendor/github.com/gin-gonic/gin/LICENSE generated vendored Normal file
View File

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

61
vendor/github.com/gin-gonic/gin/Makefile generated vendored Normal file
View File

@@ -0,0 +1,61 @@
GOFMT ?= gofmt "-s"
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*")
all: build
install: deps
govendor sync
.PHONY: test
test:
go test -v -covermode=count -coverprofile=coverage.out
.PHONY: fmt
fmt:
$(GOFMT) -w $(GOFILES)
.PHONY: fmt-check
fmt-check:
# get all go files and run go fmt on them
@diff=$$($(GOFMT) -d $(GOFILES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
vet:
go vet $(PACKAGES)
deps:
@hash govendor > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/kardianos/govendor; \
fi
@hash embedmd > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/campoy/embedmd; \
fi
embedmd:
embedmd -d *.md
.PHONY: lint
lint:
@hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/golang/lint/golint; \
fi
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
.PHONY: misspell-check
misspell-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -error $(GOFILES)
.PHONY: misspell
misspell:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -w $(GOFILES)

977
vendor/github.com/gin-gonic/gin/README.md generated vendored Normal file
View File

@@ -0,0 +1,977 @@
# Gin Web Framework
<img align="right" src="https://raw.githubusercontent.com/gin-gonic/gin/master/logo.jpg">
[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)
[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin)
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin)
[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin)
[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.
![Gin console logger](https://gin-gonic.github.io/gin/other/console.png)
```sh
$ cat test.go
```
```go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
```
## Benchmarks
Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter)
[See all benchmarks](/BENCHMARKS.md)
Benchmark name | (1) | (2) | (3) | (4)
--------------------------------|----------:|----------:|----------:|------:
BenchmarkAce_GithubAll | 10000 | 109482 | 13792 | 167
BenchmarkBear_GithubAll | 10000 | 287490 | 79952 | 943
BenchmarkBeego_GithubAll | 3000 | 562184 | 146272 | 2092
BenchmarkBone_GithubAll | 500 | 2578716 | 648016 | 8119
BenchmarkDenco_GithubAll | 20000 | 94955 | 20224 | 167
BenchmarkEcho_GithubAll | 30000 | 58705 | 0 | 0
**BenchmarkGin_GithubAll** | **30000** | **50991** | **0** | **0**
BenchmarkGocraftWeb_GithubAll | 5000 | 449648 | 133280 | 1889
BenchmarkGoji_GithubAll | 2000 | 689748 | 56113 | 334
BenchmarkGoJsonRest_GithubAll | 5000 | 537769 | 135995 | 2940
BenchmarkGoRestful_GithubAll | 100 | 18410628 | 797236 | 7725
BenchmarkGorillaMux_GithubAll | 200 | 8036360 | 153137 | 1791
BenchmarkHttpRouter_GithubAll | 20000 | 63506 | 13792 | 167
BenchmarkHttpTreeMux_GithubAll | 10000 | 165927 | 56112 | 334
BenchmarkKocha_GithubAll | 10000 | 171362 | 23304 | 843
BenchmarkMacaron_GithubAll | 2000 | 817008 | 224960 | 2315
BenchmarkMartini_GithubAll | 100 | 12609209 | 237952 | 2686
BenchmarkPat_GithubAll | 300 | 4830398 | 1504101 | 32222
BenchmarkPossum_GithubAll | 10000 | 301716 | 97440 | 812
BenchmarkR2router_GithubAll | 10000 | 270691 | 77328 | 1182
BenchmarkRevel_GithubAll | 1000 | 1491919 | 345553 | 5918
BenchmarkRivet_GithubAll | 10000 | 283860 | 84272 | 1079
BenchmarkTango_GithubAll | 5000 | 473821 | 87078 | 2470
BenchmarkTigerTonic_GithubAll | 2000 | 1120131 | 241088 | 6052
BenchmarkTraffic_GithubAll | 200 | 8708979 | 2664762 | 22390
BenchmarkVulcan_GithubAll | 5000 | 353392 | 19894 | 609
BenchmarkZeus_GithubAll | 2000 | 944234 | 300688 | 2648
(1): Total Repetitions
(2): Single Repetition Duration (ns/op)
(3): Heap Memory (B/op)
(4): Average Allocations per Repetition (allocs/op)
## Gin v1. stable
- [x] Zero allocation router.
- [x] Still the fastest http router and framework. From routing to writing.
- [x] Complete suite of unit tests
- [x] Battle tested
- [x] API frozen, new releases will not break your code.
## Start using it
1. Download and install it:
```sh
$ go get github.com/gin-gonic/gin
```
2. Import it in your code:
```go
import "github.com/gin-gonic/gin"
```
3. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`.
```go
import "net/http"
```
## API Examples
### Using GET, POST, PUT, PATCH, DELETE and OPTIONS
```go
func main() {
// Disable Console Color
// gin.DisableConsoleColor()
// Creates a gin router with default middleware:
// logger and recovery (crash-free) middleware
router := gin.Default()
router.GET("/someGet", getting)
router.POST("/somePost", posting)
router.PUT("/somePut", putting)
router.DELETE("/someDelete", deleting)
router.PATCH("/somePatch", patching)
router.HEAD("/someHead", head)
router.OPTIONS("/someOptions", options)
// By default it serves on :8080 unless a
// PORT environment variable was defined.
router.Run()
// router.Run(":3000") for a hard coded port
}
```
### Parameters in path
```go
func main() {
router := gin.Default()
// This handler will match /user/john but will not match neither /user/ or /user
router.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name")
c.String(http.StatusOK, "Hello %s", name)
})
// However, this one will match /user/john/ and also /user/john/send
// If no other routers match /user/john, it will redirect to /user/john/
router.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
message := name + " is " + action
c.String(http.StatusOK, message)
})
router.Run(":8080")
}
```
### Querystring parameters
```go
func main() {
router := gin.Default()
// Query string parameters are parsed using the existing underlying request object.
// The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe
router.GET("/welcome", func(c *gin.Context) {
firstname := c.DefaultQuery("firstname", "Guest")
lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")
c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
})
router.Run(":8080")
}
```
### Multipart/Urlencoded Form
```go
func main() {
router := gin.Default()
router.POST("/form_post", func(c *gin.Context) {
message := c.PostForm("message")
nick := c.DefaultPostForm("nick", "anonymous")
c.JSON(200, gin.H{
"status": "posted",
"message": message,
"nick": nick,
})
})
router.Run(":8080")
}
```
### Another example: query + post form
```
POST /post?id=1234&page=1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
name=manu&message=this_is_great
```
```go
func main() {
router := gin.Default()
router.POST("/post", func(c *gin.Context) {
id := c.Query("id")
page := c.DefaultQuery("page", "0")
name := c.PostForm("name")
message := c.PostForm("message")
fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
})
router.Run(":8080")
}
```
```
id: 1234; page: 1; name: manu; message: this_is_great
```
### Upload files
#### Single file
References issue [#774](https://github.com/gin-gonic/gin/issues/774) and detail [example code](examples/upload-file/single).
```go
func main() {
router := gin.Default()
router.POST("/upload", func(c *gin.Context) {
// single file
file, _ := c.FormFile("file")
log.Println(file.Filename)
c.String(http.StatusOK, fmt.Printf("'%s' uploaded!", file.Filename))
})
router.Run(":8080")
}
```
How to `curl`:
```bash
curl -X POST http://localhost:8080/upload \
-F "file=@/Users/appleboy/test.zip" \
-H "Content-Type: multipart/form-data"
```
#### Multiple files
See the detail [example code](examples/upload-file/multiple).
```go
func main() {
router := gin.Default()
router.POST("/upload", func(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
files := form.File["upload[]"]
for _, file := range files {
log.Println(file.Filename)
}
c.String(http.StatusOK, fmt.Printf("%d files uploaded!", len(files)))
})
router.Run(":8080")
}
```
How to `curl`:
```bash
curl -X POST http://localhost:8080/upload \
-F "upload[]=@/Users/appleboy/test1.zip" \
-F "upload[]=@/Users/appleboy/test2.zip" \
-H "Content-Type: multipart/form-data"
```
### Grouping routes
```go
func main() {
router := gin.Default()
// Simple group: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// Simple group: v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}
router.Run(":8080")
}
```
### Blank Gin without middleware by default
Use
```go
r := gin.New()
```
instead of
```go
r := gin.Default()
```
### Using middleware
```go
func main() {
// Creates a router without any middleware by default
r := gin.New()
// Global middleware
r.Use(gin.Logger())
r.Use(gin.Recovery())
// Per route middleware, you can add as many as you desire.
r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
// Authorization group
// authorized := r.Group("/", AuthRequired())
// exactly the same as:
authorized := r.Group("/")
// per group middleware! in this case we use the custom created
// AuthRequired() middleware just in the "authorized" group.
authorized.Use(AuthRequired())
{
authorized.POST("/login", loginEndpoint)
authorized.POST("/submit", submitEndpoint)
authorized.POST("/read", readEndpoint)
// nested group
testing := authorized.Group("testing")
testing.GET("/analytics", analyticsEndpoint)
}
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
### Model binding and validation
To bind a request body into a type, use model binding. We currently support binding of JSON, XML and standard form values (foo=bar&boo=baz).
Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`.
When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use BindWith.
You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has a empty value when binding, the current request will fail with an error.
```go
// Binding from JSON
type Login struct {
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
func main() {
router := gin.Default()
// Example for binding JSON ({"user": "manu", "password": "123"})
router.POST("/loginJSON", func(c *gin.Context) {
var json Login
if c.BindJSON(&json) == nil {
if json.User == "manu" && json.Password == "123" {
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
}
}
})
// Example for binding a HTML form (user=manu&password=123)
router.POST("/loginForm", func(c *gin.Context) {
var form Login
// This will infer what binder to use depending on the content-type header.
if c.Bind(&form) == nil {
if form.User == "manu" && form.Password == "123" {
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
}
}
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
```
### Bind Query String
See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292).
```go
package main
import "log"
import "github.com/gin-gonic/gin"
type Person struct {
Name string `form:"name"`
Address string `form:"address"`
}
func main() {
route := gin.Default()
route.GET("/testing", startPage)
route.Run(":8085")
}
func startPage(c *gin.Context) {
var person Person
// If `GET`, only `Form` binding engine (`query`) used.
// If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).
// See more at https://github.com/gin-gonic/gin/blob/develop/binding/binding.go#L45
if c.Bind(&person) == nil {
log.Println(person.Name)
log.Println(person.Address)
}
c.String(200, "Success")
}
```
### Multipart/Urlencoded binding
```go
package main
import (
"github.com/gin-gonic/gin"
)
type LoginForm struct {
User string `form:"user" binding:"required"`
Password string `form:"password" binding:"required"`
}
func main() {
router := gin.Default()
router.POST("/login", func(c *gin.Context) {
// you can bind multipart form with explicit binding declaration:
// c.MustBindWith(&form, binding.Form)
// or you can simply use autobinding with Bind method:
var form LoginForm
// in this case proper binding will be automatically selected
if c.Bind(&form) == nil {
if form.User == "user" && form.Password == "password" {
c.JSON(200, gin.H{"status": "you are logged in"})
} else {
c.JSON(401, gin.H{"status": "unauthorized"})
}
}
})
router.Run(":8080")
}
```
Test it with:
```sh
$ curl -v --form user=user --form password=password http://localhost:8080/login
```
### XML, JSON and YAML rendering
```go
func main() {
r := gin.Default()
// gin.H is a shortcut for map[string]interface{}
r.GET("/someJSON", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})
r.GET("/moreJSON", func(c *gin.Context) {
// You also can use a struct
var msg struct {
Name string `json:"user"`
Message string
Number int
}
msg.Name = "Lena"
msg.Message = "hey"
msg.Number = 123
// Note that msg.Name becomes "user" in the JSON
// Will output : {"user": "Lena", "Message": "hey", "Number": 123}
c.JSON(http.StatusOK, msg)
})
r.GET("/someXML", func(c *gin.Context) {
c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})
r.GET("/someYAML", func(c *gin.Context) {
c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
### Serving static files
```go
func main() {
router := gin.Default()
router.Static("/assets", "./assets")
router.StaticFS("/more_static", http.Dir("my_file_system"))
router.StaticFile("/favicon.ico", "./resources/favicon.ico")
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
```
### HTML rendering
Using LoadHTMLGlob() or LoadHTMLFiles()
```go
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/*")
//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
router.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "Main website",
})
})
router.Run(":8080")
}
```
templates/index.tmpl
```html
<html>
<h1>
{{ .title }}
</h1>
</html>
```
Using templates with same name in different directories
```go
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/**/*")
router.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts",
})
})
router.GET("/users/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "Users",
})
})
router.Run(":8080")
}
```
templates/posts/index.tmpl
```html
{{ define "posts/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using posts/index.tmpl</p>
</html>
{{ end }}
```
templates/users/index.tmpl
```html
{{ define "users/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using users/index.tmpl</p>
</html>
{{ end }}
```
You can also use your own html template render
```go
import "html/template"
func main() {
router := gin.Default()
html := template.Must(template.ParseFiles("file1", "file2"))
router.SetHTMLTemplate(html)
router.Run(":8080")
}
```
You may use custom delims
```go
r := gin.Default()
r.Delims("{[{", "}]}")
r.LoadHTMLGlob("/path/to/templates"))
```
#### Add custom template funcs
main.go
```go
...
func formatAsDate(t time.Time) string {
year, month, day := t.Date()
return fmt.Sprintf("%d/%02d/%02d", year, month, day)
}
...
router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate,
})
...
router.GET("/raw", func(c *Context) {
c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
})
})
...
```
raw.tmpl
```html
Date: {[{.now | formatAsDate}]}
```
Result:
```
Date: 2017/07/01
```
### Multitemplate
Gin allow by default use only one html.Template. Check [a multitemplate render](https://github.com/gin-contrib/multitemplate) for using features like go 1.6 `block template`.
### Redirects
Issuing a HTTP redirect is easy:
```go
r.GET("/test", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
})
```
Both internal and external locations are supported.
### Custom Middleware
```go
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
// Set example variable
c.Set("example", "12345")
// before request
c.Next()
// after request
latency := time.Since(t)
log.Print(latency)
// access the status we are sending
status := c.Writer.Status()
log.Println(status)
}
}
func main() {
r := gin.New()
r.Use(Logger())
r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)
// it would print: "12345"
log.Println(example)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
### Using BasicAuth() middleware
```go
// simulate some private data
var secrets = gin.H{
"foo": gin.H{"email": "foo@bar.com", "phone": "123433"},
"austin": gin.H{"email": "austin@example.com", "phone": "666"},
"lena": gin.H{"email": "lena@guapa.com", "phone": "523443"},
}
func main() {
r := gin.Default()
// Group using gin.BasicAuth() middleware
// gin.Accounts is a shortcut for map[string]string
authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{
"foo": "bar",
"austin": "1234",
"lena": "hello2",
"manu": "4321",
}))
// /admin/secrets endpoint
// hit "localhost:8080/admin/secrets
authorized.GET("/secrets", func(c *gin.Context) {
// get user, it was set by the BasicAuth middleware
user := c.MustGet(gin.AuthUserKey).(string)
if secret, ok := secrets[user]; ok {
c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})
} else {
c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("})
}
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
### Goroutines inside a middleware
When starting inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy.
```go
func main() {
r := gin.Default()
r.GET("/long_async", func(c *gin.Context) {
// create copy to be used inside the goroutine
cCp := c.Copy()
go func() {
// simulate a long task with time.Sleep(). 5 seconds
time.Sleep(5 * time.Second)
// note that you are using the copied context "cCp", IMPORTANT
log.Println("Done! in path " + cCp.Request.URL.Path)
}()
})
r.GET("/long_sync", func(c *gin.Context) {
// simulate a long task with time.Sleep(). 5 seconds
time.Sleep(5 * time.Second)
// since we are NOT using a goroutine, we do not have to copy the context
log.Println("Done! in path " + c.Request.URL.Path)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
### Custom HTTP configuration
Use `http.ListenAndServe()` directly, like this:
```go
func main() {
router := gin.Default()
http.ListenAndServe(":8080", router)
}
```
or
```go
func main() {
router := gin.Default()
s := &http.Server{
Addr: ":8080",
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()
}
```
### Support Let's Encrypt
example for 1-line LetsEncrypt HTTPS servers.
[embedmd]:# (examples/auto-tls/example1.go go)
```go
package main
import (
"log"
"github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Ping handler
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
log.Fatal(autotls.Run(r, "example1.com", "example2.com"))
}
```
example for custom autocert manager.
[embedmd]:# (examples/auto-tls/example2.go go)
```go
package main
import (
"log"
"github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/acme/autocert"
)
func main() {
r := gin.Default()
// Ping handler
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
Cache: autocert.DirCache("/var/www/.cache"),
}
log.Fatal(autotls.RunWithManager(r, m))
}
```
### Graceful restart or stop
Do you want to graceful restart or stop your web server?
There are some ways this can be done.
We can use [fvbock/endless](https://github.com/fvbock/endless) to replace the default `ListenAndServe`. Refer issue [#296](https://github.com/gin-gonic/gin/issues/296) for more details.
```go
router := gin.Default()
router.GET("/", handler)
// [...]
endless.ListenAndServe(":4242", router)
```
An alternative to endless:
* [manners](https://github.com/braintree/manners): A polite Go HTTP server that shuts down gracefully.
* [graceful](https://github.com/tylerb/graceful): Graceful is a Go package enabling graceful shutdown of an http.Handler server.
* [grace](https://github.com/facebookgo/grace): Graceful restart & zero downtime deploy for Go servers.
If you are using Go 1.8, you may not need to use this library! Consider using http.Server's built-in [Shutdown()](https://golang.org/pkg/net/http/#Server.Shutdown) method for graceful shutdowns. See the full [graceful-shutdown](./examples/graceful-shutdown) example with gin.
[embedmd]:# (examples/graceful-shutdown/graceful-shutdown/server.go go)
```go
// +build go1.8
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"time"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
time.Sleep(5 * time.Second)
c.String(http.StatusOK, "Welcome Gin Server")
})
srv := &http.Server{
Addr: ":8080",
Handler: router,
}
go func() {
// service connections
if err := srv.ListenAndServe(); err != nil {
log.Printf("listen: %s\n", err)
}
}()
// Wait for interrupt signal to gracefully shutdown the server with
// a timeout of 5 seconds.
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
<-quit
log.Println("Shutdown Server ...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server Shutdown:", err)
}
log.Println("Server exist")
}
```
## Contributing
- With issues:
- Use the search tool before opening a new issue.
- Please provide source code and commit sha if you found a bug.
- Review existing issues and provide feedback or react to them.
- With pull requests:
- Open your pull request against develop
- Your pull request should have no more than two commits, if not you should squash them.
- It should pass all tests in the available continuous integrations systems such as TravisCI.
- You should add/modify tests to cover your proposed code changes.
- If your pull request contains a new feature, please document it on the README.
## Users
Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework.
* [drone](https://github.com/drone/drone): Drone is a Continuous Delivery platform built on Docker, written in Go
* [gorush](https://github.com/appleboy/gorush): A push notification server written in Go.

92
vendor/github.com/gin-gonic/gin/auth.go generated vendored Normal file
View File

@@ -0,0 +1,92 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"crypto/subtle"
"encoding/base64"
"strconv"
)
const AuthUserKey = "user"
type (
Accounts map[string]string
authPair struct {
Value string
User string
}
authPairs []authPair
)
func (a authPairs) searchCredential(authValue string) (string, bool) {
if len(authValue) == 0 {
return "", false
}
for _, pair := range a {
if pair.Value == authValue {
return pair.User, true
}
}
return "", false
}
// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where
// the key is the user name and the value is the password, as well as the name of the Realm.
// If the realm is empty, "Authorization Required" will be used by default.
// (see http://tools.ietf.org/html/rfc2617#section-1.2)
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
if realm == "" {
realm = "Authorization Required"
}
realm = "Basic realm=" + strconv.Quote(realm)
pairs := processAccounts(accounts)
return func(c *Context) {
// Search user in the slice of allowed credentials
user, found := pairs.searchCredential(c.Request.Header.Get("Authorization"))
if !found {
// Credentials doesn't match, we return 401 and abort handlers chain.
c.Header("WWW-Authenticate", realm)
c.AbortWithStatus(401)
} else {
// The user credentials was found, set user's id to key AuthUserKey in this context, the userId can be read later using
// c.MustGet(gin.AuthUserKey)
c.Set(AuthUserKey, user)
}
}
}
// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where
// the key is the user name and the value is the password.
func BasicAuth(accounts Accounts) HandlerFunc {
return BasicAuthForRealm(accounts, "")
}
func processAccounts(accounts Accounts) authPairs {
assert1(len(accounts) > 0, "Empty list of authorized credentials")
pairs := make(authPairs, 0, len(accounts))
for user, password := range accounts {
assert1(len(user) > 0, "User can not be empty")
value := authorizationHeader(user, password)
pairs = append(pairs, authPair{
Value: value,
User: user,
})
}
return pairs
}
func authorizationHeader(user, password string) string {
base := user + ":" + password
return "Basic " + base64.StdEncoding.EncodeToString([]byte(base))
}
func secureCompare(given, actual string) bool {
if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1
}
/* Securely compare actual to itself to keep constant time, but always return false */
return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
}

146
vendor/github.com/gin-gonic/gin/auth_test.go generated vendored Normal file
View File

@@ -0,0 +1,146 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"encoding/base64"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestBasicAuth(t *testing.T) {
pairs := processAccounts(Accounts{
"admin": "password",
"foo": "bar",
"bar": "foo",
})
assert.Len(t, pairs, 3)
assert.Contains(t, pairs, authPair{
User: "bar",
Value: "Basic YmFyOmZvbw==",
})
assert.Contains(t, pairs, authPair{
User: "foo",
Value: "Basic Zm9vOmJhcg==",
})
assert.Contains(t, pairs, authPair{
User: "admin",
Value: "Basic YWRtaW46cGFzc3dvcmQ=",
})
}
func TestBasicAuthFails(t *testing.T) {
assert.Panics(t, func() { processAccounts(nil) })
assert.Panics(t, func() {
processAccounts(Accounts{
"": "password",
"foo": "bar",
})
})
}
func TestBasicAuthSearchCredential(t *testing.T) {
pairs := processAccounts(Accounts{
"admin": "password",
"foo": "bar",
"bar": "foo",
})
user, found := pairs.searchCredential(authorizationHeader("admin", "password"))
assert.Equal(t, user, "admin")
assert.True(t, found)
user, found = pairs.searchCredential(authorizationHeader("foo", "bar"))
assert.Equal(t, user, "foo")
assert.True(t, found)
user, found = pairs.searchCredential(authorizationHeader("bar", "foo"))
assert.Equal(t, user, "bar")
assert.True(t, found)
user, found = pairs.searchCredential(authorizationHeader("admins", "password"))
assert.Empty(t, user)
assert.False(t, found)
user, found = pairs.searchCredential(authorizationHeader("foo", "bar "))
assert.Empty(t, user)
assert.False(t, found)
user, found = pairs.searchCredential("")
assert.Empty(t, user)
assert.False(t, found)
}
func TestBasicAuthAuthorizationHeader(t *testing.T) {
assert.Equal(t, authorizationHeader("admin", "password"), "Basic YWRtaW46cGFzc3dvcmQ=")
}
func TestBasicAuthSecureCompare(t *testing.T) {
assert.True(t, secureCompare("1234567890", "1234567890"))
assert.False(t, secureCompare("123456789", "1234567890"))
assert.False(t, secureCompare("12345678900", "1234567890"))
assert.False(t, secureCompare("1234567891", "1234567890"))
}
func TestBasicAuthSucceed(t *testing.T) {
accounts := Accounts{"admin": "password"}
router := New()
router.Use(BasicAuth(accounts))
router.GET("/login", func(c *Context) {
c.String(200, c.MustGet(AuthUserKey).(string))
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/login", nil)
req.Header.Set("Authorization", authorizationHeader("admin", "password"))
router.ServeHTTP(w, req)
assert.Equal(t, w.Code, 200)
assert.Equal(t, w.Body.String(), "admin")
}
func TestBasicAuth401(t *testing.T) {
called := false
accounts := Accounts{"foo": "bar"}
router := New()
router.Use(BasicAuth(accounts))
router.GET("/login", func(c *Context) {
called = true
c.String(200, c.MustGet(AuthUserKey).(string))
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/login", nil)
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
router.ServeHTTP(w, req)
assert.False(t, called)
assert.Equal(t, w.Code, 401)
assert.Equal(t, w.HeaderMap.Get("WWW-Authenticate"), "Basic realm=\"Authorization Required\"")
}
func TestBasicAuth401WithCustomRealm(t *testing.T) {
called := false
accounts := Accounts{"foo": "bar"}
router := New()
router.Use(BasicAuthForRealm(accounts, "My Custom \"Realm\""))
router.GET("/login", func(c *Context) {
called = true
c.String(200, c.MustGet(AuthUserKey).(string))
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/login", nil)
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
router.ServeHTTP(w, req)
assert.False(t, called)
assert.Equal(t, w.Code, 401)
assert.Equal(t, w.HeaderMap.Get("WWW-Authenticate"), "Basic realm=\"My Custom \\\"Realm\\\"\"")
}

162
vendor/github.com/gin-gonic/gin/benchmarks_test.go generated vendored Normal file
View File

@@ -0,0 +1,162 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"html/template"
"net/http"
"os"
"testing"
)
func BenchmarkOneRoute(B *testing.B) {
router := New()
router.GET("/ping", func(c *Context) {})
runRequest(B, router, "GET", "/ping")
}
func BenchmarkRecoveryMiddleware(B *testing.B) {
router := New()
router.Use(Recovery())
router.GET("/", func(c *Context) {})
runRequest(B, router, "GET", "/")
}
func BenchmarkLoggerMiddleware(B *testing.B) {
router := New()
router.Use(LoggerWithWriter(newMockWriter()))
router.GET("/", func(c *Context) {})
runRequest(B, router, "GET", "/")
}
func BenchmarkManyHandlers(B *testing.B) {
router := New()
router.Use(Recovery(), LoggerWithWriter(newMockWriter()))
router.Use(func(c *Context) {})
router.Use(func(c *Context) {})
router.GET("/ping", func(c *Context) {})
runRequest(B, router, "GET", "/ping")
}
func Benchmark5Params(B *testing.B) {
DefaultWriter = os.Stdout
router := New()
router.Use(func(c *Context) {})
router.GET("/param/:param1/:params2/:param3/:param4/:param5", func(c *Context) {})
runRequest(B, router, "GET", "/param/path/to/parameter/john/12345")
}
func BenchmarkOneRouteJSON(B *testing.B) {
router := New()
data := struct {
Status string `json:"status"`
}{"ok"}
router.GET("/json", func(c *Context) {
c.JSON(200, data)
})
runRequest(B, router, "GET", "/json")
}
var htmlContentType = []string{"text/html; charset=utf-8"}
func BenchmarkOneRouteHTML(B *testing.B) {
router := New()
t := template.Must(template.New("index").Parse(`
<html><body><h1>{{.}}</h1></body></html>`))
router.SetHTMLTemplate(t)
router.GET("/html", func(c *Context) {
c.HTML(200, "index", "hola")
})
runRequest(B, router, "GET", "/html")
}
func BenchmarkOneRouteSet(B *testing.B) {
router := New()
router.GET("/ping", func(c *Context) {
c.Set("key", "value")
})
runRequest(B, router, "GET", "/ping")
}
func BenchmarkOneRouteString(B *testing.B) {
router := New()
router.GET("/text", func(c *Context) {
c.String(200, "this is a plain text")
})
runRequest(B, router, "GET", "/text")
}
func BenchmarkManyRoutesFist(B *testing.B) {
router := New()
router.Any("/ping", func(c *Context) {})
runRequest(B, router, "GET", "/ping")
}
func BenchmarkManyRoutesLast(B *testing.B) {
router := New()
router.Any("/ping", func(c *Context) {})
runRequest(B, router, "OPTIONS", "/ping")
}
func Benchmark404(B *testing.B) {
router := New()
router.Any("/something", func(c *Context) {})
router.NoRoute(func(c *Context) {})
runRequest(B, router, "GET", "/ping")
}
func Benchmark404Many(B *testing.B) {
router := New()
router.GET("/", func(c *Context) {})
router.GET("/path/to/something", func(c *Context) {})
router.GET("/post/:id", func(c *Context) {})
router.GET("/view/:id", func(c *Context) {})
router.GET("/favicon.ico", func(c *Context) {})
router.GET("/robots.txt", func(c *Context) {})
router.GET("/delete/:id", func(c *Context) {})
router.GET("/user/:id/:mode", func(c *Context) {})
router.NoRoute(func(c *Context) {})
runRequest(B, router, "GET", "/viewfake")
}
type mockWriter struct {
headers http.Header
}
func newMockWriter() *mockWriter {
return &mockWriter{
http.Header{},
}
}
func (m *mockWriter) Header() (h http.Header) {
return m.headers
}
func (m *mockWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
func (m *mockWriter) WriteString(s string) (n int, err error) {
return len(s), nil
}
func (m *mockWriter) WriteHeader(int) {}
func runRequest(B *testing.B, r *Engine, method, path string) {
// create fake request
req, err := http.NewRequest(method, path, nil)
if err != nil {
panic(err)
}
w := newMockWriter()
B.ReportAllocs()
B.ResetTimer()
for i := 0; i < B.N; i++ {
r.ServeHTTP(w, req)
}
}

72
vendor/github.com/gin-gonic/gin/binding/binding.go generated vendored Normal file
View File

@@ -0,0 +1,72 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import "net/http"
const (
MIMEJSON = "application/json"
MIMEHTML = "text/html"
MIMEXML = "application/xml"
MIMEXML2 = "text/xml"
MIMEPlain = "text/plain"
MIMEPOSTForm = "application/x-www-form-urlencoded"
MIMEMultipartPOSTForm = "multipart/form-data"
MIMEPROTOBUF = "application/x-protobuf"
MIMEMSGPACK = "application/x-msgpack"
MIMEMSGPACK2 = "application/msgpack"
)
type Binding interface {
Name() string
Bind(*http.Request, interface{}) error
}
type StructValidator interface {
// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
// If the received type is not a struct, any validation should be skipped and nil must be returned.
// If the received type is a struct or pointer to a struct, the validation should be performed.
// If the struct is not valid or the validation itself fails, a descriptive error should be returned.
// Otherwise nil must be returned.
ValidateStruct(interface{}) error
}
var Validator StructValidator = &defaultValidator{}
var (
JSON = jsonBinding{}
XML = xmlBinding{}
Form = formBinding{}
FormPost = formPostBinding{}
FormMultipart = formMultipartBinding{}
ProtoBuf = protobufBinding{}
MsgPack = msgpackBinding{}
)
func Default(method, contentType string) Binding {
if method == "GET" {
return Form
}
switch contentType {
case MIMEJSON:
return JSON
case MIMEXML, MIMEXML2:
return XML
case MIMEPROTOBUF:
return ProtoBuf
case MIMEMSGPACK, MIMEMSGPACK2:
return MsgPack
default: //case MIMEPOSTForm, MIMEMultipartPOSTForm:
return Form
}
}
func validate(obj interface{}) error {
if Validator == nil {
return nil
}
return Validator.ValidateStruct(obj)
}

259
vendor/github.com/gin-gonic/gin/binding/binding_test.go generated vendored Normal file
View File

@@ -0,0 +1,259 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import (
"bytes"
"mime/multipart"
"net/http"
"testing"
"github.com/gin-gonic/gin/binding/example"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
"github.com/ugorji/go/codec"
)
type FooStruct struct {
Foo string `msgpack:"foo" json:"foo" form:"foo" xml:"foo" binding:"required"`
}
type FooBarStruct struct {
FooStruct
Bar string `msgpack:"bar" json:"bar" form:"bar" xml:"bar" binding:"required"`
}
func TestBindingDefault(t *testing.T) {
assert.Equal(t, Default("GET", ""), Form)
assert.Equal(t, Default("GET", MIMEJSON), Form)
assert.Equal(t, Default("POST", MIMEJSON), JSON)
assert.Equal(t, Default("PUT", MIMEJSON), JSON)
assert.Equal(t, Default("POST", MIMEXML), XML)
assert.Equal(t, Default("PUT", MIMEXML2), XML)
assert.Equal(t, Default("POST", MIMEPOSTForm), Form)
assert.Equal(t, Default("PUT", MIMEPOSTForm), Form)
assert.Equal(t, Default("POST", MIMEMultipartPOSTForm), Form)
assert.Equal(t, Default("PUT", MIMEMultipartPOSTForm), Form)
assert.Equal(t, Default("POST", MIMEPROTOBUF), ProtoBuf)
assert.Equal(t, Default("PUT", MIMEPROTOBUF), ProtoBuf)
assert.Equal(t, Default("POST", MIMEMSGPACK), MsgPack)
assert.Equal(t, Default("PUT", MIMEMSGPACK2), MsgPack)
}
func TestBindingJSON(t *testing.T) {
testBodyBinding(t,
JSON, "json",
"/", "/",
`{"foo": "bar"}`, `{"bar": "foo"}`)
}
func TestBindingForm(t *testing.T) {
testFormBinding(t, "POST",
"/", "/",
"foo=bar&bar=foo", "bar2=foo")
}
func TestBindingForm2(t *testing.T) {
testFormBinding(t, "GET",
"/?foo=bar&bar=foo", "/?bar2=foo",
"", "")
}
func TestBindingXML(t *testing.T) {
testBodyBinding(t,
XML, "xml",
"/", "/",
"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
}
func createFormPostRequest() *http.Request {
req, _ := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo"))
req.Header.Set("Content-Type", MIMEPOSTForm)
return req
}
func createFormMultipartRequest() *http.Request {
boundary := "--testboundary"
body := new(bytes.Buffer)
mw := multipart.NewWriter(body)
defer mw.Close()
mw.SetBoundary(boundary)
mw.WriteField("foo", "bar")
mw.WriteField("bar", "foo")
req, _ := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
return req
}
func TestBindingFormPost(t *testing.T) {
req := createFormPostRequest()
var obj FooBarStruct
FormPost.Bind(req, &obj)
assert.Equal(t, obj.Foo, "bar")
assert.Equal(t, obj.Bar, "foo")
}
func TestBindingFormMultipart(t *testing.T) {
req := createFormMultipartRequest()
var obj FooBarStruct
FormMultipart.Bind(req, &obj)
assert.Equal(t, obj.Foo, "bar")
assert.Equal(t, obj.Bar, "foo")
}
func TestBindingProtoBuf(t *testing.T) {
test := &example.Test{
Label: proto.String("yes"),
}
data, _ := proto.Marshal(test)
testProtoBodyBinding(t,
ProtoBuf, "protobuf",
"/", "/",
string(data), string(data[1:]))
}
func TestBindingMsgPack(t *testing.T) {
test := FooStruct{
Foo: "bar",
}
h := new(codec.MsgpackHandle)
assert.NotNil(t, h)
buf := bytes.NewBuffer([]byte{})
assert.NotNil(t, buf)
err := codec.NewEncoder(buf, h).Encode(test)
assert.NoError(t, err)
data := buf.Bytes()
testMsgPackBodyBinding(t,
MsgPack, "msgpack",
"/", "/",
string(data), string(data[1:]))
}
func TestValidationFails(t *testing.T) {
var obj FooStruct
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
err := JSON.Bind(req, &obj)
assert.Error(t, err)
}
func TestValidationDisabled(t *testing.T) {
backup := Validator
Validator = nil
defer func() { Validator = backup }()
var obj FooStruct
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
err := JSON.Bind(req, &obj)
assert.NoError(t, err)
}
func TestExistsSucceeds(t *testing.T) {
type HogeStruct struct {
Hoge *int `json:"hoge" binding:"exists"`
}
var obj HogeStruct
req := requestWithBody("POST", "/", `{"hoge": 0}`)
err := JSON.Bind(req, &obj)
assert.NoError(t, err)
}
func TestExistsFails(t *testing.T) {
type HogeStruct struct {
Hoge *int `json:"foo" binding:"exists"`
}
var obj HogeStruct
req := requestWithBody("POST", "/", `{"boen": 0}`)
err := JSON.Bind(req, &obj)
assert.Error(t, err)
}
func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
b := Form
assert.Equal(t, b.Name(), "form")
obj := FooBarStruct{}
req := requestWithBody(method, path, body)
if method == "POST" {
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
assert.Equal(t, obj.Foo, "bar")
assert.Equal(t, obj.Bar, "foo")
obj = FooBarStruct{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
}
func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
assert.Equal(t, b.Name(), name)
obj := FooStruct{}
req := requestWithBody("POST", path, body)
err := b.Bind(req, &obj)
assert.NoError(t, err)
assert.Equal(t, obj.Foo, "bar")
obj = FooStruct{}
req = requestWithBody("POST", badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
}
func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
assert.Equal(t, b.Name(), name)
obj := example.Test{}
req := requestWithBody("POST", path, body)
req.Header.Add("Content-Type", MIMEPROTOBUF)
err := b.Bind(req, &obj)
assert.NoError(t, err)
assert.Equal(t, *obj.Label, "yes")
obj = example.Test{}
req = requestWithBody("POST", badPath, badBody)
req.Header.Add("Content-Type", MIMEPROTOBUF)
err = ProtoBuf.Bind(req, &obj)
assert.Error(t, err)
}
func testMsgPackBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
assert.Equal(t, b.Name(), name)
obj := FooStruct{}
req := requestWithBody("POST", path, body)
req.Header.Add("Content-Type", MIMEMSGPACK)
err := b.Bind(req, &obj)
assert.NoError(t, err)
assert.Equal(t, obj.Foo, "bar")
obj = FooStruct{}
req = requestWithBody("POST", badPath, badBody)
req.Header.Add("Content-Type", MIMEMSGPACK)
err = MsgPack.Bind(req, &obj)
assert.Error(t, err)
}
func requestWithBody(method, path, body string) (req *http.Request) {
req, _ = http.NewRequest(method, path, bytes.NewBufferString(body))
return
}

View File

@@ -0,0 +1,45 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import (
"reflect"
"sync"
"gopkg.in/go-playground/validator.v8"
)
type defaultValidator struct {
once sync.Once
validate *validator.Validate
}
var _ StructValidator = &defaultValidator{}
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
if kindOfData(obj) == reflect.Struct {
v.lazyinit()
if err := v.validate.Struct(obj); err != nil {
return error(err)
}
}
return nil
}
func (v *defaultValidator) lazyinit() {
v.once.Do(func() {
config := &validator.Config{TagName: "binding"}
v.validate = validator.New(config)
})
}
func kindOfData(data interface{}) reflect.Kind {
value := reflect.ValueOf(data)
valueType := value.Kind()
if valueType == reflect.Ptr {
valueType = value.Elem().Kind()
}
return valueType
}

View File

@@ -0,0 +1,113 @@
// Code generated by protoc-gen-go.
// source: test.proto
// DO NOT EDIT!
/*
Package example is a generated protocol buffer package.
It is generated from these files:
test.proto
It has these top-level messages:
Test
*/
package example
import proto "github.com/golang/protobuf/proto"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = math.Inf
type FOO int32
const (
FOO_X FOO = 17
)
var FOO_name = map[int32]string{
17: "X",
}
var FOO_value = map[string]int32{
"X": 17,
}
func (x FOO) Enum() *FOO {
p := new(FOO)
*p = x
return p
}
func (x FOO) String() string {
return proto.EnumName(FOO_name, int32(x))
}
func (x *FOO) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO")
if err != nil {
return err
}
*x = FOO(value)
return nil
}
type Test struct {
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Test) Reset() { *m = Test{} }
func (m *Test) String() string { return proto.CompactTextString(m) }
func (*Test) ProtoMessage() {}
const Default_Test_Type int32 = 77
func (m *Test) GetLabel() string {
if m != nil && m.Label != nil {
return *m.Label
}
return ""
}
func (m *Test) GetType() int32 {
if m != nil && m.Type != nil {
return *m.Type
}
return Default_Test_Type
}
func (m *Test) GetReps() []int64 {
if m != nil {
return m.Reps
}
return nil
}
func (m *Test) GetOptionalgroup() *Test_OptionalGroup {
if m != nil {
return m.Optionalgroup
}
return nil
}
type Test_OptionalGroup struct {
RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} }
func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) }
func (*Test_OptionalGroup) ProtoMessage() {}
func (m *Test_OptionalGroup) GetRequiredField() string {
if m != nil && m.RequiredField != nil {
return *m.RequiredField
}
return ""
}
func init() {
proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
}

View File

@@ -0,0 +1,12 @@
package example;
enum FOO {X=17;};
message Test {
required string label = 1;
optional int32 type = 2[default=77];
repeated int64 reps = 3;
optional group OptionalGroup = 4{
required string RequiredField = 5;
}
}

54
vendor/github.com/gin-gonic/gin/binding/form.go generated vendored Normal file
View File

@@ -0,0 +1,54 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import "net/http"
type formBinding struct{}
type formPostBinding struct{}
type formMultipartBinding struct{}
func (formBinding) Name() string {
return "form"
}
func (formBinding) Bind(req *http.Request, obj interface{}) error {
if err := req.ParseForm(); err != nil {
return err
}
req.ParseMultipartForm(32 << 10) // 32 MB
if err := mapForm(obj, req.Form); err != nil {
return err
}
return validate(obj)
}
func (formPostBinding) Name() string {
return "form-urlencoded"
}
func (formPostBinding) Bind(req *http.Request, obj interface{}) error {
if err := req.ParseForm(); err != nil {
return err
}
if err := mapForm(obj, req.PostForm); err != nil {
return err
}
return validate(obj)
}
func (formMultipartBinding) Name() string {
return "multipart/form-data"
}
func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error {
if err := req.ParseMultipartForm(32 << 10); err != nil {
return err
}
if err := mapForm(obj, req.MultipartForm.Value); err != nil {
return err
}
return validate(obj)
}

182
vendor/github.com/gin-gonic/gin/binding/form_mapping.go generated vendored Normal file
View File

@@ -0,0 +1,182 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import (
"errors"
"reflect"
"strconv"
"time"
)
func mapForm(ptr interface{}, form map[string][]string) error {
typ := reflect.TypeOf(ptr).Elem()
val := reflect.ValueOf(ptr).Elem()
for i := 0; i < typ.NumField(); i++ {
typeField := typ.Field(i)
structField := val.Field(i)
if !structField.CanSet() {
continue
}
structFieldKind := structField.Kind()
inputFieldName := typeField.Tag.Get("form")
if inputFieldName == "" {
inputFieldName = typeField.Name
// if "form" tag is nil, we inspect if the field is a struct.
// this would not make sense for JSON parsing but it does for a form
// since data is flatten
if structFieldKind == reflect.Struct {
err := mapForm(structField.Addr().Interface(), form)
if err != nil {
return err
}
continue
}
}
inputValue, exists := form[inputFieldName]
if !exists {
continue
}
numElems := len(inputValue)
if structFieldKind == reflect.Slice && numElems > 0 {
sliceOf := structField.Type().Elem().Kind()
slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
for i := 0; i < numElems; i++ {
if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil {
return err
}
}
val.Field(i).Set(slice)
} else {
if _, isTime := structField.Interface().(time.Time); isTime {
if err := setTimeField(inputValue[0], typeField, structField); err != nil {
return err
}
continue
}
if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
return err
}
}
}
return nil
}
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
switch valueKind {
case reflect.Int:
return setIntField(val, 0, structField)
case reflect.Int8:
return setIntField(val, 8, structField)
case reflect.Int16:
return setIntField(val, 16, structField)
case reflect.Int32:
return setIntField(val, 32, structField)
case reflect.Int64:
return setIntField(val, 64, structField)
case reflect.Uint:
return setUintField(val, 0, structField)
case reflect.Uint8:
return setUintField(val, 8, structField)
case reflect.Uint16:
return setUintField(val, 16, structField)
case reflect.Uint32:
return setUintField(val, 32, structField)
case reflect.Uint64:
return setUintField(val, 64, structField)
case reflect.Bool:
return setBoolField(val, structField)
case reflect.Float32:
return setFloatField(val, 32, structField)
case reflect.Float64:
return setFloatField(val, 64, structField)
case reflect.String:
structField.SetString(val)
default:
return errors.New("Unknown type")
}
return nil
}
func setIntField(val string, bitSize int, field reflect.Value) error {
if val == "" {
val = "0"
}
intVal, err := strconv.ParseInt(val, 10, bitSize)
if err == nil {
field.SetInt(intVal)
}
return err
}
func setUintField(val string, bitSize int, field reflect.Value) error {
if val == "" {
val = "0"
}
uintVal, err := strconv.ParseUint(val, 10, bitSize)
if err == nil {
field.SetUint(uintVal)
}
return err
}
func setBoolField(val string, field reflect.Value) error {
if val == "" {
val = "false"
}
boolVal, err := strconv.ParseBool(val)
if err == nil {
field.SetBool(boolVal)
}
return nil
}
func setFloatField(val string, bitSize int, field reflect.Value) error {
if val == "" {
val = "0.0"
}
floatVal, err := strconv.ParseFloat(val, bitSize)
if err == nil {
field.SetFloat(floatVal)
}
return err
}
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
timeFormat := structField.Tag.Get("time_format")
if timeFormat == "" {
return errors.New("Blank time format")
}
if val == "" {
value.Set(reflect.ValueOf(time.Time{}))
return nil
}
l := time.Local
if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
l = time.UTC
}
t, err := time.ParseInLocation(timeFormat, val, l)
if err != nil {
return err
}
value.Set(reflect.ValueOf(t))
return nil
}
// Don't pass in pointers to bind to. Can lead to bugs. See:
// https://github.com/codegangsta/martini-contrib/issues/40
// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659
func ensureNotPointer(obj interface{}) {
if reflect.TypeOf(obj).Kind() == reflect.Ptr {
panic("Pointers are not accepted as binding models")
}
}

24
vendor/github.com/gin-gonic/gin/binding/json.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import (
"encoding/json"
"net/http"
)
type jsonBinding struct{}
func (jsonBinding) Name() string {
return "json"
}
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
decoder := json.NewDecoder(req.Body)
if err := decoder.Decode(obj); err != nil {
return err
}
return validate(obj)
}

28
vendor/github.com/gin-gonic/gin/binding/msgpack.go generated vendored Normal file
View File

@@ -0,0 +1,28 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import (
"net/http"
"github.com/ugorji/go/codec"
)
type msgpackBinding struct{}
func (msgpackBinding) Name() string {
return "msgpack"
}
func (msgpackBinding) Bind(req *http.Request, obj interface{}) error {
if err := codec.NewDecoder(req.Body, new(codec.MsgpackHandle)).Decode(&obj); err != nil {
//var decoder *codec.Decoder = codec.NewDecoder(req.Body, &codec.MsgpackHandle)
//if err := decoder.Decode(&obj); err != nil {
return err
}
return validate(obj)
}

35
vendor/github.com/gin-gonic/gin/binding/protobuf.go generated vendored Normal file
View File

@@ -0,0 +1,35 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import (
"io/ioutil"
"net/http"
"github.com/golang/protobuf/proto"
)
type protobufBinding struct{}
func (protobufBinding) Name() string {
return "protobuf"
}
func (protobufBinding) Bind(req *http.Request, obj interface{}) error {
buf, err := ioutil.ReadAll(req.Body)
if err != nil {
return err
}
if err = proto.Unmarshal(buf, obj.(proto.Message)); err != nil {
return err
}
//Here it's same to return validate(obj), but util now we cann't add `binding:""` to the struct
//which automatically generate by gen-proto
return nil
//return validate(obj)
}

View File

@@ -0,0 +1,192 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import (
"bytes"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type testInterface interface {
String() string
}
type substructNoValidation struct {
IString string
IInt int
}
type mapNoValidationSub map[string]substructNoValidation
type structNoValidationValues struct {
substructNoValidation
Boolean bool
Uinteger uint
Integer int
Integer8 int8
Integer16 int16
Integer32 int32
Integer64 int64
Uinteger8 uint8
Uinteger16 uint16
Uinteger32 uint32
Uinteger64 uint64
Float32 float32
Float64 float64
String string
Date time.Time
Struct substructNoValidation
InlinedStruct struct {
String []string
Integer int
}
IntSlice []int
IntPointerSlice []*int
StructPointerSlice []*substructNoValidation
StructSlice []substructNoValidation
InterfaceSlice []testInterface
UniversalInterface interface{}
CustomInterface testInterface
FloatMap map[string]float32
StructMap mapNoValidationSub
}
func createNoValidationValues() structNoValidationValues {
integer := 1
s := structNoValidationValues{
Boolean: true,
Uinteger: 1 << 29,
Integer: -10000,
Integer8: 120,
Integer16: -20000,
Integer32: 1 << 29,
Integer64: 1 << 61,
Uinteger8: 250,
Uinteger16: 50000,
Uinteger32: 1 << 31,
Uinteger64: 1 << 62,
Float32: 123.456,
Float64: 123.456789,
String: "text",
Date: time.Time{},
CustomInterface: &bytes.Buffer{},
Struct: substructNoValidation{},
IntSlice: []int{-3, -2, 1, 0, 1, 2, 3},
IntPointerSlice: []*int{&integer},
StructSlice: []substructNoValidation{},
UniversalInterface: 1.2,
FloatMap: map[string]float32{
"foo": 1.23,
"bar": 232.323,
},
StructMap: mapNoValidationSub{
"foo": substructNoValidation{},
"bar": substructNoValidation{},
},
// StructPointerSlice []noValidationSub
// InterfaceSlice []testInterface
}
s.InlinedStruct.Integer = 1000
s.InlinedStruct.String = []string{"first", "second"}
s.IString = "substring"
s.IInt = 987654
return s
}
func TestValidateNoValidationValues(t *testing.T) {
origin := createNoValidationValues()
test := createNoValidationValues()
empty := structNoValidationValues{}
assert.Nil(t, validate(test))
assert.Nil(t, validate(&test))
assert.Nil(t, validate(empty))
assert.Nil(t, validate(&empty))
assert.Equal(t, origin, test)
}
type structNoValidationPointer struct {
substructNoValidation
Boolean bool
Uinteger *uint
Integer *int
Integer8 *int8
Integer16 *int16
Integer32 *int32
Integer64 *int64
Uinteger8 *uint8
Uinteger16 *uint16
Uinteger32 *uint32
Uinteger64 *uint64
Float32 *float32
Float64 *float64
String *string
Date *time.Time
Struct *substructNoValidation
IntSlice *[]int
IntPointerSlice *[]*int
StructPointerSlice *[]*substructNoValidation
StructSlice *[]substructNoValidation
InterfaceSlice *[]testInterface
FloatMap *map[string]float32
StructMap *mapNoValidationSub
}
func TestValidateNoValidationPointers(t *testing.T) {
//origin := createNoValidation_values()
//test := createNoValidation_values()
empty := structNoValidationPointer{}
//assert.Nil(t, validate(test))
//assert.Nil(t, validate(&test))
assert.Nil(t, validate(empty))
assert.Nil(t, validate(&empty))
//assert.Equal(t, origin, test)
}
type Object map[string]interface{}
func TestValidatePrimitives(t *testing.T) {
obj := Object{"foo": "bar", "bar": 1}
assert.NoError(t, validate(obj))
assert.NoError(t, validate(&obj))
assert.Equal(t, obj, Object{"foo": "bar", "bar": 1})
obj2 := []Object{{"foo": "bar", "bar": 1}, {"foo": "bar", "bar": 1}}
assert.NoError(t, validate(obj2))
assert.NoError(t, validate(&obj2))
nu := 10
assert.NoError(t, validate(nu))
assert.NoError(t, validate(&nu))
assert.Equal(t, nu, 10)
str := "value"
assert.NoError(t, validate(str))
assert.NoError(t, validate(&str))
assert.Equal(t, str, "value")
}

24
vendor/github.com/gin-gonic/gin/binding/xml.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package binding
import (
"encoding/xml"
"net/http"
)
type xmlBinding struct{}
func (xmlBinding) Name() string {
return "xml"
}
func (xmlBinding) Bind(req *http.Request, obj interface{}) error {
decoder := xml.NewDecoder(req.Body)
if err := decoder.Decode(obj); err != nil {
return err
}
return validate(obj)
}

5
vendor/github.com/gin-gonic/gin/codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,5 @@
coverage:
notify:
gitter:
default:
url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165

766
vendor/github.com/gin-gonic/gin/context.go generated vendored Normal file
View File

@@ -0,0 +1,766 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"errors"
"io"
"io/ioutil"
"math"
"mime/multipart"
"net"
"net/http"
"net/url"
"strings"
"time"
"github.com/gin-contrib/sse"
"github.com/gin-gonic/gin/binding"
"github.com/gin-gonic/gin/render"
)
// Content-Type MIME of the most common data formats
const (
MIMEJSON = binding.MIMEJSON
MIMEHTML = binding.MIMEHTML
MIMEXML = binding.MIMEXML
MIMEXML2 = binding.MIMEXML2
MIMEPlain = binding.MIMEPlain
MIMEPOSTForm = binding.MIMEPOSTForm
MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
)
const (
defaultMemory = 32 << 20 // 32 MB
abortIndex int8 = math.MaxInt8 / 2
)
// Context is the most important part of gin. It allows us to pass variables between middleware,
// manage the flow, validate the JSON of a request and render a JSON response for example.
type Context struct {
writermem responseWriter
Request *http.Request
Writer ResponseWriter
Params Params
handlers HandlersChain
index int8
engine *Engine
Keys map[string]interface{}
Errors errorMsgs
Accepted []string
}
/************************************/
/********** CONTEXT CREATION ********/
/************************************/
func (c *Context) reset() {
c.Writer = &c.writermem
c.Params = c.Params[0:0]
c.handlers = nil
c.index = -1
c.Keys = nil
c.Errors = c.Errors[0:0]
c.Accepted = nil
}
// Copy returns a copy of the current context that can be safely used outside the request's scope.
// This has to be used when the context has to be passed to a goroutine.
func (c *Context) Copy() *Context {
var cp = *c
cp.writermem.ResponseWriter = nil
cp.Writer = &cp.writermem
cp.index = abortIndex
cp.handlers = nil
return &cp
}
// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", this
// function will return "main.handleGetUsers"
func (c *Context) HandlerName() string {
return nameOfFunction(c.handlers.Last())
}
// Handler returns the main handler.
func (c *Context) Handler() HandlerFunc {
return c.handlers.Last()
}
/************************************/
/*********** FLOW CONTROL ***********/
/************************************/
// Next should be used only inside middleware.
// It executes the pending handlers in the chain inside the calling handler.
// See example in GitHub.
func (c *Context) Next() {
c.index++
s := int8(len(c.handlers))
for ; c.index < s; c.index++ {
c.handlers[c.index](c)
}
}
// IsAborted returns true if the current context was aborted.
func (c *Context) IsAborted() bool {
return c.index >= abortIndex
}
// Abort prevents pending handlers from being called. Note that this will not stop the current handler.
// Let's say you have an authorization middleware that validates that the current request is authorized. If the
// authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
// for this request are not called.
func (c *Context) Abort() {
c.index = abortIndex
}
// AbortWithStatus calls `Abort()` and writes the headers with the specified status code.
// For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401).
func (c *Context) AbortWithStatus(code int) {
c.Status(code)
c.Writer.WriteHeaderNow()
c.Abort()
}
// AbortWithStatusJSON calls `Abort()` and then `JSON` internally. This method stops the chain, writes the status code and return a JSON body
// It also sets the Content-Type as "application/json".
func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) {
c.Abort()
c.JSON(code, jsonObj)
}
// AbortWithError calls `AbortWithStatus()` and `Error()` internally. This method stops the chain, writes the status code and
// pushes the specified error to `c.Errors`.
// See Context.Error() for more details.
func (c *Context) AbortWithError(code int, err error) *Error {
c.AbortWithStatus(code)
return c.Error(err)
}
/************************************/
/********* ERROR MANAGEMENT *********/
/************************************/
// Attaches an error to the current context. The error is pushed to a list of errors.
// It's a good idea to call Error for each error that occurred during the resolution of a request.
// A middleware can be used to collect all the errors
// and push them to a database together, print a log, or append it in the HTTP response.
func (c *Context) Error(err error) *Error {
var parsedError *Error
switch err.(type) {
case *Error:
parsedError = err.(*Error)
default:
parsedError = &Error{
Err: err,
Type: ErrorTypePrivate,
}
}
c.Errors = append(c.Errors, parsedError)
return parsedError
}
/************************************/
/******** METADATA MANAGEMENT********/
/************************************/
// Set is used to store a new key/value pair exclusively for this context.
// It also lazy initializes c.Keys if it was not used previously.
func (c *Context) Set(key string, value interface{}) {
if c.Keys == nil {
c.Keys = make(map[string]interface{})
}
c.Keys[key] = value
}
// Get returns the value for the given key, ie: (value, true).
// If the value does not exists it returns (nil, false)
func (c *Context) Get(key string) (value interface{}, exists bool) {
value, exists = c.Keys[key]
return
}
// MustGet returns the value for the given key if it exists, otherwise it panics.
func (c *Context) MustGet(key string) interface{} {
if value, exists := c.Get(key); exists {
return value
}
panic("Key \"" + key + "\" does not exist")
}
// GetString returns the value associated with the key as a string.
func (c *Context) GetString(key string) (s string) {
if val, ok := c.Get(key); ok && val != nil {
s, _ = val.(string)
}
return
}
// GetBool returns the value associated with the key as a boolean.
func (c *Context) GetBool(key string) (b bool) {
if val, ok := c.Get(key); ok && val != nil {
b, _ = val.(bool)
}
return
}
// GetInt returns the value associated with the key as an integer.
func (c *Context) GetInt(key string) (i int) {
if val, ok := c.Get(key); ok && val != nil {
i, _ = val.(int)
}
return
}
// GetInt64 returns the value associated with the key as an integer.
func (c *Context) GetInt64(key string) (i64 int64) {
if val, ok := c.Get(key); ok && val != nil {
i64, _ = val.(int64)
}
return
}
// GetFloat64 returns the value associated with the key as a float64.
func (c *Context) GetFloat64(key string) (f64 float64) {
if val, ok := c.Get(key); ok && val != nil {
f64, _ = val.(float64)
}
return
}
// GetTime returns the value associated with the key as time.
func (c *Context) GetTime(key string) (t time.Time) {
if val, ok := c.Get(key); ok && val != nil {
t, _ = val.(time.Time)
}
return
}
// GetDuration returns the value associated with the key as a duration.
func (c *Context) GetDuration(key string) (d time.Duration) {
if val, ok := c.Get(key); ok && val != nil {
d, _ = val.(time.Duration)
}
return
}
// GetStringSlice returns the value associated with the key as a slice of strings.
func (c *Context) GetStringSlice(key string) (ss []string) {
if val, ok := c.Get(key); ok && val != nil {
ss, _ = val.([]string)
}
return
}
// GetStringMap returns the value associated with the key as a map of interfaces.
func (c *Context) GetStringMap(key string) (sm map[string]interface{}) {
if val, ok := c.Get(key); ok && val != nil {
sm, _ = val.(map[string]interface{})
}
return
}
// GetStringMapString returns the value associated with the key as a map of strings.
func (c *Context) GetStringMapString(key string) (sms map[string]string) {
if val, ok := c.Get(key); ok && val != nil {
sms, _ = val.(map[string]string)
}
return
}
// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.
func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) {
if val, ok := c.Get(key); ok && val != nil {
smss, _ = val.(map[string][]string)
}
return
}
/************************************/
/************ INPUT DATA ************/
/************************************/
// Param returns the value of the URL param.
// It is a shortcut for c.Params.ByName(key)
// router.GET("/user/:id", func(c *gin.Context) {
// // a GET request to /user/john
// id := c.Param("id") // id == "john"
// })
func (c *Context) Param(key string) string {
return c.Params.ByName(key)
}
// Query returns the keyed url query value if it exists,
// otherwise it returns an empty string `("")`.
// It is shortcut for `c.Request.URL.Query().Get(key)`
// GET /path?id=1234&name=Manu&value=
// c.Query("id") == "1234"
// c.Query("name") == "Manu"
// c.Query("value") == ""
// c.Query("wtf") == ""
func (c *Context) Query(key string) string {
value, _ := c.GetQuery(key)
return value
}
// DefaultQuery returns the keyed url query value if it exists,
// otherwise it returns the specified defaultValue string.
// See: Query() and GetQuery() for further information.
// GET /?name=Manu&lastname=
// c.DefaultQuery("name", "unknown") == "Manu"
// c.DefaultQuery("id", "none") == "none"
// c.DefaultQuery("lastname", "none") == ""
func (c *Context) DefaultQuery(key, defaultValue string) string {
if value, ok := c.GetQuery(key); ok {
return value
}
return defaultValue
}
// GetQuery is like Query(), it returns the keyed url query value
// if it exists `(value, true)` (even when the value is an empty string),
// otherwise it returns `("", false)`.
// It is shortcut for `c.Request.URL.Query().Get(key)`
// GET /?name=Manu&lastname=
// ("Manu", true) == c.GetQuery("name")
// ("", false) == c.GetQuery("id")
// ("", true) == c.GetQuery("lastname")
func (c *Context) GetQuery(key string) (string, bool) {
if values, ok := c.GetQueryArray(key); ok {
return values[0], ok
}
return "", false
}
// QueryArray returns a slice of strings for a given query key.
// The length of the slice depends on the number of params with the given key.
func (c *Context) QueryArray(key string) []string {
values, _ := c.GetQueryArray(key)
return values
}
// GetQueryArray returns a slice of strings for a given query key, plus
// a boolean value whether at least one value exists for the given key.
func (c *Context) GetQueryArray(key string) ([]string, bool) {
req := c.Request
if values, ok := req.URL.Query()[key]; ok && len(values) > 0 {
return values, true
}
return []string{}, false
}
// PostForm returns the specified key from a POST urlencoded form or multipart form
// when it exists, otherwise it returns an empty string `("")`.
func (c *Context) PostForm(key string) string {
value, _ := c.GetPostForm(key)
return value
}
// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form
// when it exists, otherwise it returns the specified defaultValue string.
// See: PostForm() and GetPostForm() for further information.
func (c *Context) DefaultPostForm(key, defaultValue string) string {
if value, ok := c.GetPostForm(key); ok {
return value
}
return defaultValue
}
// GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded
// form or multipart form when it exists `(value, true)` (even when the value is an empty string),
// otherwise it returns ("", false).
// For example, during a PATCH request to update the user's email:
// email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com"
// email= --> ("", true) := GetPostForm("email") // set email to ""
// --> ("", false) := GetPostForm("email") // do nothing with email
func (c *Context) GetPostForm(key string) (string, bool) {
if values, ok := c.GetPostFormArray(key); ok {
return values[0], ok
}
return "", false
}
// PostFormArray returns a slice of strings for a given form key.
// The length of the slice depends on the number of params with the given key.
func (c *Context) PostFormArray(key string) []string {
values, _ := c.GetPostFormArray(key)
return values
}
// GetPostFormArray returns a slice of strings for a given form key, plus
// a boolean value whether at least one value exists for the given key.
func (c *Context) GetPostFormArray(key string) ([]string, bool) {
req := c.Request
req.ParseForm()
req.ParseMultipartForm(defaultMemory)
if values := req.PostForm[key]; len(values) > 0 {
return values, true
}
if req.MultipartForm != nil && req.MultipartForm.File != nil {
if values := req.MultipartForm.Value[key]; len(values) > 0 {
return values, true
}
}
return []string{}, false
}
// FormFile returns the first file for the provided form key.
func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
_, fh, err := c.Request.FormFile(name)
return fh, err
}
// MultipartForm is the parsed multipart form, including file uploads.
func (c *Context) MultipartForm() (*multipart.Form, error) {
err := c.Request.ParseMultipartForm(defaultMemory)
return c.Request.MultipartForm, err
}
// Bind checks the Content-Type to select a binding engine automatically,
// Depending the "Content-Type" header different bindings are used:
// "application/json" --> JSON binding
// "application/xml" --> XML binding
// otherwise --> returns an error
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
// It decodes the json payload into the struct specified as a pointer.
// Like ParseBody() but this method also writes a 400 error if the json is not valid.
func (c *Context) Bind(obj interface{}) error {
b := binding.Default(c.Request.Method, c.ContentType())
return c.MustBindWith(obj, b)
}
// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON)
func (c *Context) BindJSON(obj interface{}) error {
return c.MustBindWith(obj, binding.JSON)
}
// MustBindWith binds the passed struct pointer using the specified binding
// engine. It will abort the request with HTTP 400 if any error ocurrs.
// See the binding package.
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) (err error) {
if err = c.ShouldBindWith(obj, b); err != nil {
c.AbortWithError(400, err).SetType(ErrorTypeBind)
}
return
}
// ShouldBindWith binds the passed struct pointer using the specified binding
// engine.
// See the binding package.
func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
return b.Bind(c.Request, obj)
}
// ClientIP implements a best effort algorithm to return the real client IP, it parses
// X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy.
// Use X-Forwarded-For before X-Real-Ip as nginx uses X-Real-Ip with the proxy's IP.
func (c *Context) ClientIP() string {
if c.engine.ForwardedByClientIP {
clientIP := c.requestHeader("X-Forwarded-For")
if index := strings.IndexByte(clientIP, ','); index >= 0 {
clientIP = clientIP[0:index]
}
clientIP = strings.TrimSpace(clientIP)
if len(clientIP) > 0 {
return clientIP
}
clientIP = strings.TrimSpace(c.requestHeader("X-Real-Ip"))
if len(clientIP) > 0 {
return clientIP
}
}
if c.engine.AppEngine {
if addr := c.Request.Header.Get("X-Appengine-Remote-Addr"); addr != "" {
return addr
}
}
if ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)); err == nil {
return ip
}
return ""
}
// ContentType returns the Content-Type header of the request.
func (c *Context) ContentType() string {
return filterFlags(c.requestHeader("Content-Type"))
}
// IsWebsocket returns true if the request headers indicate that a websocket
// handshake is being initiated by the client.
func (c *Context) IsWebsocket() bool {
if strings.Contains(strings.ToLower(c.requestHeader("Connection")), "upgrade") &&
strings.ToLower(c.requestHeader("Upgrade")) == "websocket" {
return true
}
return false
}
func (c *Context) requestHeader(key string) string {
if values, _ := c.Request.Header[key]; len(values) > 0 {
return values[0]
}
return ""
}
/************************************/
/******** RESPONSE RENDERING ********/
/************************************/
// bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function
func bodyAllowedForStatus(status int) bool {
switch {
case status >= 100 && status <= 199:
return false
case status == 204:
return false
case status == 304:
return false
}
return true
}
func (c *Context) Status(code int) {
c.writermem.WriteHeader(code)
}
// Header is a intelligent shortcut for c.Writer.Header().Set(key, value)
// It writes a header in the response.
// If value == "", this method removes the header `c.Writer.Header().Del(key)`
func (c *Context) Header(key, value string) {
if len(value) == 0 {
c.Writer.Header().Del(key)
} else {
c.Writer.Header().Set(key, value)
}
}
// GetHeader returns value from request headers
func (c *Context) GetHeader(key string) string {
return c.requestHeader(key)
}
// GetRawData return stream data
func (c *Context) GetRawData() ([]byte, error) {
return ioutil.ReadAll(c.Request.Body)
}
func (c *Context) SetCookie(
name string,
value string,
maxAge int,
path string,
domain string,
secure bool,
httpOnly bool,
) {
if path == "" {
path = "/"
}
http.SetCookie(c.Writer, &http.Cookie{
Name: name,
Value: url.QueryEscape(value),
MaxAge: maxAge,
Path: path,
Domain: domain,
Secure: secure,
HttpOnly: httpOnly,
})
}
func (c *Context) Cookie(name string) (string, error) {
cookie, err := c.Request.Cookie(name)
if err != nil {
return "", err
}
val, _ := url.QueryUnescape(cookie.Value)
return val, nil
}
func (c *Context) Render(code int, r render.Render) {
c.Status(code)
if !bodyAllowedForStatus(code) {
r.WriteContentType(c.Writer)
c.Writer.WriteHeaderNow()
return
}
if err := r.Render(c.Writer); err != nil {
panic(err)
}
}
// HTML renders the HTTP template specified by its file name.
// It also updates the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
func (c *Context) HTML(code int, name string, obj interface{}) {
instance := c.engine.HTMLRender.Instance(name, obj)
c.Render(code, instance)
}
// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
// It also sets the Content-Type as "application/json".
// WARNING: we recommend to use this only for development purposes since printing pretty JSON is
// more CPU and bandwidth consuming. Use Context.JSON() instead.
func (c *Context) IndentedJSON(code int, obj interface{}) {
c.Render(code, render.IndentedJSON{Data: obj})
}
// JSON serializes the given struct as JSON into the response body.
// It also sets the Content-Type as "application/json".
func (c *Context) JSON(code int, obj interface{}) {
c.Render(code, render.JSON{Data: obj})
}
// XML serializes the given struct as XML into the response body.
// It also sets the Content-Type as "application/xml".
func (c *Context) XML(code int, obj interface{}) {
c.Render(code, render.XML{Data: obj})
}
// YAML serializes the given struct as YAML into the response body.
func (c *Context) YAML(code int, obj interface{}) {
c.Render(code, render.YAML{Data: obj})
}
// String writes the given string into the response body.
func (c *Context) String(code int, format string, values ...interface{}) {
c.Render(code, render.String{Format: format, Data: values})
}
// Redirect returns a HTTP redirect to the specific location.
func (c *Context) Redirect(code int, location string) {
c.Render(-1, render.Redirect{
Code: code,
Location: location,
Request: c.Request,
})
}
// Data writes some data into the body stream and updates the HTTP code.
func (c *Context) Data(code int, contentType string, data []byte) {
c.Render(code, render.Data{
ContentType: contentType,
Data: data,
})
}
// File writes the specified file into the body stream in a efficient way.
func (c *Context) File(filepath string) {
http.ServeFile(c.Writer, c.Request, filepath)
}
// SSEvent writes a Server-Sent Event into the body stream.
func (c *Context) SSEvent(name string, message interface{}) {
c.Render(-1, sse.Event{
Event: name,
Data: message,
})
}
func (c *Context) Stream(step func(w io.Writer) bool) {
w := c.Writer
clientGone := w.CloseNotify()
for {
select {
case <-clientGone:
return
default:
keepOpen := step(w)
w.Flush()
if !keepOpen {
return
}
}
}
}
/************************************/
/******** CONTENT NEGOTIATION *******/
/************************************/
type Negotiate struct {
Offered []string
HTMLName string
HTMLData interface{}
JSONData interface{}
XMLData interface{}
Data interface{}
}
func (c *Context) Negotiate(code int, config Negotiate) {
switch c.NegotiateFormat(config.Offered...) {
case binding.MIMEJSON:
data := chooseData(config.JSONData, config.Data)
c.JSON(code, data)
case binding.MIMEHTML:
data := chooseData(config.HTMLData, config.Data)
c.HTML(code, config.HTMLName, data)
case binding.MIMEXML:
data := chooseData(config.XMLData, config.Data)
c.XML(code, data)
default:
c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server"))
}
}
func (c *Context) NegotiateFormat(offered ...string) string {
assert1(len(offered) > 0, "you must provide at least one offer")
if c.Accepted == nil {
c.Accepted = parseAccept(c.requestHeader("Accept"))
}
if len(c.Accepted) == 0 {
return offered[0]
}
for _, accepted := range c.Accepted {
for _, offert := range offered {
if accepted == offert {
return offert
}
}
}
return ""
}
func (c *Context) SetAccepted(formats ...string) {
c.Accepted = formats
}
/************************************/
/***** GOLANG.ORG/X/NET/CONTEXT *****/
/************************************/
func (c *Context) Deadline() (deadline time.Time, ok bool) {
return
}
func (c *Context) Done() <-chan struct{} {
return nil
}
func (c *Context) Err() error {
return nil
}
func (c *Context) Value(key interface{}) interface{} {
if key == 0 {
return c.Request
}
if keyAsString, ok := key.(string); ok {
val, _ := c.Get(keyAsString)
return val
}
return nil
}

11
vendor/github.com/gin-gonic/gin/context_appengine.go generated vendored Normal file
View File

@@ -0,0 +1,11 @@
// +build appengine
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
func init() {
defaultAppEngine = true
}

1191
vendor/github.com/gin-gonic/gin/context_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

71
vendor/github.com/gin-gonic/gin/debug.go generated vendored Normal file
View File

@@ -0,0 +1,71 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"bytes"
"html/template"
"log"
)
func init() {
log.SetFlags(0)
}
// IsDebugging returns true if the framework is running in debug mode.
// Use SetMode(gin.Release) to switch to disable the debug mode.
func IsDebugging() bool {
return ginMode == debugCode
}
func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) {
if IsDebugging() {
nuHandlers := len(handlers)
handlerName := nameOfFunction(handlers.Last())
debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers)
}
}
func debugPrintLoadTemplate(tmpl *template.Template) {
if IsDebugging() {
var buf bytes.Buffer
for _, tmpl := range tmpl.Templates() {
buf.WriteString("\t- ")
buf.WriteString(tmpl.Name())
buf.WriteString("\n")
}
debugPrint("Loaded HTML Templates (%d): \n%s\n", len(tmpl.Templates()), buf.String())
}
}
func debugPrint(format string, values ...interface{}) {
if IsDebugging() {
log.Printf("[GIN-debug] "+format, values...)
}
}
func debugPrintWARNINGNew() {
debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
`)
}
func debugPrintWARNINGSetHTMLTemplate() {
debugPrint(`[WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called
at initialization. ie. before any route is registered or the router is listening in a socket:
router := gin.Default()
router.SetHTMLTemplate(template) // << good place
`)
}
func debugPrintError(err error) {
if err != nil {
debugPrint("[ERROR] %v\n", err)
}
}

97
vendor/github.com/gin-gonic/gin/debug_test.go generated vendored Normal file
View File

@@ -0,0 +1,97 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"bytes"
"errors"
"html/template"
"io"
"log"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
// TODO
// func debugRoute(httpMethod, absolutePath string, handlers HandlersChain) {
// func debugPrint(format string, values ...interface{}) {
func TestIsDebugging(t *testing.T) {
SetMode(DebugMode)
assert.True(t, IsDebugging())
SetMode(ReleaseMode)
assert.False(t, IsDebugging())
SetMode(TestMode)
assert.False(t, IsDebugging())
}
func TestDebugPrint(t *testing.T) {
var w bytes.Buffer
setup(&w)
defer teardown()
SetMode(ReleaseMode)
debugPrint("DEBUG this!")
SetMode(TestMode)
debugPrint("DEBUG this!")
assert.Empty(t, w.String())
SetMode(DebugMode)
debugPrint("these are %d %s\n", 2, "error messages")
assert.Equal(t, w.String(), "[GIN-debug] these are 2 error messages\n")
}
func TestDebugPrintError(t *testing.T) {
var w bytes.Buffer
setup(&w)
defer teardown()
SetMode(DebugMode)
debugPrintError(nil)
assert.Empty(t, w.String())
debugPrintError(errors.New("this is an error"))
assert.Equal(t, w.String(), "[GIN-debug] [ERROR] this is an error\n")
}
func TestDebugPrintRoutes(t *testing.T) {
var w bytes.Buffer
setup(&w)
defer teardown()
debugPrintRoute("GET", "/path/to/route/:param", HandlersChain{func(c *Context) {}, handlerNameTest})
assert.Regexp(t, `^\[GIN-debug\] GET /path/to/route/:param --> (.*/vendor/)?github.com/gin-gonic/gin.handlerNameTest \(2 handlers\)\n$`, w.String())
}
func TestDebugPrintLoadTemplate(t *testing.T) {
var w bytes.Buffer
setup(&w)
defer teardown()
templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./fixtures/basic/hello.tmpl"))
debugPrintLoadTemplate(templ)
assert.Equal(t, w.String(), "[GIN-debug] Loaded HTML Templates (2): \n\t- \n\t- hello.tmpl\n\n")
}
func TestDebugPrintWARNINGSetHTMLTemplate(t *testing.T) {
var w bytes.Buffer
setup(&w)
defer teardown()
debugPrintWARNINGSetHTMLTemplate()
assert.Equal(t, w.String(), "[GIN-debug] [WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called\nat initialization. ie. before any route is registered or the router is listening in a socket:\n\n\trouter := gin.Default()\n\trouter.SetHTMLTemplate(template) // << good place\n\n")
}
func setup(w io.Writer) {
SetMode(DebugMode)
log.SetOutput(w)
}
func teardown() {
SetMode(TestMode)
log.SetOutput(os.Stdout)
}

25
vendor/github.com/gin-gonic/gin/deprecated.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"github.com/gin-gonic/gin/binding"
"log"
)
func (c *Context) GetCookie(name string) (string, error) {
log.Println("GetCookie() method is deprecated. Use Cookie() instead.")
return c.Cookie(name)
}
// BindWith binds the passed struct pointer using the specified binding engine.
// See the binding package.
func (c *Context) BindWith(obj interface{}, b binding.Binding) error {
log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to
be deprecated, please check issue #662 and either use MustBindWith() if you
want HTTP 400 to be automatically returned if any error occur, of use
ShouldBindWith() if you need to manage the error.`)
return c.MustBindWith(obj, b)
}

159
vendor/github.com/gin-gonic/gin/errors.go generated vendored Normal file
View File

@@ -0,0 +1,159 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
)
type ErrorType uint64
const (
ErrorTypeBind ErrorType = 1 << 63 // used when c.Bind() fails
ErrorTypeRender ErrorType = 1 << 62 // used when c.Render() fails
ErrorTypePrivate ErrorType = 1 << 0
ErrorTypePublic ErrorType = 1 << 1
ErrorTypeAny ErrorType = 1<<64 - 1
ErrorTypeNu = 2
)
type (
Error struct {
Err error
Type ErrorType
Meta interface{}
}
errorMsgs []*Error
)
var _ error = &Error{}
func (msg *Error) SetType(flags ErrorType) *Error {
msg.Type = flags
return msg
}
func (msg *Error) SetMeta(data interface{}) *Error {
msg.Meta = data
return msg
}
func (msg *Error) JSON() interface{} {
json := H{}
if msg.Meta != nil {
value := reflect.ValueOf(msg.Meta)
switch value.Kind() {
case reflect.Struct:
return msg.Meta
case reflect.Map:
for _, key := range value.MapKeys() {
json[key.String()] = value.MapIndex(key).Interface()
}
default:
json["meta"] = msg.Meta
}
}
if _, ok := json["error"]; !ok {
json["error"] = msg.Error()
}
return json
}
// MarshalJSON implements the json.Marshaller interface
func (msg *Error) MarshalJSON() ([]byte, error) {
return json.Marshal(msg.JSON())
}
// Implements the error interface
func (msg Error) Error() string {
return msg.Err.Error()
}
func (msg *Error) IsType(flags ErrorType) bool {
return (msg.Type & flags) > 0
}
// Returns a readonly copy filtered the byte.
// ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic
func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
if len(a) == 0 {
return nil
}
if typ == ErrorTypeAny {
return a
}
var result errorMsgs
for _, msg := range a {
if msg.IsType(typ) {
result = append(result, msg)
}
}
return result
}
// Returns the last error in the slice. It returns nil if the array is empty.
// Shortcut for errors[len(errors)-1]
func (a errorMsgs) Last() *Error {
length := len(a)
if length > 0 {
return a[length-1]
}
return nil
}
// Returns an array will all the error messages.
// Example:
// c.Error(errors.New("first"))
// c.Error(errors.New("second"))
// c.Error(errors.New("third"))
// c.Errors.Errors() // == []string{"first", "second", "third"}
func (a errorMsgs) Errors() []string {
if len(a) == 0 {
return nil
}
errorStrings := make([]string, len(a))
for i, err := range a {
errorStrings[i] = err.Error()
}
return errorStrings
}
func (a errorMsgs) JSON() interface{} {
switch len(a) {
case 0:
return nil
case 1:
return a.Last().JSON()
default:
json := make([]interface{}, len(a))
for i, err := range a {
json[i] = err.JSON()
}
return json
}
}
func (a errorMsgs) MarshalJSON() ([]byte, error) {
return json.Marshal(a.JSON())
}
func (a errorMsgs) String() string {
if len(a) == 0 {
return ""
}
var buffer bytes.Buffer
for i, msg := range a {
fmt.Fprintf(&buffer, "Error #%02d: %s\n", (i + 1), msg.Err)
if msg.Meta != nil {
fmt.Fprintf(&buffer, " Meta: %v\n", msg.Meta)
}
}
return buffer.String()
}

106
vendor/github.com/gin-gonic/gin/errors_test.go generated vendored Normal file
View File

@@ -0,0 +1,106 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"encoding/json"
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
func TestError(t *testing.T) {
baseError := errors.New("test error")
err := &Error{
Err: baseError,
Type: ErrorTypePrivate,
}
assert.Equal(t, err.Error(), baseError.Error())
assert.Equal(t, err.JSON(), H{"error": baseError.Error()})
assert.Equal(t, err.SetType(ErrorTypePublic), err)
assert.Equal(t, err.Type, ErrorTypePublic)
assert.Equal(t, err.SetMeta("some data"), err)
assert.Equal(t, err.Meta, "some data")
assert.Equal(t, err.JSON(), H{
"error": baseError.Error(),
"meta": "some data",
})
jsonBytes, _ := json.Marshal(err)
assert.Equal(t, string(jsonBytes), "{\"error\":\"test error\",\"meta\":\"some data\"}")
err.SetMeta(H{
"status": "200",
"data": "some data",
})
assert.Equal(t, err.JSON(), H{
"error": baseError.Error(),
"status": "200",
"data": "some data",
})
err.SetMeta(H{
"error": "custom error",
"status": "200",
"data": "some data",
})
assert.Equal(t, err.JSON(), H{
"error": "custom error",
"status": "200",
"data": "some data",
})
type customError struct {
status string
data string
}
err.SetMeta(customError{status: "200", data: "other data"})
assert.Equal(t, err.JSON(), customError{status: "200", data: "other data"})
}
func TestErrorSlice(t *testing.T) {
errs := errorMsgs{
{Err: errors.New("first"), Type: ErrorTypePrivate},
{Err: errors.New("second"), Type: ErrorTypePrivate, Meta: "some data"},
{Err: errors.New("third"), Type: ErrorTypePublic, Meta: H{"status": "400"}},
}
assert.Equal(t, errs, errs.ByType(ErrorTypeAny))
assert.Equal(t, errs.Last().Error(), "third")
assert.Equal(t, errs.Errors(), []string{"first", "second", "third"})
assert.Equal(t, errs.ByType(ErrorTypePublic).Errors(), []string{"third"})
assert.Equal(t, errs.ByType(ErrorTypePrivate).Errors(), []string{"first", "second"})
assert.Equal(t, errs.ByType(ErrorTypePublic|ErrorTypePrivate).Errors(), []string{"first", "second", "third"})
assert.Empty(t, errs.ByType(ErrorTypeBind))
assert.Empty(t, errs.ByType(ErrorTypeBind).String())
assert.Equal(t, errs.String(), `Error #01: first
Error #02: second
Meta: some data
Error #03: third
Meta: map[status:400]
`)
assert.Equal(t, errs.JSON(), []interface{}{
H{"error": "first"},
H{"error": "second", "meta": "some data"},
H{"error": "third", "status": "400"},
})
jsonBytes, _ := json.Marshal(errs)
assert.Equal(t, string(jsonBytes), "[{\"error\":\"first\"},{\"error\":\"second\",\"meta\":\"some data\"},{\"error\":\"third\",\"status\":\"400\"}]")
errs = errorMsgs{
{Err: errors.New("first"), Type: ErrorTypePrivate},
}
assert.Equal(t, errs.JSON(), H{"error": "first"})
jsonBytes, _ = json.Marshal(errs)
assert.Equal(t, string(jsonBytes), "{\"error\":\"first\"}")
errs = errorMsgs{}
assert.Nil(t, errs.Last())
assert.Nil(t, errs.JSON())
assert.Empty(t, errs.String())
}

View File

@@ -0,0 +1,7 @@
# Guide to run Gin under App Engine LOCAL Development Server
1. Download, install and setup Go in your computer. (That includes setting your `$GOPATH`.)
2. Download SDK for your platform from here: `https://developers.google.com/appengine/downloads?hl=es#Google_App_Engine_SDK_for_Go`
3. Download Gin source code using: `$ go get github.com/gin-gonic/gin`
4. Navigate to examples folder: `$ cd $GOPATH/src/github.com/gin-gonic/gin/examples/`
5. Run it: `$ goapp serve app-engine/`

View File

@@ -0,0 +1,8 @@
application: hello
version: 1
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app

View File

@@ -0,0 +1,24 @@
package hello
import (
"net/http"
"github.com/gin-gonic/gin"
)
// This function's name is a must. App Engine uses it to drive the requests properly.
func init() {
// Starts a new Gin instance with no middle-ware
r := gin.New()
// Define your handlers
r.GET("/", func(c *gin.Context) {
c.String(200, "Hello World!")
})
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
// Handle all requests using net/http
http.Handle("/", r)
}

View File

@@ -0,0 +1,19 @@
package main
import (
"log"
"github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Ping handler
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
log.Fatal(autotls.Run(r, "example1.com", "example2.com"))
}

View File

@@ -0,0 +1,26 @@
package main
import (
"log"
"github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/acme/autocert"
)
func main() {
r := gin.Default()
// Ping handler
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
Cache: autocert.DirCache("/var/www/.cache"),
}
log.Fatal(autotls.RunWithManager(r, m))
}

58
vendor/github.com/gin-gonic/gin/examples/basic/main.go generated vendored Normal file
View File

@@ -0,0 +1,58 @@
package main
import (
"github.com/gin-gonic/gin"
)
var DB = make(map[string]string)
func main() {
// Disable Console Color
// gin.DisableConsoleColor()
r := gin.Default()
// Ping test
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
// Get user value
r.GET("/user/:name", func(c *gin.Context) {
user := c.Params.ByName("name")
value, ok := DB[user]
if ok {
c.JSON(200, gin.H{"user": user, "value": value})
} else {
c.JSON(200, gin.H{"user": user, "status": "no value"})
}
})
// Authorized group (uses gin.BasicAuth() middleware)
// Same than:
// authorized := r.Group("/")
// authorized.Use(gin.BasicAuth(gin.Credentials{
// "foo": "bar",
// "manu": "123",
//}))
authorized := r.Group("/", gin.BasicAuth(gin.Accounts{
"foo": "bar", // user:foo password:bar
"manu": "123", // user:manu password:123
}))
authorized.POST("admin", func(c *gin.Context) {
user := c.MustGet(gin.AuthUserKey).(string)
// Parse JSON
var json struct {
Value string `json:"value" binding:"required"`
}
if c.Bind(&json) == nil {
DB[user] = json.Value
c.JSON(200, gin.H{"status": "ok"})
}
})
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}

View File

@@ -0,0 +1,45 @@
// +build go1.8
package main
import (
"log"
"net/http"
"os"
"os/signal"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Welcome Gin Server")
})
server := &http.Server{
Addr: ":8080",
Handler: router,
}
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
go func() {
<-quit
log.Println("receive interrupt signal")
if err := server.Close(); err != nil {
log.Fatal("Server Close:", err)
}
}()
if err := server.ListenAndServe(); err != nil {
if err == http.ErrServerClosed {
log.Println("Server closed under request")
} else {
log.Fatal("Server closed unexpect")
}
}
log.Println("Server exist")
}

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