Merge remote-tracking branch 'upstream/v2.2' into mrg-current-v2.2
This commit is contained in:
commit
73ca7ad0c1
156 changed files with 1768 additions and 892 deletions
|
@ -9,9 +9,7 @@ import (
|
|||
"github.com/containous/traefik/v2/pkg/middlewares"
|
||||
)
|
||||
|
||||
var (
|
||||
_ middlewares.Stateful = &captureResponseWriterWithCloseNotify{}
|
||||
)
|
||||
var _ middlewares.Stateful = &captureResponseWriterWithCloseNotify{}
|
||||
|
||||
type capturer interface {
|
||||
http.ResponseWriter
|
||||
|
|
|
@ -19,7 +19,7 @@ type FieldHandler struct {
|
|||
}
|
||||
|
||||
// NewFieldHandler creates a Field handler.
|
||||
func NewFieldHandler(next http.Handler, name string, value string, applyFn FieldApply) http.Handler {
|
||||
func NewFieldHandler(next http.Handler, name, value string, applyFn FieldApply) http.Handler {
|
||||
return &FieldHandler{next: next, name: name, value: value, applyFn: applyFn}
|
||||
}
|
||||
|
||||
|
|
|
@ -131,11 +131,11 @@ func NewHandler(config *types.AccessLog) (*Handler, error) {
|
|||
func openAccessLogFile(filePath string) (*os.File, error) {
|
||||
dir := filepath.Dir(filePath)
|
||||
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create log path %s: %w", dir, err)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0664)
|
||||
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o664)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening file %s: %w", filePath, err)
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ func (h *Handler) Rotate() error {
|
|||
}
|
||||
|
||||
var err error
|
||||
h.file, err = os.OpenFile(h.config.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0664)
|
||||
h.file, err = os.OpenFile(h.config.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o664)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ func (h *Handler) Rotate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func silentSplitHostPort(value string) (host string, port string) {
|
||||
func silentSplitHostPort(value string) (host, port string) {
|
||||
host, port, err := net.SplitHostPort(value)
|
||||
if err != nil {
|
||||
return value, "-"
|
||||
|
|
|
@ -21,7 +21,7 @@ type CommonLogFormatter struct{}
|
|||
func (f *CommonLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
var timestamp = defaultValue
|
||||
timestamp := defaultValue
|
||||
if v, ok := entry.Data[StartUTC]; ok {
|
||||
timestamp = v.(time.Time).Format(commonLogTimeFormat)
|
||||
} else if v, ok := entry.Data[StartLocal]; ok {
|
||||
|
@ -52,7 +52,7 @@ func (f *CommonLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|||
return b.Bytes(), err
|
||||
}
|
||||
|
||||
func toLog(fields logrus.Fields, key string, defaultValue string, quoted bool) interface{} {
|
||||
func toLog(fields logrus.Fields, key, defaultValue string, quoted bool) interface{} {
|
||||
if v, ok := fields[key]; ok {
|
||||
if v == nil {
|
||||
return defaultValue
|
||||
|
@ -73,7 +73,7 @@ func toLog(fields logrus.Fields, key string, defaultValue string, quoted bool) i
|
|||
return defaultValue
|
||||
}
|
||||
|
||||
func toLogEntry(s string, defaultValue string, quote bool) string {
|
||||
func toLogEntry(s, defaultValue string, quote bool) string {
|
||||
if len(s) == 0 {
|
||||
return defaultValue
|
||||
}
|
||||
|
|
|
@ -62,29 +62,39 @@ func (b *basicAuth) GetTracingInformation() (string, ext.SpanKindEnum) {
|
|||
func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
logger := log.FromContext(middlewares.GetLoggerCtx(req.Context(), b.name, basicTypeName))
|
||||
|
||||
if username := b.auth.CheckAuth(req); username == "" {
|
||||
user, password, ok := req.BasicAuth()
|
||||
if ok {
|
||||
secret := b.auth.Secrets(user, b.auth.Realm)
|
||||
if secret == "" || !goauth.CheckSecret(password, secret) {
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
|
||||
logData := accesslog.GetLogData(req)
|
||||
if logData != nil {
|
||||
logData.Core[accesslog.ClientUsername] = user
|
||||
}
|
||||
|
||||
if !ok {
|
||||
logger.Debug("Authentication failed")
|
||||
tracing.SetErrorWithEvent(req, "Authentication failed")
|
||||
|
||||
b.auth.RequireAuth(rw, req)
|
||||
} else {
|
||||
logger.Debug("Authentication succeeded")
|
||||
req.URL.User = url.User(username)
|
||||
|
||||
logData := accesslog.GetLogData(req)
|
||||
if logData != nil {
|
||||
logData.Core[accesslog.ClientUsername] = username
|
||||
}
|
||||
|
||||
if b.headerField != "" {
|
||||
req.Header[b.headerField] = []string{username}
|
||||
}
|
||||
|
||||
if b.removeHeader {
|
||||
logger.Debug("Removing authorization header")
|
||||
req.Header.Del(authorizationHeader)
|
||||
}
|
||||
b.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Debug("Authentication succeeded")
|
||||
req.URL.User = url.User(user)
|
||||
|
||||
if b.headerField != "" {
|
||||
req.Header[b.headerField] = []string{user}
|
||||
}
|
||||
|
||||
if b.removeHeader {
|
||||
logger.Debug("Removing authorization header")
|
||||
req.Header.Del(authorizationHeader)
|
||||
}
|
||||
b.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
func (b *basicAuth) secretBasic(user, realm string) string {
|
||||
|
|
|
@ -63,6 +63,19 @@ func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
|
||||
username, authinfo := d.auth.CheckAuth(req)
|
||||
if username == "" {
|
||||
headerField := d.headerField
|
||||
if d.headerField == "" {
|
||||
headerField = "Authorization"
|
||||
}
|
||||
|
||||
auth := goauth.DigestAuthParams(req.Header.Get(headerField))
|
||||
if auth["username"] != "" {
|
||||
logData := accesslog.GetLogData(req)
|
||||
if logData != nil {
|
||||
logData.Core[accesslog.ClientUsername] = auth["username"]
|
||||
}
|
||||
}
|
||||
|
||||
if authinfo != nil && *authinfo == "stale" {
|
||||
logger.Debug("Digest authentication failed, possibly because out of order requests")
|
||||
tracing.SetErrorWithEvent(req, "Digest authentication failed, possibly because out of order requests")
|
||||
|
|
|
@ -158,7 +158,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
fa.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
func writeHeader(req *http.Request, forwardReq *http.Request, trustForwardHeader bool) {
|
||||
func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool) {
|
||||
utils.CopyHeaders(forwardReq.Header, req.Header)
|
||||
utils.RemoveHeaders(forwardReq.Header, forward.HopHeaders...)
|
||||
|
||||
|
|
|
@ -325,7 +325,8 @@ func Test_writeHeader(t *testing.T) {
|
|||
"X-Forwarded-Host": "foo.bar",
|
||||
"X-Forwarded-Uri": "/path?q=1",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
name: "trust Forward Header with forwarded request Method",
|
||||
headers: map[string]string{
|
||||
"X-Forwarded-Method": "OPTIONS",
|
||||
|
|
|
@ -246,7 +246,8 @@ func TestServeHTTP(t *testing.T) {
|
|||
expectedHeaders: map[string]string{
|
||||
xForwardedHost: "foo.com:8080",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
desc: "xForwardedServer from req XForwarded",
|
||||
host: "foo.com:8080",
|
||||
expectedHeaders: map[string]string{
|
||||
|
|
|
@ -54,13 +54,13 @@ func New(ctx context.Context, next http.Handler, cfg dynamic.Headers, name strin
|
|||
nextHandler := next
|
||||
|
||||
if hasSecureHeaders {
|
||||
logger.Debug("Setting up secureHeaders from %v", cfg)
|
||||
logger.Debugf("Setting up secureHeaders from %v", cfg)
|
||||
handler = newSecure(next, cfg, name)
|
||||
nextHandler = handler
|
||||
}
|
||||
|
||||
if hasCustomHeaders || hasCorsHeaders {
|
||||
logger.Debug("Setting up customHeaders/Cors from %v", cfg)
|
||||
logger.Debugf("Setting up customHeaders/Cors from %v", cfg)
|
||||
handler = NewHeader(nextHandler, cfg)
|
||||
}
|
||||
|
||||
|
|
|
@ -552,7 +552,8 @@ func TestCORSResponses(t *testing.T) {
|
|||
expected: map[string][]string{
|
||||
"Access-Control-Allow-Origin": {"*"},
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
desc: "Test Simple CustomRequestHeaders Not Hijacked by CORS",
|
||||
header: NewHeader(emptyHandler, dynamic.Headers{
|
||||
CustomRequestHeaders: map[string]string{"foo": "bar"},
|
||||
|
|
|
@ -7,6 +7,6 @@ import (
|
|||
)
|
||||
|
||||
// GetLoggerCtx creates a logger context with the middleware fields.
|
||||
func GetLoggerCtx(ctx context.Context, middleware string, middlewareType string) context.Context {
|
||||
func GetLoggerCtx(ctx context.Context, middleware, middlewareType string) context.Context {
|
||||
return log.With(ctx, log.Str(log.MiddlewareName, middleware), log.Str(log.MiddlewareType, middlewareType))
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ func writeParts(ctx context.Context, content io.StringWriter, entries []string,
|
|||
}
|
||||
}
|
||||
|
||||
func writePart(ctx context.Context, content io.StringWriter, entry string, prefix string) {
|
||||
func writePart(ctx context.Context, content io.StringWriter, entry, prefix string) {
|
||||
if len(entry) > 0 {
|
||||
_, err := content.WriteString(fmt.Sprintf("%s=%s%s", prefix, entry, subFieldSeparator))
|
||||
if err != nil {
|
||||
|
|
|
@ -24,7 +24,7 @@ type redirect struct {
|
|||
}
|
||||
|
||||
// New creates a Redirect middleware.
|
||||
func newRedirect(next http.Handler, regex string, replacement string, permanent bool, name string) (http.Handler, error) {
|
||||
func newRedirect(next http.Handler, regex, replacement string, permanent bool, name string) (http.Handler, error) {
|
||||
re, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -115,7 +115,7 @@ func rawURL(req *http.Request) string {
|
|||
port := ""
|
||||
uri := req.RequestURI
|
||||
|
||||
schemeRegex := `^(https?):\/\/([\w\._-]+)(:\d+)?(.*)$`
|
||||
schemeRegex := `^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
|
||||
re, _ := regexp.Compile(schemeRegex)
|
||||
if re.Match([]byte(req.RequestURI)) {
|
||||
match := re.FindStringSubmatch(req.RequestURI)
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
const (
|
||||
typeSchemeName = "RedirectScheme"
|
||||
schemeRedirectRegex = `^(https?:\/\/)?([\w\._-]+)(:\d+)?(.*)$`
|
||||
schemeRedirectRegex = `^(https?:\/\/)?(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
|
||||
)
|
||||
|
||||
// NewRedirectScheme creates a new RedirectScheme middleware.
|
||||
|
|
|
@ -186,6 +186,44 @@ func TestRedirectSchemeHandler(t *testing.T) {
|
|||
expectedURL: "https://foo",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "IPV6 HTTP to HTTPS redirection without port",
|
||||
config: dynamic.RedirectScheme{
|
||||
Scheme: "https",
|
||||
},
|
||||
url: "http://[::1]",
|
||||
expectedURL: "https://[::1]",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "IPV6 HTTP to HTTPS redirection with port",
|
||||
config: dynamic.RedirectScheme{
|
||||
Scheme: "https",
|
||||
Port: "8443",
|
||||
},
|
||||
url: "http://[::1]",
|
||||
expectedURL: "https://[::1]:8443",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "IPV6 HTTP with port 80 to HTTPS redirection without port",
|
||||
config: dynamic.RedirectScheme{
|
||||
Scheme: "https",
|
||||
},
|
||||
url: "http://[::1]:80",
|
||||
expectedURL: "https://[::1]",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "IPV6 HTTP with port 80 to HTTPS redirection with port",
|
||||
config: dynamic.RedirectScheme{
|
||||
Scheme: "https",
|
||||
Port: "8443",
|
||||
},
|
||||
url: "http://[::1]:80",
|
||||
expectedURL: "https://[::1]:8443",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
@ -235,7 +273,7 @@ func TestRedirectSchemeHandler(t *testing.T) {
|
|||
require.Errorf(t, err, "Location %v", location)
|
||||
}
|
||||
|
||||
schemeRegex := `^(https?):\/\/([\w\._-]+)(:\d+)?(.*)$`
|
||||
schemeRegex := `^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
|
||||
re, _ := regexp.Compile(schemeRegex)
|
||||
|
||||
if re.Match([]byte(test.url)) {
|
||||
|
|
|
@ -47,7 +47,7 @@ func (hr *Resolver) CNAMEFlatten(ctx context.Context, host string) string {
|
|||
}
|
||||
|
||||
logger := log.FromContext(ctx)
|
||||
var cacheDuration = 0 * time.Second
|
||||
cacheDuration := 0 * time.Second
|
||||
for depth := 0; depth < hr.ResolvDepth; depth++ {
|
||||
resolv, err := cnameResolve(ctx, request, hr.ResolvConfig)
|
||||
if err != nil {
|
||||
|
@ -73,7 +73,7 @@ func (hr *Resolver) CNAMEFlatten(ctx context.Context, host string) string {
|
|||
}
|
||||
|
||||
// cnameResolve resolves CNAME if exists, and return with the highest TTL.
|
||||
func cnameResolve(ctx context.Context, host string, resolvPath string) (*cnameResolv, error) {
|
||||
func cnameResolve(ctx context.Context, host, resolvPath string) (*cnameResolv, error) {
|
||||
config, err := dns.ClientConfigFromFile(resolvPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid resolver configuration file: %s", resolvPath)
|
||||
|
@ -102,7 +102,7 @@ func cnameResolve(ctx context.Context, host string, resolvPath string) (*cnameRe
|
|||
return result[0], nil
|
||||
}
|
||||
|
||||
func getRecord(client *dns.Client, msg *dns.Msg, server string, port string) (*cnameResolv, error) {
|
||||
func getRecord(client *dns.Client, msg *dns.Msg, server, port string) (*cnameResolv, error) {
|
||||
resp, _, err := client.Exchange(msg, net.JoinHostPort(server, port))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("exchange error for server %s: %w", server, err)
|
||||
|
|
|
@ -45,7 +45,8 @@ func TestNewForwarder(t *testing.T) {
|
|||
},
|
||||
OperationName: "forward some-service.domain.tld/some-service.domain.tld",
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
desc: "Simple Forward Tracer with truncation and hashing",
|
||||
spanNameLimit: 101,
|
||||
tracing: &trackingBackenMock{
|
||||
|
|
|
@ -18,12 +18,12 @@ func (n MockTracer) StartSpan(operationName string, opts ...opentracing.StartSpa
|
|||
}
|
||||
|
||||
// Inject belongs to the Tracer interface.
|
||||
func (n MockTracer) Inject(sp opentracing.SpanContext, format interface{}, carrier interface{}) error {
|
||||
func (n MockTracer) Inject(sp opentracing.SpanContext, format, carrier interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Extract belongs to the Tracer interface.
|
||||
func (n MockTracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
|
||||
func (n MockTracer) Extract(format, carrier interface{}) (opentracing.SpanContext, error) {
|
||||
return nil, opentracing.ErrSpanContextNotFound
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue