1
0
Fork 0

Merge v2.10 into v3.0

This commit is contained in:
mmatur 2023-10-11 16:20:26 +02:00
commit 286181aa61
No known key found for this signature in database
GPG key ID: 2FFE42FC256CFF8E
62 changed files with 712 additions and 189 deletions

View file

@ -42,8 +42,8 @@ func (f *FieldHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
}
// AddOriginFields add origin fields.
func AddOriginFields(rw http.ResponseWriter, req *http.Request, next http.Handler, data *LogData) {
// AddServiceFields add service fields.
func AddServiceFields(rw http.ResponseWriter, req *http.Request, next http.Handler, data *LogData) {
start := time.Now().UTC()
next.ServeHTTP(rw, req)
@ -65,3 +65,14 @@ func AddOriginFields(rw http.ResponseWriter, req *http.Request, next http.Handle
data.Core[OriginStatus] = capt.StatusCode()
data.Core[OriginContentSize] = capt.ResponseSize()
}
// InitServiceFields init service fields.
func InitServiceFields(rw http.ResponseWriter, req *http.Request, next http.Handler, data *LogData) {
// Because they are expected to be initialized when the logger is processing the data table,
// the origin fields are initialized in case the response is returned by Traefik itself, and not a service.
data.Core[OriginDuration] = time.Duration(0)
data.Core[OriginStatus] = 0
data.Core[OriginContentSize] = int64(0)
next.ServeHTTP(rw, req)
}

View file

@ -40,8 +40,8 @@ func (f *CommonLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
toLog(entry.Data, RequestMethod, defaultValue, false),
toLog(entry.Data, RequestPath, defaultValue, false),
toLog(entry.Data, RequestProtocol, defaultValue, false),
toLog(entry.Data, OriginStatus, defaultValue, true),
toLog(entry.Data, OriginContentSize, defaultValue, true),
toLog(entry.Data, DownstreamStatus, defaultValue, true),
toLog(entry.Data, DownstreamContentSize, defaultValue, true),
toLog(entry.Data, "request_Referer", `"-"`, true),
toLog(entry.Data, "request_User-Agent", `"-"`, true),
toLog(entry.Data, RequestCount, defaultValue, true),

View file

@ -18,7 +18,7 @@ func TestCommonLogFormatter_Format(t *testing.T) {
expectedLog string
}{
{
name: "OriginStatus & OriginContentSize are nil",
name: "DownstreamStatus & DownstreamContentSize are nil",
data: map[string]interface{}{
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
Duration: 123 * time.Second,
@ -27,8 +27,8 @@ func TestCommonLogFormatter_Format(t *testing.T) {
RequestMethod: http.MethodGet,
RequestPath: "/foo",
RequestProtocol: "http",
OriginStatus: nil,
OriginContentSize: nil,
DownstreamStatus: nil,
DownstreamContentSize: nil,
RequestRefererHeader: "",
RequestUserAgentHeader: "",
RequestCount: 0,
@ -48,8 +48,8 @@ func TestCommonLogFormatter_Format(t *testing.T) {
RequestMethod: http.MethodGet,
RequestPath: "/foo",
RequestProtocol: "http",
OriginStatus: 123,
OriginContentSize: 132,
DownstreamStatus: 123,
DownstreamContentSize: 132,
RequestRefererHeader: "referer",
RequestUserAgentHeader: "agent",
RequestCount: nil,
@ -69,8 +69,8 @@ func TestCommonLogFormatter_Format(t *testing.T) {
RequestMethod: http.MethodGet,
RequestPath: "/foo",
RequestProtocol: "http",
OriginStatus: 123,
OriginContentSize: 132,
DownstreamStatus: 123,
DownstreamContentSize: 132,
RequestRefererHeader: "referer",
RequestUserAgentHeader: "agent",
RequestCount: nil,

View file

@ -125,6 +125,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusInternalServerError)
return
}
defer forwardResponse.Body.Close()
body, readError := io.ReadAll(forwardResponse.Body)
if readError != nil {
@ -135,7 +136,6 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusInternalServerError)
return
}
defer forwardResponse.Body.Close()
// Pass the forward response's body and selected headers if it
// didn't return a response within the range of [200, 300).

View file

@ -5,6 +5,7 @@ import (
"fmt"
"mime"
"net/http"
"slices"
"strings"
"github.com/klauspost/compress/gzhttp"
@ -87,7 +88,7 @@ func (c *compress) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// Notably for text/event-stream requests the response should not be compressed.
// See https://github.com/traefik/traefik/issues/2576
if contains(c.excludes, mediaType) {
if slices.Contains(c.excludes, mediaType) {
c.next.ServeHTTP(rw, req)
return
}
@ -158,13 +159,3 @@ func encodingAccepts(acceptEncoding []string, typ string) bool {
return false
}
func contains(values []string, val string) bool {
for _, v := range values {
if v == val {
return true
}
}
return false
}

View file

@ -8,6 +8,7 @@ import (
"strings"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/vulcand/oxy/v2/forward"
)
// Header is a middleware that helps setup a few basic security features.
@ -47,6 +48,7 @@ func NewHeader(next http.Handler, cfg dynamic.Headers) (*Header, error) {
func (s *Header) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// Handle Cors headers and preflight if configured.
if isPreflight := s.processCorsHeaders(rw, req); isPreflight {
rw.WriteHeader(http.StatusOK)
return
}
@ -65,6 +67,10 @@ func (s *Header) modifyCustomRequestHeaders(req *http.Request) {
// Loop through Custom request headers
for header, value := range s.headers.CustomRequestHeaders {
switch {
// Handling https://github.com/golang/go/commit/ecdbffd4ec68b509998792f120868fec319de59b.
case value == "" && header == forward.XForwardedFor:
req.Header[header] = nil
case value == "":
req.Header.Del(header)

View file

@ -29,11 +29,14 @@ func TestNewHeader_customRequestHeader(t *testing.T) {
desc: "delete a header",
cfg: dynamic.Headers{
CustomRequestHeaders: map[string]string{
"X-Forwarded-For": "",
"X-Custom-Request-Header": "",
"Foo": "",
},
},
expected: http.Header{},
expected: http.Header{
"X-Forwarded-For": nil,
},
},
{
desc: "override a header",

View file

@ -2,6 +2,7 @@ package requestdecorator
import (
"context"
"errors"
"fmt"
"net"
"sort"
@ -65,9 +66,7 @@ func (hr *Resolver) CNAMEFlatten(ctx context.Context, host string) string {
request = resolv.Record
}
if err := hr.cache.Add(host, result, cacheDuration); err != nil {
logger.Error().Err(err).Send()
}
hr.cache.Set(host, result, cacheDuration)
return result
}
@ -79,6 +78,10 @@ func cnameResolve(ctx context.Context, host, resolvPath string) (*cnameResolv, e
return nil, fmt.Errorf("invalid resolver configuration file: %s", resolvPath)
}
if net.ParseIP(host) != nil {
return nil, nil
}
client := &dns.Client{Timeout: 30 * time.Second}
m := &dns.Msg{}
@ -88,7 +91,11 @@ func cnameResolve(ctx context.Context, host, resolvPath string) (*cnameResolv, e
for _, server := range config.Servers {
tempRecord, err := getRecord(client, m, server, config.Port)
if err != nil {
log.Ctx(ctx).Error().Err(err).Msgf("Failed to resolve host %s", host)
if errors.Is(err, errNoCNAMERecord) {
log.Ctx(ctx).Debug().Err(err).Msgf("CNAME lookup for hostname %q", host)
continue
}
log.Ctx(ctx).Error().Err(err).Msgf("CNAME lookup for hostname %q", host)
continue
}
result = append(result, tempRecord)
@ -102,6 +109,8 @@ func cnameResolve(ctx context.Context, host, resolvPath string) (*cnameResolv, e
return result[0], nil
}
var errNoCNAMERecord = errors.New("no CNAME record for host")
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 {
@ -109,7 +118,7 @@ func getRecord(client *dns.Client, msg *dns.Msg, server, port string) (*cnameRes
}
if resp == nil || len(resp.Answer) == 0 {
return nil, fmt.Errorf("empty answer for server %s", server)
return nil, fmt.Errorf("%w: %s", errNoCNAMERecord, server)
}
rr, ok := resp.Answer[0].(*dns.CNAME)