diff --git a/cmd/bucket-replication.go b/cmd/bucket-replication.go index deaec4ef0..be28efa64 100644 --- a/cmd/bucket-replication.go +++ b/cmd/bucket-replication.go @@ -1004,7 +1004,7 @@ func replicateObject(ctx context.Context, ri ReplicateObjectInfo, objectAPI Obje }, } - _, _ = objectAPI.PutObjectMetadata(ctx, bucket, object, popts); + _, _ = objectAPI.PutObjectMetadata(ctx, bucket, object, popts) opType := replication.MetadataReplicationType if rinfos.Action() == replicateAll { opType = replication.ObjectReplicationType diff --git a/cmd/generic-handlers.go b/cmd/generic-handlers.go index c6850719c..fe381931d 100644 --- a/cmd/generic-handlers.go +++ b/cmd/generic-handlers.go @@ -555,7 +555,7 @@ func addCustomHeaders(h http.Handler) http.Handler { if globalLocalNodeName != "" { w.Header().Set(xhttp.AmzRequestHostID, globalLocalNodeNameHex) } - h.ServeHTTP(xhttp.NewResponseRecorder(w), r) + h.ServeHTTP(w, r) }) } diff --git a/cmd/handler-utils.go b/cmd/handler-utils.go index 01e83d27a..046aa4478 100644 --- a/cmd/handler-utils.go +++ b/cmd/handler-utils.go @@ -355,11 +355,11 @@ func collectAPIStats(api string, f http.HandlerFunc) http.HandlerFunc { globalHTTPStats.currentS3Requests.Inc(api) defer globalHTTPStats.currentS3Requests.Dec(api) - statsWriter := xhttp.NewResponseRecorder(w) + f.ServeHTTP(w, r) - f.ServeHTTP(statsWriter, r) - - globalHTTPStats.updateStats(api, r, statsWriter) + if sw, ok := w.(*xhttp.ResponseRecorder); ok { + globalHTTPStats.updateStats(api, r, sw) + } } } diff --git a/cmd/http-tracer.go b/cmd/http-tracer.go index 7e57576c8..03b0f0ce6 100644 --- a/cmd/http-tracer.go +++ b/cmd/http-tracer.go @@ -67,8 +67,12 @@ func getOpName(name string) (op string) { // otherwise, generate a trace event with request information but no response. func httpTracer(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Setup a http request response recorder - this is needed for + // http stats requests and audit if enabled. + respRecorder := xhttp.NewResponseRecorder(w) + if globalTrace.NumSubscribers(madmin.TraceS3|madmin.TraceInternal) == 0 { - h.ServeHTTP(w, r) + h.ServeHTTP(respRecorder, r) return } @@ -80,9 +84,8 @@ func httpTracer(h http.Handler) http.Handler { ctx := context.WithValue(r.Context(), mcontext.ContextTraceKey, &tc) r = r.WithContext(ctx) - // Setup a http request and response body recorder + // Setup a http request body recorder reqRecorder := &xhttp.RequestRecorder{Reader: r.Body} - respRecorder := xhttp.NewResponseRecorder(w) tc.RequestRecorder = reqRecorder tc.ResponseRecorder = respRecorder diff --git a/internal/logger/audit.go b/internal/logger/audit.go index a1bf11c3a..3cdc03b23 100644 --- a/internal/logger/audit.go +++ b/internal/logger/audit.go @@ -24,6 +24,7 @@ import ( "strconv" "time" + "github.com/minio/minio/internal/http/stats" internalAudit "github.com/minio/minio/internal/logger/message/audit" "github.com/minio/pkg/logger/message/audit" @@ -96,20 +97,27 @@ func AuditLog(ctx context.Context, w http.ResponseWriter, r *http.Request, reqCl ) var st *xhttp.ResponseRecorder - switch v := w.(type) { - case *xhttp.ResponseRecorder: - st = v - case *gzhttp.GzipResponseWriter: - // the writer may be obscured by gzip response writer - if rw, ok := v.ResponseWriter.(*xhttp.ResponseRecorder); ok { - st = rw - } - case *gzhttp.NoGzipResponseWriter: - // the writer may be obscured by no-gzip response writer - if rw, ok := v.ResponseWriter.(*xhttp.ResponseRecorder); ok { - st = rw + + for { + switch v := w.(type) { + case *gzhttp.GzipResponseWriter: + // the writer may be obscured by gzip response writer + w = v.ResponseWriter + case *gzhttp.NoGzipResponseWriter: + // the writer may be obscured by no-gzip response writer + w = v.ResponseWriter + case *stats.OutgoingTrafficMeter: + // the writer may be obscured by http stats response writer + w = v.ResponseWriter + case *xhttp.ResponseRecorder: + st = v + goto exit + default: + goto exit } } + exit: + if st != nil { statusCode = st.StatusCode timeToResponse = time.Now().UTC().Sub(st.StartTime)