Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
caddyhttp: Fix trailers when recording responses (fixes #3236)
Matthew Holt committed
Apr 20, 2020 at 21:06 UTC
026937fab54de4a840e25e676cd8998030a6778a
2 files changed
+11
-39
modules/caddyhttp/caddyhttp.go
-13
@@ -165,19 +165,6 @@ func (ws WeakString) String() string {
165
return string(ws)
166
}
167
168
-// CopyHeader copies HTTP headers by completely
169
-// replacing dest with src. (This allows deletions
170
-// to be propagated, assuming src started as a
171
-// consistent copy of dest.)
172
-func CopyHeader(dest, src http.Header) {
173
- for field := range dest {
174
- delete(dest, field)
175
- }
176
- for field, val := range src {
177
- dest[field] = val
178
- }
179
-}
180
-
168
// StatusCodeMatches returns true if a real HTTP status code matches
169
// the configured status code, which may be either a real HTTP status
170
// code or an integer representing a class of codes (e.g. 4 for all
modules/caddyhttp/responsewriter.go
+11
-26
@@ -80,7 +80,6 @@ type responseRecorder struct {
80
buf *bytes.Buffer
81
shouldBuffer ShouldBufferFunc
82
size int
83
- header http.Header
83
wroteHeader bool
84
stream bool
85
}
@@ -122,46 +121,34 @@ type responseRecorder struct {
121
// }
122
// // process the buffered response here
123
//
125
-// After a response has been buffered, remember that any upstream header
126
-// manipulations are only manifest in the recorder's Header(), not the
127
-// Header() of the underlying ResponseWriter. Thus if you wish to inspect
128
-// or change response headers, you either need to use rec.Header(), or
129
-// copy rec.Header() into w.Header() first (see caddyhttp.CopyHeader).
124
+// The header map is not buffered; i.e. the ResponseRecorder's Header()
125
+// method returns the same header map of the underlying ResponseWriter.
126
+// This is a crucial design decision to allow HTTP trailers to be
127
+// flushed properly (https://github.com/caddyserver/caddy/issues/3236).
128
//
131
-// Once you are ready to write the response, there are two ways you can do
132
-// it. The easier way is to have the recorder do it:
129
+// Once you are ready to write the response, there are two ways you can
130
+// do it. The easier way is to have the recorder do it:
131
//
132
// rec.WriteResponse()
133
//
134
// This writes the recorded response headers as well as the buffered body.
135
// Or, you may wish to do it yourself, especially if you manipulated the
138
-// buffered body. First you will need to copy the recorded headers, then
139
-// write the headers with the recorded status code, then write the body
140
-// (this example writes the recorder's body buffer, but you might have
141
-// your own body to write instead):
136
+// buffered body. First you will need to write the headers with the
137
+// recorded status code, then write the body (this example writes the
138
+// recorder's body buffer, but you might have your own body to write
139
+// instead):
140
//
143
-// caddyhttp.CopyHeader(w.Header(), rec.Header())
141
// w.WriteHeader(rec.Status())
142
// io.Copy(w, rec.Buffer())
143
//
144
func NewResponseRecorder(w http.ResponseWriter, buf *bytes.Buffer, shouldBuffer ShouldBufferFunc) ResponseRecorder {
148
- // copy the current response header into this buffer so
149
- // that any header manipulations on the buffered header
150
- // are consistent with what would be written out
151
- hdr := make(http.Header)
152
- CopyHeader(hdr, w.Header())
145
return &responseRecorder{
146
ResponseWriterWrapper: &ResponseWriterWrapper{ResponseWriter: w},
147
buf: buf,
148
shouldBuffer: shouldBuffer,
157
- header: hdr,
149
}
150
}
151
161
-func (rr *responseRecorder) Header() http.Header {
162
- return rr.header
163
-}
164
-
152
func (rr *responseRecorder) WriteHeader(statusCode int) {
153
if rr.wroteHeader {
154
return
@@ -173,12 +160,11 @@ func (rr *responseRecorder) WriteHeader(statusCode int) {
160
if rr.shouldBuffer == nil {
161
rr.stream = true
162
} else {
176
- rr.stream = !rr.shouldBuffer(rr.statusCode, rr.header)
163
+ rr.stream = !rr.shouldBuffer(rr.statusCode, rr.ResponseWriterWrapper.Header())
164
}
165
166
// if not buffered, immediately write header
167
if rr.stream {
181
- CopyHeader(rr.ResponseWriterWrapper.Header(), rr.header)
168
rr.ResponseWriterWrapper.WriteHeader(rr.statusCode)
169
}
170
}
@@ -224,7 +210,6 @@ func (rr *responseRecorder) WriteResponse() error {
210
if rr.stream {
211
return nil
212
}
227
- CopyHeader(rr.ResponseWriterWrapper.Header(), rr.header)
213
if rr.statusCode == 0 {
214
// could happen if no handlers actually wrote anything,
215
// and this prevents a panic; status must be > 0