summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/responsewriter.go
diff options
context:
space:
mode:
authorfleandro <3987005+flga@users.noreply.github.com>2022-09-07 21:13:35 +0100
committerGitHub <noreply@github.com>2022-09-07 21:13:35 +0100
commitdd9813c65be3af8e222bda6e63f5eea9232c6eee (patch)
tree30357f52e5e46c85d274698778c72e9a6c89afba /modules/caddyhttp/responsewriter.go
parent1c9c8f6a13f99817cb35a9b100287da81255be21 (diff)
caddyhttp: ensure ResponseWriterWrapper and ResponseRecorder use ReadFrom if the underlying response writer implements it. (#5022)
Doing so allows for splice/sendfile optimizations when available. Fixes #4731 Co-authored-by: flga <flga@users.noreply.github.com> Co-authored-by: Matthew Holt <mholt@users.noreply.github.com>
Diffstat (limited to 'modules/caddyhttp/responsewriter.go')
-rw-r--r--modules/caddyhttp/responsewriter.go37
1 files changed, 35 insertions, 2 deletions
diff --git a/modules/caddyhttp/responsewriter.go b/modules/caddyhttp/responsewriter.go
index 374bbfb..9820b41 100644
--- a/modules/caddyhttp/responsewriter.go
+++ b/modules/caddyhttp/responsewriter.go
@@ -62,6 +62,16 @@ func (rww *ResponseWriterWrapper) Push(target string, opts *http.PushOptions) er
return ErrNotImplemented
}
+// ReadFrom implements io.ReaderFrom. It simply calls the underlying
+// ResponseWriter's ReadFrom method if there is one, otherwise it defaults
+// to io.Copy.
+func (rww *ResponseWriterWrapper) ReadFrom(r io.Reader) (n int64, err error) {
+ if rf, ok := rww.ResponseWriter.(io.ReaderFrom); ok {
+ return rf.ReadFrom(r)
+ }
+ return io.Copy(rww.ResponseWriter, r)
+}
+
// HTTPInterfaces mix all the interfaces that middleware ResponseWriters need to support.
type HTTPInterfaces interface {
http.ResponseWriter
@@ -188,9 +198,26 @@ func (rr *responseRecorder) Write(data []byte) (int, error) {
} else {
n, err = rr.buf.Write(data)
}
- if err == nil {
- rr.size += n
+
+ rr.size += n
+ return n, err
+}
+
+func (rr *responseRecorder) ReadFrom(r io.Reader) (int64, error) {
+ rr.WriteHeader(http.StatusOK)
+ var n int64
+ var err error
+ if rr.stream {
+ if rf, ok := rr.ResponseWriter.(io.ReaderFrom); ok {
+ n, err = rf.ReadFrom(r)
+ } else {
+ n, err = io.Copy(rr.ResponseWriter, r)
+ }
+ } else {
+ n, err = rr.buf.ReadFrom(r)
}
+
+ rr.size += int(n)
return n, err
}
@@ -251,4 +278,10 @@ type ShouldBufferFunc func(status int, header http.Header) bool
var (
_ HTTPInterfaces = (*ResponseWriterWrapper)(nil)
_ ResponseRecorder = (*responseRecorder)(nil)
+
+ // Implementing ReaderFrom can be such a significant
+ // optimization that it should probably be required!
+ // see PR #5022 (25%-50% speedup)
+ _ io.ReaderFrom = (*ResponseWriterWrapper)(nil)
+ _ io.ReaderFrom = (*responseRecorder)(nil)
)