update rest lib to fix recoverd panic

This commit is contained in:
Umputun
2019-02-06 00:45:47 -06:00
parent 58acbecf53
commit 4917ba01ec
6 changed files with 136 additions and 22 deletions
+3 -3
View File
@@ -162,7 +162,7 @@
version = "v1.1.1"
[[projects]]
digest = "1:9aba5c95373481f118e57e9740d9e82f86802d86849809ab89324bcb4f236451"
digest = "1:27df73e1f59fffb9aaa2c28ba81561f177710576f18ad602564949355fac3e23"
name = "github.com/go-pkgz/rest"
packages = [
".",
@@ -170,8 +170,8 @@
"logger",
]
pruneopts = "UT"
revision = "e7d08d0194d613b8854de2e487bf7732500fa153"
version = "v1.2.0"
revision = "27af5e3ba9439ec0df51c30794f473befe0a0e6d"
version = "v1.3.1"
[[projects]]
digest = "1:92b44856ee15e8a98b91d751a60b512017e0ba227d1ed9d2c02ad13d67062ff8"
+3 -2
View File
@@ -7,13 +7,14 @@ install: true
before_install:
- export TZ=America/Chicago
- curl -L https://git.io/vp6lP | sh
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.13.2
- go get github.com/mattn/goveralls
- export PATH=$(pwd)/bin:$PATH
script:
- GO111MODULE=on go get ./...
- GO111MODULE=on go mod vendor
- GO111MODULE=on go test -v -mod=vendor -covermode=count -coverprofile=profile.cov ./... || travis_terminate 1
- ./bin/gometalinter --deadline=120s --exclude=test --exclude=mock --exclude=vendor --exclude=_example --disable-all --enable=errcheck --enable=vet --enable=vetshadow --enable=megacheck --enable=ineffassign --enable=varcheck --enable=unconvert --enable=deadcode --enable=interfacer --enable=gotype ./... || travis_terminate 1;
- golangci-lint run || travis_terminate 1;
- $GOPATH/bin/goveralls -coverprofile=profile.cov -service=travis-ci
+5
View File
@@ -32,3 +32,8 @@ func BlackWords(words ...string) func(http.Handler) http.Handler {
return http.HandlerFunc(fn)
}
}
// BlackWordsFn middleware uses func to get the list and doesn't allow some words in the request body
func BlackWordsFn(fn func() []string) func(http.Handler) http.Handler {
return BlackWords(fn()...)
}
+64 -17
View File
@@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"regexp"
"sort"
"strings"
"time"
)
@@ -23,6 +24,7 @@ type Middleware struct {
flags []Flag
ipFn func(ip string) string
userFn func(r *http.Request) (string, error)
subjFn func(r *http.Request) (string, error)
log Backend
}
@@ -99,8 +101,37 @@ func (l *Middleware) Handler(next http.Handler) http.Handler {
remoteIP = l.ipFn(remoteIP)
}
l.log.Logf("%s %s - %s - %s - %d (%d) - %v %s %s",
l.prefix, r.Method, q, remoteIP, ww.status, ww.size, t2.Sub(t1), user, body)
var bld strings.Builder
if l.prefix != "" {
bld.WriteString(l.prefix)
bld.WriteString(" ")
}
bld.WriteString(fmt.Sprintf("%s - %s - %s - %d (%d) - %v", r.Method, q, remoteIP, ww.status, ww.size, t2.Sub(t1)))
if user != "" {
bld.WriteString(" - ")
bld.WriteString(user)
}
if l.subjFn != nil {
if subj, err := l.subjFn(r); err == nil {
bld.WriteString(" - ")
bld.WriteString(subj)
}
}
if traceID := r.Header.Get("X-Request-ID"); traceID != "" {
bld.WriteString(" - ")
bld.WriteString(traceID)
}
if body != "" {
bld.WriteString(" - ")
bld.WriteString(body)
}
l.log.Logf("%s", bld.String())
}()
next.ServeHTTP(ww, r)
@@ -133,7 +164,7 @@ func (l *Middleware) getBodyAndUser(r *http.Request) (body string, user string)
if l.inLogFlags(User) && l.userFn != nil {
u, err := l.userFn(r)
if err == nil && u != "" {
user = fmt.Sprintf(" - %s", u)
user = u
}
}
@@ -149,24 +180,40 @@ func (l *Middleware) inLogFlags(f Flag) bool {
return false
}
var hideWords = []string{"password", "passwd", "secret", "credentials", "token"}
// hide query values for hideWords. May change order of query params
func (l *Middleware) sanitizeQuery(inp string) string {
out := []rune(inp)
hide := []string{"password", "passwd", "secret", "credentials"}
for _, h := range hide {
if strings.Contains(strings.ToLower(inp), h+"=") {
stPos := strings.Index(strings.ToLower(inp), h+"=") + len(h) + 1
fnPos := strings.Index(inp[stPos:], "&")
if fnPos == -1 {
fnPos = len(inp)
} else {
fnPos = stPos + fnPos
}
for i := stPos; i < fnPos; i++ {
out[i] = rune('*')
inHiddenWords := func(str string) bool {
for _, w := range hideWords {
if strings.EqualFold(w, str) {
return true
}
}
return false
}
return string(out)
parts := strings.SplitN(inp, "?", 2)
if len(parts) < 2 {
return inp
}
q, e := url.ParseQuery(parts[1])
if e != nil || len(q) == 0 {
return inp
}
res := []string{}
for k, v := range q {
if inHiddenWords(k) {
res = append(res, fmt.Sprintf("%s=********", k))
} else {
res = append(res, fmt.Sprintf("%s=%v", k, v[0]))
}
}
sort.Strings(res) // to make testing persistent
return parts[0] + "?" + strings.Join(res, "&")
}
// customResponseWriter implements ResponseWriter and keeping status and size
+7
View File
@@ -44,6 +44,13 @@ func UserFn(userFn func(r *http.Request) (string, error)) Option {
}
}
// SubjFn functional option defines subject function.
func SubjFn(userFn func(r *http.Request) (string, error)) Option {
return func(l *Middleware) {
l.subjFn = userFn
}
}
// Log functional option defines loging backend.
func Log(log Backend) Option {
return func(l *Middleware) {
+54
View File
@@ -0,0 +1,54 @@
package rest
import (
"context"
"crypto/rand"
"crypto/sha1"
"fmt"
"net/http"
"time"
)
type contextKey string
const traceHeader = "X-Request-ID"
// Trace looks for header X-Request-ID and makes it as random id if not found, then populates it to the result's header
// and to request context
func Trace(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
traceID := r.Header.Get(traceHeader)
if traceID == "" {
traceID = randToken()
}
w.Header().Set(traceHeader, traceID)
ctx := context.WithValue(r.Context(), contextKey("requestID"), traceID)
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
// GetTraceID returns request id from the context
func GetTraceID(r *http.Request) string {
if id, ok := r.Context().Value(contextKey("requestID")).(string); ok {
return id
}
return ""
}
func randToken() string {
fallback := func() string {
return fmt.Sprintf("%x", time.Now().Nanosecond())
}
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
return fallback()
}
s := sha1.New()
if _, err := s.Write(b); err != nil {
return fallback()
}
return fmt.Sprintf("%x", s.Sum(nil))
}