Use one http response recorder per external http call (#16938)

This commit is contained in:
Anis Eleuch 2023-03-31 17:37:29 +01:00 committed by GitHub
parent 216a471bbb
commit d90d0c8931
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 32 additions and 21 deletions

View File

@ -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 opType := replication.MetadataReplicationType
if rinfos.Action() == replicateAll { if rinfos.Action() == replicateAll {
opType = replication.ObjectReplicationType opType = replication.ObjectReplicationType

View File

@ -555,7 +555,7 @@ func addCustomHeaders(h http.Handler) http.Handler {
if globalLocalNodeName != "" { if globalLocalNodeName != "" {
w.Header().Set(xhttp.AmzRequestHostID, globalLocalNodeNameHex) w.Header().Set(xhttp.AmzRequestHostID, globalLocalNodeNameHex)
} }
h.ServeHTTP(xhttp.NewResponseRecorder(w), r) h.ServeHTTP(w, r)
}) })
} }

View File

@ -355,11 +355,11 @@ func collectAPIStats(api string, f http.HandlerFunc) http.HandlerFunc {
globalHTTPStats.currentS3Requests.Inc(api) globalHTTPStats.currentS3Requests.Inc(api)
defer globalHTTPStats.currentS3Requests.Dec(api) defer globalHTTPStats.currentS3Requests.Dec(api)
statsWriter := xhttp.NewResponseRecorder(w) f.ServeHTTP(w, r)
f.ServeHTTP(statsWriter, r) if sw, ok := w.(*xhttp.ResponseRecorder); ok {
globalHTTPStats.updateStats(api, r, sw)
globalHTTPStats.updateStats(api, r, statsWriter) }
} }
} }

View File

@ -67,8 +67,12 @@ func getOpName(name string) (op string) {
// otherwise, generate a trace event with request information but no response. // otherwise, generate a trace event with request information but no response.
func httpTracer(h http.Handler) http.Handler { func httpTracer(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 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 { if globalTrace.NumSubscribers(madmin.TraceS3|madmin.TraceInternal) == 0 {
h.ServeHTTP(w, r) h.ServeHTTP(respRecorder, r)
return return
} }
@ -80,9 +84,8 @@ func httpTracer(h http.Handler) http.Handler {
ctx := context.WithValue(r.Context(), mcontext.ContextTraceKey, &tc) ctx := context.WithValue(r.Context(), mcontext.ContextTraceKey, &tc)
r = r.WithContext(ctx) r = r.WithContext(ctx)
// Setup a http request and response body recorder // Setup a http request body recorder
reqRecorder := &xhttp.RequestRecorder{Reader: r.Body} reqRecorder := &xhttp.RequestRecorder{Reader: r.Body}
respRecorder := xhttp.NewResponseRecorder(w)
tc.RequestRecorder = reqRecorder tc.RequestRecorder = reqRecorder
tc.ResponseRecorder = respRecorder tc.ResponseRecorder = respRecorder

View File

@ -24,6 +24,7 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/minio/minio/internal/http/stats"
internalAudit "github.com/minio/minio/internal/logger/message/audit" internalAudit "github.com/minio/minio/internal/logger/message/audit"
"github.com/minio/pkg/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 var st *xhttp.ResponseRecorder
switch v := w.(type) {
case *xhttp.ResponseRecorder: for {
st = v switch v := w.(type) {
case *gzhttp.GzipResponseWriter: case *gzhttp.GzipResponseWriter:
// the writer may be obscured by gzip response writer // the writer may be obscured by gzip response writer
if rw, ok := v.ResponseWriter.(*xhttp.ResponseRecorder); ok { w = v.ResponseWriter
st = rw case *gzhttp.NoGzipResponseWriter:
} // the writer may be obscured by no-gzip response writer
case *gzhttp.NoGzipResponseWriter: w = v.ResponseWriter
// the writer may be obscured by no-gzip response writer case *stats.OutgoingTrafficMeter:
if rw, ok := v.ResponseWriter.(*xhttp.ResponseRecorder); ok { // the writer may be obscured by http stats response writer
st = rw w = v.ResponseWriter
case *xhttp.ResponseRecorder:
st = v
goto exit
default:
goto exit
} }
} }
exit:
if st != nil { if st != nil {
statusCode = st.StatusCode statusCode = st.StatusCode
timeToResponse = time.Now().UTC().Sub(st.StartTime) timeToResponse = time.Now().UTC().Sub(st.StartTime)