1
0
Fork 0

Merge current v2.4 into v2.5

This commit is contained in:
romain 2021-07-13 18:12:29 +02:00
commit 3a180e2afc
28 changed files with 847 additions and 166 deletions

View file

@ -10,6 +10,7 @@ import (
"net/url"
"os"
"path/filepath"
"strings"
"sync"
"sync/atomic"
"time"
@ -347,7 +348,7 @@ func (h *Handler) redactHeaders(headers http.Header, fields logrus.Fields, prefi
for k := range headers {
v := h.config.Fields.KeepHeader(k)
if v == types.AccessLogKeep {
fields[prefix+k] = headers.Get(k)
fields[prefix+k] = strings.Join(headers.Values(k), ",")
} else if v == types.AccessLogRedact {
fields[prefix+k] = "REDACTED"
}

View file

@ -114,7 +114,7 @@ func lineCount(t *testing.T, fileName string) int {
}
func TestLoggerHeaderFields(t *testing.T) {
expectedValue := "expectedValue"
expectedValues := []string{"AAA", "BBB"}
testCases := []struct {
desc string
@ -191,7 +191,10 @@ func TestLoggerHeaderFields(t *testing.T) {
Path: testPath,
},
}
req.Header.Set(test.header, expectedValue)
for _, s := range expectedValues {
req.Header.Add(test.header, s)
}
logger.ServeHTTP(httptest.NewRecorder(), req, http.HandlerFunc(func(writer http.ResponseWriter, r *http.Request) {
writer.WriteHeader(http.StatusOK)
@ -201,9 +204,9 @@ func TestLoggerHeaderFields(t *testing.T) {
require.NoError(t, err)
if test.expected == types.AccessLogDrop {
assert.NotContains(t, string(logData), expectedValue)
assert.NotContains(t, string(logData), strings.Join(expectedValues, ","))
} else {
assert.Contains(t, string(logData), expectedValue)
assert.Contains(t, string(logData), strings.Join(expectedValues, ","))
}
})
}

View file

@ -10,8 +10,8 @@ import (
)
type responseModifier struct {
r *http.Request
w http.ResponseWriter
req *http.Request
rw http.ResponseWriter
headersSent bool // whether headers have already been sent
code int // status code, must default to 200
@ -24,71 +24,76 @@ type responseModifier struct {
// modifier can be nil.
func newResponseModifier(w http.ResponseWriter, r *http.Request, modifier func(*http.Response) error) *responseModifier {
return &responseModifier{
r: r,
w: w,
req: r,
rw: w,
modifier: modifier,
code: http.StatusOK,
}
}
func (w *responseModifier) WriteHeader(code int) {
if w.headersSent {
func (r *responseModifier) WriteHeader(code int) {
if r.headersSent {
return
}
defer func() {
w.code = code
w.headersSent = true
r.code = code
r.headersSent = true
}()
if w.modifier == nil || w.modified {
w.w.WriteHeader(code)
if r.modifier == nil || r.modified {
r.rw.WriteHeader(code)
return
}
resp := http.Response{
Header: w.w.Header(),
Request: w.r,
Header: r.rw.Header(),
Request: r.req,
}
if err := w.modifier(&resp); err != nil {
w.modifierErr = err
if err := r.modifier(&resp); err != nil {
r.modifierErr = err
// we are propagating when we are called in Write, but we're logging anyway,
// because we could be called from another place which does not take care of
// checking w.modifierErr.
log.WithoutContext().Errorf("Error when applying response modifier: %v", err)
w.w.WriteHeader(http.StatusInternalServerError)
r.rw.WriteHeader(http.StatusInternalServerError)
return
}
w.modified = true
w.w.WriteHeader(code)
r.modified = true
r.rw.WriteHeader(code)
}
func (w *responseModifier) Header() http.Header {
return w.w.Header()
func (r *responseModifier) Header() http.Header {
return r.rw.Header()
}
func (w *responseModifier) Write(b []byte) (int, error) {
w.WriteHeader(w.code)
if w.modifierErr != nil {
return 0, w.modifierErr
func (r *responseModifier) Write(b []byte) (int, error) {
r.WriteHeader(r.code)
if r.modifierErr != nil {
return 0, r.modifierErr
}
return w.w.Write(b)
return r.rw.Write(b)
}
// Hijack hijacks the connection.
func (w *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if h, ok := w.w.(http.Hijacker); ok {
func (r *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if h, ok := r.rw.(http.Hijacker); ok {
return h.Hijack()
}
return nil, nil, fmt.Errorf("not a hijacker: %T", w.w)
return nil, nil, fmt.Errorf("not a hijacker: %T", r.rw)
}
// Flush sends any buffered data to the client.
func (w *responseModifier) Flush() {
if flusher, ok := w.w.(http.Flusher); ok {
func (r *responseModifier) Flush() {
if flusher, ok := r.rw.(http.Flusher); ok {
flusher.Flush()
}
}
// CloseNotify implements http.CloseNotifier.
func (r *responseModifier) CloseNotify() <-chan bool {
return r.rw.(http.CloseNotifier).CloseNotify()
}