@marcel91200 / caddy Mirror · read-only / commits / 026937fa
Fork 0

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