2017-05-09 12:02:44 +00:00
|
|
|
package accesslog
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
2017-06-08 19:14:30 +00:00
|
|
|
|
2020-09-16 13:46:04 +00:00
|
|
|
"github.com/traefik/traefik/v2/pkg/middlewares"
|
2017-05-09 12:02:44 +00:00
|
|
|
)
|
|
|
|
|
2020-07-07 12:42:03 +00:00
|
|
|
var _ middlewares.Stateful = &captureResponseWriterWithCloseNotify{}
|
2017-05-09 12:02:44 +00:00
|
|
|
|
2019-12-10 17:18:04 +00:00
|
|
|
type capturer interface {
|
|
|
|
http.ResponseWriter
|
|
|
|
Size() int64
|
|
|
|
Status() int
|
|
|
|
}
|
|
|
|
|
|
|
|
func newCaptureResponseWriter(rw http.ResponseWriter) capturer {
|
|
|
|
capt := &captureResponseWriter{rw: rw}
|
|
|
|
if _, ok := rw.(http.CloseNotifier); !ok {
|
|
|
|
return capt
|
|
|
|
}
|
2019-12-12 14:12:05 +00:00
|
|
|
return &captureResponseWriterWithCloseNotify{capt}
|
2019-12-10 17:18:04 +00:00
|
|
|
}
|
|
|
|
|
2017-05-09 12:02:44 +00:00
|
|
|
// captureResponseWriter is a wrapper of type http.ResponseWriter
|
2020-05-11 10:06:07 +00:00
|
|
|
// that tracks request status and size.
|
2017-05-09 12:02:44 +00:00
|
|
|
type captureResponseWriter struct {
|
|
|
|
rw http.ResponseWriter
|
|
|
|
status int
|
|
|
|
size int64
|
|
|
|
}
|
|
|
|
|
2019-12-10 17:18:04 +00:00
|
|
|
type captureResponseWriterWithCloseNotify struct {
|
|
|
|
*captureResponseWriter
|
|
|
|
}
|
|
|
|
|
|
|
|
// CloseNotify returns a channel that receives at most a
|
|
|
|
// single value (true) when the client connection has gone away.
|
|
|
|
func (r *captureResponseWriterWithCloseNotify) CloseNotify() <-chan bool {
|
|
|
|
return r.rw.(http.CloseNotifier).CloseNotify()
|
|
|
|
}
|
|
|
|
|
2017-05-09 12:02:44 +00:00
|
|
|
func (crw *captureResponseWriter) Header() http.Header {
|
|
|
|
return crw.rw.Header()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (crw *captureResponseWriter) Write(b []byte) (int, error) {
|
|
|
|
if crw.status == 0 {
|
|
|
|
crw.status = http.StatusOK
|
|
|
|
}
|
|
|
|
size, err := crw.rw.Write(b)
|
|
|
|
crw.size += int64(size)
|
|
|
|
return size, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (crw *captureResponseWriter) WriteHeader(s int) {
|
|
|
|
crw.rw.WriteHeader(s)
|
|
|
|
crw.status = s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (crw *captureResponseWriter) Flush() {
|
|
|
|
if f, ok := crw.rw.(http.Flusher); ok {
|
|
|
|
f.Flush()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (crw *captureResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
|
|
if h, ok := crw.rw.(http.Hijacker); ok {
|
|
|
|
return h.Hijack()
|
|
|
|
}
|
2018-07-03 08:02:03 +00:00
|
|
|
return nil, nil, fmt.Errorf("not a hijacker: %T", crw.rw)
|
2017-05-09 12:02:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (crw *captureResponseWriter) Status() int {
|
|
|
|
return crw.status
|
|
|
|
}
|
|
|
|
|
|
|
|
func (crw *captureResponseWriter) Size() int64 {
|
|
|
|
return crw.size
|
|
|
|
}
|