2019-10-08 00:05:46 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2020-04-03 17:39:20 +00:00
|
|
|
kithttp "github.com/influxdata/influxdb/v2/kit/transport/http"
|
2019-10-08 00:05:46 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
)
|
|
|
|
|
2019-10-21 21:37:30 +00:00
|
|
|
// LoggingMW middleware for logging inflight http requests.
|
2020-01-08 19:19:18 +00:00
|
|
|
func LoggingMW(log *zap.Logger) kithttp.Middleware {
|
2019-10-08 00:05:46 +00:00
|
|
|
return func(next http.Handler) http.Handler {
|
|
|
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
2020-01-08 19:19:18 +00:00
|
|
|
srw := kithttp.NewStatusResponseWriter(w)
|
2019-10-08 00:05:46 +00:00
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
r.Body = &bodyEchoer{
|
|
|
|
rc: r.Body,
|
|
|
|
teedR: io.TeeReader(r.Body, &buf),
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func(start time.Time) {
|
|
|
|
errField := zap.Skip()
|
2020-02-03 19:07:43 +00:00
|
|
|
if errStr := w.Header().Get(kithttp.PlatformErrorCodeHeader); errStr != "" {
|
2019-10-08 00:05:46 +00:00
|
|
|
errField = zap.Error(errors.New(errStr))
|
|
|
|
}
|
|
|
|
|
|
|
|
errReferenceField := zap.Skip()
|
2020-02-03 19:07:43 +00:00
|
|
|
if errReference := w.Header().Get(kithttp.PlatformErrorCodeHeader); errReference != "" {
|
2020-03-17 17:35:24 +00:00
|
|
|
errReferenceField = zap.String("error_code", errReference)
|
2019-10-08 00:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fields := []zap.Field{
|
|
|
|
zap.String("method", r.Method),
|
|
|
|
zap.String("host", r.Host),
|
|
|
|
zap.String("path", r.URL.Path),
|
|
|
|
zap.String("query", r.URL.Query().Encode()),
|
|
|
|
zap.String("proto", r.Proto),
|
2020-01-08 19:19:18 +00:00
|
|
|
zap.Int("status_code", srw.Code()),
|
|
|
|
zap.Int("response_size", srw.ResponseBytes()),
|
2019-10-08 00:05:46 +00:00
|
|
|
zap.Int64("content_length", r.ContentLength),
|
|
|
|
zap.String("referrer", r.Referer()),
|
|
|
|
zap.String("remote", r.RemoteAddr),
|
2020-01-08 19:19:18 +00:00
|
|
|
zap.String("user_agent", kithttp.UserAgent(r)),
|
2019-10-08 00:05:46 +00:00
|
|
|
zap.Duration("took", time.Since(start)),
|
|
|
|
errField,
|
|
|
|
errReferenceField,
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidMethodFn, ok := mapURLPath(r.URL.Path)
|
|
|
|
if !ok || !invalidMethodFn(r.Method) {
|
|
|
|
fields = append(fields, zap.ByteString("body", buf.Bytes()))
|
|
|
|
}
|
|
|
|
|
2019-12-04 23:10:23 +00:00
|
|
|
log.Debug("Request", fields...)
|
2019-10-08 00:05:46 +00:00
|
|
|
}(time.Now())
|
|
|
|
|
|
|
|
next.ServeHTTP(srw, r)
|
|
|
|
}
|
|
|
|
return http.HandlerFunc(fn)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type isValidMethodFn func(method string) bool
|
|
|
|
|
|
|
|
func mapURLPath(rawPath string) (isValidMethodFn, bool) {
|
|
|
|
if fn, ok := blacklistEndpoints[rawPath]; ok {
|
|
|
|
return fn, true
|
|
|
|
}
|
|
|
|
|
|
|
|
shiftPath := func(p string) (head, tail string) {
|
|
|
|
p = path.Clean("/" + p)
|
|
|
|
i := strings.Index(p[1:], "/") + 1
|
|
|
|
if i <= 0 {
|
|
|
|
return p[1:], "/"
|
|
|
|
}
|
|
|
|
return p[1:i], p[i:]
|
|
|
|
}
|
|
|
|
|
|
|
|
// ugh, should probably make this whole operation use a trie
|
|
|
|
partsMatch := func(raw, source string) bool {
|
|
|
|
return raw == source || (strings.HasPrefix(source, ":") && raw != "")
|
|
|
|
}
|
|
|
|
|
|
|
|
compareRawSourceURLs := func(raw, source string) bool {
|
|
|
|
sourceHead, sourceTail := shiftPath(source)
|
|
|
|
for rawHead, rawTail := shiftPath(rawPath); rawHead != ""; {
|
|
|
|
if !partsMatch(rawHead, sourceHead) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
rawHead, rawTail = shiftPath(rawTail)
|
|
|
|
sourceHead, sourceTail = shiftPath(sourceTail)
|
|
|
|
}
|
|
|
|
return sourceHead == ""
|
|
|
|
}
|
|
|
|
|
|
|
|
for sourcePath, fn := range blacklistEndpoints {
|
|
|
|
match := compareRawSourceURLs(rawPath, sourcePath)
|
|
|
|
if match {
|
|
|
|
return fn, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
func ignoreMethod(ignoredMethods ...string) isValidMethodFn {
|
|
|
|
if len(ignoredMethods) == 0 {
|
|
|
|
return func(string) bool { return true }
|
|
|
|
}
|
|
|
|
|
|
|
|
ignoreMap := make(map[string]bool)
|
|
|
|
for _, method := range ignoredMethods {
|
|
|
|
ignoreMap[method] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return func(method string) bool {
|
|
|
|
return ignoreMap[method]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
refactor(kv): delete deprecated kv service code
This includes removal of a lot of kv.Service responsibilities. However,
it does not finish the re-wiring. It removes documents, telegrafs,
notification rules + endpoints, checks, orgs, users, buckets, passwords,
urms, labels and authorizations. There are some oustanding pieces that
are needed to get kv service compiling (dashboard service urm
dependency). Then all the call sites for kv service need updating and
the new implementations of telegraf and notification rules + endpoints
needed installing (along with any necessary migrations).
2020-10-20 13:25:36 +00:00
|
|
|
const (
|
|
|
|
prefixSetup = "/api/v2/setup"
|
|
|
|
organizationsIDSecretsPath = "/api/v2/orgs/:id/secrets"
|
|
|
|
organizationsIDSecretsDeletePath = "/api/v2/orgs/:id/secrets/delete"
|
|
|
|
)
|
|
|
|
|
2020-02-03 19:07:43 +00:00
|
|
|
// TODO(@jsteenb2): make this a stronger type that handlers can register routes that should not be logged.
|
2019-10-08 00:05:46 +00:00
|
|
|
var blacklistEndpoints = map[string]isValidMethodFn{
|
2019-12-09 23:54:16 +00:00
|
|
|
prefixSignIn: ignoreMethod(),
|
|
|
|
prefixSignOut: ignoreMethod(),
|
|
|
|
prefixMe: ignoreMethod(),
|
2019-10-08 00:05:46 +00:00
|
|
|
mePasswordPath: ignoreMethod(),
|
|
|
|
usersPasswordPath: ignoreMethod(),
|
2020-02-03 19:07:43 +00:00
|
|
|
"/api/v2/packages/apply": ignoreMethod(),
|
2019-12-09 23:54:16 +00:00
|
|
|
prefixWrite: ignoreMethod("POST"),
|
2020-11-23 19:48:20 +00:00
|
|
|
"/write": ignoreMethod("POST"),
|
2019-10-08 00:05:46 +00:00
|
|
|
organizationsIDSecretsPath: ignoreMethod("PATCH"),
|
|
|
|
organizationsIDSecretsDeletePath: ignoreMethod("POST"),
|
2019-12-09 23:54:16 +00:00
|
|
|
prefixSetup: ignoreMethod("POST"),
|
|
|
|
prefixNotificationEndpoints: ignoreMethod("POST"),
|
2019-10-08 00:05:46 +00:00
|
|
|
notificationEndpointsIDPath: ignoreMethod("PUT"),
|
2021-03-23 11:28:38 +00:00
|
|
|
restoreKVPath: ignoreMethod(),
|
2021-06-14 15:52:31 +00:00
|
|
|
restoreSqlPath: ignoreMethod(),
|
2021-03-23 11:28:38 +00:00
|
|
|
restoreBucketPath: ignoreMethod(),
|
|
|
|
restoreShardPath: ignoreMethod(),
|
2019-10-08 00:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type bodyEchoer struct {
|
|
|
|
rc io.ReadCloser
|
|
|
|
teedR io.Reader
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *bodyEchoer) Read(p []byte) (int, error) {
|
|
|
|
return b.teedR.Read(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *bodyEchoer) Close() error {
|
|
|
|
return b.rc.Close()
|
|
|
|
}
|