From fbf0f4c425b23c39dbddd975d36df506cca5f45b Mon Sep 17 00:00:00 2001
From: Francis Lavoie <lavofr@gmail.com>
Date: Tue, 22 Oct 2024 14:10:46 -0400
Subject: [PATCH] reverseproxy: Sync changes from stdlib for 1xx handling
 (#6656)

* reverseproxy: Sync changes from stdlib for 1xx handling

Sourced from https://github.com/golang/go/commit/960654be0c4ad7918376e2e1d47491c9bc7520e0

* Use clear()

https://github.com/golang/go/commit/3bc28402fae2a1646e4d2756344b5eb34994d25f
---
 modules/caddyhttp/headers/headers.go          |  4 +--
 .../caddyhttp/reverseproxy/reverseproxy.go    | 26 +++++++++++++++----
 2 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/modules/caddyhttp/headers/headers.go b/modules/caddyhttp/headers/headers.go
index a3279d913..c66bd4144 100644
--- a/modules/caddyhttp/headers/headers.go
+++ b/modules/caddyhttp/headers/headers.go
@@ -200,9 +200,7 @@ func (ops HeaderOps) ApplyTo(hdr http.Header, repl *caddy.Replacer) {
 	for _, fieldName := range ops.Delete {
 		fieldName = repl.ReplaceKnown(fieldName, "")
 		if fieldName == "*" {
-			for existingField := range hdr {
-				delete(hdr, existingField)
-			}
+			clear(hdr)
 		}
 	}
 
diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go
index 123bf774b..1250eae6c 100644
--- a/modules/caddyhttp/reverseproxy/reverseproxy.go
+++ b/modules/caddyhttp/reverseproxy/reverseproxy.go
@@ -807,17 +807,26 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe
 	shouldLogCredentials := server.Logs != nil && server.Logs.ShouldLogCredentials
 
 	// Forward 1xx status codes, backported from https://github.com/golang/go/pull/53164
+	var (
+		roundTripMutex sync.Mutex
+		roundTripDone  bool
+	)
 	trace := &httptrace.ClientTrace{
 		Got1xxResponse: func(code int, header textproto.MIMEHeader) error {
+			roundTripMutex.Lock()
+			defer roundTripMutex.Unlock()
+			if roundTripDone {
+				// If RoundTrip has returned, don't try to further modify
+				// the ResponseWriter's header map.
+				return nil
+			}
 			h := rw.Header()
 			copyHeader(h, http.Header(header))
 			rw.WriteHeader(code)
 
 			// Clear headers coming from the backend
 			// (it's not automatically done by ResponseWriter.WriteHeader() for 1xx responses)
-			for k := range header {
-				delete(h, k)
-			}
+			clear(h)
 
 			return nil
 		},
@@ -833,11 +842,18 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe
 		req = req.WithContext(context.WithoutCancel(req.Context()))
 	}
 
-	// do the round-trip; emit debug log with values we know are
-	// safe, or if there is no error, emit fuller log entry
+	// do the round-trip
 	start := time.Now()
 	res, err := h.Transport.RoundTrip(req)
 	duration := time.Since(start)
+
+	// record that the round trip is done for the 1xx response handler
+	roundTripMutex.Lock()
+	roundTripDone = true
+	roundTripMutex.Unlock()
+
+	// emit debug log with values we know are safe,
+	// or if there is no error, emit fuller log entry
 	logger := h.logger.With(
 		zap.String("upstream", di.Upstream.String()),
 		zap.Duration("duration", duration),