mirror of
https://github.com/documize/community.git
synced 2025-07-19 05:09:42 +02:00
go dep
Migrated from plain /vendor to go dep
This commit is contained in:
parent
0262763c95
commit
fd693f4ff4
957 changed files with 36866 additions and 177595 deletions
157
Gopkg.lock
generated
Normal file
157
Gopkg.lock
generated
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/codegangsta/negroni"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "5dbbc83f748fc3ad38585842b0aedab546d0ea1e"
|
||||||
|
version = "v0.3.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/dgrijalva/jwt-go"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "dbeaa9332f19a944acb5736b4456cfcc02140e29"
|
||||||
|
version = "v3.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/documize/blackfriday"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "cadec560ec52d93835bf2f15bd794700d3a2473b"
|
||||||
|
version = "v2.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/documize/glick"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "a8ccbef88237fcafe9cef3c9aee7ad83d0e132f9"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/documize/html-diff"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "f61c192c7796644259832ef705c49259797e7fff"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/elazarl/go-bindata-assetfs"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "30f82fa23fd844bd5bb1e5f216db87fd77b5eb43"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/go-sql-driver/mysql"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "a0583e0143b1624142adab07e0e97fe106d99561"
|
||||||
|
version = "v1.3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/golang/protobuf"
|
||||||
|
packages = ["proto"]
|
||||||
|
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/google/go-github"
|
||||||
|
packages = ["github"]
|
||||||
|
revision = "e48060a28fac52d0f1cb758bc8b87c07bac4a87d"
|
||||||
|
version = "v15.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/google/go-querystring"
|
||||||
|
packages = ["query"]
|
||||||
|
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/gorilla/context"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
|
||||||
|
version = "v1.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/gorilla/mux"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "53c1911da2b537f792e7cafcb446b05ffe33b996"
|
||||||
|
version = "v1.6.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/jmoiron/sqlx"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"reflectx"
|
||||||
|
]
|
||||||
|
revision = "05cef0741ade10ca668982355b3f3f0bcf0ff0a8"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/mb0/diff"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "d8d9a906c24d7b0ee77287e0463e5ca7f026032e"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/nu7hatch/gouuid"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "179d4d0c4d8d407a32af483c2354df1d2c91e6c3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/pkg/errors"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||||
|
version = "v0.8.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/shurcooL/sanitized_anchor_name"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/crypto"
|
||||||
|
packages = [
|
||||||
|
"bcrypt",
|
||||||
|
"blowfish"
|
||||||
|
]
|
||||||
|
revision = "650f4a345ab4e5b245a3034b110ebc7299e68186"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
packages = [
|
||||||
|
"context",
|
||||||
|
"context/ctxhttp",
|
||||||
|
"html",
|
||||||
|
"html/atom"
|
||||||
|
]
|
||||||
|
revision = "f5dfe339be1d06f81b22525fe34671ee7d2c8904"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/oauth2"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"internal"
|
||||||
|
]
|
||||||
|
revision = "543e37812f10c46c622c9575afd7ad22f22a12ba"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "google.golang.org/appengine"
|
||||||
|
packages = [
|
||||||
|
"internal",
|
||||||
|
"internal/base",
|
||||||
|
"internal/datastore",
|
||||||
|
"internal/log",
|
||||||
|
"internal/remote_api",
|
||||||
|
"internal/urlfetch",
|
||||||
|
"urlfetch"
|
||||||
|
]
|
||||||
|
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
inputs-digest = "98ebdf85207168f55b51629c6c21eb1459881fa58c280503054994887cbde045"
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
90
Gopkg.toml
Normal file
90
Gopkg.toml
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
# Gopkg.toml example
|
||||||
|
#
|
||||||
|
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||||
|
# for detailed Gopkg.toml documentation.
|
||||||
|
#
|
||||||
|
# required = ["github.com/user/thing/cmd/thing"]
|
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project"
|
||||||
|
# version = "1.0.0"
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project2"
|
||||||
|
# branch = "dev"
|
||||||
|
# source = "github.com/myfork/project2"
|
||||||
|
#
|
||||||
|
# [[override]]
|
||||||
|
# name = "github.com/x/y"
|
||||||
|
# version = "2.4.0"
|
||||||
|
#
|
||||||
|
# [prune]
|
||||||
|
# non-go = false
|
||||||
|
# go-tests = true
|
||||||
|
# unused-packages = true
|
||||||
|
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/codegangsta/negroni"
|
||||||
|
version = "0.3.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/dgrijalva/jwt-go"
|
||||||
|
version = "3.1.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/documize/blackfriday"
|
||||||
|
version = "2.0.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/documize/glick"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/documize/html-diff"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/elazarl/go-bindata-assetfs"
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/go-sql-driver/mysql"
|
||||||
|
version = "1.3.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/google/go-github"
|
||||||
|
version = "15.0.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/gorilla/mux"
|
||||||
|
version = "1.6.1"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/nu7hatch/gouuid"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/pkg/errors"
|
||||||
|
version = "0.8.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/crypto"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/oauth2"
|
||||||
|
|
||||||
|
[prune]
|
||||||
|
go-tests = true
|
||||||
|
unused-packages = true
|
|
@ -12,7 +12,7 @@
|
||||||
// Package uniqueid provides utility functions specific to the http-end-point component of Documize.
|
// Package uniqueid provides utility functions specific to the http-end-point component of Documize.
|
||||||
package uniqueid
|
package uniqueid
|
||||||
|
|
||||||
import "github.com/rs/xid"
|
import "github.com/documize/community/core/uniqueid/xid"
|
||||||
|
|
||||||
// Generate creates a randomly generated string suitable for use as part of an URI.
|
// Generate creates a randomly generated string suitable for use as part of an URI.
|
||||||
// It returns a string that is always 16 characters long.
|
// It returns a string that is always 16 characters long.
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
package github
|
package github
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -46,7 +47,7 @@ func validateToken(ctx provider.Context, s *domain.Store, ptoken string) error {
|
||||||
Username: clientID(ctx.Request, s),
|
Username: clientID(ctx.Request, s),
|
||||||
Password: clientSecret(ctx.Request, s),
|
Password: clientSecret(ctx.Request, s),
|
||||||
}).Client())
|
}).Client())
|
||||||
_, _, err := authClient.Authorizations.Check(clientID(ctx.Request, s), ptoken)
|
_, _, err := authClient.Authorizations.Check(context.Background(), clientID(ctx.Request, s), ptoken)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
package github
|
package github
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -96,7 +97,7 @@ func getCommits(client *gogithub.Client, config *githubConfig) ([]githubCommit,
|
||||||
for _, orb := range config.Lists {
|
for _, orb := range config.Lists {
|
||||||
if orb.Included {
|
if orb.Included {
|
||||||
|
|
||||||
branches, _, err := client.Repositories.ListBranches(orb.Owner, orb.Repo,
|
branches, _, err := client.Repositories.ListBranches(context.Background(), orb.Owner, orb.Repo,
|
||||||
&gogithub.ListOptions{PerPage: 100})
|
&gogithub.ListOptions{PerPage: 100})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
render := make([]githubBranch, len(branches))
|
render := make([]githubBranch, len(branches))
|
||||||
|
@ -141,7 +142,7 @@ func getCommits(client *gogithub.Client, config *githubConfig) ([]githubCommit,
|
||||||
opts.Since = *config.SincePtr
|
opts.Since = *config.SincePtr
|
||||||
}
|
}
|
||||||
|
|
||||||
guff, _, err := client.Repositories.ListCommits(orb.Owner, orb.Repo, opts)
|
guff, _, err := client.Repositories.ListCommits(context.Background(), orb.Owner, orb.Repo, opts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
package github
|
package github
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"html/template"
|
"html/template"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
@ -128,7 +129,7 @@ func getIssues(client *gogithub.Client, config *githubConfig) ([]githubIssue, er
|
||||||
opts.Since = *config.SincePtr
|
opts.Since = *config.SincePtr
|
||||||
}
|
}
|
||||||
|
|
||||||
guff, _, err := client.Issues.ListByRepo(orb.Owner, orb.Repo, opts)
|
guff, _, err := client.Issues.ListByRepo(context.Background(), orb.Owner, orb.Repo, opts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, err
|
return ret, err
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
package github
|
package github
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
@ -25,14 +26,14 @@ func listFailed(rt *env.Runtime, method string, config githubConfig, client *gog
|
||||||
|
|
||||||
case "owners":
|
case "owners":
|
||||||
|
|
||||||
me, _, err := client.Users.Get("")
|
me, _, err := client.Users.Get(context.Background(), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rt.Log.Error("github get user details:", err)
|
rt.Log.Error("github get user details:", err)
|
||||||
provider.WriteError(w, "github", err)
|
provider.WriteError(w, "github", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
orgs, _, err := client.Organizations.List("", nil)
|
orgs, _, err := client.Organizations.List(context.Background(), "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rt.Log.Error("github get user's organisations:", err)
|
rt.Log.Error("github get user's organisations:", err)
|
||||||
provider.WriteError(w, "github", err)
|
provider.WriteError(w, "github", err)
|
||||||
|
@ -56,7 +57,7 @@ func listFailed(rt *env.Runtime, method string, config githubConfig, client *gog
|
||||||
var render []githubBranch
|
var render []githubBranch
|
||||||
if config.Owner != "" {
|
if config.Owner != "" {
|
||||||
|
|
||||||
me, _, err := client.Users.Get("")
|
me, _, err := client.Users.Get(context.Background(), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rt.Log.Error("github get user details:", err)
|
rt.Log.Error("github get user details:", err)
|
||||||
provider.WriteError(w, "github", err)
|
provider.WriteError(w, "github", err)
|
||||||
|
@ -65,12 +66,12 @@ func listFailed(rt *env.Runtime, method string, config githubConfig, client *gog
|
||||||
|
|
||||||
var repos []*gogithub.Repository
|
var repos []*gogithub.Repository
|
||||||
if config.Owner == *me.Login {
|
if config.Owner == *me.Login {
|
||||||
repos, _, err = client.Repositories.List(config.Owner, nil)
|
repos, _, err = client.Repositories.List(context.Background(), config.Owner, nil)
|
||||||
} else {
|
} else {
|
||||||
opt := &gogithub.RepositoryListByOrgOptions{
|
opt := &gogithub.RepositoryListByOrgOptions{
|
||||||
ListOptions: gogithub.ListOptions{PerPage: 100},
|
ListOptions: gogithub.ListOptions{PerPage: 100},
|
||||||
}
|
}
|
||||||
repos, _, err = client.Repositories.ListByOrg(config.Owner, opt)
|
repos, _, err = client.Repositories.ListByOrg(context.Background(), config.Owner, opt)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rt.Log.Error("github get user/org repositories:", err)
|
rt.Log.Error("github get user/org repositories:", err)
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
package github
|
package github
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -98,7 +99,7 @@ func getMilestones(client *gogithub.Client, config *githubConfig) ([]githubMiles
|
||||||
State: state,
|
State: state,
|
||||||
ListOptions: gogithub.ListOptions{PerPage: config.BranchLines}}
|
ListOptions: gogithub.ListOptions{PerPage: config.BranchLines}}
|
||||||
|
|
||||||
guff, _, err := client.Issues.ListMilestones(orb.Owner, orb.Repo, opts)
|
guff, _, err := client.Issues.ListMilestones(context.Background(), orb.Owner, orb.Repo, opts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, err
|
return ret, err
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
package github
|
package github
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -181,7 +182,7 @@ func getUserName(client *gogithub.Client, config *githubConfig, login string) (f
|
||||||
an = content
|
an = content
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
usr, _, err := client.Users.Get(login)
|
usr, _, err := client.Users.Get(context.Background(), login)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if usr.Name != nil {
|
if usr.Name != nil {
|
||||||
if len(*usr.Name) > 0 {
|
if len(*usr.Name) > 0 {
|
||||||
|
|
File diff suppressed because one or more lines are too long
1
vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
1
vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
|
@ -1 +0,0 @@
|
||||||
logrus
|
|
7
vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
7
vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
|
@ -1,7 +0,0 @@
|
||||||
language: go
|
|
||||||
go:
|
|
||||||
- 1.1
|
|
||||||
- 1.2
|
|
||||||
- tip
|
|
||||||
before_script:
|
|
||||||
- go get github.com/stretchr/testify
|
|
21
vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
21
vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2014 Simon Eskildsen
|
|
||||||
|
|
||||||
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.
|
|
335
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
335
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
|
@ -1,335 +0,0 @@
|
||||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://travis-ci.org/Sirupsen/logrus)
|
|
||||||
|
|
||||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
|
||||||
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
|
||||||
yet stable (pre 1.0), the core API is unlikely change much but please version
|
|
||||||
control your Logrus to make sure you aren't fetching latest `master` on every
|
|
||||||
build.**
|
|
||||||
|
|
||||||
Nicely color-coded in development (when a TTY is attached, otherwise just
|
|
||||||
plain text):
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash
|
|
||||||
or Splunk:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
|
||||||
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
|
||||||
|
|
||||||
{"level":"warning","msg":"The group's number increased tremendously!",
|
|
||||||
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
|
||||||
|
|
||||||
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
|
||||||
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
|
||||||
|
|
||||||
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
|
||||||
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
|
||||||
|
|
||||||
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
|
||||||
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
|
||||||
```
|
|
||||||
|
|
||||||
With the default `log.Formatter = new(logrus.TextFormatter)` when a TTY is not
|
|
||||||
attached, the output is compatible with the
|
|
||||||
[l2met](http://r.32k.io/l2met-introduction) format:
|
|
||||||
|
|
||||||
```text
|
|
||||||
time="2014-04-20 15:36:23.830442383 -0400 EDT" level="info" msg="A group of walrus emerges from the ocean" animal="walrus" size=10
|
|
||||||
time="2014-04-20 15:36:23.830584199 -0400 EDT" level="warning" msg="The group's number increased tremendously!" omg=true number=122
|
|
||||||
time="2014-04-20 15:36:23.830596521 -0400 EDT" level="info" msg="A giant walrus appears!" animal="walrus" size=10
|
|
||||||
time="2014-04-20 15:36:23.830611837 -0400 EDT" level="info" msg="Tremendously sized cow enters the ocean." animal="walrus" size=9
|
|
||||||
time="2014-04-20 15:36:23.830626464 -0400 EDT" level="fatal" msg="The ice breaks!" omg=true number=100
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
|
|
||||||
The simplest way to use Logrus is simply the package-level exported logger:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
}).Info("A walrus appears")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that it's completely api-compatible with the stdlib logger, so you can
|
|
||||||
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
|
|
||||||
and you'll now have the flexibility of Logrus. You can customize it all you
|
|
||||||
want:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Log as JSON instead of the default ASCII formatter.
|
|
||||||
log.SetFormatter(logrus.JSONFormatter)
|
|
||||||
|
|
||||||
// Use the Airbrake hook to report errors that have Error severity or above to
|
|
||||||
// an exception tracker. You can create custom hooks, see the Hooks section.
|
|
||||||
log.AddHook(logrus_airbrake.AirbrakeHook)
|
|
||||||
|
|
||||||
// Output to stderr instead of stdout, could also be a file.
|
|
||||||
log.SetOuput(os.Stderr)
|
|
||||||
|
|
||||||
// Only log the warning severity or above.
|
|
||||||
log.SetLevel(logrus.WarnLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
"size": 10,
|
|
||||||
}).Info("A group of walrus emerges from the ocean")
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"omg": true,
|
|
||||||
"number": 122,
|
|
||||||
}).Warn("The group's number increased tremendously!")
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"omg": true,
|
|
||||||
"number": 100,
|
|
||||||
}).Fatal("The ice breaks!")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For more advanced usage such as logging to multiple locations from the same
|
|
||||||
application, you can also create an instance of the `logrus` Logger:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create a new instance of the logger. You can have any number of instances.
|
|
||||||
var log = logrus.New()
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// The API for setting attributes is a little different than the package level
|
|
||||||
// exported logger. See Godoc.
|
|
||||||
log.Out = os.Stderr
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
"size": 10,
|
|
||||||
}).Info("A group of walrus emerges from the ocean")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Fields
|
|
||||||
|
|
||||||
Logrus encourages careful, structured logging though logging fields instead of
|
|
||||||
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
|
||||||
to send event %s to topic %s with key %d")`, you should log the much more
|
|
||||||
discoverable:
|
|
||||||
|
|
||||||
```go
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event": event,
|
|
||||||
"topic": topic,
|
|
||||||
"key": key,
|
|
||||||
}).Fatal("Failed to send event")
|
|
||||||
```
|
|
||||||
|
|
||||||
We've found this API forces you to think about logging in a way that produces
|
|
||||||
much more useful logging messages. We've been in countless situations where just
|
|
||||||
a single added field to a log statement that was already there would've saved us
|
|
||||||
hours. The `WithFields` call is optional.
|
|
||||||
|
|
||||||
In general, with Logrus using any of the `printf`-family functions should be
|
|
||||||
seen as a hint you should add a field, however, you can still use the
|
|
||||||
`printf`-family functions with Logrus.
|
|
||||||
|
|
||||||
#### Hooks
|
|
||||||
|
|
||||||
You can add hooks for logging levels. For example to send errors to an exception
|
|
||||||
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
|
||||||
multiple places simultaneously, e.g. syslog.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Not the real implementation of the Airbrake hook. Just a simple sample.
|
|
||||||
import (
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
log.AddHook(new(AirbrakeHook))
|
|
||||||
}
|
|
||||||
|
|
||||||
type AirbrakeHook struct{}
|
|
||||||
|
|
||||||
// `Fire()` takes the entry that the hook is fired for. `entry.Data[]` contains
|
|
||||||
// the fields for the entry. See the Fields section of the README.
|
|
||||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
|
||||||
err := airbrake.Notify(entry.Data["error"].(error))
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"source": "airbrake",
|
|
||||||
"endpoint": airbrake.Endpoint,
|
|
||||||
}).Info("Failed to send error to Airbrake")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// `Levels()` returns a slice of `Levels` the hook is fired for.
|
|
||||||
func (hook *AirbrakeHook) Levels() []log.Level {
|
|
||||||
return []log.Level{
|
|
||||||
log.ErrorLevel,
|
|
||||||
log.FatalLevel,
|
|
||||||
log.PanicLevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Logrus comes with built-in hooks. Add those, or your custom hook, in `init`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
|
||||||
"github.com/Sirupsen/logrus/hooks/syslog"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
log.AddHook(new(logrus_airbrake.AirbrakeHook))
|
|
||||||
log.AddHook(logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* [`github.com/Sirupsen/logrus/hooks/airbrake`](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go).
|
|
||||||
Send errors to an exception tracking service compatible with the Airbrake API.
|
|
||||||
Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes.
|
|
||||||
|
|
||||||
* [`github.com/Sirupsen/logrus/hooks/syslog`](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go).
|
|
||||||
Send errors to remote syslog server.
|
|
||||||
Uses standard library `log/syslog` behind the scenes.
|
|
||||||
|
|
||||||
#### Level logging
|
|
||||||
|
|
||||||
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
|
||||||
|
|
||||||
```go
|
|
||||||
log.Debug("Useful debugging information.")
|
|
||||||
log.Info("Something noteworthy happened!")
|
|
||||||
log.Warn("You should probably take a look at this.")
|
|
||||||
log.Error("Something failed but I'm not quitting.")
|
|
||||||
// Calls os.Exit(1) after logging
|
|
||||||
log.Fatal("Bye.")
|
|
||||||
// Calls panic() after logging
|
|
||||||
log.Panic("I'm bailing.")
|
|
||||||
```
|
|
||||||
|
|
||||||
You can set the logging level on a `Logger`, then it will only log entries with
|
|
||||||
that severity or anything above it:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Will log anything that is info or above (warn, error, fatal, panic). Default.
|
|
||||||
log.SetLevel(log.InfoLevel)
|
|
||||||
```
|
|
||||||
|
|
||||||
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
|
|
||||||
environment if your application has that.
|
|
||||||
|
|
||||||
#### Entries
|
|
||||||
|
|
||||||
Besides the fields added with `WithField` or `WithFields` some fields are
|
|
||||||
automatically added to all logging events:
|
|
||||||
|
|
||||||
1. `time`. The timestamp when the entry was created.
|
|
||||||
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
|
|
||||||
the `AddFields` call. E.g. `Failed to send event.`
|
|
||||||
3. `level`. The logging level. E.g. `info`.
|
|
||||||
|
|
||||||
#### Environments
|
|
||||||
|
|
||||||
Logrus has no notion of environment.
|
|
||||||
|
|
||||||
If you wish for hooks and formatters to only be used in specific environments,
|
|
||||||
you should handle that yourself. For example, if your application has a global
|
|
||||||
variable `Environment`, which is a string representation of the environment you
|
|
||||||
could do:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
init() {
|
|
||||||
// do something here to set environment depending on an environment variable
|
|
||||||
// or command-line flag
|
|
||||||
if Environment == "production" {
|
|
||||||
log.SetFormatter(logrus.JSONFormatter)
|
|
||||||
} else {
|
|
||||||
// The TextFormatter is default, you don't actually have to do this.
|
|
||||||
log.SetFormatter(logrus.TextFormatter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This configuration is how `logrus` was intended to be used, but JSON in
|
|
||||||
production is mostly only useful if you do log aggregation with tools like
|
|
||||||
Splunk or Logstash.
|
|
||||||
|
|
||||||
#### Formatters
|
|
||||||
|
|
||||||
The built-in logging formatters are:
|
|
||||||
|
|
||||||
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
|
||||||
without colors.
|
|
||||||
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
|
||||||
field to `true`.
|
|
||||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
|
||||||
|
|
||||||
Third party logging formatters:
|
|
||||||
|
|
||||||
* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
|
||||||
|
|
||||||
You can define your formatter by implementing the `Formatter` interface,
|
|
||||||
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
|
||||||
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
|
||||||
default ones (see Entries section above):
|
|
||||||
|
|
||||||
```go
|
|
||||||
type MyJSONFormatter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
log.SetFormatter(new(MyJSONFormatter))
|
|
||||||
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|
||||||
// Note this doesn't include Time, Level and Message which are available on
|
|
||||||
// the Entry. Consult `godoc` on information about those fields or read the
|
|
||||||
// source of the official loggers.
|
|
||||||
serialized, err := json.Marshal(entry.Data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
|
||||||
}
|
|
||||||
return append(serialized, '\n'), nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Rotation
|
|
||||||
|
|
||||||
Log rotation is not provided with Logrus. Log rotation should be done by an
|
|
||||||
external program (like `logrotated(8)`) that can compress and delete old log
|
|
||||||
entries. It should not be a feature of the application-level logger.
|
|
||||||
|
|
||||||
|
|
||||||
[godoc]: https://godoc.org/github.com/Sirupsen/logrus
|
|
242
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
242
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
|
@ -1,242 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An entry is the final or intermediate Logrus logging entry. It containts all
|
|
||||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
|
||||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
|
||||||
// passed around as much as you wish to avoid field duplication.
|
|
||||||
type Entry struct {
|
|
||||||
Logger *Logger
|
|
||||||
|
|
||||||
// Contains all the fields set by the user.
|
|
||||||
Data Fields
|
|
||||||
|
|
||||||
// Time at which the log entry was created
|
|
||||||
Time time.Time
|
|
||||||
|
|
||||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
|
||||||
Level Level
|
|
||||||
|
|
||||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
var baseTimestamp time.Time
|
|
||||||
|
|
||||||
func NewEntry(logger *Logger) *Entry {
|
|
||||||
return &Entry{
|
|
||||||
Logger: logger,
|
|
||||||
// Default is three fields, give a little extra room
|
|
||||||
Data: make(Fields, 5),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a reader for the entry, which is a proxy to the formatter.
|
|
||||||
func (entry *Entry) Reader() (*bytes.Buffer, error) {
|
|
||||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
|
||||||
return bytes.NewBuffer(serialized), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the string representation from the reader and ultimately the
|
|
||||||
// formatter.
|
|
||||||
func (entry *Entry) String() (string, error) {
|
|
||||||
reader, err := entry.Reader()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader.String(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a single field to the Entry.
|
|
||||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
|
||||||
return entry.WithFields(Fields{key: value})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a map of fields to the Entry.
|
|
||||||
func (entry *Entry) WithFields(fields Fields) *Entry {
|
|
||||||
data := Fields{}
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
for k, v := range fields {
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
return &Entry{Logger: entry.Logger, Data: data}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) log(level Level, msg string) string {
|
|
||||||
entry.Time = time.Now()
|
|
||||||
entry.Level = level
|
|
||||||
entry.Message = msg
|
|
||||||
|
|
||||||
if err := entry.Logger.Hooks.Fire(level, entry); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to fire hook", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
reader, err := entry.Reader()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
defer entry.Logger.mu.Unlock()
|
|
||||||
|
|
||||||
_, err = io.Copy(entry.Logger.Out, reader)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Debug(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= DebugLevel {
|
|
||||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Print(args ...interface{}) {
|
|
||||||
entry.Info(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Info(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= InfoLevel {
|
|
||||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warn(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= WarnLevel {
|
|
||||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Error(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= ErrorLevel {
|
|
||||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Fatal(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= FatalLevel {
|
|
||||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Panic(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= PanicLevel {
|
|
||||||
msg := entry.log(PanicLevel, fmt.Sprint(args...))
|
|
||||||
panic(msg)
|
|
||||||
}
|
|
||||||
panic(fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry Printf family functions
|
|
||||||
|
|
||||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= DebugLevel {
|
|
||||||
entry.Debug(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= InfoLevel {
|
|
||||||
entry.Info(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
|
||||||
entry.Infof(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= WarnLevel {
|
|
||||||
entry.Warn(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
|
||||||
entry.Warnf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= ErrorLevel {
|
|
||||||
entry.Error(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= FatalLevel {
|
|
||||||
entry.Fatal(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= PanicLevel {
|
|
||||||
entry.Panic(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry Println family functions
|
|
||||||
|
|
||||||
func (entry *Entry) Debugln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= DebugLevel {
|
|
||||||
entry.Debug(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Infoln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= InfoLevel {
|
|
||||||
entry.Info(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Println(args ...interface{}) {
|
|
||||||
entry.Infoln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warnln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= WarnLevel {
|
|
||||||
entry.Warn(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warningln(args ...interface{}) {
|
|
||||||
entry.Warnln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Errorln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= ErrorLevel {
|
|
||||||
entry.Error(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= FatalLevel {
|
|
||||||
entry.Fatal(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Panicln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= PanicLevel {
|
|
||||||
entry.Panic(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
|
||||||
// fmt.Sprintln where spaces are always added between operands, regardless of
|
|
||||||
// their type. Instead of vendoring the Sprintln implementation to spare a
|
|
||||||
// string allocation, we do the simplest thing.
|
|
||||||
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
|
||||||
msg := fmt.Sprintln(args...)
|
|
||||||
return msg[:len(msg)-1]
|
|
||||||
}
|
|
29
vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
29
vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
|
@ -1,29 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/documize/community/Godeps/_workspace/src/github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var log = logrus.New()
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
log.Formatter = new(logrus.JSONFormatter)
|
|
||||||
log.Formatter = new(logrus.TextFormatter) // default
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
"size": 10,
|
|
||||||
}).Info("A group of walrus emerges from the ocean")
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"omg": true,
|
|
||||||
"number": 122,
|
|
||||||
}).Warn("The group's number increased tremendously!")
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"omg": true,
|
|
||||||
"number": 100,
|
|
||||||
}).Fatal("The ice breaks!")
|
|
||||||
}
|
|
35
vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
35
vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
|
@ -1,35 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/documize/community/Godeps/_workspace/src/github.com/Sirupsen/logrus"
|
|
||||||
"github.com/documize/community/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake"
|
|
||||||
"github.com/tobi/airbrake-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
var log = logrus.New()
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
log.Formatter = new(logrus.TextFormatter) // default
|
|
||||||
log.Hooks.Add(new(logrus_airbrake.AirbrakeHook))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
airbrake.Endpoint = "https://exceptions.whatever.com/notifier_api/v2/notices.xml"
|
|
||||||
airbrake.ApiKey = "whatever"
|
|
||||||
airbrake.Environment = "production"
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
"size": 10,
|
|
||||||
}).Info("A group of walrus emerges from the ocean")
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"omg": true,
|
|
||||||
"number": 122,
|
|
||||||
}).Warn("The group's number increased tremendously!")
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"omg": true,
|
|
||||||
"number": 100,
|
|
||||||
}).Fatal("The ice breaks!")
|
|
||||||
}
|
|
177
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
177
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
|
@ -1,177 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// std is the name of the standard logger in stdlib `log`
|
|
||||||
std = New()
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetOutput sets the standard logger output.
|
|
||||||
func SetOutput(out io.Writer) {
|
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Out = out
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFormatter sets the standard logger formatter.
|
|
||||||
func SetFormatter(formatter Formatter) {
|
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Formatter = formatter
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetLevel sets the standard logger level.
|
|
||||||
func SetLevel(level Level) {
|
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Level = level
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHook adds a hook to the standard logger hooks.
|
|
||||||
func AddHook(hook Hook) {
|
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Hooks.Add(hook)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithField creates an entry from the standard logger and adds a field to
|
|
||||||
// it. If you want multiple fields, use `WithFields`.
|
|
||||||
//
|
|
||||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
|
||||||
// or Panic on the Entry it returns.
|
|
||||||
func WithField(key string, value interface{}) *Entry {
|
|
||||||
return std.WithField(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithFields creates an entry from the standard logger and adds multiple
|
|
||||||
// fields to it. This is simply a helper for `WithField`, invoking it
|
|
||||||
// once for each field.
|
|
||||||
//
|
|
||||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
|
||||||
// or Panic on the Entry it returns.
|
|
||||||
func WithFields(fields Fields) *Entry {
|
|
||||||
return std.WithFields(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug logs a message at level Debug on the standard logger.
|
|
||||||
func Debug(args ...interface{}) {
|
|
||||||
std.Debug(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print logs a message at level Info on the standard logger.
|
|
||||||
func Print(args ...interface{}) {
|
|
||||||
std.Print(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info logs a message at level Info on the standard logger.
|
|
||||||
func Info(args ...interface{}) {
|
|
||||||
std.Info(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warn logs a message at level Warn on the standard logger.
|
|
||||||
func Warn(args ...interface{}) {
|
|
||||||
std.Warn(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warning logs a message at level Warn on the standard logger.
|
|
||||||
func Warning(args ...interface{}) {
|
|
||||||
std.Warning(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error logs a message at level Error on the standard logger.
|
|
||||||
func Error(args ...interface{}) {
|
|
||||||
std.Error(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panic logs a message at level Panic on the standard logger.
|
|
||||||
func Panic(args ...interface{}) {
|
|
||||||
std.Panic(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatal logs a message at level Fatal on the standard logger.
|
|
||||||
func Fatal(args ...interface{}) {
|
|
||||||
std.Fatal(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debugf logs a message at level Debugf on the standard logger.
|
|
||||||
func Debugf(format string, args ...interface{}) {
|
|
||||||
std.Debugf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Printf logs a message at level Info on the standard logger.
|
|
||||||
func Printf(format string, args ...interface{}) {
|
|
||||||
std.Printf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infof logs a message at level Info on the standard logger.
|
|
||||||
func Infof(format string, args ...interface{}) {
|
|
||||||
std.Infof(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warnf logs a message at level Warn on the standard logger.
|
|
||||||
func Warnf(format string, args ...interface{}) {
|
|
||||||
std.Warnf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warningf logs a message at level Warn on the standard logger.
|
|
||||||
func Warningf(format string, args ...interface{}) {
|
|
||||||
std.Warningf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf logs a message at level Error on the standard logger.
|
|
||||||
func Errorf(format string, args ...interface{}) {
|
|
||||||
std.Errorf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panicf logs a message at level Pancf on the standard logger.
|
|
||||||
func Panicf(format string, args ...interface{}) {
|
|
||||||
std.Panicf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalf logs a message at level Fatal on the standard logger.
|
|
||||||
func Fatalf(format string, args ...interface{}) {
|
|
||||||
std.Fatalf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debugln logs a message at level Debug on the standard logger.
|
|
||||||
func Debugln(args ...interface{}) {
|
|
||||||
std.Debugln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Println logs a message at level Info on the standard logger.
|
|
||||||
func Println(args ...interface{}) {
|
|
||||||
std.Println(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infoln logs a message at level Info on the standard logger.
|
|
||||||
func Infoln(args ...interface{}) {
|
|
||||||
std.Infoln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warnln logs a message at level Warn on the standard logger.
|
|
||||||
func Warnln(args ...interface{}) {
|
|
||||||
std.Warnln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warningln logs a message at level Warn on the standard logger.
|
|
||||||
func Warningln(args ...interface{}) {
|
|
||||||
std.Warningln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorln logs a message at level Error on the standard logger.
|
|
||||||
func Errorln(args ...interface{}) {
|
|
||||||
std.Errorln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panicln logs a message at level Panic on the standard logger.
|
|
||||||
func Panicln(args ...interface{}) {
|
|
||||||
std.Panicln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalln logs a message at level Fatal on the standard logger.
|
|
||||||
func Fatalln(args ...interface{}) {
|
|
||||||
std.Fatalln(args...)
|
|
||||||
}
|
|
54
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
54
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
|
@ -1,54 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
|
||||||
// `Entry`. It exposes all the fields, including the default ones:
|
|
||||||
//
|
|
||||||
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
|
||||||
// * `entry.Data["time"]`. The timestamp.
|
|
||||||
// * `entry.Data["level"]. The level the entry was logged at.
|
|
||||||
//
|
|
||||||
// Any additional fields added with `WithField` or `WithFields` are also in
|
|
||||||
// `entry.Data`. Format is expected to return an array of bytes which are then
|
|
||||||
// logged to `logger.Out`.
|
|
||||||
type Formatter interface {
|
|
||||||
Format(*Entry) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
|
||||||
// dumping it. If this code wasn't there doing:
|
|
||||||
//
|
|
||||||
// logrus.WithField("level", 1).Info("hello")
|
|
||||||
//
|
|
||||||
// Would just silently drop the user provided level. Instead with this code
|
|
||||||
// it'll logged as:
|
|
||||||
//
|
|
||||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
|
||||||
//
|
|
||||||
// It's not exported because it's still using Data in an opionated way. It's to
|
|
||||||
// avoid code duplication between the two default formatters.
|
|
||||||
func prefixFieldClashes(entry *Entry) {
|
|
||||||
_, ok := entry.Data["time"]
|
|
||||||
if ok {
|
|
||||||
entry.Data["fields.time"] = entry.Data["time"]
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.Data["time"] = entry.Time.Format(time.RFC3339)
|
|
||||||
|
|
||||||
_, ok = entry.Data["msg"]
|
|
||||||
if ok {
|
|
||||||
entry.Data["fields.msg"] = entry.Data["msg"]
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.Data["msg"] = entry.Message
|
|
||||||
|
|
||||||
_, ok = entry.Data["level"]
|
|
||||||
if ok {
|
|
||||||
entry.Data["fields.level"] = entry.Data["level"]
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.Data["level"] = entry.Level.String()
|
|
||||||
}
|
|
122
vendor/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
122
vendor/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
|
@ -1,122 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestHook struct {
|
|
||||||
Fired bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *TestHook) Fire(entry *Entry) error {
|
|
||||||
hook.Fired = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *TestHook) Levels() []Level {
|
|
||||||
return []Level{
|
|
||||||
DebugLevel,
|
|
||||||
InfoLevel,
|
|
||||||
WarnLevel,
|
|
||||||
ErrorLevel,
|
|
||||||
FatalLevel,
|
|
||||||
PanicLevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHookFires(t *testing.T) {
|
|
||||||
hook := new(TestHook)
|
|
||||||
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Hooks.Add(hook)
|
|
||||||
assert.Equal(t, hook.Fired, false)
|
|
||||||
|
|
||||||
log.Print("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, hook.Fired, true)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type ModifyHook struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *ModifyHook) Fire(entry *Entry) error {
|
|
||||||
entry.Data["wow"] = "whale"
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *ModifyHook) Levels() []Level {
|
|
||||||
return []Level{
|
|
||||||
DebugLevel,
|
|
||||||
InfoLevel,
|
|
||||||
WarnLevel,
|
|
||||||
ErrorLevel,
|
|
||||||
FatalLevel,
|
|
||||||
PanicLevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHookCanModifyEntry(t *testing.T) {
|
|
||||||
hook := new(ModifyHook)
|
|
||||||
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Hooks.Add(hook)
|
|
||||||
log.WithField("wow", "elephant").Print("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["wow"], "whale")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCanFireMultipleHooks(t *testing.T) {
|
|
||||||
hook1 := new(ModifyHook)
|
|
||||||
hook2 := new(TestHook)
|
|
||||||
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Hooks.Add(hook1)
|
|
||||||
log.Hooks.Add(hook2)
|
|
||||||
|
|
||||||
log.WithField("wow", "elephant").Print("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["wow"], "whale")
|
|
||||||
assert.Equal(t, hook2.Fired, true)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrorHook struct {
|
|
||||||
Fired bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *ErrorHook) Fire(entry *Entry) error {
|
|
||||||
hook.Fired = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *ErrorHook) Levels() []Level {
|
|
||||||
return []Level{
|
|
||||||
ErrorLevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorHookShouldntFireOnInfo(t *testing.T) {
|
|
||||||
hook := new(ErrorHook)
|
|
||||||
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Hooks.Add(hook)
|
|
||||||
log.Info("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, hook.Fired, false)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorHookShouldFireOnError(t *testing.T) {
|
|
||||||
hook := new(ErrorHook)
|
|
||||||
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Hooks.Add(hook)
|
|
||||||
log.Error("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, hook.Fired, true)
|
|
||||||
})
|
|
||||||
}
|
|
34
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
34
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
|
@ -1,34 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
// A hook to be fired when logging on the logging levels returned from
|
|
||||||
// `Levels()` on your implementation of the interface. Note that this is not
|
|
||||||
// fired in a goroutine or a channel with workers, you should handle such
|
|
||||||
// functionality yourself if your call is non-blocking and you don't wish for
|
|
||||||
// the logging calls for levels returned from `Levels()` to block.
|
|
||||||
type Hook interface {
|
|
||||||
Levels() []Level
|
|
||||||
Fire(*Entry) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal type for storing the hooks on a logger instance.
|
|
||||||
type levelHooks map[Level][]Hook
|
|
||||||
|
|
||||||
// Add a hook to an instance of logger. This is called with
|
|
||||||
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
|
||||||
func (hooks levelHooks) Add(hook Hook) {
|
|
||||||
for _, level := range hook.Levels() {
|
|
||||||
hooks[level] = append(hooks[level], hook)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
|
||||||
// appropriate hooks for a log entry.
|
|
||||||
func (hooks levelHooks) Fire(level Level, entry *Entry) error {
|
|
||||||
for _, hook := range hooks[level] {
|
|
||||||
if err := hook.Fire(entry); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
54
vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
generated
vendored
54
vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
generated
vendored
|
@ -1,54 +0,0 @@
|
||||||
package logrus_airbrake
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/documize/community/Godeps/_workspace/src/github.com/Sirupsen/logrus"
|
|
||||||
"github.com/tobi/airbrake-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
|
||||||
// with the Airbrake API. You must set:
|
|
||||||
// * airbrake.Endpoint
|
|
||||||
// * airbrake.ApiKey
|
|
||||||
// * airbrake.Environment (only sends exceptions when set to "production")
|
|
||||||
//
|
|
||||||
// Before using this hook, to send an error. Entries that trigger an Error,
|
|
||||||
// Fatal or Panic should now include an "error" field to send to Airbrake.
|
|
||||||
type AirbrakeHook struct{}
|
|
||||||
|
|
||||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
|
||||||
if entry.Data["error"] == nil {
|
|
||||||
entry.Logger.WithFields(logrus.Fields{
|
|
||||||
"source": "airbrake",
|
|
||||||
"endpoint": airbrake.Endpoint,
|
|
||||||
}).Warn("Exceptions sent to Airbrake must have an 'error' key with the error")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err, ok := entry.Data["error"].(error)
|
|
||||||
if !ok {
|
|
||||||
entry.Logger.WithFields(logrus.Fields{
|
|
||||||
"source": "airbrake",
|
|
||||||
"endpoint": airbrake.Endpoint,
|
|
||||||
}).Warn("Exceptions sent to Airbrake must have an `error` key of type `error`")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
airErr := airbrake.Notify(err)
|
|
||||||
if airErr != nil {
|
|
||||||
entry.Logger.WithFields(logrus.Fields{
|
|
||||||
"source": "airbrake",
|
|
||||||
"endpoint": airbrake.Endpoint,
|
|
||||||
"error": airErr,
|
|
||||||
}).Warn("Failed to send error to Airbrake")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *AirbrakeHook) Levels() []logrus.Level {
|
|
||||||
return []logrus.Level{
|
|
||||||
logrus.ErrorLevel,
|
|
||||||
logrus.FatalLevel,
|
|
||||||
logrus.PanicLevel,
|
|
||||||
}
|
|
||||||
}
|
|
20
vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
20
vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
|
@ -1,20 +0,0 @@
|
||||||
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
"log/syslog"
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/Sirupsen/logrus/hooks/syslog"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log := logrus.New()
|
|
||||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
log.Hooks.Add(hook)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
59
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
59
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
|
@ -1,59 +0,0 @@
|
||||||
package logrus_syslog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/documize/community/Godeps/_workspace/src/github.com/Sirupsen/logrus"
|
|
||||||
"fmt"
|
|
||||||
"log/syslog"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SyslogHook to send logs via syslog.
|
|
||||||
type SyslogHook struct {
|
|
||||||
Writer *syslog.Writer
|
|
||||||
SyslogNetwork string
|
|
||||||
SyslogRaddr string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a hook to be added to an instance of logger. This is called with
|
|
||||||
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
|
|
||||||
// `if err == nil { log.Hooks.Add(hook) }`
|
|
||||||
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
|
|
||||||
w, err := syslog.Dial(network, raddr, priority, tag)
|
|
||||||
return &SyslogHook{w, network, raddr}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
|
|
||||||
line, err := entry.String()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch entry.Data["level"] {
|
|
||||||
case "panic":
|
|
||||||
return hook.Writer.Crit(line)
|
|
||||||
case "fatal":
|
|
||||||
return hook.Writer.Crit(line)
|
|
||||||
case "error":
|
|
||||||
return hook.Writer.Err(line)
|
|
||||||
case "warn":
|
|
||||||
return hook.Writer.Warning(line)
|
|
||||||
case "info":
|
|
||||||
return hook.Writer.Info(line)
|
|
||||||
case "debug":
|
|
||||||
return hook.Writer.Debug(line)
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *SyslogHook) Levels() []logrus.Level {
|
|
||||||
return []logrus.Level{
|
|
||||||
logrus.PanicLevel,
|
|
||||||
logrus.FatalLevel,
|
|
||||||
logrus.ErrorLevel,
|
|
||||||
logrus.WarnLevel,
|
|
||||||
logrus.InfoLevel,
|
|
||||||
logrus.DebugLevel,
|
|
||||||
}
|
|
||||||
}
|
|
26
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
26
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
|
@ -1,26 +0,0 @@
|
||||||
package logrus_syslog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/documize/community/Godeps/_workspace/src/github.com/Sirupsen/logrus"
|
|
||||||
"log/syslog"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLocalhostAddAndPrint(t *testing.T) {
|
|
||||||
log := logrus.New()
|
|
||||||
hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unable to connect to local syslog.")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Hooks.Add(hook)
|
|
||||||
|
|
||||||
for _, level := range hook.Levels() {
|
|
||||||
if len(log.Hooks[level]) != 1 {
|
|
||||||
t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Congratulations!")
|
|
||||||
}
|
|
19
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
19
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
|
@ -1,19 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JSONFormatter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|
||||||
prefixFieldClashes(entry)
|
|
||||||
|
|
||||||
serialized, err := json.Marshal(entry.Data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
|
||||||
}
|
|
||||||
return append(serialized, '\n'), nil
|
|
||||||
}
|
|
161
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
161
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
|
@ -1,161 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Logger struct {
|
|
||||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
|
||||||
// file, or leave it default which is `os.Stdout`. You can also set this to
|
|
||||||
// something more adventorous, such as logging to Kafka.
|
|
||||||
Out io.Writer
|
|
||||||
// Hooks for the logger instance. These allow firing events based on logging
|
|
||||||
// levels and log entries. For example, to send errors to an error tracking
|
|
||||||
// service, log to StatsD or dump the core on fatal errors.
|
|
||||||
Hooks levelHooks
|
|
||||||
// All log entries pass through the formatter before logged to Out. The
|
|
||||||
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
|
||||||
// TextFormatter is the default. In development (when a TTY is attached) it
|
|
||||||
// logs with colors, but to a file it wouldn't. You can easily implement your
|
|
||||||
// own that implements the `Formatter` interface, see the `README` or included
|
|
||||||
// formatters for examples.
|
|
||||||
Formatter Formatter
|
|
||||||
// The logging level the logger should log at. This is typically (and defaults
|
|
||||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
|
||||||
// logged. `logrus.Debug` is useful in
|
|
||||||
Level Level
|
|
||||||
// Used to sync writing to the log.
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
|
||||||
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
|
||||||
// instantiate your own:
|
|
||||||
//
|
|
||||||
// var log = &Logger{
|
|
||||||
// Out: os.Stderr,
|
|
||||||
// Formatter: new(JSONFormatter),
|
|
||||||
// Hooks: make(levelHooks),
|
|
||||||
// Level: logrus.Debug,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// It's recommended to make this a global instance called `log`.
|
|
||||||
func New() *Logger {
|
|
||||||
return &Logger{
|
|
||||||
Out: os.Stdout,
|
|
||||||
Formatter: new(TextFormatter),
|
|
||||||
Hooks: make(levelHooks),
|
|
||||||
Level: InfoLevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds a field to the log entry, note that you it doesn't log until you call
|
|
||||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
|
||||||
// Ff you want multiple fields, use `WithFields`.
|
|
||||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
|
||||||
return NewEntry(logger).WithField(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
|
||||||
// each `Field`.
|
|
||||||
func (logger *Logger) WithFields(fields Fields) *Entry {
|
|
||||||
return NewEntry(logger).WithFields(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
|
||||||
NewEntry(logger).Debugf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
|
||||||
NewEntry(logger).Infof(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
|
||||||
NewEntry(logger).Printf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
|
||||||
NewEntry(logger).Warnf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
|
||||||
NewEntry(logger).Warnf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
|
||||||
NewEntry(logger).Errorf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
|
||||||
NewEntry(logger).Fatalf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
|
||||||
NewEntry(logger).Panicf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Debug(args ...interface{}) {
|
|
||||||
NewEntry(logger).Debug(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Info(args ...interface{}) {
|
|
||||||
NewEntry(logger).Info(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Print(args ...interface{}) {
|
|
||||||
NewEntry(logger).Info(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warn(args ...interface{}) {
|
|
||||||
NewEntry(logger).Warn(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warning(args ...interface{}) {
|
|
||||||
NewEntry(logger).Warn(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Error(args ...interface{}) {
|
|
||||||
NewEntry(logger).Error(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Fatal(args ...interface{}) {
|
|
||||||
NewEntry(logger).Fatal(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Panic(args ...interface{}) {
|
|
||||||
NewEntry(logger).Panic(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Debugln(args ...interface{}) {
|
|
||||||
NewEntry(logger).Debugln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Infoln(args ...interface{}) {
|
|
||||||
NewEntry(logger).Infoln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Println(args ...interface{}) {
|
|
||||||
NewEntry(logger).Println(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warnln(args ...interface{}) {
|
|
||||||
NewEntry(logger).Warnln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warningln(args ...interface{}) {
|
|
||||||
NewEntry(logger).Warnln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Errorln(args ...interface{}) {
|
|
||||||
NewEntry(logger).Errorln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
|
||||||
NewEntry(logger).Fatalln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Panicln(args ...interface{}) {
|
|
||||||
NewEntry(logger).Panicln(args...)
|
|
||||||
}
|
|
72
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
72
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
|
@ -1,72 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fields type, used to pass to `WithFields`.
|
|
||||||
type Fields map[string]interface{}
|
|
||||||
|
|
||||||
// Level type
|
|
||||||
type Level uint8
|
|
||||||
|
|
||||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
|
||||||
func (level Level) String() string {
|
|
||||||
switch level {
|
|
||||||
case DebugLevel:
|
|
||||||
return "debug"
|
|
||||||
case InfoLevel:
|
|
||||||
return "info"
|
|
||||||
case WarnLevel:
|
|
||||||
return "warning"
|
|
||||||
case ErrorLevel:
|
|
||||||
return "error"
|
|
||||||
case FatalLevel:
|
|
||||||
return "fatal"
|
|
||||||
case PanicLevel:
|
|
||||||
return "panic"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are the different logging levels. You can set the logging level to log
|
|
||||||
// on your instance of logger, obtained with `logrus.New()`.
|
|
||||||
const (
|
|
||||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
|
||||||
// message passed to Debug, Info, ...
|
|
||||||
PanicLevel Level = iota
|
|
||||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
|
||||||
// logging level is set to Panic.
|
|
||||||
FatalLevel
|
|
||||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
|
||||||
// Commonly used for hooks to send errors to an error tracking service.
|
|
||||||
ErrorLevel
|
|
||||||
// WarnLevel level. Non-critical entries that deserve eyes.
|
|
||||||
WarnLevel
|
|
||||||
// InfoLevel level. General operational entries about what's going on inside the
|
|
||||||
// application.
|
|
||||||
InfoLevel
|
|
||||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
|
||||||
DebugLevel
|
|
||||||
)
|
|
||||||
|
|
||||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
|
||||||
var _ StdLogger = &log.Logger{}
|
|
||||||
|
|
||||||
// StdLogger is what your logrus-enabled library should take, that way
|
|
||||||
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
|
||||||
// interface, this is the closest we get, unfortunately.
|
|
||||||
type StdLogger interface {
|
|
||||||
Print(...interface{})
|
|
||||||
Printf(string, ...interface{})
|
|
||||||
Println(...interface{})
|
|
||||||
|
|
||||||
Fatal(...interface{})
|
|
||||||
Fatalf(string, ...interface{})
|
|
||||||
Fatalln(...interface{})
|
|
||||||
|
|
||||||
Panic(...interface{})
|
|
||||||
Panicf(string, ...interface{})
|
|
||||||
Panicln(...interface{})
|
|
||||||
}
|
|
173
vendor/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
173
vendor/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
|
@ -1,173 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
var fields Fields
|
|
||||||
|
|
||||||
logger := New()
|
|
||||||
logger.Out = &buffer
|
|
||||||
logger.Formatter = new(JSONFormatter)
|
|
||||||
|
|
||||||
log(logger)
|
|
||||||
|
|
||||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
assertions(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrint(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Print("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "test")
|
|
||||||
assert.Equal(t, fields["level"], "info")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfo(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Info("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "test")
|
|
||||||
assert.Equal(t, fields["level"], "info")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWarn(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Warn("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "test")
|
|
||||||
assert.Equal(t, fields["level"], "warning")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Infoln("test", "test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "test test")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Infoln("test", 10)
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "test 10")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Infoln(10, 10)
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "10 10")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Infoln(10, 10)
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "10 10")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Info("test", 10)
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "test10")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.Info("test", "test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "testtest")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithFieldsShouldAllowAssignments(t *testing.T) {
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
var fields Fields
|
|
||||||
|
|
||||||
logger := New()
|
|
||||||
logger.Out = &buffer
|
|
||||||
logger.Formatter = new(JSONFormatter)
|
|
||||||
|
|
||||||
localLog := logger.WithFields(Fields{
|
|
||||||
"key1": "value1",
|
|
||||||
})
|
|
||||||
|
|
||||||
localLog.WithField("key2", "value2").Info("test")
|
|
||||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, "value2", fields["key2"])
|
|
||||||
assert.Equal(t, "value1", fields["key1"])
|
|
||||||
|
|
||||||
buffer = bytes.Buffer{}
|
|
||||||
fields = Fields{}
|
|
||||||
localLog.Info("test")
|
|
||||||
err = json.Unmarshal(buffer.Bytes(), &fields)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
_, ok := fields["key2"]
|
|
||||||
assert.Equal(t, false, ok)
|
|
||||||
assert.Equal(t, "value1", fields["key1"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.WithField("msg", "hello").Info("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "test")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.WithField("msg", "hello").Info("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["msg"], "test")
|
|
||||||
assert.Equal(t, fields["fields.msg"], "hello")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.WithField("time", "hello").Info("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["fields.time"], "hello")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
|
|
||||||
LogAndAssertJSON(t, func(log *Logger) {
|
|
||||||
log.WithField("level", 1).Info("test")
|
|
||||||
}, func(fields Fields) {
|
|
||||||
assert.Equal(t, fields["level"], "info")
|
|
||||||
assert.Equal(t, fields["fields.level"], 1)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertLevelToString(t *testing.T) {
|
|
||||||
assert.Equal(t, "debug", DebugLevel.String())
|
|
||||||
assert.Equal(t, "info", InfoLevel.String())
|
|
||||||
assert.Equal(t, "warning", WarnLevel.String())
|
|
||||||
assert.Equal(t, "error", ErrorLevel.String())
|
|
||||||
assert.Equal(t, "fatal", FatalLevel.String())
|
|
||||||
assert.Equal(t, "panic", PanicLevel.String())
|
|
||||||
}
|
|
12
vendor/github.com/Sirupsen/logrus/terminal_darwin.go
generated
vendored
12
vendor/github.com/Sirupsen/logrus/terminal_darwin.go
generated
vendored
|
@ -1,12 +0,0 @@
|
||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
const ioctlReadTermios = syscall.TIOCGETA
|
|
||||||
|
|
||||||
type Termios syscall.Termios
|
|
20
vendor/github.com/Sirupsen/logrus/terminal_freebsd.go
generated
vendored
20
vendor/github.com/Sirupsen/logrus/terminal_freebsd.go
generated
vendored
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin.
|
|
||||||
*/
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
const ioctlReadTermios = syscall.TIOCGETA
|
|
||||||
|
|
||||||
type Termios struct {
|
|
||||||
Iflag uint32
|
|
||||||
Oflag uint32
|
|
||||||
Cflag uint32
|
|
||||||
Lflag uint32
|
|
||||||
Cc [20]uint8
|
|
||||||
Ispeed uint32
|
|
||||||
Ospeed uint32
|
|
||||||
}
|
|
12
vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
12
vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
|
@ -1,12 +0,0 @@
|
||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
const ioctlReadTermios = syscall.TCGETS
|
|
||||||
|
|
||||||
type Termios syscall.Termios
|
|
21
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
21
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
|
@ -1,21 +0,0 @@
|
||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build linux,!appengine darwin freebsd
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
|
||||||
func IsTerminal() bool {
|
|
||||||
fd := syscall.Stdout
|
|
||||||
var termios Termios
|
|
||||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
|
||||||
return err == 0
|
|
||||||
}
|
|
27
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
27
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
|
@ -1,27 +0,0 @@
|
||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
||||||
|
|
||||||
var (
|
|
||||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
|
||||||
func IsTerminal() bool {
|
|
||||||
fd := syscall.Stdout
|
|
||||||
var st uint32
|
|
||||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
||||||
return r != 0 && e == 0
|
|
||||||
}
|
|
85
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
85
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
|
@ -1,85 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
nocolor = 0
|
|
||||||
red = 31
|
|
||||||
green = 32
|
|
||||||
yellow = 33
|
|
||||||
blue = 34
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
baseTimestamp = time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
func miniTS() int {
|
|
||||||
return int(time.Since(baseTimestamp) / time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
type TextFormatter struct {
|
|
||||||
// Set to true to bypass checking for a TTY before outputting colors.
|
|
||||||
ForceColors bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|
||||||
b := &bytes.Buffer{}
|
|
||||||
|
|
||||||
prefixFieldClashes(entry)
|
|
||||||
|
|
||||||
if f.ForceColors || IsTerminal() {
|
|
||||||
levelText := strings.ToUpper(entry.Data["level"].(string))[0:4]
|
|
||||||
|
|
||||||
levelColor := blue
|
|
||||||
|
|
||||||
if entry.Data["level"] == "warning" {
|
|
||||||
levelColor = yellow
|
|
||||||
} else if entry.Data["level"] == "error" ||
|
|
||||||
entry.Data["level"] == "fatal" ||
|
|
||||||
entry.Data["level"] == "panic" {
|
|
||||||
levelColor = red
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Data["msg"])
|
|
||||||
|
|
||||||
keys := make([]string, 0)
|
|
||||||
for k, _ := range entry.Data {
|
|
||||||
if k != "level" && k != "time" && k != "msg" {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
for _, k := range keys {
|
|
||||||
v := entry.Data[k]
|
|
||||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
f.AppendKeyValue(b, "time", entry.Data["time"].(string))
|
|
||||||
f.AppendKeyValue(b, "level", entry.Data["level"].(string))
|
|
||||||
f.AppendKeyValue(b, "msg", entry.Data["msg"].(string))
|
|
||||||
|
|
||||||
for key, value := range entry.Data {
|
|
||||||
if key != "time" && key != "level" && key != "msg" {
|
|
||||||
f.AppendKeyValue(b, key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.WriteByte('\n')
|
|
||||||
return b.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) AppendKeyValue(b *bytes.Buffer, key, value interface{}) {
|
|
||||||
if _, ok := value.(string); ok {
|
|
||||||
fmt.Fprintf(b, "%v=%q ", key, value)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(b, "%v=%v ", key, value)
|
|
||||||
}
|
|
||||||
}
|
|
1
vendor/github.com/codegangsta/negroni/.gitignore
generated
vendored
Normal file
1
vendor/github.com/codegangsta/negroni/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/coverage.txt
|
27
vendor/github.com/codegangsta/negroni/.travis.yml
generated
vendored
Normal file
27
vendor/github.com/codegangsta/negroni/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
language: go
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.x
|
||||||
|
- 1.2.x
|
||||||
|
- 1.3.x
|
||||||
|
- 1.4.x
|
||||||
|
- 1.5.x
|
||||||
|
- 1.6.x
|
||||||
|
- 1.7.x
|
||||||
|
- 1.8.x
|
||||||
|
- master
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- find "${GOPATH%%:*}" -name '*.a' -delete
|
||||||
|
- rm -rf "${GOPATH%%:*}/src/golang.org"
|
||||||
|
- go get golang.org/x/tools/cover
|
||||||
|
- go get golang.org/x/tools/cmd/cover
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -race -coverprofile=coverage.txt -covermode=atomic
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s "https://codecov.io/bash")
|
64
vendor/github.com/codegangsta/negroni/CHANGELOG.md
generated
vendored
Normal file
64
vendor/github.com/codegangsta/negroni/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# Change Log
|
||||||
|
|
||||||
|
**ATTN**: This project uses [semantic versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [Unreleased] -
|
||||||
|
|
||||||
|
## [0.3.0] - 2017-11-11
|
||||||
|
### Added
|
||||||
|
- `With()` helper for building a new `Negroni` struct chaining handlers from
|
||||||
|
existing `Negroni` structs
|
||||||
|
- Format log output in `Logger` middleware via a configurable `text/template`
|
||||||
|
string injectable via `.SetFormat`. Added `LoggerDefaultFormat` and
|
||||||
|
`LoggerDefaultDateFormat` to configure the default template and date format
|
||||||
|
used by the `Logger` middleware.
|
||||||
|
- Support for HTTP/2 pusher support via `http.Pusher` interface for Go 1.8+.
|
||||||
|
- `WrapFunc` to convert `http.HandlerFunc` into a `negroni.Handler`
|
||||||
|
- `Formatter` field added to `Recovery` middleware to allow configuring how
|
||||||
|
`panic`s are output. Default of `TextFormatter` (how it was output in
|
||||||
|
`0.2.0`) used. `HTMLPanicFormatter` also added to allow easy outputing of
|
||||||
|
`panic`s as HTML.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `Written()` correct returns `false` if no response header has been written
|
||||||
|
- Only implement `http.CloseNotifier` with the `negroni.ResponseWriter` if the
|
||||||
|
underlying `http.ResponseWriter` implements it (previously would always
|
||||||
|
implement it and panic if the underlying `http.ResponseWriter` did not.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Set default status to `0` in the case that no handler writes status -- was
|
||||||
|
previously `200` (in 0.2.0, before that it was `0` so this reestablishes that
|
||||||
|
behavior)
|
||||||
|
- Catch `panic`s thrown by callbacks provided to the `Recovery` handler
|
||||||
|
- Recovery middleware will set `text/plain` content-type if none is set
|
||||||
|
- `ALogger` interface to allow custom logger outputs to be used with the
|
||||||
|
`Logger` middleware. Changes embeded field in `negroni.Logger` from `Logger`
|
||||||
|
to `ALogger`.
|
||||||
|
- Default `Logger` middleware output changed to be more structure and verbose
|
||||||
|
(also now configurable, see `Added`)
|
||||||
|
- Automatically bind to port specified in `$PORT` in `.Run()` if an address is
|
||||||
|
not passed in. Fall back to binding to `:8080` if no address specified
|
||||||
|
(configuable via `DefaultAddress`).
|
||||||
|
- `PanicHandlerFunc` added to `Recovery` middleware to enhance custom handling
|
||||||
|
of `panic`s by providing additional information to the handler including the
|
||||||
|
stack and the `http.Request`. `Recovery.ErrorHandlerFunc` was also added, but
|
||||||
|
deprecated in favor of the new `PanicHandlerFunc`.
|
||||||
|
|
||||||
|
## [0.2.0] - 2016-05-10
|
||||||
|
### Added
|
||||||
|
- Support for variadic handlers in `New()`
|
||||||
|
- Added `Negroni.Handlers()` to fetch all of the handlers for a given chain
|
||||||
|
- Allowed size in `Recovery` handler was bumped to 8k
|
||||||
|
- `Negroni.UseFunc` to push another handler onto the chain
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Set the status before calling `beforeFuncs` so the information is available to them
|
||||||
|
- Set default status to `200` in the case that no handler writes status -- was previously `0`
|
||||||
|
- Panic if `nil` handler is given to `negroni.Use`
|
||||||
|
|
||||||
|
## 0.1.0 - 2013-07-22
|
||||||
|
### Added
|
||||||
|
- Initial implementation.
|
||||||
|
|
||||||
|
[Unreleased]: https://github.com/urfave/negroni/compare/v0.2.0...HEAD
|
||||||
|
[0.2.0]: https://github.com/urfave/negroni/compare/v0.1.0...v0.2.0
|
517
vendor/github.com/codegangsta/negroni/README.md
generated
vendored
517
vendor/github.com/codegangsta/negroni/README.md
generated
vendored
|
@ -1,20 +1,42 @@
|
||||||
# Negroni [](http://godoc.org/github.com/codegangsta/negroni) [](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61)
|
# Negroni
|
||||||
|
[](http://godoc.org/github.com/urfave/negroni)
|
||||||
|
[](https://travis-ci.org/urfave/negroni)
|
||||||
|
[](https://codebeat.co/projects/github-com-urfave-negroni)
|
||||||
|
[](https://codecov.io/gh/urfave/negroni)
|
||||||
|
|
||||||
Negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of `net/http` Handlers.
|
**Notice:** This is the library formerly known as
|
||||||
|
`github.com/codegangsta/negroni` -- Github will automatically redirect requests
|
||||||
|
to this repository, but we recommend updating your references for clarity.
|
||||||
|
|
||||||
If you like the idea of [Martini](http://github.com/go-martini/martini), but you think it contains too much magic, then Negroni is a great fit.
|
Negroni is an idiomatic approach to web middleware in Go. It is tiny,
|
||||||
|
non-intrusive, and encourages use of `net/http` Handlers.
|
||||||
|
|
||||||
|
If you like the idea of [Martini](https://github.com/go-martini/martini), but
|
||||||
|
you think it contains too much magic, then Negroni is a great fit.
|
||||||
|
|
||||||
|
Language Translations:
|
||||||
|
* [Deutsch (de_DE)](translations/README_de_de.md)
|
||||||
|
* [Português Brasileiro (pt_BR)](translations/README_pt_br.md)
|
||||||
|
* [简体中文 (zh_cn)](translations/README_zh_CN.md)
|
||||||
|
* [繁體中文 (zh_tw)](translations/README_zh_tw.md)
|
||||||
|
* [日本語 (ja_JP)](translations/README_ja_JP.md)
|
||||||
|
* [Français (fr_FR)](translations/README_fr_FR.md)
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`.
|
After installing Go and setting up your
|
||||||
|
[GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file.
|
||||||
|
We'll call it `server.go`.
|
||||||
|
|
||||||
~~~ go
|
<!-- { "interrupt": true } -->
|
||||||
|
``` go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/codegangsta/negroni"
|
|
||||||
"net/http"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/urfave/negroni"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -23,34 +45,47 @@ func main() {
|
||||||
fmt.Fprintf(w, "Welcome to the home page!")
|
fmt.Fprintf(w, "Welcome to the home page!")
|
||||||
})
|
})
|
||||||
|
|
||||||
n := negroni.Classic()
|
n := negroni.Classic() // Includes some default middlewares
|
||||||
n.UseHandler(mux)
|
n.UseHandler(mux)
|
||||||
n.Run(":3000")
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Then install the Negroni package (**go 1.1** and greater is required):
|
http.ListenAndServe(":3000", n)
|
||||||
~~~
|
}
|
||||||
go get github.com/codegangsta/negroni
|
```
|
||||||
~~~
|
|
||||||
|
Then install the Negroni package (**NOTE**: >= **go 1.1** is required):
|
||||||
|
|
||||||
|
```
|
||||||
|
go get github.com/urfave/negroni
|
||||||
|
```
|
||||||
|
|
||||||
Then run your server:
|
Then run your server:
|
||||||
~~~
|
|
||||||
|
```
|
||||||
go run server.go
|
go run server.go
|
||||||
~~~
|
```
|
||||||
|
|
||||||
You will now have a Go net/http webserver running on `localhost:3000`.
|
You will now have a Go `net/http` webserver running on `localhost:3000`.
|
||||||
|
|
||||||
## Need Help?
|
### Packaging
|
||||||
If you have a question or feature request, [go ask the mailing list](https://groups.google.com/forum/#!forum/negroni-users). The GitHub issues for Negroni will be used exclusively for bug reports and pull requests.
|
|
||||||
|
If you are on Debian, `negroni` is also available as [a
|
||||||
|
package](https://packages.debian.org/sid/golang-github-urfave-negroni-dev) that
|
||||||
|
you can install via `apt install golang-github-urfave-negroni-dev` (at the time
|
||||||
|
of writing, it is in the `sid` repositories).
|
||||||
|
|
||||||
## Is Negroni a Framework?
|
## Is Negroni a Framework?
|
||||||
Negroni is **not** a framework. It is a library that is designed to work directly with net/http.
|
|
||||||
|
Negroni is **not** a framework. It is a middleware-focused library that is
|
||||||
|
designed to work directly with `net/http`.
|
||||||
|
|
||||||
## Routing?
|
## Routing?
|
||||||
Negroni is BYOR (Bring your own Router). The Go community already has a number of great http routers available, Negroni tries to play well with all of them by fully supporting `net/http`. For instance, integrating with [Gorilla Mux](http://github.com/gorilla/mux) looks like so:
|
|
||||||
|
|
||||||
~~~ go
|
Negroni is BYOR (Bring your own Router). The Go community already has a number
|
||||||
|
of great http routers available, and Negroni tries to play well with all of them
|
||||||
|
by fully supporting `net/http`. For instance, integrating with [Gorilla Mux]
|
||||||
|
looks like so:
|
||||||
|
|
||||||
|
``` go
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.HandleFunc("/", HomeHandler)
|
router.HandleFunc("/", HomeHandler)
|
||||||
|
|
||||||
|
@ -60,47 +95,54 @@ n.Use(Middleware3)
|
||||||
// router goes last
|
// router goes last
|
||||||
n.UseHandler(router)
|
n.UseHandler(router)
|
||||||
|
|
||||||
n.Run(":3000")
|
http.ListenAndServe(":3001", n)
|
||||||
~~~
|
```
|
||||||
|
|
||||||
## `negroni.Classic()`
|
## `negroni.Classic()`
|
||||||
`negroni.Classic()` provides some default middleware that is useful for most applications:
|
|
||||||
|
|
||||||
* `negroni.Recovery` - Panic Recovery Middleware.
|
`negroni.Classic()` provides some default middleware that is useful for most
|
||||||
* `negroni.Logging` - Request/Response Logging Middleware.
|
applications:
|
||||||
* `negroni.Static` - Static File serving under the "public" directory.
|
|
||||||
|
* [`negroni.Recovery`](#recovery) - Panic Recovery Middleware.
|
||||||
|
* [`negroni.Logger`](#logger) - Request/Response Logger Middleware.
|
||||||
|
* [`negroni.Static`](#static) - Static File serving under the "public"
|
||||||
|
directory.
|
||||||
|
|
||||||
This makes it really easy to get started with some useful features from Negroni.
|
This makes it really easy to get started with some useful features from Negroni.
|
||||||
|
|
||||||
## Handlers
|
## Handlers
|
||||||
Negroni provides a bidirectional middleware flow. This is done through the `negroni.Handler` interface:
|
|
||||||
|
|
||||||
~~~ go
|
Negroni provides a bidirectional middleware flow. This is done through the
|
||||||
|
`negroni.Handler` interface:
|
||||||
|
|
||||||
|
``` go
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
|
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
|
||||||
}
|
}
|
||||||
~~~
|
```
|
||||||
|
|
||||||
If a middleware hasn't already written to the ResponseWriter, it should call the next `http.HandlerFunc` in the chain to yield to the next middleware handler. This can be used for great good:
|
If a middleware hasn't already written to the `ResponseWriter`, it should call
|
||||||
|
the next `http.HandlerFunc` in the chain to yield to the next middleware
|
||||||
|
handler. This can be used for great good:
|
||||||
|
|
||||||
~~~ go
|
``` go
|
||||||
func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
// do some stuff before
|
// do some stuff before
|
||||||
next(rw, r)
|
next(rw, r)
|
||||||
// do some stuff after
|
// do some stuff after
|
||||||
}
|
}
|
||||||
~~~
|
```
|
||||||
|
|
||||||
And you can map it to the handler chain with the `Use` function:
|
And you can map it to the handler chain with the `Use` function:
|
||||||
|
|
||||||
~~~ go
|
``` go
|
||||||
n := negroni.New()
|
n := negroni.New()
|
||||||
n.Use(negroni.HandlerFunc(MyMiddleware))
|
n.Use(negroni.HandlerFunc(MyMiddleware))
|
||||||
~~~
|
```
|
||||||
|
|
||||||
You can also map plain old `http.Handler`s:
|
You can also map plain old `http.Handler`s:
|
||||||
|
|
||||||
~~~ go
|
``` go
|
||||||
n := negroni.New()
|
n := negroni.New()
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
@ -108,72 +150,397 @@ mux := http.NewServeMux()
|
||||||
|
|
||||||
n.UseHandler(mux)
|
n.UseHandler(mux)
|
||||||
|
|
||||||
n.Run(":3000")
|
http.ListenAndServe(":3000", n)
|
||||||
~~~
|
```
|
||||||
|
|
||||||
|
## `With()`
|
||||||
|
|
||||||
|
Negroni has a convenience function called `With`. `With` takes one or more
|
||||||
|
`Handler` instances and returns a new `Negroni` with the combination of the
|
||||||
|
receiver's handlers and the new handlers.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// middleware we want to reuse
|
||||||
|
common := negroni.New()
|
||||||
|
common.Use(MyMiddleware1)
|
||||||
|
common.Use(MyMiddleware2)
|
||||||
|
|
||||||
|
// `specific` is a new negroni with the handlers from `common` combined with the
|
||||||
|
// the handlers passed in
|
||||||
|
specific := common.With(
|
||||||
|
SpecificMiddleware1,
|
||||||
|
SpecificMiddleware2
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
## `Run()`
|
## `Run()`
|
||||||
Negroni has a convenience function called `Run`. `Run` takes an addr string identical to [http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe).
|
|
||||||
|
|
||||||
~~~ go
|
Negroni has a convenience function called `Run`. `Run` takes an addr string
|
||||||
n := negroni.Classic()
|
identical to [`http.ListenAndServe`](https://godoc.org/net/http#ListenAndServe).
|
||||||
// ...
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", n))
|
<!-- { "interrupt": true } -->
|
||||||
~~~
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/urfave/negroni"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
n := negroni.Classic()
|
||||||
|
n.Run(":8080")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
If no address is provided, the `PORT` environment variable is used instead.
|
||||||
|
If the `PORT` environment variable is not defined, the default address will be used.
|
||||||
|
See [Run](https://godoc.org/github.com/urfave/negroni#Negroni.Run) for a complete description.
|
||||||
|
|
||||||
|
In general, you will want to use `net/http` methods and pass `negroni` as a
|
||||||
|
`Handler`, as this is more flexible, e.g.:
|
||||||
|
|
||||||
|
<!-- { "interrupt": true } -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/urfave/negroni"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
fmt.Fprintf(w, "Welcome to the home page!")
|
||||||
|
})
|
||||||
|
|
||||||
|
n := negroni.Classic() // Includes some default middlewares
|
||||||
|
n.UseHandler(mux)
|
||||||
|
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: ":8080",
|
||||||
|
Handler: n,
|
||||||
|
ReadTimeout: 10 * time.Second,
|
||||||
|
WriteTimeout: 10 * time.Second,
|
||||||
|
MaxHeaderBytes: 1 << 20,
|
||||||
|
}
|
||||||
|
log.Fatal(s.ListenAndServe())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Route Specific Middleware
|
## Route Specific Middleware
|
||||||
If you have a route group of routes that need specific middleware to be executed, you can simply create a new Negroni instance and use it as your route handler.
|
|
||||||
|
|
||||||
~~~ go
|
If you have a route group of routes that need specific middleware to be
|
||||||
|
executed, you can simply create a new Negroni instance and use it as your route
|
||||||
|
handler.
|
||||||
|
|
||||||
|
``` go
|
||||||
|
router := mux.NewRouter()
|
||||||
|
adminRoutes := mux.NewRouter()
|
||||||
|
// add admin routes here
|
||||||
|
|
||||||
|
// Create a new negroni for the admin middleware
|
||||||
|
router.PathPrefix("/admin").Handler(negroni.New(
|
||||||
|
Middleware1,
|
||||||
|
Middleware2,
|
||||||
|
negroni.Wrap(adminRoutes),
|
||||||
|
))
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using [Gorilla Mux], here is an example using a subrouter:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
router := mux.NewRouter()
|
||||||
|
subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true)
|
||||||
|
subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/"
|
||||||
|
subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id"
|
||||||
|
|
||||||
|
// "/subpath" is necessary to ensure the subRouter and main router linkup
|
||||||
|
router.PathPrefix("/subpath").Handler(negroni.New(
|
||||||
|
Middleware1,
|
||||||
|
Middleware2,
|
||||||
|
negroni.Wrap(subRouter),
|
||||||
|
))
|
||||||
|
```
|
||||||
|
|
||||||
|
`With()` can be used to eliminate redundancy for middlewares shared across
|
||||||
|
routes.
|
||||||
|
|
||||||
|
``` go
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
apiRoutes := mux.NewRouter()
|
apiRoutes := mux.NewRouter()
|
||||||
// add api routes here
|
// add api routes here
|
||||||
// eg apiRoutes.HandleFunc("/api", apiHandler)
|
webRoutes := mux.NewRouter()
|
||||||
// eg apiRoutes.HandleFunc("/api/users", userHandler)
|
// add web routes here
|
||||||
// eg apiRoutes.HandleFunc("/api/products", productHandler)
|
|
||||||
|
|
||||||
// Create a new negroni for the api middleware
|
// create common middleware to be shared across routes
|
||||||
router.PathPrefix("/api").Handler( negroni.New(
|
common := negroni.New(
|
||||||
Middleware1,
|
Middleware1,
|
||||||
Middleware2,
|
Middleware2,
|
||||||
|
)
|
||||||
|
|
||||||
|
// create a new negroni for the api middleware
|
||||||
|
// using the common middleware as a base
|
||||||
|
router.PathPrefix("/api").Handler(common.With(
|
||||||
|
APIMiddleware1,
|
||||||
negroni.Wrap(apiRoutes),
|
negroni.Wrap(apiRoutes),
|
||||||
))
|
))
|
||||||
~~~
|
// create a new negroni for the web middleware
|
||||||
|
// using the common middleware as a base
|
||||||
|
router.PathPrefix("/web").Handler(common.With(
|
||||||
|
WebMiddleware1,
|
||||||
|
negroni.Wrap(webRoutes),
|
||||||
|
))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bundled Middleware
|
||||||
|
|
||||||
|
### Static
|
||||||
|
|
||||||
|
This middleware will serve files on the filesystem. If the files do not exist,
|
||||||
|
it proxies the request to the next middleware. If you want the requests for
|
||||||
|
non-existent files to return a `404 File Not Found` to the user you should look
|
||||||
|
at using [http.FileServer](https://golang.org/pkg/net/http/#FileServer) as
|
||||||
|
a handler.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
<!-- { "interrupt": true } -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/urfave/negroni"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
fmt.Fprintf(w, "Welcome to the home page!")
|
||||||
|
})
|
||||||
|
|
||||||
|
// Example of using a http.FileServer if you want "server-like" rather than "middleware" behavior
|
||||||
|
// mux.Handle("/public", http.FileServer(http.Dir("/home/public")))
|
||||||
|
|
||||||
|
n := negroni.New()
|
||||||
|
n.Use(negroni.NewStatic(http.Dir("/tmp")))
|
||||||
|
n.UseHandler(mux)
|
||||||
|
|
||||||
|
http.ListenAndServe(":3002", n)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will serve files from the `/tmp` directory first, but proxy calls to the next
|
||||||
|
handler if the request does not match a file on the filesystem.
|
||||||
|
|
||||||
|
### Recovery
|
||||||
|
|
||||||
|
This middleware catches `panic`s and responds with a `500` response code. If
|
||||||
|
any other middleware has written a response code or body, this middleware will
|
||||||
|
fail to properly send a 500 to the client, as the client has already received
|
||||||
|
the HTTP response code. Additionally, an `PanicHandlerFunc` can be attached
|
||||||
|
to report 500's to an error reporting service such as Sentry or Airbrake.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
<!-- { "interrupt": true } -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/urfave/negroni"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
panic("oh no")
|
||||||
|
})
|
||||||
|
|
||||||
|
n := negroni.New()
|
||||||
|
n.Use(negroni.NewRecovery())
|
||||||
|
n.UseHandler(mux)
|
||||||
|
|
||||||
|
http.ListenAndServe(":3003", n)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will return a `500 Internal Server Error` to each request. It will also log the
|
||||||
|
stack traces as well as print the stack trace to the requester if `PrintStack`
|
||||||
|
is set to `true` (the default).
|
||||||
|
|
||||||
|
Example with error handler:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/urfave/negroni"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
panic("oh no")
|
||||||
|
})
|
||||||
|
|
||||||
|
n := negroni.New()
|
||||||
|
recovery := negroni.NewRecovery()
|
||||||
|
recovery.PanicHandlerFunc = reportToSentry
|
||||||
|
n.Use(recovery)
|
||||||
|
n.UseHandler(mux)
|
||||||
|
|
||||||
|
http.ListenAndServe(":3003", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reportToSentry(info *negroni.PanicInformation) {
|
||||||
|
// write code here to report error to Sentry
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The middleware simply output the informations on STDOUT by default.
|
||||||
|
You can customize the output process by using the `SetFormatter()` function.
|
||||||
|
|
||||||
|
You can use also the `HTMLPanicFormatter` to display a pretty HTML when a crash occurs.
|
||||||
|
|
||||||
|
<!-- { "interrupt": true } -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/urfave/negroni"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
panic("oh no")
|
||||||
|
})
|
||||||
|
|
||||||
|
n := negroni.New()
|
||||||
|
recovery := negroni.NewRecovery()
|
||||||
|
recovery.Formatter = &negroni.HTMLPanicFormatter{}
|
||||||
|
n.Use(recovery)
|
||||||
|
n.UseHandler(mux)
|
||||||
|
|
||||||
|
http.ListenAndServe(":3003", n)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logger
|
||||||
|
|
||||||
|
This middleware logs each incoming request and response.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
<!-- { "interrupt": true } -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/urfave/negroni"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
fmt.Fprintf(w, "Welcome to the home page!")
|
||||||
|
})
|
||||||
|
|
||||||
|
n := negroni.New()
|
||||||
|
n.Use(negroni.NewLogger())
|
||||||
|
n.UseHandler(mux)
|
||||||
|
|
||||||
|
http.ListenAndServe(":3004", n)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will print a log similar to:
|
||||||
|
|
||||||
|
```
|
||||||
|
[negroni] 2017-10-04T14:56:25+02:00 | 200 | 378µs | localhost:3004 | GET /
|
||||||
|
```
|
||||||
|
|
||||||
|
on each request.
|
||||||
|
|
||||||
|
You can also set your own log format by calling the `SetFormat` function. The format is a template string with fields as mentioned in the `LoggerEntry` struct. So, as an example -
|
||||||
|
|
||||||
|
```go
|
||||||
|
l.SetFormat("[{{.Status}} {{.Duration}}] - {{.Request.UserAgent}}")
|
||||||
|
```
|
||||||
|
|
||||||
|
will show something like - `[200 18.263µs] - Go-User-Agent/1.1 `
|
||||||
|
|
||||||
## Third Party Middleware
|
## Third Party Middleware
|
||||||
|
|
||||||
Here is a current list of Negroni compatible middlware. Feel free to put up a PR linking your middleware if you have built one:
|
Here is a current list of Negroni compatible middlware. Feel free to put up a PR
|
||||||
|
linking your middleware if you have built one:
|
||||||
|
|
||||||
| Middleware | Author | Description |
|
| Middleware | Author | Description |
|
||||||
| -----------|--------|-------------|
|
| -----------|--------|-------------|
|
||||||
| [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints |
|
| [authz](https://github.com/casbin/negroni-authz) | [Yang Luo](https://github.com/hsluoyz) | ACL, RBAC, ABAC Authorization middlware based on [Casbin](https://github.com/casbin/casbin) |
|
||||||
| [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown |
|
|
||||||
| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins |
|
|
||||||
| [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it|
|
|
||||||
| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs |
|
| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs |
|
||||||
| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger |
|
| [cloudwatch](https://github.com/cvillecsteele/negroni-cloudwatch) | [Colin Steele](https://github.com/cvillecsteele) | AWS cloudwatch metrics middleware |
|
||||||
| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates |
|
|
||||||
| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime |
|
|
||||||
| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression |
|
|
||||||
| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware |
|
|
||||||
| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management |
|
|
||||||
| [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions |
|
|
||||||
| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly |
|
|
||||||
| [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support |
|
| [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support |
|
||||||
| [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request |
|
| [csp](https://github.com/awakenetworks/csp) | [Awake Networks](https://github.com/awakenetworks) | [Content Security Policy](https://www.w3.org/TR/CSP2/) (CSP) support |
|
||||||
|
| [delay](https://github.com/jeffbmartinez/delay) | [Jeff Martinez](https://github.com/jeffbmartinez) | Add delays/latency to endpoints. Useful when testing effects of high latency |
|
||||||
|
| [New Relic Go Agent](https://github.com/yadvendar/negroni-newrelic-go-agent) | [Yadvendar Champawat](https://github.com/yadvendar) | Official [New Relic Go Agent](https://github.com/newrelic/go-agent) (currently in beta) |
|
||||||
|
| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime |
|
||||||
|
| [Graceful](https://github.com/tylerb/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown |
|
||||||
|
| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression |
|
||||||
|
| [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it|
|
||||||
|
| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger |
|
||||||
|
| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware |
|
||||||
|
| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly |
|
||||||
|
| [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions |
|
||||||
|
| [prometheus](https://github.com/zbindenren/negroni-prometheus) | [Rene Zbinden](https://github.com/zbindenren) | Easily create metrics endpoint for the [prometheus](http://prometheus.io) instrumentation tool |
|
||||||
|
| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates |
|
||||||
|
| [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints |
|
||||||
|
| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins |
|
||||||
|
| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management |
|
||||||
|
| [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Store information about your web application (response time, etc.) |
|
||||||
| [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware |
|
| [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware |
|
||||||
|
| [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request |
|
||||||
|
| [mgo session](https://github.com/joeljames/nigroni-mgo-session) | [Joel James](https://github.com/joeljames) | Middleware that handles creating and closing mgo sessions per request |
|
||||||
|
| [digits](https://github.com/bamarni/digits) | [Bilal Amarni](https://github.com/bamarni) | Middleware that handles [Twitter Digits](https://get.digits.com/) authentication |
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
[Alexander Rødseth](https://github.com/xyproto) created [mooseware](https://github.com/xyproto/mooseware), a skeleton for writing a Negroni middleware handler.
|
|
||||||
|
[Alexander Rødseth](https://github.com/xyproto) created
|
||||||
|
[mooseware](https://github.com/xyproto/mooseware), a skeleton for writing a
|
||||||
|
Negroni middleware handler.
|
||||||
|
|
||||||
|
[Prasanga Siripala](https://github.com/pjebs) created an effective skeleton structure for web-based Go/Negroni projects: [Go-Skeleton](https://github.com/pjebs/go-skeleton)
|
||||||
|
|
||||||
## Live code reload?
|
## Live code reload?
|
||||||
[gin](https://github.com/codegangsta/gin) and [fresh](https://github.com/pilu/fresh) both live reload negroni apps.
|
|
||||||
|
[gin](https://github.com/codegangsta/gin) and
|
||||||
|
[fresh](https://github.com/pilu/fresh) both live reload negroni apps.
|
||||||
|
|
||||||
## Essential Reading for Beginners of Go & Negroni
|
## Essential Reading for Beginners of Go & Negroni
|
||||||
|
|
||||||
* [Using a Context to pass information from middleware to end handler](http://elithrar.github.io/article/map-string-interface/)
|
* [Using a Context to pass information from middleware to end handler](http://elithrar.github.io/article/map-string-interface/)
|
||||||
* [Understanding middleware](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters)
|
* [Understanding middleware](https://mattstauffer.co/blog/laravel-5.0-middleware-filter-style)
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
Negroni is obsessively designed by none other than the [Code Gangsta](http://codegangsta.io/)
|
Negroni is obsessively designed by none other than the [Code
|
||||||
|
Gangsta](https://codegangsta.io/)
|
||||||
|
|
||||||
|
[Gorilla Mux]: https://github.com/gorilla/mux
|
||||||
|
[`http.FileSystem`]: https://godoc.org/net/http#FileSystem
|
||||||
|
|
4
vendor/github.com/codegangsta/negroni/doc.go
generated
vendored
4
vendor/github.com/codegangsta/negroni/doc.go
generated
vendored
|
@ -2,12 +2,12 @@
|
||||||
//
|
//
|
||||||
// If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit.
|
// If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit.
|
||||||
//
|
//
|
||||||
// For a full guide visit http://github.com/codegangsta/negroni
|
// For a full guide visit http://github.com/urfave/negroni
|
||||||
//
|
//
|
||||||
// package main
|
// package main
|
||||||
//
|
//
|
||||||
// import (
|
// import (
|
||||||
// "github.com/codegangsta/negroni"
|
// "github.com/urfave/negroni"
|
||||||
// "net/http"
|
// "net/http"
|
||||||
// "fmt"
|
// "fmt"
|
||||||
// )
|
// )
|
||||||
|
|
63
vendor/github.com/codegangsta/negroni/logger.go
generated
vendored
63
vendor/github.com/codegangsta/negroni/logger.go
generated
vendored
|
@ -1,29 +1,82 @@
|
||||||
package negroni
|
package negroni
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LoggerEntry is the structure
|
||||||
|
// passed to the template.
|
||||||
|
type LoggerEntry struct {
|
||||||
|
StartTime string
|
||||||
|
Status int
|
||||||
|
Duration time.Duration
|
||||||
|
Hostname string
|
||||||
|
Method string
|
||||||
|
Path string
|
||||||
|
Request *http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoggerDefaultFormat is the format
|
||||||
|
// logged used by the default Logger instance.
|
||||||
|
var LoggerDefaultFormat = "{{.StartTime}} | {{.Status}} | \t {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}} \n"
|
||||||
|
|
||||||
|
// LoggerDefaultDateFormat is the
|
||||||
|
// format used for date by the
|
||||||
|
// default Logger instance.
|
||||||
|
var LoggerDefaultDateFormat = time.RFC3339
|
||||||
|
|
||||||
|
// ALogger interface
|
||||||
|
type ALogger interface {
|
||||||
|
Println(v ...interface{})
|
||||||
|
Printf(format string, v ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
|
// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
// Logger inherits from log.Logger used to log messages with the Logger middleware
|
// ALogger implements just enough log.Logger interface to be compatible with other implementations
|
||||||
*log.Logger
|
ALogger
|
||||||
|
dateFormat string
|
||||||
|
template *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLogger returns a new Logger instance
|
// NewLogger returns a new Logger instance
|
||||||
func NewLogger() *Logger {
|
func NewLogger() *Logger {
|
||||||
return &Logger{log.New(os.Stdout, "[negroni] ", 0)}
|
logger := &Logger{ALogger: log.New(os.Stdout, "[negroni] ", 0), dateFormat: LoggerDefaultDateFormat}
|
||||||
|
logger.SetFormat(LoggerDefaultFormat)
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) SetFormat(format string) {
|
||||||
|
l.template = template.Must(template.New("negroni_parser").Parse(format))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) SetDateFormat(format string) {
|
||||||
|
l.dateFormat = format
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
l.Printf("Started %s %s", r.Method, r.URL.Path)
|
|
||||||
|
|
||||||
next(rw, r)
|
next(rw, r)
|
||||||
|
|
||||||
res := rw.(ResponseWriter)
|
res := rw.(ResponseWriter)
|
||||||
l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start))
|
log := LoggerEntry{
|
||||||
|
StartTime: start.Format(l.dateFormat),
|
||||||
|
Status: res.Status(),
|
||||||
|
Duration: time.Since(start),
|
||||||
|
Hostname: r.Host,
|
||||||
|
Method: r.Method,
|
||||||
|
Path: r.URL.Path,
|
||||||
|
Request: r,
|
||||||
|
}
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
l.template.Execute(buff, log)
|
||||||
|
l.Printf(buff.String())
|
||||||
}
|
}
|
||||||
|
|
33
vendor/github.com/codegangsta/negroni/logger_test.go
generated
vendored
33
vendor/github.com/codegangsta/negroni/logger_test.go
generated
vendored
|
@ -1,33 +0,0 @@
|
||||||
package negroni
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Logger(t *testing.T) {
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
|
|
||||||
l := NewLogger()
|
|
||||||
l.Logger = log.New(buff, "[negroni] ", 0)
|
|
||||||
|
|
||||||
n := New()
|
|
||||||
// replace log for testing
|
|
||||||
n.Use(l)
|
|
||||||
n.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
rw.WriteHeader(http.StatusNotFound)
|
|
||||||
}))
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://localhost:3000/foobar", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n.ServeHTTP(recorder, req)
|
|
||||||
expect(t, recorder.Code, http.StatusNotFound)
|
|
||||||
refute(t, len(buff.String()), 0)
|
|
||||||
}
|
|
60
vendor/github.com/codegangsta/negroni/negroni.go
generated
vendored
60
vendor/github.com/codegangsta/negroni/negroni.go
generated
vendored
|
@ -6,6 +6,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultAddress is used if no other is specified.
|
||||||
|
DefaultAddress = ":8080"
|
||||||
|
)
|
||||||
|
|
||||||
// Handler handler is an interface that objects can implement to be registered to serve as middleware
|
// Handler handler is an interface that objects can implement to be registered to serve as middleware
|
||||||
// in the Negroni middleware stack.
|
// in the Negroni middleware stack.
|
||||||
// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
|
// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
|
||||||
|
@ -43,6 +48,16 @@ func Wrap(handler http.Handler) Handler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WrapFunc converts a http.HandlerFunc into a negroni.Handler so it can be used as a Negroni
|
||||||
|
// middleware. The next http.HandlerFunc is automatically called after the Handler
|
||||||
|
// is executed.
|
||||||
|
func WrapFunc(handlerFunc http.HandlerFunc) Handler {
|
||||||
|
return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
|
handlerFunc(rw, r)
|
||||||
|
next(rw, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
|
// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
|
||||||
// Negroni middleware is evaluated in the order that they are added to the stack using
|
// Negroni middleware is evaluated in the order that they are added to the stack using
|
||||||
// the Use and UseHandler methods.
|
// the Use and UseHandler methods.
|
||||||
|
@ -59,6 +74,14 @@ func New(handlers ...Handler) *Negroni {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// With returns a new Negroni instance that is a combination of the negroni
|
||||||
|
// receiver's handlers and the provided handlers.
|
||||||
|
func (n *Negroni) With(handlers ...Handler) *Negroni {
|
||||||
|
return New(
|
||||||
|
append(n.handlers, handlers...)...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Classic returns a new Negroni instance with the default middleware already
|
// Classic returns a new Negroni instance with the default middleware already
|
||||||
// in the stack.
|
// in the stack.
|
||||||
//
|
//
|
||||||
|
@ -75,25 +98,52 @@ func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
|
// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
|
||||||
func (n *Negroni) Use(handler Handler) {
|
func (n *Negroni) Use(handler Handler) {
|
||||||
|
if handler == nil {
|
||||||
|
panic("handler cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
n.handlers = append(n.handlers, handler)
|
n.handlers = append(n.handlers, handler)
|
||||||
n.middleware = build(n.handlers)
|
n.middleware = build(n.handlers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UseFunc adds a Negroni-style handler function onto the middleware stack.
|
||||||
|
func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
|
||||||
|
n.Use(HandlerFunc(handlerFunc))
|
||||||
|
}
|
||||||
|
|
||||||
// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
|
// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
|
||||||
func (n *Negroni) UseHandler(handler http.Handler) {
|
func (n *Negroni) UseHandler(handler http.Handler) {
|
||||||
n.Use(Wrap(handler))
|
n.Use(Wrap(handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UseHandlerFunc adds a http.HandlerFunc-style handler function onto the middleware stack.
|
||||||
|
func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
|
||||||
|
n.UseHandler(http.HandlerFunc(handlerFunc))
|
||||||
|
}
|
||||||
|
|
||||||
// Run is a convenience function that runs the negroni stack as an HTTP
|
// Run is a convenience function that runs the negroni stack as an HTTP
|
||||||
// server. The addr string takes the same format as http.ListenAndServe.
|
// server. The addr string, if provided, takes the same format as http.ListenAndServe.
|
||||||
func (n *Negroni) Run(addr string) {
|
// If no address is provided but the PORT environment variable is set, the PORT value is used.
|
||||||
|
// If neither is provided, the address' value will equal the DefaultAddress constant.
|
||||||
|
func (n *Negroni) Run(addr ...string) {
|
||||||
l := log.New(os.Stdout, "[negroni] ", 0)
|
l := log.New(os.Stdout, "[negroni] ", 0)
|
||||||
l.Printf("listening on %s", addr)
|
finalAddr := detectAddress(addr...)
|
||||||
l.Fatal(http.ListenAndServe(addr, n))
|
l.Printf("listening on %s", finalAddr)
|
||||||
|
l.Fatal(http.ListenAndServe(finalAddr, n))
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectAddress(addr ...string) string {
|
||||||
|
if len(addr) > 0 {
|
||||||
|
return addr[0]
|
||||||
|
}
|
||||||
|
if port := os.Getenv("PORT"); port != "" {
|
||||||
|
return ":" + port
|
||||||
|
}
|
||||||
|
return DefaultAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a list of all the handlers in the current Negroni middleware chain.
|
// Returns a list of all the handlers in the current Negroni middleware chain.
|
||||||
func (n *Negroni) Handlers() ([]Handler) {
|
func (n *Negroni) Handlers() []Handler {
|
||||||
return n.handlers
|
return n.handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
75
vendor/github.com/codegangsta/negroni/negroni_test.go
generated
vendored
75
vendor/github.com/codegangsta/negroni/negroni_test.go
generated
vendored
|
@ -1,75 +0,0 @@
|
||||||
package negroni
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
/* 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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refute(t *testing.T, a interface{}, b interface{}) {
|
|
||||||
if a == b {
|
|
||||||
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNegroniRun(t *testing.T) {
|
|
||||||
// just test that Run doesn't bomb
|
|
||||||
go New().Run(":3000")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNegroniServeHTTP(t *testing.T) {
|
|
||||||
result := ""
|
|
||||||
response := httptest.NewRecorder()
|
|
||||||
|
|
||||||
n := New()
|
|
||||||
n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
||||||
result += "foo"
|
|
||||||
next(rw, r)
|
|
||||||
result += "ban"
|
|
||||||
}))
|
|
||||||
n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
||||||
result += "bar"
|
|
||||||
next(rw, r)
|
|
||||||
result += "baz"
|
|
||||||
}))
|
|
||||||
n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
||||||
result += "bat"
|
|
||||||
rw.WriteHeader(http.StatusBadRequest)
|
|
||||||
}))
|
|
||||||
|
|
||||||
n.ServeHTTP(response, (*http.Request)(nil))
|
|
||||||
|
|
||||||
expect(t, result, "foobarbatbazban")
|
|
||||||
expect(t, response.Code, http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensures that a Negroni middleware chain
|
|
||||||
// can correctly return all of its handlers.
|
|
||||||
func TestHandlers(t *testing.T) {
|
|
||||||
response := httptest.NewRecorder()
|
|
||||||
n := New()
|
|
||||||
handlers := n.Handlers()
|
|
||||||
expect(t, 0, len(handlers))
|
|
||||||
|
|
||||||
n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
||||||
rw.WriteHeader(http.StatusOK)
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Expects the length of handlers to be exactly 1
|
|
||||||
// after adding exactly one handler to the middleware chain
|
|
||||||
handlers = n.Handlers()
|
|
||||||
expect(t, 1, len(handlers))
|
|
||||||
|
|
||||||
// Ensures that the first handler that is in sequence behaves
|
|
||||||
// exactly the same as the one that was registered earlier
|
|
||||||
handlers[0].ServeHTTP(response, (*http.Request)(nil), nil)
|
|
||||||
expect(t, response.Code, http.StatusOK)
|
|
||||||
}
|
|
164
vendor/github.com/codegangsta/negroni/recovery.go
generated
vendored
164
vendor/github.com/codegangsta/negroni/recovery.go
generated
vendored
|
@ -6,14 +6,137 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"runtime/debug"
|
||||||
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
panicText = "PANIC: %s\n%s"
|
||||||
|
panicHTML = `<html>
|
||||||
|
<head><title>PANIC: {{.RecoveredPanic}}</title></head>
|
||||||
|
<style type="text/css">
|
||||||
|
html, body {
|
||||||
|
font-family: Helvetica, Arial, Sans;
|
||||||
|
color: #333333;
|
||||||
|
background-color: #ffffff;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #f14c4c;
|
||||||
|
padding: 20px;
|
||||||
|
border-bottom: 1px solid #2b3848;
|
||||||
|
}
|
||||||
|
.block {
|
||||||
|
margin: 2em;
|
||||||
|
}
|
||||||
|
.panic-interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
.panic-stack-raw pre {
|
||||||
|
padding: 1em;
|
||||||
|
background: #f6f8fa;
|
||||||
|
border: dashed 1px;
|
||||||
|
}
|
||||||
|
.panic-interface-title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<h1>Negroni - PANIC</h1>
|
||||||
|
|
||||||
|
<div class="panic-interface block">
|
||||||
|
<h3>{{.RequestDescription}}</h3>
|
||||||
|
<span class="panic-interface-title">Runtime error:</span> <span class="panic-interface-element">{{.RecoveredPanic}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ if .Stack }}
|
||||||
|
<div class="panic-stack-raw block">
|
||||||
|
<h3>Runtime Stack</h3>
|
||||||
|
<pre>{{.StackAsString}}</pre>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
nilRequestMessage = "Request is nil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var panicHTMLTemplate = template.Must(template.New("PanicPage").Parse(panicHTML))
|
||||||
|
|
||||||
|
// PanicInformation contains all
|
||||||
|
// elements for printing stack informations.
|
||||||
|
type PanicInformation struct {
|
||||||
|
RecoveredPanic interface{}
|
||||||
|
Stack []byte
|
||||||
|
Request *http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackAsString returns a printable version of the stack
|
||||||
|
func (p *PanicInformation) StackAsString() string {
|
||||||
|
return string(p.Stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestDescription returns a printable description of the url
|
||||||
|
func (p *PanicInformation) RequestDescription() string {
|
||||||
|
|
||||||
|
if p.Request == nil {
|
||||||
|
return nilRequestMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
var queryOutput string
|
||||||
|
if p.Request.URL.RawQuery != "" {
|
||||||
|
queryOutput = "?" + p.Request.URL.RawQuery
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s %s%s", p.Request.Method, p.Request.URL.Path, queryOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PanicFormatter is an interface on object can implement
|
||||||
|
// to be able to output the stack trace
|
||||||
|
type PanicFormatter interface {
|
||||||
|
// FormatPanicError output the stack for a given answer/response.
|
||||||
|
// In case the the middleware should not output the stack trace,
|
||||||
|
// the field `Stack` of the passed `PanicInformation` instance equals `[]byte{}`.
|
||||||
|
FormatPanicError(rw http.ResponseWriter, r *http.Request, infos *PanicInformation)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TextPanicFormatter output the stack
|
||||||
|
// as simple text on os.Stdout. If no `Content-Type` is set,
|
||||||
|
// it will output the data as `text/plain; charset=utf-8`.
|
||||||
|
// Otherwise, the origin `Content-Type` is kept.
|
||||||
|
type TextPanicFormatter struct{}
|
||||||
|
|
||||||
|
func (t *TextPanicFormatter) FormatPanicError(rw http.ResponseWriter, r *http.Request, infos *PanicInformation) {
|
||||||
|
if rw.Header().Get("Content-Type") == "" {
|
||||||
|
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(rw, panicText, infos.RecoveredPanic, infos.Stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTMLPanicFormatter output the stack inside
|
||||||
|
// an HTML page. This has been largely inspired by
|
||||||
|
// https://github.com/go-martini/martini/pull/156/commits.
|
||||||
|
type HTMLPanicFormatter struct{}
|
||||||
|
|
||||||
|
func (t *HTMLPanicFormatter) FormatPanicError(rw http.ResponseWriter, r *http.Request, infos *PanicInformation) {
|
||||||
|
if rw.Header().Get("Content-Type") == "" {
|
||||||
|
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
}
|
||||||
|
panicHTMLTemplate.Execute(rw, infos)
|
||||||
|
}
|
||||||
|
|
||||||
// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one.
|
// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one.
|
||||||
type Recovery struct {
|
type Recovery struct {
|
||||||
Logger *log.Logger
|
Logger ALogger
|
||||||
PrintStack bool
|
PrintStack bool
|
||||||
StackAll bool
|
PanicHandlerFunc func(*PanicInformation)
|
||||||
StackSize int
|
StackAll bool
|
||||||
|
StackSize int
|
||||||
|
Formatter PanicFormatter
|
||||||
|
|
||||||
|
// Deprecated: Use PanicHandlerFunc instead to receive panic
|
||||||
|
// error with additional information (see PanicInformation)
|
||||||
|
ErrorHandlerFunc func(interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRecovery returns a new instance of Recovery
|
// NewRecovery returns a new instance of Recovery
|
||||||
|
@ -23,6 +146,7 @@ func NewRecovery() *Recovery {
|
||||||
PrintStack: true,
|
PrintStack: true,
|
||||||
StackAll: false,
|
StackAll: false,
|
||||||
StackSize: 1024 * 8,
|
StackSize: 1024 * 8,
|
||||||
|
Formatter: &TextPanicFormatter{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,14 +154,38 @@ func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next htt
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
rw.WriteHeader(http.StatusInternalServerError)
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
|
|
||||||
stack := make([]byte, rec.StackSize)
|
stack := make([]byte, rec.StackSize)
|
||||||
stack = stack[:runtime.Stack(stack, rec.StackAll)]
|
stack = stack[:runtime.Stack(stack, rec.StackAll)]
|
||||||
|
infos := &PanicInformation{RecoveredPanic: err, Request: r}
|
||||||
f := "PANIC: %s\n%s"
|
|
||||||
rec.Logger.Printf(f, err, stack)
|
|
||||||
|
|
||||||
if rec.PrintStack {
|
if rec.PrintStack {
|
||||||
fmt.Fprintf(rw, f, err, stack)
|
infos.Stack = stack
|
||||||
|
}
|
||||||
|
rec.Logger.Printf(panicText, err, stack)
|
||||||
|
rec.Formatter.FormatPanicError(rw, r, infos)
|
||||||
|
|
||||||
|
if rec.ErrorHandlerFunc != nil {
|
||||||
|
func() {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
rec.Logger.Printf("provided ErrorHandlerFunc panic'd: %s, trace:\n%s", err, debug.Stack())
|
||||||
|
rec.Logger.Printf("%s\n", debug.Stack())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
rec.ErrorHandlerFunc(err)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if rec.PanicHandlerFunc != nil {
|
||||||
|
func() {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
rec.Logger.Printf("provided PanicHandlerFunc panic'd: %s, trace:\n%s", err, debug.Stack())
|
||||||
|
rec.Logger.Printf("%s\n", debug.Stack())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
rec.PanicHandlerFunc(infos)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
28
vendor/github.com/codegangsta/negroni/recovery_test.go
generated
vendored
28
vendor/github.com/codegangsta/negroni/recovery_test.go
generated
vendored
|
@ -1,28 +0,0 @@
|
||||||
package negroni
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRecovery(t *testing.T) {
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
|
|
||||||
rec := NewRecovery()
|
|
||||||
rec.Logger = log.New(buff, "[negroni] ", 0)
|
|
||||||
|
|
||||||
n := New()
|
|
||||||
// replace log for testing
|
|
||||||
n.Use(rec)
|
|
||||||
n.UseHandler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
|
||||||
panic("here is a panic!")
|
|
||||||
}))
|
|
||||||
n.ServeHTTP(recorder, (*http.Request)(nil))
|
|
||||||
expect(t, recorder.Code, http.StatusInternalServerError)
|
|
||||||
refute(t, recorder.Body.Len(), 0)
|
|
||||||
refute(t, len(buff.String()), 0)
|
|
||||||
}
|
|
29
vendor/github.com/codegangsta/negroni/response_writer.go
generated
vendored
29
vendor/github.com/codegangsta/negroni/response_writer.go
generated
vendored
|
@ -13,7 +13,8 @@ import (
|
||||||
type ResponseWriter interface {
|
type ResponseWriter interface {
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
http.Flusher
|
http.Flusher
|
||||||
// Status returns the status code of the response or 0 if the response has not been written.
|
// Status returns the status code of the response or 0 if the response has
|
||||||
|
// not been written
|
||||||
Status() int
|
Status() int
|
||||||
// Written returns whether or not the ResponseWriter has been written.
|
// Written returns whether or not the ResponseWriter has been written.
|
||||||
Written() bool
|
Written() bool
|
||||||
|
@ -28,7 +29,15 @@ type beforeFunc func(ResponseWriter)
|
||||||
|
|
||||||
// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
|
// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
|
||||||
func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
|
func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
|
||||||
return &responseWriter{rw, 0, 0, nil}
|
nrw := &responseWriter{
|
||||||
|
ResponseWriter: rw,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := rw.(http.CloseNotifier); ok {
|
||||||
|
return &responseWriterCloseNotifer{nrw}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nrw
|
||||||
}
|
}
|
||||||
|
|
||||||
type responseWriter struct {
|
type responseWriter struct {
|
||||||
|
@ -78,10 +87,6 @@ func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
return hijacker.Hijack()
|
return hijacker.Hijack()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *responseWriter) CloseNotify() <-chan bool {
|
|
||||||
return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rw *responseWriter) callBefore() {
|
func (rw *responseWriter) callBefore() {
|
||||||
for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
|
for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
|
||||||
rw.beforeFuncs[i](rw)
|
rw.beforeFuncs[i](rw)
|
||||||
|
@ -91,6 +96,18 @@ func (rw *responseWriter) callBefore() {
|
||||||
func (rw *responseWriter) Flush() {
|
func (rw *responseWriter) Flush() {
|
||||||
flusher, ok := rw.ResponseWriter.(http.Flusher)
|
flusher, ok := rw.ResponseWriter.(http.Flusher)
|
||||||
if ok {
|
if ok {
|
||||||
|
if !rw.Written() {
|
||||||
|
// The status will be StatusOK if WriteHeader has not been called yet
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type responseWriterCloseNotifer struct {
|
||||||
|
*responseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriterCloseNotifer) CloseNotify() <-chan bool {
|
||||||
|
return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||||
|
}
|
||||||
|
|
16
vendor/github.com/codegangsta/negroni/response_writer_pusher.go
generated
vendored
Normal file
16
vendor/github.com/codegangsta/negroni/response_writer_pusher.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
//+build go1.8
|
||||||
|
|
||||||
|
package negroni
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (rw *responseWriter) Push(target string, opts *http.PushOptions) error {
|
||||||
|
pusher, ok := rw.ResponseWriter.(http.Pusher)
|
||||||
|
if ok {
|
||||||
|
return pusher.Push(target, opts)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("the ResponseWriter doesn't support the Pusher interface")
|
||||||
|
}
|
150
vendor/github.com/codegangsta/negroni/response_writer_test.go
generated
vendored
150
vendor/github.com/codegangsta/negroni/response_writer_test.go
generated
vendored
|
@ -1,150 +0,0 @@
|
||||||
package negroni
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type closeNotifyingRecorder struct {
|
|
||||||
*httptest.ResponseRecorder
|
|
||||||
closed chan bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCloseNotifyingRecorder() *closeNotifyingRecorder {
|
|
||||||
return &closeNotifyingRecorder{
|
|
||||||
httptest.NewRecorder(),
|
|
||||||
make(chan bool, 1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *closeNotifyingRecorder) close() {
|
|
||||||
c.closed <- true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
|
|
||||||
return c.closed
|
|
||||||
}
|
|
||||||
|
|
||||||
type hijackableResponse struct {
|
|
||||||
Hijacked bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newHijackableResponse() *hijackableResponse {
|
|
||||||
return &hijackableResponse{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *hijackableResponse) Header() http.Header { return nil }
|
|
||||||
func (h *hijackableResponse) Write(buf []byte) (int, error) { return 0, nil }
|
|
||||||
func (h *hijackableResponse) WriteHeader(code int) {}
|
|
||||||
func (h *hijackableResponse) Flush() {}
|
|
||||||
func (h *hijackableResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
||||||
h.Hijacked = true
|
|
||||||
return nil, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResponseWriterWritingString(t *testing.T) {
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
rw := NewResponseWriter(rec)
|
|
||||||
|
|
||||||
rw.Write([]byte("Hello world"))
|
|
||||||
|
|
||||||
expect(t, rec.Code, rw.Status())
|
|
||||||
expect(t, rec.Body.String(), "Hello world")
|
|
||||||
expect(t, rw.Status(), http.StatusOK)
|
|
||||||
expect(t, rw.Size(), 11)
|
|
||||||
expect(t, rw.Written(), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResponseWriterWritingStrings(t *testing.T) {
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
rw := NewResponseWriter(rec)
|
|
||||||
|
|
||||||
rw.Write([]byte("Hello world"))
|
|
||||||
rw.Write([]byte("foo bar bat baz"))
|
|
||||||
|
|
||||||
expect(t, rec.Code, rw.Status())
|
|
||||||
expect(t, rec.Body.String(), "Hello worldfoo bar bat baz")
|
|
||||||
expect(t, rw.Status(), http.StatusOK)
|
|
||||||
expect(t, rw.Size(), 26)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResponseWriterWritingHeader(t *testing.T) {
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
rw := NewResponseWriter(rec)
|
|
||||||
|
|
||||||
rw.WriteHeader(http.StatusNotFound)
|
|
||||||
|
|
||||||
expect(t, rec.Code, rw.Status())
|
|
||||||
expect(t, rec.Body.String(), "")
|
|
||||||
expect(t, rw.Status(), http.StatusNotFound)
|
|
||||||
expect(t, rw.Size(), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResponseWriterBefore(t *testing.T) {
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
rw := NewResponseWriter(rec)
|
|
||||||
result := ""
|
|
||||||
|
|
||||||
rw.Before(func(ResponseWriter) {
|
|
||||||
result += "foo"
|
|
||||||
})
|
|
||||||
rw.Before(func(ResponseWriter) {
|
|
||||||
result += "bar"
|
|
||||||
})
|
|
||||||
|
|
||||||
rw.WriteHeader(http.StatusNotFound)
|
|
||||||
|
|
||||||
expect(t, rec.Code, rw.Status())
|
|
||||||
expect(t, rec.Body.String(), "")
|
|
||||||
expect(t, rw.Status(), http.StatusNotFound)
|
|
||||||
expect(t, rw.Size(), 0)
|
|
||||||
expect(t, result, "barfoo")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResponseWriterHijack(t *testing.T) {
|
|
||||||
hijackable := newHijackableResponse()
|
|
||||||
rw := NewResponseWriter(hijackable)
|
|
||||||
hijacker, ok := rw.(http.Hijacker)
|
|
||||||
expect(t, ok, true)
|
|
||||||
_, _, err := hijacker.Hijack()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
expect(t, hijackable.Hijacked, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResponseWriteHijackNotOK(t *testing.T) {
|
|
||||||
hijackable := new(http.ResponseWriter)
|
|
||||||
rw := NewResponseWriter(*hijackable)
|
|
||||||
hijacker, ok := rw.(http.Hijacker)
|
|
||||||
expect(t, ok, true)
|
|
||||||
_, _, err := hijacker.Hijack()
|
|
||||||
|
|
||||||
refute(t, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResponseWriterCloseNotify(t *testing.T) {
|
|
||||||
rec := newCloseNotifyingRecorder()
|
|
||||||
rw := NewResponseWriter(rec)
|
|
||||||
closed := false
|
|
||||||
notifier := rw.(http.CloseNotifier).CloseNotify()
|
|
||||||
rec.close()
|
|
||||||
select {
|
|
||||||
case <-notifier:
|
|
||||||
closed = true
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
}
|
|
||||||
expect(t, closed, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResponseWriterFlusher(t *testing.T) {
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
rw := NewResponseWriter(rec)
|
|
||||||
|
|
||||||
_, ok := rw.(http.Flusher)
|
|
||||||
expect(t, ok, true)
|
|
||||||
}
|
|
6
vendor/github.com/codegangsta/negroni/static.go
generated
vendored
6
vendor/github.com/codegangsta/negroni/static.go
generated
vendored
|
@ -6,7 +6,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Static is a middleware handler that serves static files in the given directory/filesystem.
|
// Static is a middleware handler that serves static files in the given
|
||||||
|
// directory/filesystem. If the file does not exist on the filesystem, it
|
||||||
|
// passes along to the next middleware in the chain. If you desire "fileserver"
|
||||||
|
// type behavior where it returns a 404 for unfound files, you should consider
|
||||||
|
// using http.FileServer from the Go stdlib.
|
||||||
type Static struct {
|
type Static struct {
|
||||||
// Dir is the directory to serve static files from
|
// Dir is the directory to serve static files from
|
||||||
Dir http.FileSystem
|
Dir http.FileSystem
|
||||||
|
|
113
vendor/github.com/codegangsta/negroni/static_test.go
generated
vendored
113
vendor/github.com/codegangsta/negroni/static_test.go
generated
vendored
|
@ -1,113 +0,0 @@
|
||||||
package negroni
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStatic(t *testing.T) {
|
|
||||||
response := httptest.NewRecorder()
|
|
||||||
response.Body = new(bytes.Buffer)
|
|
||||||
|
|
||||||
n := New()
|
|
||||||
n.Use(NewStatic(http.Dir(".")))
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
n.ServeHTTP(response, req)
|
|
||||||
expect(t, response.Code, http.StatusOK)
|
|
||||||
expect(t, response.Header().Get("Expires"), "")
|
|
||||||
if response.Body.Len() == 0 {
|
|
||||||
t.Errorf("Got empty body for GET request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStaticHead(t *testing.T) {
|
|
||||||
response := httptest.NewRecorder()
|
|
||||||
response.Body = new(bytes.Buffer)
|
|
||||||
|
|
||||||
n := New()
|
|
||||||
n.Use(NewStatic(http.Dir(".")))
|
|
||||||
n.UseHandler(http.NotFoundHandler())
|
|
||||||
|
|
||||||
req, err := http.NewRequest("HEAD", "http://localhost:3000/negroni.go", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n.ServeHTTP(response, req)
|
|
||||||
expect(t, response.Code, http.StatusOK)
|
|
||||||
if response.Body.Len() != 0 {
|
|
||||||
t.Errorf("Got non-empty body for HEAD request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStaticAsPost(t *testing.T) {
|
|
||||||
response := httptest.NewRecorder()
|
|
||||||
|
|
||||||
n := New()
|
|
||||||
n.Use(NewStatic(http.Dir(".")))
|
|
||||||
n.UseHandler(http.NotFoundHandler())
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", "http://localhost:3000/negroni.go", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n.ServeHTTP(response, req)
|
|
||||||
expect(t, response.Code, http.StatusNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStaticBadDir(t *testing.T) {
|
|
||||||
response := httptest.NewRecorder()
|
|
||||||
|
|
||||||
n := Classic()
|
|
||||||
n.UseHandler(http.NotFoundHandler())
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n.ServeHTTP(response, req)
|
|
||||||
refute(t, response.Code, http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStaticOptionsServeIndex(t *testing.T) {
|
|
||||||
response := httptest.NewRecorder()
|
|
||||||
|
|
||||||
n := New()
|
|
||||||
s := NewStatic(http.Dir("."))
|
|
||||||
s.IndexFile = "negroni.go"
|
|
||||||
n.Use(s)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://localhost:3000/", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n.ServeHTTP(response, req)
|
|
||||||
expect(t, response.Code, http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStaticOptionsPrefix(t *testing.T) {
|
|
||||||
response := httptest.NewRecorder()
|
|
||||||
|
|
||||||
n := New()
|
|
||||||
s := NewStatic(http.Dir("."))
|
|
||||||
s.Prefix = "/public"
|
|
||||||
n.Use(s)
|
|
||||||
|
|
||||||
// Check file content behaviour
|
|
||||||
req, err := http.NewRequest("GET", "http://localhost:3000/public/negroni.go", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n.ServeHTTP(response, req)
|
|
||||||
expect(t, response.Code, http.StatusOK)
|
|
||||||
}
|
|
10
vendor/github.com/dgrijalva/jwt-go/.travis.yml
generated
vendored
10
vendor/github.com/dgrijalva/jwt-go/.travis.yml
generated
vendored
|
@ -1,7 +1,13 @@
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go vet ./...
|
||||||
|
- go test -v ./...
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.3.3
|
- 1.3
|
||||||
- 1.4.2
|
- 1.4
|
||||||
- 1.5
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- 1.7
|
||||||
- tip
|
- tip
|
||||||
|
|
6
vendor/github.com/dgrijalva/jwt-go/README.md
generated
vendored
6
vendor/github.com/dgrijalva/jwt-go/README.md
generated
vendored
|
@ -4,7 +4,7 @@ A [go](http://www.golang.org) (or 'golang' for search engine friendliness) imple
|
||||||
|
|
||||||
**BREAKING CHANGES:*** Version 3.0.0 is here. It includes _a lot_ of changes including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code.
|
**BREAKING CHANGES:*** Version 3.0.0 is here. It includes _a lot_ of changes including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code.
|
||||||
|
|
||||||
**NOTICE:** A vulnerability in JWT was [recently published](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). As this library doesn't force users to validate the `alg` is what they expected, it's possible your usage is effected. There will be an update soon to remedy this, and it will likey require backwards-incompatible changes to the API. In the short term, please make sure your implementation verifies the `alg` is what you expect.
|
**NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided.
|
||||||
|
|
||||||
|
|
||||||
## What the heck is a JWT?
|
## What the heck is a JWT?
|
||||||
|
@ -74,7 +74,7 @@ It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is
|
||||||
|
|
||||||
Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
|
Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
|
||||||
|
|
||||||
* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth.
|
* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth.
|
||||||
* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
|
* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
|
||||||
* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
|
* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
|
||||||
|
|
||||||
|
@ -82,4 +82,4 @@ Without going too far down the rabbit hole, here's a description of the interact
|
||||||
|
|
||||||
Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
|
Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
|
||||||
|
|
||||||
The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in to documentation.
|
The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation.
|
||||||
|
|
6
vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
generated
vendored
6
vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
generated
vendored
|
@ -1,5 +1,11 @@
|
||||||
## `jwt-go` Version History
|
## `jwt-go` Version History
|
||||||
|
|
||||||
|
#### 3.1.0
|
||||||
|
|
||||||
|
* Improvements to `jwt` command line tool
|
||||||
|
* Added `SkipClaimsValidation` option to `Parser`
|
||||||
|
* Documentation updates
|
||||||
|
|
||||||
#### 3.0.0
|
#### 3.0.0
|
||||||
|
|
||||||
* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
|
* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
|
||||||
|
|
13
vendor/github.com/dgrijalva/jwt-go/cmd/jwt/README.md
generated
vendored
13
vendor/github.com/dgrijalva/jwt-go/cmd/jwt/README.md
generated
vendored
|
@ -1,13 +0,0 @@
|
||||||
`jwt` command-line tool
|
|
||||||
=======================
|
|
||||||
|
|
||||||
This is a simple tool to sign, verify and show JSON Web Tokens from
|
|
||||||
the command line.
|
|
||||||
|
|
||||||
The following will create and sign a token, then verify it and output the original claims:
|
|
||||||
|
|
||||||
echo {\"foo\":\"bar\"} | ./jwt -key ../../test/sample_key -alg RS256 -sign - | ./jwt -key ../../test/sample_key.pub -alg RS256 -verify -
|
|
||||||
|
|
||||||
To simply display a token, use:
|
|
||||||
|
|
||||||
echo $JWT | ./jwt -show -
|
|
282
vendor/github.com/dgrijalva/jwt-go/cmd/jwt/app.go
generated
vendored
282
vendor/github.com/dgrijalva/jwt-go/cmd/jwt/app.go
generated
vendored
|
@ -1,282 +0,0 @@
|
||||||
// A useful example app. You can use this to debug your tokens on the command line.
|
|
||||||
// This is also a great place to look at how you might use this library.
|
|
||||||
//
|
|
||||||
// Example usage:
|
|
||||||
// The following will create and sign a token, then verify it and output the original claims.
|
|
||||||
// echo {\"foo\":\"bar\"} | bin/jwt -key test/sample_key -alg RS256 -sign - | bin/jwt -key test/sample_key.pub -verify -
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
jwt "github.com/dgrijalva/jwt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Options
|
|
||||||
flagAlg = flag.String("alg", "", "signing algorithm identifier")
|
|
||||||
flagKey = flag.String("key", "", "path to key file or '-' to read from stdin")
|
|
||||||
flagCompact = flag.Bool("compact", false, "output compact JSON")
|
|
||||||
flagDebug = flag.Bool("debug", false, "print out all kinds of debug data")
|
|
||||||
flagClaims = make(ArgList)
|
|
||||||
flagHead = make(ArgList)
|
|
||||||
|
|
||||||
// Modes - exactly one of these is required
|
|
||||||
flagSign = flag.String("sign", "", "path to claims object to sign, '-' to read from stdin, or '+' to use only -claim args")
|
|
||||||
flagVerify = flag.String("verify", "", "path to JWT token to verify or '-' to read from stdin")
|
|
||||||
flagShow = flag.String("show", "", "path to JWT file or '-' to read from stdin")
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Plug in Var flags
|
|
||||||
flag.Var(flagClaims, "claim", "add additional claims. may be used more than once")
|
|
||||||
flag.Var(flagHead, "header", "add additional header params. may be used more than once")
|
|
||||||
|
|
||||||
// Usage message if you ask for -help or if you mess up inputs.
|
|
||||||
flag.Usage = func() {
|
|
||||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
|
||||||
fmt.Fprintf(os.Stderr, " One of the following flags is required: sign, verify\n")
|
|
||||||
flag.PrintDefaults()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse command line options
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
// Do the thing. If something goes wrong, print error to stderr
|
|
||||||
// and exit with a non-zero status code
|
|
||||||
if err := start(); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out which thing to do and then do that
|
|
||||||
func start() error {
|
|
||||||
if *flagSign != "" {
|
|
||||||
return signToken()
|
|
||||||
} else if *flagVerify != "" {
|
|
||||||
return verifyToken()
|
|
||||||
} else if *flagShow != "" {
|
|
||||||
return showToken()
|
|
||||||
} else {
|
|
||||||
flag.Usage()
|
|
||||||
return fmt.Errorf("None of the required flags are present. What do you want me to do?")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper func: Read input from specified file or stdin
|
|
||||||
func loadData(p string) ([]byte, error) {
|
|
||||||
if p == "" {
|
|
||||||
return nil, fmt.Errorf("No path specified")
|
|
||||||
}
|
|
||||||
|
|
||||||
var rdr io.Reader
|
|
||||||
if p == "-" {
|
|
||||||
rdr = os.Stdin
|
|
||||||
} else if p == "+" {
|
|
||||||
return []byte("{}"), nil
|
|
||||||
} else {
|
|
||||||
if f, err := os.Open(p); err == nil {
|
|
||||||
rdr = f
|
|
||||||
defer f.Close()
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ioutil.ReadAll(rdr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print a json object in accordance with the prophecy (or the command line options)
|
|
||||||
func printJSON(j interface{}) error {
|
|
||||||
var out []byte
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if *flagCompact == false {
|
|
||||||
out, err = json.MarshalIndent(j, "", " ")
|
|
||||||
} else {
|
|
||||||
out, err = json.Marshal(j)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
fmt.Println(string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify a token and output the claims. This is a great example
|
|
||||||
// of how to verify and view a token.
|
|
||||||
func verifyToken() error {
|
|
||||||
// get the token
|
|
||||||
tokData, err := loadData(*flagVerify)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Couldn't read token: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim possible whitespace from token
|
|
||||||
tokData = regexp.MustCompile(`\s*$`).ReplaceAll(tokData, []byte{})
|
|
||||||
if *flagDebug {
|
|
||||||
fmt.Fprintf(os.Stderr, "Token len: %v bytes\n", len(tokData))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the token. Load the key from command line option
|
|
||||||
token, err := jwt.Parse(string(tokData), func(t *jwt.Token) (interface{}, error) {
|
|
||||||
data, err := loadData(*flagKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if isEs() {
|
|
||||||
return jwt.ParseECPublicKeyFromPEM(data)
|
|
||||||
} else if isRs() {
|
|
||||||
return jwt.ParseRSAPublicKeyFromPEM(data)
|
|
||||||
}
|
|
||||||
return data, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// Print some debug data
|
|
||||||
if *flagDebug && token != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Header:\n%v\n", token.Header)
|
|
||||||
fmt.Fprintf(os.Stderr, "Claims:\n%v\n", token.Claims)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print an error if we can't parse for some reason
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Couldn't parse token: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is token invalid?
|
|
||||||
if !token.Valid {
|
|
||||||
return fmt.Errorf("Token is invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the token details
|
|
||||||
if err := printJSON(token.Claims); err != nil {
|
|
||||||
return fmt.Errorf("Failed to output claims: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create, sign, and output a token. This is a great, simple example of
|
|
||||||
// how to use this library to create and sign a token.
|
|
||||||
func signToken() error {
|
|
||||||
// get the token data from command line arguments
|
|
||||||
tokData, err := loadData(*flagSign)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Couldn't read token: %v", err)
|
|
||||||
} else if *flagDebug {
|
|
||||||
fmt.Fprintf(os.Stderr, "Token: %v bytes", len(tokData))
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the JSON of the claims
|
|
||||||
var claims jwt.MapClaims
|
|
||||||
if err := json.Unmarshal(tokData, &claims); err != nil {
|
|
||||||
return fmt.Errorf("Couldn't parse claims JSON: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add command line claims
|
|
||||||
if len(flagClaims) > 0 {
|
|
||||||
for k, v := range flagClaims {
|
|
||||||
claims[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the key
|
|
||||||
var key interface{}
|
|
||||||
key, err = loadData(*flagKey)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Couldn't read key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the signing alg
|
|
||||||
alg := jwt.GetSigningMethod(*flagAlg)
|
|
||||||
if alg == nil {
|
|
||||||
return fmt.Errorf("Couldn't find signing method: %v", *flagAlg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a new token
|
|
||||||
token := jwt.NewWithClaims(alg, claims)
|
|
||||||
|
|
||||||
// add command line headers
|
|
||||||
if len(flagHead) > 0 {
|
|
||||||
for k, v := range flagHead {
|
|
||||||
token.Header[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if isEs() {
|
|
||||||
if k, ok := key.([]byte); !ok {
|
|
||||||
return fmt.Errorf("Couldn't convert key data to key")
|
|
||||||
} else {
|
|
||||||
key, err = jwt.ParseECPrivateKeyFromPEM(k)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if isRs() {
|
|
||||||
if k, ok := key.([]byte); !ok {
|
|
||||||
return fmt.Errorf("Couldn't convert key data to key")
|
|
||||||
} else {
|
|
||||||
key, err = jwt.ParseRSAPrivateKeyFromPEM(k)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if out, err := token.SignedString(key); err == nil {
|
|
||||||
fmt.Println(out)
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("Error signing token: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// showToken pretty-prints the token on the command line.
|
|
||||||
func showToken() error {
|
|
||||||
// get the token
|
|
||||||
tokData, err := loadData(*flagShow)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Couldn't read token: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim possible whitespace from token
|
|
||||||
tokData = regexp.MustCompile(`\s*$`).ReplaceAll(tokData, []byte{})
|
|
||||||
if *flagDebug {
|
|
||||||
fmt.Fprintf(os.Stderr, "Token len: %v bytes\n", len(tokData))
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := jwt.Parse(string(tokData), nil)
|
|
||||||
if token == nil {
|
|
||||||
return fmt.Errorf("malformed token: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the token details
|
|
||||||
fmt.Println("Header:")
|
|
||||||
if err := printJSON(token.Header); err != nil {
|
|
||||||
return fmt.Errorf("Failed to output header: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Claims:")
|
|
||||||
if err := printJSON(token.Claims); err != nil {
|
|
||||||
return fmt.Errorf("Failed to output claims: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isEs() bool {
|
|
||||||
return strings.HasPrefix(*flagAlg, "ES")
|
|
||||||
}
|
|
||||||
|
|
||||||
func isRs() bool {
|
|
||||||
return strings.HasPrefix(*flagAlg, "RS")
|
|
||||||
}
|
|
23
vendor/github.com/dgrijalva/jwt-go/cmd/jwt/args.go
generated
vendored
23
vendor/github.com/dgrijalva/jwt-go/cmd/jwt/args.go
generated
vendored
|
@ -1,23 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ArgList map[string]string
|
|
||||||
|
|
||||||
func (l ArgList) String() string {
|
|
||||||
data, _ := json.Marshal(l)
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l ArgList) Set(arg string) error {
|
|
||||||
parts := strings.SplitN(arg, "=", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return fmt.Errorf("Invalid argument '%v'. Must use format 'key=value'. %v", arg, parts)
|
|
||||||
}
|
|
||||||
l[parts[0]] = parts[1]
|
|
||||||
return nil
|
|
||||||
}
|
|
100
vendor/github.com/dgrijalva/jwt-go/ecdsa_test.go
generated
vendored
100
vendor/github.com/dgrijalva/jwt-go/ecdsa_test.go
generated
vendored
|
@ -1,100 +0,0 @@
|
||||||
package jwt_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ecdsaTestData = []struct {
|
|
||||||
name string
|
|
||||||
keys map[string]string
|
|
||||||
tokenString string
|
|
||||||
alg string
|
|
||||||
claims map[string]interface{}
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"Basic ES256",
|
|
||||||
map[string]string{"private": "test/ec256-private.pem", "public": "test/ec256-public.pem"},
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJmb28iOiJiYXIifQ.feG39E-bn8HXAKhzDZq7yEAPWYDhZlwTn3sePJnU9VrGMmwdXAIEyoOnrjreYlVM_Z4N13eK9-TmMTWyfKJtHQ",
|
|
||||||
"ES256",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Basic ES384",
|
|
||||||
map[string]string{"private": "test/ec384-private.pem", "public": "test/ec384-public.pem"},
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJmb28iOiJiYXIifQ.ngAfKMbJUh0WWubSIYe5GMsA-aHNKwFbJk_wq3lq23aPp8H2anb1rRILIzVR0gUf4a8WzDtrzmiikuPWyCS6CN4-PwdgTk-5nehC7JXqlaBZU05p3toM3nWCwm_LXcld",
|
|
||||||
"ES384",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Basic ES512",
|
|
||||||
map[string]string{"private": "test/ec512-private.pem", "public": "test/ec512-public.pem"},
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJmb28iOiJiYXIifQ.AAU0TvGQOcdg2OvrwY73NHKgfk26UDekh9Prz-L_iWuTBIBqOFCWwwLsRiHB1JOddfKAls5do1W0jR_F30JpVd-6AJeTjGKA4C1A1H6gIKwRY0o_tFDIydZCl_lMBMeG5VNFAjO86-WCSKwc3hqaGkq1MugPRq_qrF9AVbuEB4JPLyL5",
|
|
||||||
"ES512",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"basic ES256 invalid: foo => bar",
|
|
||||||
map[string]string{"private": "test/ec256-private.pem", "public": "test/ec256-public.pem"},
|
|
||||||
"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.MEQCIHoSJnmGlPaVQDqacx_2XlXEhhqtWceVopjomc2PJLtdAiAUTeGPoNYxZw0z8mgOnnIcjoxRuNDVZvybRZF3wR1l8W",
|
|
||||||
"ES256",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestECDSAVerify(t *testing.T) {
|
|
||||||
for _, data := range ecdsaTestData {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
key, _ := ioutil.ReadFile(data.keys["public"])
|
|
||||||
|
|
||||||
var ecdsaKey *ecdsa.PublicKey
|
|
||||||
if ecdsaKey, err = jwt.ParseECPublicKeyFromPEM(key); err != nil {
|
|
||||||
t.Errorf("Unable to parse ECDSA public key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
err = method.Verify(strings.Join(parts[0:2], "."), parts[2], ecdsaKey)
|
|
||||||
if data.valid && err != nil {
|
|
||||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if !data.valid && err == nil {
|
|
||||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestECDSASign(t *testing.T) {
|
|
||||||
for _, data := range ecdsaTestData {
|
|
||||||
var err error
|
|
||||||
key, _ := ioutil.ReadFile(data.keys["private"])
|
|
||||||
|
|
||||||
var ecdsaKey *ecdsa.PrivateKey
|
|
||||||
if ecdsaKey, err = jwt.ParseECPrivateKeyFromPEM(key); err != nil {
|
|
||||||
t.Errorf("Unable to parse ECDSA private key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.valid {
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), ecdsaKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if sig == parts[2] {
|
|
||||||
t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], sig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
114
vendor/github.com/dgrijalva/jwt-go/example_test.go
generated
vendored
114
vendor/github.com/dgrijalva/jwt-go/example_test.go
generated
vendored
|
@ -1,114 +0,0 @@
|
||||||
package jwt_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Example (atypical) using the StandardClaims type by itself to parse a token.
|
|
||||||
// The StandardClaims type is designed to be embedded into your custom types
|
|
||||||
// to provide standard validation features. You can use it alone, but there's
|
|
||||||
// no way to retrieve other fields after parsing.
|
|
||||||
// See the CustomClaimsType example for intended usage.
|
|
||||||
func ExampleNewWithClaims_standardClaims() {
|
|
||||||
mySigningKey := []byte("AllYourBase")
|
|
||||||
|
|
||||||
// Create the Claims
|
|
||||||
claims := &jwt.StandardClaims{
|
|
||||||
ExpiresAt: 15000,
|
|
||||||
Issuer: "test",
|
|
||||||
}
|
|
||||||
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
||||||
ss, err := token.SignedString(mySigningKey)
|
|
||||||
fmt.Printf("%v %v", ss, err)
|
|
||||||
//Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.QsODzZu3lUZMVdhbO76u3Jv02iYCvEHcYVUI1kOWEU0 <nil>
|
|
||||||
}
|
|
||||||
|
|
||||||
// Example creating a token using a custom claims type. The StandardClaim is embedded
|
|
||||||
// in the custom type to allow for easy encoding, parsing and validation of standard claims.
|
|
||||||
func ExampleNewWithClaims_customClaimsType() {
|
|
||||||
mySigningKey := []byte("AllYourBase")
|
|
||||||
|
|
||||||
type MyCustomClaims struct {
|
|
||||||
Foo string `json:"foo"`
|
|
||||||
jwt.StandardClaims
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the Claims
|
|
||||||
claims := MyCustomClaims{
|
|
||||||
"bar",
|
|
||||||
jwt.StandardClaims{
|
|
||||||
ExpiresAt: 15000,
|
|
||||||
Issuer: "test",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
||||||
ss, err := token.SignedString(mySigningKey)
|
|
||||||
fmt.Printf("%v %v", ss, err)
|
|
||||||
//Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c <nil>
|
|
||||||
}
|
|
||||||
|
|
||||||
// Example creating a token using a custom claims type. The StandardClaim is embedded
|
|
||||||
// in the custom type to allow for easy encoding, parsing and validation of standard claims.
|
|
||||||
func ExampleParseWithClaims_customClaimsType() {
|
|
||||||
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
|
|
||||||
|
|
||||||
type MyCustomClaims struct {
|
|
||||||
Foo string `json:"foo"`
|
|
||||||
jwt.StandardClaims
|
|
||||||
}
|
|
||||||
|
|
||||||
// sample token is expired. override time so it parses as valid
|
|
||||||
at(time.Unix(0, 0), func() {
|
|
||||||
token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
return []byte("AllYourBase"), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
|
|
||||||
fmt.Printf("%v %v", claims.Foo, claims.StandardClaims.ExpiresAt)
|
|
||||||
} else {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Output: bar 15000
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override time value for tests. Restore default value after.
|
|
||||||
func at(t time.Time, f func()) {
|
|
||||||
jwt.TimeFunc = func() time.Time {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
f()
|
|
||||||
jwt.TimeFunc = time.Now
|
|
||||||
}
|
|
||||||
|
|
||||||
// An example of parsing the error types using bitfield checks
|
|
||||||
func ExampleParse_errorChecking() {
|
|
||||||
// Token from another example. This token is expired
|
|
||||||
var tokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
|
|
||||||
|
|
||||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
return []byte("AllYourBase"), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if token.Valid {
|
|
||||||
fmt.Println("You look nice today")
|
|
||||||
} else if ve, ok := err.(*jwt.ValidationError); ok {
|
|
||||||
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
|
|
||||||
fmt.Println("That's not even a token")
|
|
||||||
} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
|
|
||||||
// Token is either expired or not active yet
|
|
||||||
fmt.Println("Timing is everything")
|
|
||||||
} else {
|
|
||||||
fmt.Println("Couldn't handle this token:", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Println("Couldn't handle this token:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output: Timing is everything
|
|
||||||
}
|
|
66
vendor/github.com/dgrijalva/jwt-go/hmac_example_test.go
generated
vendored
66
vendor/github.com/dgrijalva/jwt-go/hmac_example_test.go
generated
vendored
|
@ -1,66 +0,0 @@
|
||||||
package jwt_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"io/ioutil"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// For HMAC signing method, the key can be any []byte. It is recommended to generate
|
|
||||||
// a key using crypto/rand or something equivalent. You need the same key for signing
|
|
||||||
// and validating.
|
|
||||||
var hmacSampleSecret []byte
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Load sample key data
|
|
||||||
if keyData, e := ioutil.ReadFile("test/hmacTestKey"); e == nil {
|
|
||||||
hmacSampleSecret = keyData
|
|
||||||
} else {
|
|
||||||
panic(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Example creating, signing, and encoding a JWT token using the HMAC signing method
|
|
||||||
func ExampleNew_hmac() {
|
|
||||||
// Create a new token object, specifying signing method and the claims
|
|
||||||
// you would like it to contain.
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
||||||
"foo": "bar",
|
|
||||||
"nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
|
|
||||||
})
|
|
||||||
|
|
||||||
// Sign and get the complete encoded token as a string using the secret
|
|
||||||
tokenString, err := token.SignedString(hmacSampleSecret)
|
|
||||||
|
|
||||||
fmt.Println(tokenString, err)
|
|
||||||
// Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.u1riaD1rW97opCoAuRCTy4w58Br-Zk-bh7vLiRIsrpU <nil>
|
|
||||||
}
|
|
||||||
|
|
||||||
// Example parsing and validating a token using the HMAC signing method
|
|
||||||
func ExampleParse_hmac() {
|
|
||||||
// sample token string taken from the New example
|
|
||||||
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.u1riaD1rW97opCoAuRCTy4w58Br-Zk-bh7vLiRIsrpU"
|
|
||||||
|
|
||||||
// Parse takes the token string and a function for looking up the key. The latter is especially
|
|
||||||
// useful if you use multiple keys for your application. The standard is to use 'kid' in the
|
|
||||||
// head of the token to identify which key to use, but the parsed token (head and claims) is provided
|
|
||||||
// to the callback, providing flexibility.
|
|
||||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
// Don't forget to validate the alg is what you expect:
|
|
||||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
||||||
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
|
||||||
}
|
|
||||||
|
|
||||||
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
|
|
||||||
return hmacSampleSecret, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
|
||||||
fmt.Println(claims["foo"], claims["nbf"])
|
|
||||||
} else {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output: bar 1.4444784e+09
|
|
||||||
}
|
|
91
vendor/github.com/dgrijalva/jwt-go/hmac_test.go
generated
vendored
91
vendor/github.com/dgrijalva/jwt-go/hmac_test.go
generated
vendored
|
@ -1,91 +0,0 @@
|
||||||
package jwt_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var hmacTestData = []struct {
|
|
||||||
name string
|
|
||||||
tokenString string
|
|
||||||
alg string
|
|
||||||
claims map[string]interface{}
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"web sample",
|
|
||||||
"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
|
|
||||||
"HS256",
|
|
||||||
map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"HS384",
|
|
||||||
"eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.KWZEuOD5lbBxZ34g7F-SlVLAQ_r5KApWNWlZIIMyQVz5Zs58a7XdNzj5_0EcNoOy",
|
|
||||||
"HS384",
|
|
||||||
map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"HS512",
|
|
||||||
"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.CN7YijRX6Aw1n2jyI2Id1w90ja-DEMYiWixhYCyHnrZ1VfJRaFQz1bEbjjA5Fn4CLYaUG432dEYmSbS4Saokmw",
|
|
||||||
"HS512",
|
|
||||||
map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"web sample: invalid",
|
|
||||||
"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXo",
|
|
||||||
"HS256",
|
|
||||||
map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sample data from http://tools.ietf.org/html/draft-jones-json-web-signature-04#appendix-A.1
|
|
||||||
var hmacTestKey, _ = ioutil.ReadFile("test/hmacTestKey")
|
|
||||||
|
|
||||||
func TestHMACVerify(t *testing.T) {
|
|
||||||
for _, data := range hmacTestData {
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], hmacTestKey)
|
|
||||||
if data.valid && err != nil {
|
|
||||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if !data.valid && err == nil {
|
|
||||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHMACSign(t *testing.T) {
|
|
||||||
for _, data := range hmacTestData {
|
|
||||||
if data.valid {
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), hmacTestKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if sig != parts[2] {
|
|
||||||
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkHS256Signing(b *testing.B) {
|
|
||||||
benchmarkSigning(b, jwt.SigningMethodHS256, hmacTestKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkHS384Signing(b *testing.B) {
|
|
||||||
benchmarkSigning(b, jwt.SigningMethodHS384, hmacTestKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkHS512Signing(b *testing.B) {
|
|
||||||
benchmarkSigning(b, jwt.SigningMethodHS512, hmacTestKey)
|
|
||||||
}
|
|
216
vendor/github.com/dgrijalva/jwt-go/http_example_test.go
generated
vendored
216
vendor/github.com/dgrijalva/jwt-go/http_example_test.go
generated
vendored
|
@ -1,216 +0,0 @@
|
||||||
package jwt_test
|
|
||||||
|
|
||||||
// Example HTTP auth using asymmetric crypto/RSA keys
|
|
||||||
// This is based on a (now outdated) example at https://gist.github.com/cryptix/45c33ecf0ae54828e63b
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/rsa"
|
|
||||||
"fmt"
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"github.com/dgrijalva/jwt-go/request"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// location of the files used for signing and verification
|
|
||||||
const (
|
|
||||||
privKeyPath = "test/sample_key" // openssl genrsa -out app.rsa keysize
|
|
||||||
pubKeyPath = "test/sample_key.pub" // openssl rsa -in app.rsa -pubout > app.rsa.pub
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
verifyKey *rsa.PublicKey
|
|
||||||
signKey *rsa.PrivateKey
|
|
||||||
serverPort int
|
|
||||||
// storing sample username/password pairs
|
|
||||||
// don't do this on a real server
|
|
||||||
users = map[string]string{
|
|
||||||
"test": "known",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// read the key files before starting http handlers
|
|
||||||
func init() {
|
|
||||||
signBytes, err := ioutil.ReadFile(privKeyPath)
|
|
||||||
fatal(err)
|
|
||||||
|
|
||||||
signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
|
|
||||||
fatal(err)
|
|
||||||
|
|
||||||
verifyBytes, err := ioutil.ReadFile(pubKeyPath)
|
|
||||||
fatal(err)
|
|
||||||
|
|
||||||
verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
|
|
||||||
fatal(err)
|
|
||||||
|
|
||||||
http.HandleFunc("/authenticate", authHandler)
|
|
||||||
http.HandleFunc("/restricted", restrictedHandler)
|
|
||||||
|
|
||||||
// Setup listener
|
|
||||||
listener, err := net.ListenTCP("tcp", &net.TCPAddr{})
|
|
||||||
serverPort = listener.Addr().(*net.TCPAddr).Port
|
|
||||||
|
|
||||||
log.Println("Listening...")
|
|
||||||
go func() {
|
|
||||||
fatal(http.Serve(listener, nil))
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
var start func()
|
|
||||||
|
|
||||||
func fatal(err error) {
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define some custom types were going to use within our tokens
|
|
||||||
type CustomerInfo struct {
|
|
||||||
Name string
|
|
||||||
Kind string
|
|
||||||
}
|
|
||||||
|
|
||||||
type CustomClaimsExample struct {
|
|
||||||
*jwt.StandardClaims
|
|
||||||
TokenType string
|
|
||||||
CustomerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func Example_getTokenViaHTTP() {
|
|
||||||
// See func authHandler for an example auth handler that produces a token
|
|
||||||
res, err := http.PostForm(fmt.Sprintf("http://localhost:%v/authenticate", serverPort), url.Values{
|
|
||||||
"user": {"test"},
|
|
||||||
"pass": {"known"},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.StatusCode != 200 {
|
|
||||||
fmt.Println("Unexpected status code", res.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the token out of the response body
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
io.Copy(buf, res.Body)
|
|
||||||
res.Body.Close()
|
|
||||||
tokenString := strings.TrimSpace(buf.String())
|
|
||||||
|
|
||||||
// Parse the token
|
|
||||||
token, err := jwt.ParseWithClaims(tokenString, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
// since we only use the one private key to sign the tokens,
|
|
||||||
// we also only use its public counter part to verify
|
|
||||||
return verifyKey, nil
|
|
||||||
})
|
|
||||||
fatal(err)
|
|
||||||
|
|
||||||
claims := token.Claims.(*CustomClaimsExample)
|
|
||||||
fmt.Println(claims.CustomerInfo.Name)
|
|
||||||
|
|
||||||
//Output: test
|
|
||||||
}
|
|
||||||
|
|
||||||
func Example_useTokenViaHTTP() {
|
|
||||||
|
|
||||||
// Make a sample token
|
|
||||||
// In a real world situation, this token will have been acquired from
|
|
||||||
// some other API call (see Example_getTokenViaHTTP)
|
|
||||||
token, err := createToken("foo")
|
|
||||||
fatal(err)
|
|
||||||
|
|
||||||
// Make request. See func restrictedHandler for example request processor
|
|
||||||
req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%v/restricted", serverPort), nil)
|
|
||||||
fatal(err)
|
|
||||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", token))
|
|
||||||
res, err := http.DefaultClient.Do(req)
|
|
||||||
fatal(err)
|
|
||||||
|
|
||||||
// Read the response body
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
io.Copy(buf, res.Body)
|
|
||||||
res.Body.Close()
|
|
||||||
fmt.Println(buf.String())
|
|
||||||
|
|
||||||
// Output: Welcome, foo
|
|
||||||
}
|
|
||||||
|
|
||||||
func createToken(user string) (string, error) {
|
|
||||||
// create a signer for rsa 256
|
|
||||||
t := jwt.New(jwt.GetSigningMethod("RS256"))
|
|
||||||
|
|
||||||
// set our claims
|
|
||||||
t.Claims = &CustomClaimsExample{
|
|
||||||
&jwt.StandardClaims{
|
|
||||||
// set the expire time
|
|
||||||
// see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4
|
|
||||||
ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
|
|
||||||
},
|
|
||||||
"level1",
|
|
||||||
CustomerInfo{user, "human"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creat token string
|
|
||||||
return t.SignedString(signKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// reads the form values, checks them and creates the token
|
|
||||||
func authHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// make sure its post
|
|
||||||
if r.Method != "POST" {
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
fmt.Fprintln(w, "No POST", r.Method)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
user := r.FormValue("user")
|
|
||||||
pass := r.FormValue("pass")
|
|
||||||
|
|
||||||
log.Printf("Authenticate: user[%s] pass[%s]\n", user, pass)
|
|
||||||
|
|
||||||
// check values
|
|
||||||
if user != "test" || pass != "known" {
|
|
||||||
w.WriteHeader(http.StatusForbidden)
|
|
||||||
fmt.Fprintln(w, "Wrong info")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenString, err := createToken(user)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
fmt.Fprintln(w, "Sorry, error while Signing Token!")
|
|
||||||
log.Printf("Token Signing error: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/jwt")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
fmt.Fprintln(w, tokenString)
|
|
||||||
}
|
|
||||||
|
|
||||||
// only accessible with a valid token
|
|
||||||
func restrictedHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// Get token from request
|
|
||||||
token, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
// since we only use the one private key to sign the tokens,
|
|
||||||
// we also only use its public counter part to verify
|
|
||||||
return verifyKey, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// If the token is missing or invalid, return error
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
fmt.Fprintln(w, "Invalid token:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token is valid
|
|
||||||
fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name)
|
|
||||||
return
|
|
||||||
}
|
|
72
vendor/github.com/dgrijalva/jwt-go/none_test.go
generated
vendored
72
vendor/github.com/dgrijalva/jwt-go/none_test.go
generated
vendored
|
@ -1,72 +0,0 @@
|
||||||
package jwt_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var noneTestData = []struct {
|
|
||||||
name string
|
|
||||||
tokenString string
|
|
||||||
alg string
|
|
||||||
key interface{}
|
|
||||||
claims map[string]interface{}
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"Basic",
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.",
|
|
||||||
"none",
|
|
||||||
jwt.UnsafeAllowNoneSignatureType,
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Basic - no key",
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.",
|
|
||||||
"none",
|
|
||||||
nil,
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Signed",
|
|
||||||
"eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.W-jEzRfBigtCWsinvVVuldiuilzVdU5ty0MvpLaSaqK9PlAWWlDQ1VIQ_qSKzwL5IXaZkvZFJXT3yL3n7OUVu7zCNJzdwznbC8Z-b0z2lYvcklJYi2VOFRcGbJtXUqgjk2oGsiqUMUMOLP70TTefkpsgqDxbRh9CDUfpOJgW-dU7cmgaoswe3wjUAUi6B6G2YEaiuXC0XScQYSYVKIzgKXJV8Zw-7AN_DBUI4GkTpsvQ9fVVjZM9csQiEXhYekyrKu1nu_POpQonGd8yqkIyXPECNmmqH5jH4sFiF67XhD7_JpkvLziBpI-uh86evBUadmHhb9Otqw3uV3NTaXLzJw",
|
|
||||||
"none",
|
|
||||||
jwt.UnsafeAllowNoneSignatureType,
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoneVerify(t *testing.T) {
|
|
||||||
for _, data := range noneTestData {
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], data.key)
|
|
||||||
if data.valid && err != nil {
|
|
||||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if !data.valid && err == nil {
|
|
||||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoneSign(t *testing.T) {
|
|
||||||
for _, data := range noneTestData {
|
|
||||||
if data.valid {
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), data.key)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if sig != parts[2] {
|
|
||||||
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
261
vendor/github.com/dgrijalva/jwt-go/parser_test.go
generated
vendored
261
vendor/github.com/dgrijalva/jwt-go/parser_test.go
generated
vendored
|
@ -1,261 +0,0 @@
|
||||||
package jwt_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rsa"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"github.com/dgrijalva/jwt-go/test"
|
|
||||||
)
|
|
||||||
|
|
||||||
var keyFuncError error = fmt.Errorf("error loading key")
|
|
||||||
|
|
||||||
var (
|
|
||||||
jwtTestDefaultKey *rsa.PublicKey
|
|
||||||
defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil }
|
|
||||||
emptyKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, nil }
|
|
||||||
errorKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, keyFuncError }
|
|
||||||
nilKeyFunc jwt.Keyfunc = nil
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub")
|
|
||||||
}
|
|
||||||
|
|
||||||
var jwtTestData = []struct {
|
|
||||||
name string
|
|
||||||
tokenString string
|
|
||||||
keyfunc jwt.Keyfunc
|
|
||||||
claims jwt.Claims
|
|
||||||
valid bool
|
|
||||||
errors uint32
|
|
||||||
parser *jwt.Parser
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"basic",
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
0,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"basic expired",
|
|
||||||
"", // autogen
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar", "exp": float64(time.Now().Unix() - 100)},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorExpired,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"basic nbf",
|
|
||||||
"", // autogen
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100)},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorNotValidYet,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"expired and nbf",
|
|
||||||
"", // autogen
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100), "exp": float64(time.Now().Unix() - 100)},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorNotValidYet | jwt.ValidationErrorExpired,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"basic invalid",
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorSignatureInvalid,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"basic nokeyfunc",
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
||||||
nilKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorUnverifiable,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"basic nokey",
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
||||||
emptyKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorSignatureInvalid,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"basic errorkey",
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
||||||
errorKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorUnverifiable,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"invalid signing method",
|
|
||||||
"",
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorSignatureInvalid,
|
|
||||||
&jwt.Parser{ValidMethods: []string{"HS256"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"valid signing method",
|
|
||||||
"",
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
0,
|
|
||||||
&jwt.Parser{ValidMethods: []string{"RS256", "HS256"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"JSON Number",
|
|
||||||
"",
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": json.Number("123.4")},
|
|
||||||
true,
|
|
||||||
0,
|
|
||||||
&jwt.Parser{UseJSONNumber: true},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Standard Claims",
|
|
||||||
"",
|
|
||||||
defaultKeyFunc,
|
|
||||||
&jwt.StandardClaims{
|
|
||||||
ExpiresAt: time.Now().Add(time.Second * 10).Unix(),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
0,
|
|
||||||
&jwt.Parser{UseJSONNumber: true},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"JSON Number - basic expired",
|
|
||||||
"", // autogen
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar", "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorExpired,
|
|
||||||
&jwt.Parser{UseJSONNumber: true},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"JSON Number - basic nbf",
|
|
||||||
"", // autogen
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorNotValidYet,
|
|
||||||
&jwt.Parser{UseJSONNumber: true},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"JSON Number - expired and nbf",
|
|
||||||
"", // autogen
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100)), "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
|
|
||||||
false,
|
|
||||||
jwt.ValidationErrorNotValidYet | jwt.ValidationErrorExpired,
|
|
||||||
&jwt.Parser{UseJSONNumber: true},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"SkipClaimsValidation during token parsing",
|
|
||||||
"", // autogen
|
|
||||||
defaultKeyFunc,
|
|
||||||
jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
|
|
||||||
true,
|
|
||||||
0,
|
|
||||||
&jwt.Parser{UseJSONNumber: true, SkipClaimsValidation: true},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParser_Parse(t *testing.T) {
|
|
||||||
privateKey := test.LoadRSAPrivateKeyFromDisk("test/sample_key")
|
|
||||||
|
|
||||||
// Iterate over test data set and run tests
|
|
||||||
for _, data := range jwtTestData {
|
|
||||||
// If the token string is blank, use helper function to generate string
|
|
||||||
if data.tokenString == "" {
|
|
||||||
data.tokenString = test.MakeSampleToken(data.claims, privateKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the token
|
|
||||||
var token *jwt.Token
|
|
||||||
var err error
|
|
||||||
var parser = data.parser
|
|
||||||
if parser == nil {
|
|
||||||
parser = new(jwt.Parser)
|
|
||||||
}
|
|
||||||
// Figure out correct claims type
|
|
||||||
switch data.claims.(type) {
|
|
||||||
case jwt.MapClaims:
|
|
||||||
token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc)
|
|
||||||
case *jwt.StandardClaims:
|
|
||||||
token, err = parser.ParseWithClaims(data.tokenString, &jwt.StandardClaims{}, data.keyfunc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify result matches expectation
|
|
||||||
if !reflect.DeepEqual(data.claims, token.Claims) {
|
|
||||||
t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims)
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.valid && err != nil {
|
|
||||||
t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !data.valid && err == nil {
|
|
||||||
t.Errorf("[%v] Invalid token passed validation", data.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == nil && !token.Valid) || (err != nil && token.Valid) {
|
|
||||||
t.Errorf("[%v] Inconsistent behavior between returned error and token.Valid", data.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.errors != 0 {
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("[%v] Expecting error. Didn't get one.", data.name)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
ve := err.(*jwt.ValidationError)
|
|
||||||
// compare the bitfield part of the error
|
|
||||||
if e := ve.Errors; e != data.errors {
|
|
||||||
t.Errorf("[%v] Errors don't match expectation. %v != %v", data.name, e, data.errors)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err.Error() == keyFuncError.Error() && ve.Inner != keyFuncError {
|
|
||||||
t.Errorf("[%v] Inner error does not match expectation. %v != %v", data.name, ve.Inner, keyFuncError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if data.valid && token.Signature == "" {
|
|
||||||
t.Errorf("[%v] Signature is left unpopulated after parsing", data.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method for benchmarking various methods
|
|
||||||
func benchmarkSigning(b *testing.B, method jwt.SigningMethod, key interface{}) {
|
|
||||||
t := jwt.New(method)
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
|
||||||
for pb.Next() {
|
|
||||||
if _, err := t.SignedString(key); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
7
vendor/github.com/dgrijalva/jwt-go/request/doc.go
generated
vendored
7
vendor/github.com/dgrijalva/jwt-go/request/doc.go
generated
vendored
|
@ -1,7 +0,0 @@
|
||||||
// Utility package for extracting JWT tokens from
|
|
||||||
// HTTP requests.
|
|
||||||
//
|
|
||||||
// The main function is ParseFromRequest and it's WithClaims variant.
|
|
||||||
// See examples for how to use the various Extractor implementations
|
|
||||||
// or roll your own.
|
|
||||||
package request
|
|
81
vendor/github.com/dgrijalva/jwt-go/request/extractor.go
generated
vendored
81
vendor/github.com/dgrijalva/jwt-go/request/extractor.go
generated
vendored
|
@ -1,81 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Errors
|
|
||||||
var (
|
|
||||||
ErrNoTokenInRequest = errors.New("no token present in request")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Interface for extracting a token from an HTTP request.
|
|
||||||
// The ExtractToken method should return a token string or an error.
|
|
||||||
// If no token is present, you must return ErrNoTokenInRequest.
|
|
||||||
type Extractor interface {
|
|
||||||
ExtractToken(*http.Request) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extractor for finding a token in a header. Looks at each specified
|
|
||||||
// header in order until there's a match
|
|
||||||
type HeaderExtractor []string
|
|
||||||
|
|
||||||
func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) {
|
|
||||||
// loop over header names and return the first one that contains data
|
|
||||||
for _, header := range e {
|
|
||||||
if ah := req.Header.Get(header); ah != "" {
|
|
||||||
return ah, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", ErrNoTokenInRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract token from request arguments. This includes a POSTed form or
|
|
||||||
// GET URL arguments. Argument names are tried in order until there's a match.
|
|
||||||
// This extractor calls `ParseMultipartForm` on the request
|
|
||||||
type ArgumentExtractor []string
|
|
||||||
|
|
||||||
func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, error) {
|
|
||||||
// Make sure form is parsed
|
|
||||||
req.ParseMultipartForm(10e6)
|
|
||||||
|
|
||||||
// loop over arg names and return the first one that contains data
|
|
||||||
for _, arg := range e {
|
|
||||||
if ah := req.Form.Get(arg); ah != "" {
|
|
||||||
return ah, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", ErrNoTokenInRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tries Extractors in order until one returns a token string or an error occurs
|
|
||||||
type MultiExtractor []Extractor
|
|
||||||
|
|
||||||
func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
|
|
||||||
// loop over header names and return the first one that contains data
|
|
||||||
for _, extractor := range e {
|
|
||||||
if tok, err := extractor.ExtractToken(req); tok != "" {
|
|
||||||
return tok, nil
|
|
||||||
} else if err != ErrNoTokenInRequest {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", ErrNoTokenInRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap an Extractor in this to post-process the value before it's handed off.
|
|
||||||
// See AuthorizationHeaderExtractor for an example
|
|
||||||
type PostExtractionFilter struct {
|
|
||||||
Extractor
|
|
||||||
Filter func(string) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *PostExtractionFilter) ExtractToken(req *http.Request) (string, error) {
|
|
||||||
if tok, err := e.Extractor.ExtractToken(req); tok != "" {
|
|
||||||
return e.Filter(tok)
|
|
||||||
} else {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
32
vendor/github.com/dgrijalva/jwt-go/request/extractor_example_test.go
generated
vendored
32
vendor/github.com/dgrijalva/jwt-go/request/extractor_example_test.go
generated
vendored
|
@ -1,32 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
exampleTokenA = "A"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleHeaderExtractor() {
|
|
||||||
req := makeExampleRequest("GET", "/", map[string]string{"Token": exampleTokenA}, nil)
|
|
||||||
tokenString, err := HeaderExtractor{"Token"}.ExtractToken(req)
|
|
||||||
if err == nil {
|
|
||||||
fmt.Println(tokenString)
|
|
||||||
} else {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
//Output: A
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleArgumentExtractor() {
|
|
||||||
req := makeExampleRequest("GET", "/", nil, url.Values{"token": {extractorTestTokenA}})
|
|
||||||
tokenString, err := ArgumentExtractor{"token"}.ExtractToken(req)
|
|
||||||
if err == nil {
|
|
||||||
fmt.Println(tokenString)
|
|
||||||
} else {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
//Output: A
|
|
||||||
}
|
|
91
vendor/github.com/dgrijalva/jwt-go/request/extractor_test.go
generated
vendored
91
vendor/github.com/dgrijalva/jwt-go/request/extractor_test.go
generated
vendored
|
@ -1,91 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var extractorTestTokenA = "A"
|
|
||||||
var extractorTestTokenB = "B"
|
|
||||||
|
|
||||||
var extractorTestData = []struct {
|
|
||||||
name string
|
|
||||||
extractor Extractor
|
|
||||||
headers map[string]string
|
|
||||||
query url.Values
|
|
||||||
token string
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "simple header",
|
|
||||||
extractor: HeaderExtractor{"Foo"},
|
|
||||||
headers: map[string]string{"Foo": extractorTestTokenA},
|
|
||||||
query: nil,
|
|
||||||
token: extractorTestTokenA,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "simple argument",
|
|
||||||
extractor: ArgumentExtractor{"token"},
|
|
||||||
headers: map[string]string{},
|
|
||||||
query: url.Values{"token": {extractorTestTokenA}},
|
|
||||||
token: extractorTestTokenA,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "multiple extractors",
|
|
||||||
extractor: MultiExtractor{
|
|
||||||
HeaderExtractor{"Foo"},
|
|
||||||
ArgumentExtractor{"token"},
|
|
||||||
},
|
|
||||||
headers: map[string]string{"Foo": extractorTestTokenA},
|
|
||||||
query: url.Values{"token": {extractorTestTokenB}},
|
|
||||||
token: extractorTestTokenA,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "simple miss",
|
|
||||||
extractor: HeaderExtractor{"This-Header-Is-Not-Set"},
|
|
||||||
headers: map[string]string{"Foo": extractorTestTokenA},
|
|
||||||
query: nil,
|
|
||||||
token: "",
|
|
||||||
err: ErrNoTokenInRequest,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "filter",
|
|
||||||
extractor: AuthorizationHeaderExtractor,
|
|
||||||
headers: map[string]string{"Authorization": "Bearer " + extractorTestTokenA},
|
|
||||||
query: nil,
|
|
||||||
token: extractorTestTokenA,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractor(t *testing.T) {
|
|
||||||
// Bearer token request
|
|
||||||
for _, data := range extractorTestData {
|
|
||||||
// Make request from test struct
|
|
||||||
r := makeExampleRequest("GET", "/", data.headers, data.query)
|
|
||||||
|
|
||||||
// Test extractor
|
|
||||||
token, err := data.extractor.ExtractToken(r)
|
|
||||||
if token != data.token {
|
|
||||||
t.Errorf("[%v] Expected token '%v'. Got '%v'", data.name, data.token, token)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != data.err {
|
|
||||||
t.Errorf("[%v] Expected error '%v'. Got '%v'", data.name, data.err, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeExampleRequest(method, path string, headers map[string]string, urlArgs url.Values) *http.Request {
|
|
||||||
r, _ := http.NewRequest(method, fmt.Sprintf("%v?%v", path, urlArgs.Encode()), nil)
|
|
||||||
for k, v := range headers {
|
|
||||||
r.Header.Set(k, v)
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
28
vendor/github.com/dgrijalva/jwt-go/request/oauth2.go
generated
vendored
28
vendor/github.com/dgrijalva/jwt-go/request/oauth2.go
generated
vendored
|
@ -1,28 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Strips 'Bearer ' prefix from bearer token string
|
|
||||||
func stripBearerPrefixFromTokenString(tok string) (string, error) {
|
|
||||||
// Should be a bearer token
|
|
||||||
if len(tok) > 6 && strings.ToUpper(tok[0:7]) == "BEARER " {
|
|
||||||
return tok[7:], nil
|
|
||||||
}
|
|
||||||
return tok, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract bearer token from Authorization header
|
|
||||||
// Uses PostExtractionFilter to strip "Bearer " prefix from header
|
|
||||||
var AuthorizationHeaderExtractor = &PostExtractionFilter{
|
|
||||||
HeaderExtractor{"Authorization"},
|
|
||||||
stripBearerPrefixFromTokenString,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extractor for OAuth2 access tokens. Looks in 'Authorization'
|
|
||||||
// header then 'access_token' argument for a token.
|
|
||||||
var OAuth2Extractor = &MultiExtractor{
|
|
||||||
AuthorizationHeaderExtractor,
|
|
||||||
ArgumentExtractor{"access_token"},
|
|
||||||
}
|
|
24
vendor/github.com/dgrijalva/jwt-go/request/request.go
generated
vendored
24
vendor/github.com/dgrijalva/jwt-go/request/request.go
generated
vendored
|
@ -1,24 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Extract and parse a JWT token from an HTTP request.
|
|
||||||
// This behaves the same as Parse, but accepts a request and an extractor
|
|
||||||
// instead of a token string. The Extractor interface allows you to define
|
|
||||||
// the logic for extracting a token. Several useful implementations are provided.
|
|
||||||
func ParseFromRequest(req *http.Request, extractor Extractor, keyFunc jwt.Keyfunc) (token *jwt.Token, err error) {
|
|
||||||
return ParseFromRequestWithClaims(req, extractor, jwt.MapClaims{}, keyFunc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseFromRequest but with custom Claims type
|
|
||||||
func ParseFromRequestWithClaims(req *http.Request, extractor Extractor, claims jwt.Claims, keyFunc jwt.Keyfunc) (token *jwt.Token, err error) {
|
|
||||||
// Extract token from request
|
|
||||||
if tokStr, err := extractor.ExtractToken(req); err == nil {
|
|
||||||
return jwt.ParseWithClaims(tokStr, claims, keyFunc)
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
103
vendor/github.com/dgrijalva/jwt-go/request/request_test.go
generated
vendored
103
vendor/github.com/dgrijalva/jwt-go/request/request_test.go
generated
vendored
|
@ -1,103 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"github.com/dgrijalva/jwt-go/test"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var requestTestData = []struct {
|
|
||||||
name string
|
|
||||||
claims jwt.MapClaims
|
|
||||||
extractor Extractor
|
|
||||||
headers map[string]string
|
|
||||||
query url.Values
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"authorization bearer token",
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
AuthorizationHeaderExtractor,
|
|
||||||
map[string]string{"Authorization": "Bearer %v"},
|
|
||||||
url.Values{},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"oauth bearer token - header",
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
OAuth2Extractor,
|
|
||||||
map[string]string{"Authorization": "Bearer %v"},
|
|
||||||
url.Values{},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"oauth bearer token - url",
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
OAuth2Extractor,
|
|
||||||
map[string]string{},
|
|
||||||
url.Values{"access_token": {"%v"}},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url token",
|
|
||||||
jwt.MapClaims{"foo": "bar"},
|
|
||||||
ArgumentExtractor{"token"},
|
|
||||||
map[string]string{},
|
|
||||||
url.Values{"token": {"%v"}},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseRequest(t *testing.T) {
|
|
||||||
// load keys from disk
|
|
||||||
privateKey := test.LoadRSAPrivateKeyFromDisk("../test/sample_key")
|
|
||||||
publicKey := test.LoadRSAPublicKeyFromDisk("../test/sample_key.pub")
|
|
||||||
keyfunc := func(*jwt.Token) (interface{}, error) {
|
|
||||||
return publicKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bearer token request
|
|
||||||
for _, data := range requestTestData {
|
|
||||||
// Make token from claims
|
|
||||||
tokenString := test.MakeSampleToken(data.claims, privateKey)
|
|
||||||
|
|
||||||
// Make query string
|
|
||||||
for k, vv := range data.query {
|
|
||||||
for i, v := range vv {
|
|
||||||
if strings.Contains(v, "%v") {
|
|
||||||
data.query[k][i] = fmt.Sprintf(v, tokenString)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make request from test struct
|
|
||||||
r, _ := http.NewRequest("GET", fmt.Sprintf("/?%v", data.query.Encode()), nil)
|
|
||||||
for k, v := range data.headers {
|
|
||||||
if strings.Contains(v, "%v") {
|
|
||||||
r.Header.Set(k, fmt.Sprintf(v, tokenString))
|
|
||||||
} else {
|
|
||||||
r.Header.Set(k, tokenString)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
token, err := ParseFromRequestWithClaims(r, data.extractor, jwt.MapClaims{}, keyfunc)
|
|
||||||
|
|
||||||
if token == nil {
|
|
||||||
t.Errorf("[%v] Token was not found: %v", data.name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(data.claims, token.Claims) {
|
|
||||||
t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims)
|
|
||||||
}
|
|
||||||
if data.valid && err != nil {
|
|
||||||
t.Errorf("[%v] Error while verifying token: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if !data.valid && err == nil {
|
|
||||||
t.Errorf("[%v] Invalid token passed validation", data.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
96
vendor/github.com/dgrijalva/jwt-go/rsa_pss_test.go
generated
vendored
96
vendor/github.com/dgrijalva/jwt-go/rsa_pss_test.go
generated
vendored
|
@ -1,96 +0,0 @@
|
||||||
// +build go1.4
|
|
||||||
|
|
||||||
package jwt_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rsa"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
var rsaPSSTestData = []struct {
|
|
||||||
name string
|
|
||||||
tokenString string
|
|
||||||
alg string
|
|
||||||
claims map[string]interface{}
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"Basic PS256",
|
|
||||||
"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.PPG4xyDVY8ffp4CcxofNmsTDXsrVG2npdQuibLhJbv4ClyPTUtR5giNSvuxo03kB6I8VXVr0Y9X7UxhJVEoJOmULAwRWaUsDnIewQa101cVhMa6iR8X37kfFoiZ6NkS-c7henVkkQWu2HtotkEtQvN5hFlk8IevXXPmvZlhQhwzB1sGzGYnoi1zOfuL98d3BIjUjtlwii5w6gYG2AEEzp7HnHCsb3jIwUPdq86Oe6hIFjtBwduIK90ca4UqzARpcfwxHwVLMpatKask00AgGVI0ysdk0BLMjmLutquD03XbThHScC2C2_Pp4cHWgMzvbgLU2RYYZcZRKr46QeNgz9w",
|
|
||||||
"PS256",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Basic PS384",
|
|
||||||
"eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.w7-qqgj97gK4fJsq_DCqdYQiylJjzWONvD0qWWWhqEOFk2P1eDULPnqHRnjgTXoO4HAw4YIWCsZPet7nR3Xxq4ZhMqvKW8b7KlfRTb9cH8zqFvzMmybQ4jv2hKc3bXYqVow3AoR7hN_CWXI3Dv6Kd2X5xhtxRHI6IL39oTVDUQ74LACe-9t4c3QRPuj6Pq1H4FAT2E2kW_0KOc6EQhCLWEhm2Z2__OZskDC8AiPpP8Kv4k2vB7l0IKQu8Pr4RcNBlqJdq8dA5D3hk5TLxP8V5nG1Ib80MOMMqoS3FQvSLyolFX-R_jZ3-zfq6Ebsqr0yEb0AH2CfsECF7935Pa0FKQ",
|
|
||||||
"PS384",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Basic PS512",
|
|
||||||
"eyJhbGciOiJQUzUxMiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.GX1HWGzFaJevuSLavqqFYaW8_TpvcjQ8KfC5fXiSDzSiT9UD9nB_ikSmDNyDILNdtjZLSvVKfXxZJqCfefxAtiozEDDdJthZ-F0uO4SPFHlGiXszvKeodh7BuTWRI2wL9-ZO4mFa8nq3GMeQAfo9cx11i7nfN8n2YNQ9SHGovG7_T_AvaMZB_jT6jkDHpwGR9mz7x1sycckEo6teLdHRnH_ZdlHlxqknmyTu8Odr5Xh0sJFOL8BepWbbvIIn-P161rRHHiDWFv6nhlHwZnVzjx7HQrWSGb6-s2cdLie9QL_8XaMcUpjLkfOMKkDOfHo6AvpL7Jbwi83Z2ZTHjJWB-A",
|
|
||||||
"PS512",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"basic PS256 invalid: foo => bar",
|
|
||||||
"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.PPG4xyDVY8ffp4CcxofNmsTDXsrVG2npdQuibLhJbv4ClyPTUtR5giNSvuxo03kB6I8VXVr0Y9X7UxhJVEoJOmULAwRWaUsDnIewQa101cVhMa6iR8X37kfFoiZ6NkS-c7henVkkQWu2HtotkEtQvN5hFlk8IevXXPmvZlhQhwzB1sGzGYnoi1zOfuL98d3BIjUjtlwii5w6gYG2AEEzp7HnHCsb3jIwUPdq86Oe6hIFjtBwduIK90ca4UqzARpcfwxHwVLMpatKask00AgGVI0ysdk0BLMjmLutquD03XbThHScC2C2_Pp4cHWgMzvbgLU2RYYZcZRKr46QeNgz9W",
|
|
||||||
"PS256",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRSAPSSVerify(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
key, _ := ioutil.ReadFile("test/sample_key.pub")
|
|
||||||
var rsaPSSKey *rsa.PublicKey
|
|
||||||
if rsaPSSKey, err = jwt.ParseRSAPublicKeyFromPEM(key); err != nil {
|
|
||||||
t.Errorf("Unable to parse RSA public key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, data := range rsaPSSTestData {
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], rsaPSSKey)
|
|
||||||
if data.valid && err != nil {
|
|
||||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if !data.valid && err == nil {
|
|
||||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRSAPSSSign(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
key, _ := ioutil.ReadFile("test/sample_key")
|
|
||||||
var rsaPSSKey *rsa.PrivateKey
|
|
||||||
if rsaPSSKey, err = jwt.ParseRSAPrivateKeyFromPEM(key); err != nil {
|
|
||||||
t.Errorf("Unable to parse RSA private key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, data := range rsaPSSTestData {
|
|
||||||
if data.valid {
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), rsaPSSKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if sig == parts[2] {
|
|
||||||
t.Errorf("[%v] Signatures shouldn't match\nnew:\n%v\noriginal:\n%v", data.name, sig, parts[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
176
vendor/github.com/dgrijalva/jwt-go/rsa_test.go
generated
vendored
176
vendor/github.com/dgrijalva/jwt-go/rsa_test.go
generated
vendored
|
@ -1,176 +0,0 @@
|
||||||
package jwt_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var rsaTestData = []struct {
|
|
||||||
name string
|
|
||||||
tokenString string
|
|
||||||
alg string
|
|
||||||
claims map[string]interface{}
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"Basic RS256",
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
||||||
"RS256",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Basic RS384",
|
|
||||||
"eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.W-jEzRfBigtCWsinvVVuldiuilzVdU5ty0MvpLaSaqK9PlAWWlDQ1VIQ_qSKzwL5IXaZkvZFJXT3yL3n7OUVu7zCNJzdwznbC8Z-b0z2lYvcklJYi2VOFRcGbJtXUqgjk2oGsiqUMUMOLP70TTefkpsgqDxbRh9CDUfpOJgW-dU7cmgaoswe3wjUAUi6B6G2YEaiuXC0XScQYSYVKIzgKXJV8Zw-7AN_DBUI4GkTpsvQ9fVVjZM9csQiEXhYekyrKu1nu_POpQonGd8yqkIyXPECNmmqH5jH4sFiF67XhD7_JpkvLziBpI-uh86evBUadmHhb9Otqw3uV3NTaXLzJw",
|
|
||||||
"RS384",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Basic RS512",
|
|
||||||
"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.zBlLlmRrUxx4SJPUbV37Q1joRcI9EW13grnKduK3wtYKmDXbgDpF1cZ6B-2Jsm5RB8REmMiLpGms-EjXhgnyh2TSHE-9W2gA_jvshegLWtwRVDX40ODSkTb7OVuaWgiy9y7llvcknFBTIg-FnVPVpXMmeV_pvwQyhaz1SSwSPrDyxEmksz1hq7YONXhXPpGaNbMMeDTNP_1oj8DZaqTIL9TwV8_1wb2Odt_Fy58Ke2RVFijsOLdnyEAjt2n9Mxihu9i3PhNBkkxa2GbnXBfq3kzvZ_xxGGopLdHhJjcGWXO-NiwI9_tiu14NRv4L2xC0ItD9Yz68v2ZIZEp_DuzwRQ",
|
|
||||||
"RS512",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"basic invalid: foo => bar",
|
|
||||||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
||||||
"RS256",
|
|
||||||
map[string]interface{}{"foo": "bar"},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRSAVerify(t *testing.T) {
|
|
||||||
keyData, _ := ioutil.ReadFile("test/sample_key.pub")
|
|
||||||
key, _ := jwt.ParseRSAPublicKeyFromPEM(keyData)
|
|
||||||
|
|
||||||
for _, data := range rsaTestData {
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], key)
|
|
||||||
if data.valid && err != nil {
|
|
||||||
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if !data.valid && err == nil {
|
|
||||||
t.Errorf("[%v] Invalid key passed validation", data.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRSASign(t *testing.T) {
|
|
||||||
keyData, _ := ioutil.ReadFile("test/sample_key")
|
|
||||||
key, _ := jwt.ParseRSAPrivateKeyFromPEM(keyData)
|
|
||||||
|
|
||||||
for _, data := range rsaTestData {
|
|
||||||
if data.valid {
|
|
||||||
parts := strings.Split(data.tokenString, ".")
|
|
||||||
method := jwt.GetSigningMethod(data.alg)
|
|
||||||
sig, err := method.Sign(strings.Join(parts[0:2], "."), key)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("[%v] Error signing token: %v", data.name, err)
|
|
||||||
}
|
|
||||||
if sig != parts[2] {
|
|
||||||
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRSAVerifyWithPreParsedPrivateKey(t *testing.T) {
|
|
||||||
key, _ := ioutil.ReadFile("test/sample_key.pub")
|
|
||||||
parsedKey, err := jwt.ParseRSAPublicKeyFromPEM(key)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
testData := rsaTestData[0]
|
|
||||||
parts := strings.Split(testData.tokenString, ".")
|
|
||||||
err = jwt.SigningMethodRS256.Verify(strings.Join(parts[0:2], "."), parts[2], parsedKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("[%v] Error while verifying key: %v", testData.name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRSAWithPreParsedPrivateKey(t *testing.T) {
|
|
||||||
key, _ := ioutil.ReadFile("test/sample_key")
|
|
||||||
parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
testData := rsaTestData[0]
|
|
||||||
parts := strings.Split(testData.tokenString, ".")
|
|
||||||
sig, err := jwt.SigningMethodRS256.Sign(strings.Join(parts[0:2], "."), parsedKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("[%v] Error signing token: %v", testData.name, err)
|
|
||||||
}
|
|
||||||
if sig != parts[2] {
|
|
||||||
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", testData.name, sig, parts[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRSAKeyParsing(t *testing.T) {
|
|
||||||
key, _ := ioutil.ReadFile("test/sample_key")
|
|
||||||
pubKey, _ := ioutil.ReadFile("test/sample_key.pub")
|
|
||||||
badKey := []byte("All your base are belong to key")
|
|
||||||
|
|
||||||
// Test parsePrivateKey
|
|
||||||
if _, e := jwt.ParseRSAPrivateKeyFromPEM(key); e != nil {
|
|
||||||
t.Errorf("Failed to parse valid private key: %v", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if k, e := jwt.ParseRSAPrivateKeyFromPEM(pubKey); e == nil {
|
|
||||||
t.Errorf("Parsed public key as valid private key: %v", k)
|
|
||||||
}
|
|
||||||
|
|
||||||
if k, e := jwt.ParseRSAPrivateKeyFromPEM(badKey); e == nil {
|
|
||||||
t.Errorf("Parsed invalid key as valid private key: %v", k)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test parsePublicKey
|
|
||||||
if _, e := jwt.ParseRSAPublicKeyFromPEM(pubKey); e != nil {
|
|
||||||
t.Errorf("Failed to parse valid public key: %v", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if k, e := jwt.ParseRSAPublicKeyFromPEM(key); e == nil {
|
|
||||||
t.Errorf("Parsed private key as valid public key: %v", k)
|
|
||||||
}
|
|
||||||
|
|
||||||
if k, e := jwt.ParseRSAPublicKeyFromPEM(badKey); e == nil {
|
|
||||||
t.Errorf("Parsed invalid key as valid private key: %v", k)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkRS256Signing(b *testing.B) {
|
|
||||||
key, _ := ioutil.ReadFile("test/sample_key")
|
|
||||||
parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
benchmarkSigning(b, jwt.SigningMethodRS256, parsedKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkRS384Signing(b *testing.B) {
|
|
||||||
key, _ := ioutil.ReadFile("test/sample_key")
|
|
||||||
parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
benchmarkSigning(b, jwt.SigningMethodRS384, parsedKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkRS512Signing(b *testing.B) {
|
|
||||||
key, _ := ioutil.ReadFile("test/sample_key")
|
|
||||||
parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
benchmarkSigning(b, jwt.SigningMethodRS512, parsedKey)
|
|
||||||
}
|
|
42
vendor/github.com/dgrijalva/jwt-go/test/helpers.go
generated
vendored
42
vendor/github.com/dgrijalva/jwt-go/test/helpers.go
generated
vendored
|
@ -1,42 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rsa"
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func LoadRSAPrivateKeyFromDisk(location string) *rsa.PrivateKey {
|
|
||||||
keyData, e := ioutil.ReadFile(location)
|
|
||||||
if e != nil {
|
|
||||||
panic(e.Error())
|
|
||||||
}
|
|
||||||
key, e := jwt.ParseRSAPrivateKeyFromPEM(keyData)
|
|
||||||
if e != nil {
|
|
||||||
panic(e.Error())
|
|
||||||
}
|
|
||||||
return key
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadRSAPublicKeyFromDisk(location string) *rsa.PublicKey {
|
|
||||||
keyData, e := ioutil.ReadFile(location)
|
|
||||||
if e != nil {
|
|
||||||
panic(e.Error())
|
|
||||||
}
|
|
||||||
key, e := jwt.ParseRSAPublicKeyFromPEM(keyData)
|
|
||||||
if e != nil {
|
|
||||||
panic(e.Error())
|
|
||||||
}
|
|
||||||
return key
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeSampleToken(c jwt.Claims, key interface{}) string {
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, c)
|
|
||||||
s, e := token.SignedString(key)
|
|
||||||
|
|
||||||
if e != nil {
|
|
||||||
panic(e.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
1
vendor/github.com/dgrijalva/jwt-go/test/hmacTestKey
generated
vendored
1
vendor/github.com/dgrijalva/jwt-go/test/hmacTestKey
generated
vendored
|
@ -1 +0,0 @@
|
||||||
#5K+・シミew{ヲ住ウ(跼Tノ(ゥ┫メP.ソモ燾辻G<>感テwb="=.!r.Oタヘ奎gミ」
|
|
27
vendor/github.com/dgrijalva/jwt-go/test/sample_key
generated
vendored
27
vendor/github.com/dgrijalva/jwt-go/test/sample_key
generated
vendored
|
@ -1,27 +0,0 @@
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEowIBAAKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtn
|
|
||||||
SgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7mCpz9Er5qLaMXJwZxzHzAahlfA0i
|
|
||||||
cqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBpHssPnpYGIn20ZZuNlX2BrClciHhC
|
|
||||||
PUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2XrHhR+1DcKJzQBSTAGnpYVaqpsAR
|
|
||||||
ap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3bODIRe1AuTyHceAbewn8b462yEWKA
|
|
||||||
Rdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy7wIDAQABAoIBAQCwia1k7+2oZ2d3
|
|
||||||
n6agCAbqIE1QXfCmh41ZqJHbOY3oRQG3X1wpcGH4Gk+O+zDVTV2JszdcOt7E5dAy
|
|
||||||
MaomETAhRxB7hlIOnEN7WKm+dGNrKRvV0wDU5ReFMRHg31/Lnu8c+5BvGjZX+ky9
|
|
||||||
POIhFFYJqwCRlopGSUIxmVj5rSgtzk3iWOQXr+ah1bjEXvlxDOWkHN6YfpV5ThdE
|
|
||||||
KdBIPGEVqa63r9n2h+qazKrtiRqJqGnOrHzOECYbRFYhexsNFz7YT02xdfSHn7gM
|
|
||||||
IvabDDP/Qp0PjE1jdouiMaFHYnLBbgvlnZW9yuVf/rpXTUq/njxIXMmvmEyyvSDn
|
|
||||||
FcFikB8pAoGBAPF77hK4m3/rdGT7X8a/gwvZ2R121aBcdPwEaUhvj/36dx596zvY
|
|
||||||
mEOjrWfZhF083/nYWE2kVquj2wjs+otCLfifEEgXcVPTnEOPO9Zg3uNSL0nNQghj
|
|
||||||
FuD3iGLTUBCtM66oTe0jLSslHe8gLGEQqyMzHOzYxNqibxcOZIe8Qt0NAoGBAO+U
|
|
||||||
I5+XWjWEgDmvyC3TrOSf/KCGjtu0TSv30ipv27bDLMrpvPmD/5lpptTFwcxvVhCs
|
|
||||||
2b+chCjlghFSWFbBULBrfci2FtliClOVMYrlNBdUSJhf3aYSG2Doe6Bgt1n2CpNn
|
|
||||||
/iu37Y3NfemZBJA7hNl4dYe+f+uzM87cdQ214+jrAoGAXA0XxX8ll2+ToOLJsaNT
|
|
||||||
OvNB9h9Uc5qK5X5w+7G7O998BN2PC/MWp8H+2fVqpXgNENpNXttkRm1hk1dych86
|
|
||||||
EunfdPuqsX+as44oCyJGFHVBnWpm33eWQw9YqANRI+pCJzP08I5WK3osnPiwshd+
|
|
||||||
hR54yjgfYhBFNI7B95PmEQkCgYBzFSz7h1+s34Ycr8SvxsOBWxymG5zaCsUbPsL0
|
|
||||||
4aCgLScCHb9J+E86aVbbVFdglYa5Id7DPTL61ixhl7WZjujspeXZGSbmq0Kcnckb
|
|
||||||
mDgqkLECiOJW2NHP/j0McAkDLL4tysF8TLDO8gvuvzNC+WQ6drO2ThrypLVZQ+ry
|
|
||||||
eBIPmwKBgEZxhqa0gVvHQG/7Od69KWj4eJP28kq13RhKay8JOoN0vPmspXJo1HY3
|
|
||||||
CKuHRG+AP579dncdUnOMvfXOtkdM4vk0+hWASBQzM9xzVcztCa+koAugjVaLS9A+
|
|
||||||
9uQoqEeVNTckxx0S2bYevRy7hGQmUJTyQm3j1zEUR5jpdbL83Fbq
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
9
vendor/github.com/dgrijalva/jwt-go/test/sample_key.pub
generated
vendored
9
vendor/github.com/dgrijalva/jwt-go/test/sample_key.pub
generated
vendored
|
@ -1,9 +0,0 @@
|
||||||
-----BEGIN PUBLIC KEY-----
|
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41
|
|
||||||
fGnJm6gOdrj8ym3rFkEU/wT8RDtnSgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7
|
|
||||||
mCpz9Er5qLaMXJwZxzHzAahlfA0icqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBp
|
|
||||||
HssPnpYGIn20ZZuNlX2BrClciHhCPUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2
|
|
||||||
XrHhR+1DcKJzQBSTAGnpYVaqpsARap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3b
|
|
||||||
ODIRe1AuTyHceAbewn8b462yEWKARdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy
|
|
||||||
7wIDAQAB
|
|
||||||
-----END PUBLIC KEY-----
|
|
7
vendor/github.com/documize/blackfriday/.travis.yml
generated
vendored
7
vendor/github.com/documize/blackfriday/.travis.yml
generated
vendored
|
@ -5,9 +5,9 @@
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.2
|
- 1.5
|
||||||
- 1.3
|
- 1.6
|
||||||
- 1.4
|
- 1.7
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- go get -d -t -v ./...
|
- go get -d -t -v ./...
|
||||||
|
@ -15,3 +15,4 @@ install:
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- go test -v ./...
|
- go test -v ./...
|
||||||
|
- go test -run=^$ -bench=BenchmarkReference -benchmem
|
||||||
|
|
1691
vendor/github.com/documize/blackfriday/block_test.go
generated
vendored
1691
vendor/github.com/documize/blackfriday/block_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
48
vendor/github.com/documize/blackfriday/esc_test.go
generated
vendored
48
vendor/github.com/documize/blackfriday/esc_test.go
generated
vendored
|
@ -1,48 +0,0 @@
|
||||||
package blackfriday
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEsc(t *testing.T) {
|
|
||||||
tests := []string{
|
|
||||||
"abc", "abc",
|
|
||||||
"a&c", "a&c",
|
|
||||||
"<", "<",
|
|
||||||
"[]:<", "[]:<",
|
|
||||||
"Hello <!--", "Hello <!--",
|
|
||||||
}
|
|
||||||
for i := 0; i < len(tests); i += 2 {
|
|
||||||
var b bytes.Buffer
|
|
||||||
escapeHTML(&b, []byte(tests[i]))
|
|
||||||
if !bytes.Equal(b.Bytes(), []byte(tests[i+1])) {
|
|
||||||
t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
|
|
||||||
tests[i], tests[i+1], b.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkEscapeHTML(b *testing.B) {
|
|
||||||
tests := [][]byte{
|
|
||||||
[]byte(""),
|
|
||||||
[]byte("AT&T has an ampersand in their name."),
|
|
||||||
[]byte("AT&T is another way to write it."),
|
|
||||||
[]byte("This & that."),
|
|
||||||
[]byte("4 < 5."),
|
|
||||||
[]byte("6 > 5."),
|
|
||||||
[]byte("Here's a [link] [1] with an ampersand in the URL."),
|
|
||||||
[]byte("Here's a link with an ampersand in the link text: [AT&T] [2]."),
|
|
||||||
[]byte("Here's an inline [link](/script?foo=1&bar=2)."),
|
|
||||||
[]byte("Here's an inline [link](</script?foo=1&bar=2>)."),
|
|
||||||
[]byte("[1]: http://example.com/?foo=1&bar=2"),
|
|
||||||
[]byte("[2]: http://att.com/ \"AT&T\""),
|
|
||||||
}
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
for _, t := range tests {
|
|
||||||
escapeHTML(&buf, t)
|
|
||||||
buf.Reset()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
186
vendor/github.com/documize/blackfriday/helpers_test.go
generated
vendored
186
vendor/github.com/documize/blackfriday/helpers_test.go
generated
vendored
|
@ -1,186 +0,0 @@
|
||||||
//
|
|
||||||
// Blackfriday Markdown Processor
|
|
||||||
// Available at http://github.com/russross/blackfriday
|
|
||||||
//
|
|
||||||
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
|
||||||
// Distributed under the Simplified BSD License.
|
|
||||||
// See README.md for details.
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// Helper functions for unit testing
|
|
||||||
//
|
|
||||||
|
|
||||||
package blackfriday
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestParams struct {
|
|
||||||
extensions Extensions
|
|
||||||
referenceOverride ReferenceOverrideFunc
|
|
||||||
HTMLFlags
|
|
||||||
HTMLRendererParameters
|
|
||||||
}
|
|
||||||
|
|
||||||
func execRecoverableTestSuite(t *testing.T, tests []string, params TestParams, suite func(candidate *string)) {
|
|
||||||
// Catch and report panics. This is useful when running 'go test -v' on
|
|
||||||
// the integration server. When developing, though, crash dump is often
|
|
||||||
// preferable, so recovery can be easily turned off with doRecover = false.
|
|
||||||
var candidate string
|
|
||||||
const doRecover = true
|
|
||||||
if doRecover {
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
suite(&candidate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runMarkdown(input string, params TestParams) string {
|
|
||||||
params.HTMLRendererParameters.Flags = params.HTMLFlags
|
|
||||||
renderer := NewHTMLRenderer(params.HTMLRendererParameters)
|
|
||||||
return string(Run([]byte(input), WithRenderer(renderer),
|
|
||||||
WithExtensions(params.extensions),
|
|
||||||
WithRefOverride(params.referenceOverride)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// doTests runs full document tests using MarkdownCommon configuration.
|
|
||||||
func doTests(t *testing.T, tests []string) {
|
|
||||||
doTestsParam(t, tests, TestParams{
|
|
||||||
extensions: CommonExtensions,
|
|
||||||
HTMLRendererParameters: HTMLRendererParameters{
|
|
||||||
Flags: CommonHTMLFlags,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func doTestsBlock(t *testing.T, tests []string, extensions Extensions) {
|
|
||||||
doTestsParam(t, tests, TestParams{
|
|
||||||
extensions: extensions,
|
|
||||||
HTMLFlags: UseXHTML,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func doTestsParam(t *testing.T, tests []string, params TestParams) {
|
|
||||||
execRecoverableTestSuite(t, tests, params, func(candidate *string) {
|
|
||||||
for i := 0; i+1 < len(tests); i += 2 {
|
|
||||||
input := tests[i]
|
|
||||||
*candidate = input
|
|
||||||
expected := tests[i+1]
|
|
||||||
actual := runMarkdown(*candidate, params)
|
|
||||||
if actual != expected {
|
|
||||||
t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
|
|
||||||
*candidate, expected, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
// now test every substring to stress test bounds checking
|
|
||||||
if !testing.Short() {
|
|
||||||
for start := 0; start < len(input); start++ {
|
|
||||||
for end := start + 1; end <= len(input); end++ {
|
|
||||||
*candidate = input[start:end]
|
|
||||||
runMarkdown(*candidate, params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func doTestsInline(t *testing.T, tests []string) {
|
|
||||||
doTestsInlineParam(t, tests, TestParams{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func doLinkTestsInline(t *testing.T, tests []string) {
|
|
||||||
doTestsInline(t, tests)
|
|
||||||
|
|
||||||
prefix := "http://localhost"
|
|
||||||
params := HTMLRendererParameters{AbsolutePrefix: prefix}
|
|
||||||
transformTests := transformLinks(tests, prefix)
|
|
||||||
doTestsInlineParam(t, transformTests, TestParams{
|
|
||||||
HTMLRendererParameters: params,
|
|
||||||
})
|
|
||||||
doTestsInlineParam(t, transformTests, TestParams{
|
|
||||||
HTMLFlags: UseXHTML,
|
|
||||||
HTMLRendererParameters: params,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func doSafeTestsInline(t *testing.T, tests []string) {
|
|
||||||
doTestsInlineParam(t, tests, TestParams{HTMLFlags: Safelink})
|
|
||||||
|
|
||||||
// All the links in this test should not have the prefix appended, so
|
|
||||||
// just rerun it with different parameters and the same expectations.
|
|
||||||
prefix := "http://localhost"
|
|
||||||
params := HTMLRendererParameters{AbsolutePrefix: prefix}
|
|
||||||
transformTests := transformLinks(tests, prefix)
|
|
||||||
doTestsInlineParam(t, transformTests, TestParams{
|
|
||||||
HTMLFlags: Safelink,
|
|
||||||
HTMLRendererParameters: params,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func doTestsInlineParam(t *testing.T, tests []string, params TestParams) {
|
|
||||||
params.extensions |= Autolink | Strikethrough
|
|
||||||
params.HTMLFlags |= UseXHTML
|
|
||||||
doTestsParam(t, tests, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
func transformLinks(tests []string, prefix string) []string {
|
|
||||||
newTests := make([]string, len(tests))
|
|
||||||
anchorRe := regexp.MustCompile(`<a href="/(.*?)"`)
|
|
||||||
imgRe := regexp.MustCompile(`<img src="/(.*?)"`)
|
|
||||||
for i, test := range tests {
|
|
||||||
if i%2 == 1 {
|
|
||||||
test = anchorRe.ReplaceAllString(test, `<a href="`+prefix+`/$1"`)
|
|
||||||
test = imgRe.ReplaceAllString(test, `<img src="`+prefix+`/$1"`)
|
|
||||||
}
|
|
||||||
newTests[i] = test
|
|
||||||
}
|
|
||||||
return newTests
|
|
||||||
}
|
|
||||||
|
|
||||||
func doTestsReference(t *testing.T, files []string, flag Extensions) {
|
|
||||||
params := TestParams{extensions: flag}
|
|
||||||
execRecoverableTestSuite(t, files, params, func(candidate *string) {
|
|
||||||
for _, basename := range files {
|
|
||||||
filename := filepath.Join("testdata", basename+".text")
|
|
||||||
inputBytes, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
input := string(inputBytes)
|
|
||||||
|
|
||||||
filename = filepath.Join("testdata", basename+".html")
|
|
||||||
expectedBytes, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
expected := string(expectedBytes)
|
|
||||||
|
|
||||||
actual := string(runMarkdown(input, params))
|
|
||||||
if actual != expected {
|
|
||||||
t.Errorf("\n [%#v]\nExpected[%#v]\nActual [%#v]",
|
|
||||||
basename+".text", expected, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
// now test every prefix of every input to check for
|
|
||||||
// bounds checking
|
|
||||||
if !testing.Short() {
|
|
||||||
start, max := 0, len(input)
|
|
||||||
for end := start + 1; end <= max; end++ {
|
|
||||||
*candidate = input[start:end]
|
|
||||||
runMarkdown(*candidate, params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
1176
vendor/github.com/documize/blackfriday/inline_test.go
generated
vendored
1176
vendor/github.com/documize/blackfriday/inline_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
38
vendor/github.com/documize/blackfriday/markdown_test.go
generated
vendored
38
vendor/github.com/documize/blackfriday/markdown_test.go
generated
vendored
|
@ -1,38 +0,0 @@
|
||||||
//
|
|
||||||
// Blackfriday Markdown Processor
|
|
||||||
// Available at http://github.com/russross/blackfriday
|
|
||||||
//
|
|
||||||
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
|
||||||
// Distributed under the Simplified BSD License.
|
|
||||||
// See README.md for details.
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// Unit tests for full document parsing and rendering
|
|
||||||
//
|
|
||||||
|
|
||||||
package blackfriday
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestDocument(t *testing.T) {
|
|
||||||
var tests = []string{
|
|
||||||
// Empty document.
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
|
|
||||||
" ",
|
|
||||||
"",
|
|
||||||
|
|
||||||
// This shouldn't panic.
|
|
||||||
// https://github.com/russross/blackfriday/issues/172
|
|
||||||
"[]:<",
|
|
||||||
"<p>[]:<</p>\n",
|
|
||||||
|
|
||||||
// This shouldn't panic.
|
|
||||||
// https://github.com/russross/blackfriday/issues/173
|
|
||||||
" [",
|
|
||||||
"<p>[</p>\n",
|
|
||||||
}
|
|
||||||
doTests(t, tests)
|
|
||||||
}
|
|
124
vendor/github.com/documize/blackfriday/ref_test.go
generated
vendored
124
vendor/github.com/documize/blackfriday/ref_test.go
generated
vendored
|
@ -1,124 +0,0 @@
|
||||||
//
|
|
||||||
// Blackfriday Markdown Processor
|
|
||||||
// Available at http://github.com/russross/blackfriday
|
|
||||||
//
|
|
||||||
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
|
||||||
// Distributed under the Simplified BSD License.
|
|
||||||
// See README.md for details.
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// Markdown 1.0.3 reference tests
|
|
||||||
//
|
|
||||||
|
|
||||||
package blackfriday
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestReference(t *testing.T) {
|
|
||||||
files := []string{
|
|
||||||
"Amps and angle encoding",
|
|
||||||
"Auto links",
|
|
||||||
"Backslash escapes",
|
|
||||||
"Blockquotes with code blocks",
|
|
||||||
"Code Blocks",
|
|
||||||
"Code Spans",
|
|
||||||
"Hard-wrapped paragraphs with list-like lines",
|
|
||||||
"Horizontal rules",
|
|
||||||
"Inline HTML (Advanced)",
|
|
||||||
"Inline HTML (Simple)",
|
|
||||||
"Inline HTML comments",
|
|
||||||
"Links, inline style",
|
|
||||||
"Links, reference style",
|
|
||||||
"Links, shortcut references",
|
|
||||||
"Literal quotes in titles",
|
|
||||||
"Markdown Documentation - Basics",
|
|
||||||
"Markdown Documentation - Syntax",
|
|
||||||
"Nested blockquotes",
|
|
||||||
"Ordered and unordered lists",
|
|
||||||
"Strong and em together",
|
|
||||||
"Tabs",
|
|
||||||
"Tidyness",
|
|
||||||
}
|
|
||||||
doTestsReference(t, files, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReference_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) {
|
|
||||||
files := []string{
|
|
||||||
"Amps and angle encoding",
|
|
||||||
"Auto links",
|
|
||||||
"Backslash escapes",
|
|
||||||
"Blockquotes with code blocks",
|
|
||||||
"Code Blocks",
|
|
||||||
"Code Spans",
|
|
||||||
"Hard-wrapped paragraphs with list-like lines no empty line before block",
|
|
||||||
"Horizontal rules",
|
|
||||||
"Inline HTML (Advanced)",
|
|
||||||
"Inline HTML (Simple)",
|
|
||||||
"Inline HTML comments",
|
|
||||||
"Links, inline style",
|
|
||||||
"Links, reference style",
|
|
||||||
"Links, shortcut references",
|
|
||||||
"Literal quotes in titles",
|
|
||||||
"Markdown Documentation - Basics",
|
|
||||||
"Markdown Documentation - Syntax",
|
|
||||||
"Nested blockquotes",
|
|
||||||
"Ordered and unordered lists",
|
|
||||||
"Strong and em together",
|
|
||||||
"Tabs",
|
|
||||||
"Tidyness",
|
|
||||||
}
|
|
||||||
doTestsReference(t, files, NoEmptyLineBeforeBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
// benchResultAnchor is an anchor variable to store the result of a benchmarked
|
|
||||||
// code so that compiler could never optimize away the call to runMarkdown()
|
|
||||||
var benchResultAnchor string
|
|
||||||
|
|
||||||
func BenchmarkReference(b *testing.B) {
|
|
||||||
params := TestParams{extensions: CommonExtensions}
|
|
||||||
files := []string{
|
|
||||||
"Amps and angle encoding",
|
|
||||||
"Auto links",
|
|
||||||
"Backslash escapes",
|
|
||||||
"Blockquotes with code blocks",
|
|
||||||
"Code Blocks",
|
|
||||||
"Code Spans",
|
|
||||||
"Hard-wrapped paragraphs with list-like lines",
|
|
||||||
"Horizontal rules",
|
|
||||||
"Inline HTML (Advanced)",
|
|
||||||
"Inline HTML (Simple)",
|
|
||||||
"Inline HTML comments",
|
|
||||||
"Links, inline style",
|
|
||||||
"Links, reference style",
|
|
||||||
"Links, shortcut references",
|
|
||||||
"Literal quotes in titles",
|
|
||||||
"Markdown Documentation - Basics",
|
|
||||||
"Markdown Documentation - Syntax",
|
|
||||||
"Nested blockquotes",
|
|
||||||
"Ordered and unordered lists",
|
|
||||||
"Strong and em together",
|
|
||||||
"Tabs",
|
|
||||||
"Tidyness",
|
|
||||||
}
|
|
||||||
var tests []string
|
|
||||||
for _, basename := range files {
|
|
||||||
filename := filepath.Join("testdata", basename+".text")
|
|
||||||
inputBytes, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
b.Errorf("Couldn't open '%s', error: %v\n", filename, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
tests = append(tests, string(inputBytes))
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
for _, test := range tests {
|
|
||||||
benchResultAnchor = runMarkdown(test, params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
17
vendor/github.com/documize/blackfriday/testdata/Amps and angle encoding.html
generated
vendored
17
vendor/github.com/documize/blackfriday/testdata/Amps and angle encoding.html
generated
vendored
|
@ -1,17 +0,0 @@
|
||||||
<p>AT&T has an ampersand in their name.</p>
|
|
||||||
|
|
||||||
<p>AT&T is another way to write it.</p>
|
|
||||||
|
|
||||||
<p>This & that.</p>
|
|
||||||
|
|
||||||
<p>4 < 5.</p>
|
|
||||||
|
|
||||||
<p>6 > 5.</p>
|
|
||||||
|
|
||||||
<p>Here's a <a href="http://example.com/?foo=1&bar=2">link</a> with an ampersand in the URL.</p>
|
|
||||||
|
|
||||||
<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&T</a>.</p>
|
|
||||||
|
|
||||||
<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
|
|
||||||
|
|
||||||
<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
|
|
21
vendor/github.com/documize/blackfriday/testdata/Amps and angle encoding.text
generated
vendored
21
vendor/github.com/documize/blackfriday/testdata/Amps and angle encoding.text
generated
vendored
|
@ -1,21 +0,0 @@
|
||||||
AT&T has an ampersand in their name.
|
|
||||||
|
|
||||||
AT&T is another way to write it.
|
|
||||||
|
|
||||||
This & that.
|
|
||||||
|
|
||||||
4 < 5.
|
|
||||||
|
|
||||||
6 > 5.
|
|
||||||
|
|
||||||
Here's a [link] [1] with an ampersand in the URL.
|
|
||||||
|
|
||||||
Here's a link with an amersand in the link text: [AT&T] [2].
|
|
||||||
|
|
||||||
Here's an inline [link](/script?foo=1&bar=2).
|
|
||||||
|
|
||||||
Here's an inline [link](</script?foo=1&bar=2>).
|
|
||||||
|
|
||||||
|
|
||||||
[1]: http://example.com/?foo=1&bar=2
|
|
||||||
[2]: http://att.com/ "AT&T"
|
|
18
vendor/github.com/documize/blackfriday/testdata/Auto links.html
generated
vendored
18
vendor/github.com/documize/blackfriday/testdata/Auto links.html
generated
vendored
|
@ -1,18 +0,0 @@
|
||||||
<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>
|
|
||||||
|
|
||||||
<p>With an ampersand: <a href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</a></p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>In a list?</li>
|
|
||||||
<li><a href="http://example.com/">http://example.com/</a></li>
|
|
||||||
<li>It should.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<p>Auto-links should not occur here: <code><http://example.com/></code></p>
|
|
||||||
|
|
||||||
<pre><code>or here: <http://example.com/>
|
|
||||||
</code></pre>
|
|
13
vendor/github.com/documize/blackfriday/testdata/Auto links.text
generated
vendored
13
vendor/github.com/documize/blackfriday/testdata/Auto links.text
generated
vendored
|
@ -1,13 +0,0 @@
|
||||||
Link: <http://example.com/>.
|
|
||||||
|
|
||||||
With an ampersand: <http://example.com/?foo=1&bar=2>
|
|
||||||
|
|
||||||
* In a list?
|
|
||||||
* <http://example.com/>
|
|
||||||
* It should.
|
|
||||||
|
|
||||||
> Blockquoted: <http://example.com/>
|
|
||||||
|
|
||||||
Auto-links should not occur here: `<http://example.com/>`
|
|
||||||
|
|
||||||
or here: <http://example.com/>
|
|
123
vendor/github.com/documize/blackfriday/testdata/Backslash escapes.html
generated
vendored
123
vendor/github.com/documize/blackfriday/testdata/Backslash escapes.html
generated
vendored
|
@ -1,123 +0,0 @@
|
||||||
<p>These should all get escaped:</p>
|
|
||||||
|
|
||||||
<p>Backslash: \</p>
|
|
||||||
|
|
||||||
<p>Backtick: `</p>
|
|
||||||
|
|
||||||
<p>Asterisk: *</p>
|
|
||||||
|
|
||||||
<p>Underscore: _</p>
|
|
||||||
|
|
||||||
<p>Left brace: {</p>
|
|
||||||
|
|
||||||
<p>Right brace: }</p>
|
|
||||||
|
|
||||||
<p>Left bracket: [</p>
|
|
||||||
|
|
||||||
<p>Right bracket: ]</p>
|
|
||||||
|
|
||||||
<p>Left paren: (</p>
|
|
||||||
|
|
||||||
<p>Right paren: )</p>
|
|
||||||
|
|
||||||
<p>Greater-than: ></p>
|
|
||||||
|
|
||||||
<p>Hash: #</p>
|
|
||||||
|
|
||||||
<p>Period: .</p>
|
|
||||||
|
|
||||||
<p>Bang: !</p>
|
|
||||||
|
|
||||||
<p>Plus: +</p>
|
|
||||||
|
|
||||||
<p>Minus: -</p>
|
|
||||||
|
|
||||||
<p>Tilde: ~</p>
|
|
||||||
|
|
||||||
<p>These should not, because they occur within a code block:</p>
|
|
||||||
|
|
||||||
<pre><code>Backslash: \\
|
|
||||||
|
|
||||||
Backtick: \`
|
|
||||||
|
|
||||||
Asterisk: \*
|
|
||||||
|
|
||||||
Underscore: \_
|
|
||||||
|
|
||||||
Left brace: \{
|
|
||||||
|
|
||||||
Right brace: \}
|
|
||||||
|
|
||||||
Left bracket: \[
|
|
||||||
|
|
||||||
Right bracket: \]
|
|
||||||
|
|
||||||
Left paren: \(
|
|
||||||
|
|
||||||
Right paren: \)
|
|
||||||
|
|
||||||
Greater-than: \>
|
|
||||||
|
|
||||||
Hash: \#
|
|
||||||
|
|
||||||
Period: \.
|
|
||||||
|
|
||||||
Bang: \!
|
|
||||||
|
|
||||||
Plus: \+
|
|
||||||
|
|
||||||
Minus: \-
|
|
||||||
|
|
||||||
Tilde: \~
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
<p>Nor should these, which occur in code spans:</p>
|
|
||||||
|
|
||||||
<p>Backslash: <code>\\</code></p>
|
|
||||||
|
|
||||||
<p>Backtick: <code>\`</code></p>
|
|
||||||
|
|
||||||
<p>Asterisk: <code>\*</code></p>
|
|
||||||
|
|
||||||
<p>Underscore: <code>\_</code></p>
|
|
||||||
|
|
||||||
<p>Left brace: <code>\{</code></p>
|
|
||||||
|
|
||||||
<p>Right brace: <code>\}</code></p>
|
|
||||||
|
|
||||||
<p>Left bracket: <code>\[</code></p>
|
|
||||||
|
|
||||||
<p>Right bracket: <code>\]</code></p>
|
|
||||||
|
|
||||||
<p>Left paren: <code>\(</code></p>
|
|
||||||
|
|
||||||
<p>Right paren: <code>\)</code></p>
|
|
||||||
|
|
||||||
<p>Greater-than: <code>\></code></p>
|
|
||||||
|
|
||||||
<p>Hash: <code>\#</code></p>
|
|
||||||
|
|
||||||
<p>Period: <code>\.</code></p>
|
|
||||||
|
|
||||||
<p>Bang: <code>\!</code></p>
|
|
||||||
|
|
||||||
<p>Plus: <code>\+</code></p>
|
|
||||||
|
|
||||||
<p>Minus: <code>\-</code></p>
|
|
||||||
|
|
||||||
<p>Tilde: <code>\~</code></p>
|
|
||||||
|
|
||||||
<p>These should get escaped, even though they're matching pairs for
|
|
||||||
other Markdown constructs:</p>
|
|
||||||
|
|
||||||
<p>*asterisks*</p>
|
|
||||||
|
|
||||||
<p>_underscores_</p>
|
|
||||||
|
|
||||||
<p>`backticks`</p>
|
|
||||||
|
|
||||||
<p>This is a code span with a literal backslash-backtick sequence: <code>\`</code></p>
|
|
||||||
|
|
||||||
<p>This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.</p>
|
|
||||||
|
|
||||||
<p>This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.</p>
|
|
126
vendor/github.com/documize/blackfriday/testdata/Backslash escapes.text
generated
vendored
126
vendor/github.com/documize/blackfriday/testdata/Backslash escapes.text
generated
vendored
|
@ -1,126 +0,0 @@
|
||||||
These should all get escaped:
|
|
||||||
|
|
||||||
Backslash: \\
|
|
||||||
|
|
||||||
Backtick: \`
|
|
||||||
|
|
||||||
Asterisk: \*
|
|
||||||
|
|
||||||
Underscore: \_
|
|
||||||
|
|
||||||
Left brace: \{
|
|
||||||
|
|
||||||
Right brace: \}
|
|
||||||
|
|
||||||
Left bracket: \[
|
|
||||||
|
|
||||||
Right bracket: \]
|
|
||||||
|
|
||||||
Left paren: \(
|
|
||||||
|
|
||||||
Right paren: \)
|
|
||||||
|
|
||||||
Greater-than: \>
|
|
||||||
|
|
||||||
Hash: \#
|
|
||||||
|
|
||||||
Period: \.
|
|
||||||
|
|
||||||
Bang: \!
|
|
||||||
|
|
||||||
Plus: \+
|
|
||||||
|
|
||||||
Minus: \-
|
|
||||||
|
|
||||||
Tilde: \~
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
These should not, because they occur within a code block:
|
|
||||||
|
|
||||||
Backslash: \\
|
|
||||||
|
|
||||||
Backtick: \`
|
|
||||||
|
|
||||||
Asterisk: \*
|
|
||||||
|
|
||||||
Underscore: \_
|
|
||||||
|
|
||||||
Left brace: \{
|
|
||||||
|
|
||||||
Right brace: \}
|
|
||||||
|
|
||||||
Left bracket: \[
|
|
||||||
|
|
||||||
Right bracket: \]
|
|
||||||
|
|
||||||
Left paren: \(
|
|
||||||
|
|
||||||
Right paren: \)
|
|
||||||
|
|
||||||
Greater-than: \>
|
|
||||||
|
|
||||||
Hash: \#
|
|
||||||
|
|
||||||
Period: \.
|
|
||||||
|
|
||||||
Bang: \!
|
|
||||||
|
|
||||||
Plus: \+
|
|
||||||
|
|
||||||
Minus: \-
|
|
||||||
|
|
||||||
Tilde: \~
|
|
||||||
|
|
||||||
|
|
||||||
Nor should these, which occur in code spans:
|
|
||||||
|
|
||||||
Backslash: `\\`
|
|
||||||
|
|
||||||
Backtick: `` \` ``
|
|
||||||
|
|
||||||
Asterisk: `\*`
|
|
||||||
|
|
||||||
Underscore: `\_`
|
|
||||||
|
|
||||||
Left brace: `\{`
|
|
||||||
|
|
||||||
Right brace: `\}`
|
|
||||||
|
|
||||||
Left bracket: `\[`
|
|
||||||
|
|
||||||
Right bracket: `\]`
|
|
||||||
|
|
||||||
Left paren: `\(`
|
|
||||||
|
|
||||||
Right paren: `\)`
|
|
||||||
|
|
||||||
Greater-than: `\>`
|
|
||||||
|
|
||||||
Hash: `\#`
|
|
||||||
|
|
||||||
Period: `\.`
|
|
||||||
|
|
||||||
Bang: `\!`
|
|
||||||
|
|
||||||
Plus: `\+`
|
|
||||||
|
|
||||||
Minus: `\-`
|
|
||||||
|
|
||||||
Tilde: `\~`
|
|
||||||
|
|
||||||
|
|
||||||
These should get escaped, even though they're matching pairs for
|
|
||||||
other Markdown constructs:
|
|
||||||
|
|
||||||
\*asterisks\*
|
|
||||||
|
|
||||||
\_underscores\_
|
|
||||||
|
|
||||||
\`backticks\`
|
|
||||||
|
|
||||||
This is a code span with a literal backslash-backtick sequence: `` \` ``
|
|
||||||
|
|
||||||
This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.
|
|
||||||
|
|
||||||
This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.
|
|
15
vendor/github.com/documize/blackfriday/testdata/Blockquotes with code blocks.html
generated
vendored
15
vendor/github.com/documize/blackfriday/testdata/Blockquotes with code blocks.html
generated
vendored
|
@ -1,15 +0,0 @@
|
||||||
<blockquote>
|
|
||||||
<p>Example:</p>
|
|
||||||
|
|
||||||
<pre><code>sub status {
|
|
||||||
print "working";
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
<p>Or:</p>
|
|
||||||
|
|
||||||
<pre><code>sub status {
|
|
||||||
return "working";
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
</blockquote>
|
|
11
vendor/github.com/documize/blackfriday/testdata/Blockquotes with code blocks.text
generated
vendored
11
vendor/github.com/documize/blackfriday/testdata/Blockquotes with code blocks.text
generated
vendored
|
@ -1,11 +0,0 @@
|
||||||
> Example:
|
|
||||||
>
|
|
||||||
> sub status {
|
|
||||||
> print "working";
|
|
||||||
> }
|
|
||||||
>
|
|
||||||
> Or:
|
|
||||||
>
|
|
||||||
> sub status {
|
|
||||||
> return "working";
|
|
||||||
> }
|
|
18
vendor/github.com/documize/blackfriday/testdata/Code Blocks.html
generated
vendored
18
vendor/github.com/documize/blackfriday/testdata/Code Blocks.html
generated
vendored
|
@ -1,18 +0,0 @@
|
||||||
<pre><code>code block on the first line
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
<p>Regular text.</p>
|
|
||||||
|
|
||||||
<pre><code>code block indented by spaces
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
<p>Regular text.</p>
|
|
||||||
|
|
||||||
<pre><code>the lines in this block
|
|
||||||
all contain trailing spaces
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
<p>Regular Text.</p>
|
|
||||||
|
|
||||||
<pre><code>code block on the last line
|
|
||||||
</code></pre>
|
|
14
vendor/github.com/documize/blackfriday/testdata/Code Blocks.text
generated
vendored
14
vendor/github.com/documize/blackfriday/testdata/Code Blocks.text
generated
vendored
|
@ -1,14 +0,0 @@
|
||||||
code block on the first line
|
|
||||||
|
|
||||||
Regular text.
|
|
||||||
|
|
||||||
code block indented by spaces
|
|
||||||
|
|
||||||
Regular text.
|
|
||||||
|
|
||||||
the lines in this block
|
|
||||||
all contain trailing spaces
|
|
||||||
|
|
||||||
Regular Text.
|
|
||||||
|
|
||||||
code block on the last line
|
|
5
vendor/github.com/documize/blackfriday/testdata/Code Spans.html
generated
vendored
5
vendor/github.com/documize/blackfriday/testdata/Code Spans.html
generated
vendored
|
@ -1,5 +0,0 @@
|
||||||
<p><code><test a="</code> content of attribute <code>"></code></p>
|
|
||||||
|
|
||||||
<p>Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span></p>
|
|
||||||
|
|
||||||
<p>Here's how you put <code>`backticks`</code> in a code span.</p>
|
|
6
vendor/github.com/documize/blackfriday/testdata/Code Spans.text
generated
vendored
6
vendor/github.com/documize/blackfriday/testdata/Code Spans.text
generated
vendored
|
@ -1,6 +0,0 @@
|
||||||
`<test a="` content of attribute `">`
|
|
||||||
|
|
||||||
Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span>
|
|
||||||
|
|
||||||
Here's how you put `` `backticks` `` in a code span.
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
<p>In Markdown 1.0.0 and earlier. Version</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>This line turns into a list item.
|
|
||||||
Because a hard-wrapped line in the
|
|
||||||
middle of a paragraph looked like a
|
|
||||||
list item.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>Here's one with a bullet.</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>criminey.</li>
|
|
||||||
</ul>
|
|
|
@ -1,8 +0,0 @@
|
||||||
In Markdown 1.0.0 and earlier. Version
|
|
||||||
8. This line turns into a list item.
|
|
||||||
Because a hard-wrapped line in the
|
|
||||||
middle of a paragraph looked like a
|
|
||||||
list item.
|
|
||||||
|
|
||||||
Here's one with a bullet.
|
|
||||||
* criminey.
|
|
|
@ -1,8 +0,0 @@
|
||||||
<p>In Markdown 1.0.0 and earlier. Version
|
|
||||||
8. This line turns into a list item.
|
|
||||||
Because a hard-wrapped line in the
|
|
||||||
middle of a paragraph looked like a
|
|
||||||
list item.</p>
|
|
||||||
|
|
||||||
<p>Here's one with a bullet.
|
|
||||||
* criminey.</p>
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue