diff options
author | Matthew Holt <mholt@users.noreply.github.com> | 2019-06-21 14:36:26 -0600 |
---|---|---|
committer | Matthew Holt <mholt@users.noreply.github.com> | 2019-06-21 14:36:26 -0600 |
commit | d49f762f6d9cdc2e92e8de40f0b0e99a9d0c4fc9 (patch) | |
tree | a4003b5967027faaf0cbbb6fbd7b8407a14a508c /modules/caddyhttp/responsewriter.go | |
parent | 81a9e125b54b34d453c425dbd58a3270b9568dca (diff) |
Various bug fixes and minor improvements
- Fix static responder so it doesn't replace its own headers config,
and instead replaces the actual response header values
- caddyhttp.ResponseRecorder type optionally buffers response
- Add interface guards to ensure regexp matchers get provisioned
- Use default HTTP port if one is not explicitly set
- Encode middleware writes status code 200 if not written upstream
- Templates and markdown only try to execute on text responses
- Static file server sets Content-Type based on file extension only
(this whole thing -- MIME sniffing, etc -- needs more configurability)
Diffstat (limited to 'modules/caddyhttp/responsewriter.go')
-rw-r--r-- | modules/caddyhttp/responsewriter.go | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/modules/caddyhttp/responsewriter.go b/modules/caddyhttp/responsewriter.go index 7fb45f3..e733db7 100644 --- a/modules/caddyhttp/responsewriter.go +++ b/modules/caddyhttp/responsewriter.go @@ -61,9 +61,11 @@ var ErrNotImplemented = fmt.Errorf("method not implemented") type responseRecorder struct { *ResponseWriterWrapper - wroteHeader bool - statusCode int - buf *bytes.Buffer + wroteHeader bool + statusCode int + buf *bytes.Buffer + shouldBuffer func(status int) bool + stream bool } // NewResponseRecorder returns a new ResponseRecorder that can be @@ -76,6 +78,16 @@ type responseRecorder struct { // responses by wrapping Write and WriteHeader methods instead of // buffering whole response bodies. // +// Recorders optionally buffer the response. When the headers are +// to be written, shouldBuffer will be called with the status +// code that is being written. The rest of the headers can be read +// from w.Header(). If shouldBuffer returns true, the response +// will be buffered. You can know the response was buffered if +// the Buffered() method returns true. If the response was not +// buffered, Buffered() will return false and that means the +// response bypassed the recorder and was written directly to the +// underlying writer. +// // Before calling this function in a middleware handler, make a // new buffer or obtain one from a pool (use the sync.Pool) type. // Using a pool is generally recommended for performance gains; @@ -85,12 +97,13 @@ type responseRecorder struct { // The returned recorder can be used in place of w when calling // the next handler in the chain. When that handler returns, you // can read the status code from the recorder's Status() method. -// The response body fills buf, and the headers are available in -// w.Header(). -func NewResponseRecorder(w http.ResponseWriter, buf *bytes.Buffer) ResponseRecorder { +// The response body fills buf if it was buffered, and the headers +// are available via w.Header(). +func NewResponseRecorder(w http.ResponseWriter, buf *bytes.Buffer, shouldBuffer func(status int) bool) ResponseRecorder { return &responseRecorder{ ResponseWriterWrapper: &ResponseWriterWrapper{ResponseWriter: w}, buf: buf, + shouldBuffer: shouldBuffer, } } @@ -100,10 +113,22 @@ func (rr *responseRecorder) WriteHeader(statusCode int) { } rr.statusCode = statusCode rr.wroteHeader = true + + // decide whether we should buffer the response + if rr.shouldBuffer == nil { + return + } + rr.stream = !rr.shouldBuffer(rr.statusCode) + if rr.stream { + rr.ResponseWriterWrapper.WriteHeader(rr.statusCode) + } } func (rr *responseRecorder) Write(data []byte) (int, error) { rr.WriteHeader(http.StatusOK) + if rr.stream { + return rr.ResponseWriterWrapper.Write(data) + } return rr.buf.Write(data) } @@ -118,12 +143,18 @@ func (rr *responseRecorder) Buffer() *bytes.Buffer { return rr.buf } +// Buffered returns whether rr has decided to buffer the response. +func (rr *responseRecorder) Buffered() bool { + return !rr.stream +} + // ResponseRecorder is a http.ResponseWriter that records // responses instead of writing them to the client. type ResponseRecorder interface { HTTPInterfaces Status() int Buffer() *bytes.Buffer + Buffered() bool } // Interface guards |