fix: %{response_size} for chunked response

This commit is contained in:
wwt 2023-12-22 00:54:09 +08:00
parent 3813ef3ebf
commit 5827d8e9a2
4 changed files with 140 additions and 26 deletions

View File

@ -4,7 +4,6 @@ import (
"log" "log"
"net/http" "net/http"
"strconv" "strconv"
"time"
"github.com/tomasen/realip" "github.com/tomasen/realip"
@ -50,7 +49,6 @@ func (d *data) Check(path string) bool {
func handle(fn handleFunc, prefix string, store *storage.Storage, server *settings.Server) http.Handler { func handle(fn handleFunc, prefix string, store *storage.Storage, server *settings.Server) http.Handler {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
begin := time.Now()
for k, v := range globalHeaders { for k, v := range globalHeaders {
w.Header().Set(k, v) w.Header().Set(k, v)
} }
@ -61,22 +59,12 @@ func handle(fn handleFunc, prefix string, store *storage.Storage, server *settin
return return
} }
d := data{ status, err := fn(w, r, &data{
Runner: &runner.Runner{Enabled: server.EnableExec, Settings: settings}, Runner: &runner.Runner{Enabled: server.EnableExec, Settings: settings},
store: store, store: store,
settings: settings, settings: settings,
server: server, server: server,
} })
status, err := fn(w, r, &d)
if server.EnableRequestLog {
LogRequest(w, r, server.RequestLogFormat, RequestLog{
user: d.user,
status: status,
elapsed: time.Now().Sub(begin).Seconds(),
})
}
if status >= 400 || err != nil { if status >= 400 || err != nil {
clientIP := realip.FromRequest(r) clientIP := realip.FromRequest(r)
log.Printf("%s: %v %s %v", r.URL.Path, status, clientIP, err) log.Printf("%s: %v %s %v", r.URL.Path, status, clientIP, err)

View File

@ -39,11 +39,11 @@ func NewHandler(
r = r.SkipClean(true) r = r.SkipClean(true)
monkey := func(fn handleFunc, prefix string) http.Handler { monkey := func(fn handleFunc, prefix string) http.Handler {
return handle(fn, prefix, store, server) return handle(RequestLogHandleFunc(fn, server), prefix, store, server)
} }
r.HandleFunc("/health", healthHandler) r.HandleFunc("/health", RequestLogHandlerFunc(healthHandler, server))
r.PathPrefix("/static").Handler(static) r.PathPrefix("/static").Handler(RequestLogHandler(static, server))
r.NotFoundHandler = index r.NotFoundHandler = index
api := r.PathPrefix("/api").Subrouter() api := r.PathPrefix("/api").Subrouter()

View File

@ -8,15 +8,17 @@ import (
"strings" "strings"
"time" "time"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
"github.com/tomasen/realip"
) )
type RequestLog struct { type RequestLog struct {
user *users.User user *users.User
ip string ip string
time time.Time time time.Time
request_size int64 request_size uint64
response_size int64 response_size uint64
path string path string
method string method string
status int status int
@ -50,19 +52,19 @@ func (r *RequestLog) time_string() string {
return r.time.Format(time.RFC3339) return r.time.Format(time.RFC3339)
} }
func LogRequest(w http.ResponseWriter, r *http.Request, format string, log_ RequestLog) { func logRequest(w http.ResponseWriter, r *http.Request, format string, log_ RequestLog) {
if log_.status == 0 { if log_.status == 0 {
log_.status = 200 log_.status = 200
} }
log_.ip = getRealIp(r) log_.ip = realip.FromRequest(r)
log_.time = time.Now() log_.time = time.Now()
log_.request_size = r.ContentLength log_.request_size = getRequestSize(r)
if log_.response_size == 0 { if log_.response_size == 0 {
log_.response_size = parseSize(w.Header().Get("Content-Length")) log_.response_size = str2uint64(w.Header().Get("Content-Length"))
} }
log_.origin = r.Header.Get("Origin") log_.origin = r.Header.Get("Origin")
log_.referer = r.Header.Get("Referer") log_.referer = r.Header.Get("Referer")
log_.path = r.URL.Path log_.path = r.RequestURI
log_.method = r.Method log_.method = r.Method
log.Println(formatLog(format, log_)) log.Println(formatLog(format, log_))
} }
@ -120,12 +122,12 @@ func parseFirstItem(s string) string {
return items[0] return items[0]
} }
func parseSize(d string) int64 { func str2uint64(d string) uint64 {
val, err := strconv.ParseInt(d, 10, 64) val, err := strconv.ParseInt(d, 10, 64)
if err != nil { if err != nil {
return 0 return 0
} }
return val return uint64(val)
} }
func int2string(val any) string { func int2string(val any) string {
@ -135,3 +137,61 @@ func int2string(val any) string {
func float2string(val float64) string { func float2string(val float64) string {
return fmt.Sprintf("%f", val) return fmt.Sprintf("%f", val)
} }
func getRequestSize(r *http.Request) uint64 {
return uint64(r.ContentLength)
}
type myHandler struct {
f http.HandlerFunc
}
func (h *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.f(w, r)
}
func handlerfunc2handler(f http.HandlerFunc) http.Handler {
return &myHandler{f: f}
}
func handler2handlerfunc(h http.Handler) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(w, r)
})
}
func RequestLogHandlerFunc(handler http.HandlerFunc, server *settings.Server) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
begin := time.Now()
writer := MakeResponseWriterWrapper(w)
handler(writer, r)
if server.EnableRequestLog {
logRequest(w, r, server.RequestLogFormat, RequestLog{
user: nil,
status: writer.GetStatus(),
elapsed: time.Now().Sub(begin).Seconds(),
response_size: writer.GetSize(),
})
}
})
}
func RequestLogHandler(handler http.Handler, server *settings.Server) http.Handler {
return handlerfunc2handler(RequestLogHandlerFunc(handler2handlerfunc(handler), server))
}
func RequestLogHandleFunc(handle handleFunc, server *settings.Server) handleFunc {
return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
begin := time.Now()
writer := MakeResponseWriterWrapper(w)
status, err := handle(writer, r, d)
if server.EnableRequestLog {
logRequest(w, r, server.RequestLogFormat, RequestLog{
user: d.user,
status: writer.GetStatus(),
elapsed: time.Now().Sub(begin).Seconds(),
response_size: writer.GetSize(),
})
}
return status, err
}
}

View File

@ -0,0 +1,66 @@
package http
import (
"net/http"
)
type _size struct {
value uint64
}
func (s *_size) get() uint64 {
return s.value
}
func (s *_size) set(v uint64) {
s.value = v
}
func (s *_size) add(v uint64) {
s.value += v
}
type _status struct {
value int
}
func (s *_status) get() int {
return s.value
}
func (s *_status) set(v int) {
s.value = v
}
type ResponseWriterWrapper struct {
writer http.ResponseWriter
size *_size
status *_status
}
func MakeResponseWriterWrapper(w http.ResponseWriter) *ResponseWriterWrapper {
return &ResponseWriterWrapper{
writer: w,
size: &_size{value: 0},
status: &_status{value: 0},
}
}
func (r *ResponseWriterWrapper) Write(data []byte) (int, error) {
r.size.add(uint64(len(data)))
return r.writer.Write(data)
}
func (r *ResponseWriterWrapper) Header() http.Header {
return r.writer.Header()
}
func (r *ResponseWriterWrapper) WriteHeader(statusCode int) {
r.status.set(statusCode)
r.writer.WriteHeader(statusCode)
}
func (r *ResponseWriterWrapper) GetSize() uint64 {
return r.size.get()
}
func (r *ResponseWriterWrapper) GetStatus() int {
return r.status.get()
}