diff options
author | WeidiDeng <[email protected]> | 2024-12-19 08:59:26 +0800 |
---|---|---|
committer | WeidiDeng <[email protected]> | 2024-12-19 08:59:26 +0800 |
commit | 1e1daf909d6440fb508ff9309b2debe00b6ae1cf (patch) | |
tree | b4eb3dc3182b4451dad1731df7757f08fe1afb83 /modules/caddyhttp/encode/encode.go | |
parent | 6790c0e38abcc534c4b3365b6e438148001fd6df (diff) | |
download | caddy-1e1daf909d6440fb508ff9309b2debe00b6ae1cf.tar.gz caddy-1e1daf909d6440fb508ff9309b2debe00b6ae1cf.zip |
try to use sendfile when encode is enabled
Diffstat (limited to 'modules/caddyhttp/encode/encode.go')
-rw-r--r-- | modules/caddyhttp/encode/encode.go | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/modules/caddyhttp/encode/encode.go b/modules/caddyhttp/encode/encode.go index 597772ccc..148cb73fb 100644 --- a/modules/caddyhttp/encode/encode.go +++ b/modules/caddyhttp/encode/encode.go @@ -347,6 +347,49 @@ func (rw *responseWriter) Write(p []byte) (int, error) { } } +type writerOnly struct { + io.Writer +} + +// copied from stdlib +const sniffLen = 512 + +// ReadFrom will try to use sendfile to copy from the reader to the response writer. +// It's only used if the response writer implements io.ReaderFrom and the data can't be compressed. +// It's based on stdlin http1.1 response writer implementation. +// https://github.com/golang/go/blob/f4e3ec3dbe3b8e04a058d266adf8e048bab563f2/src/net/http/server.go#L586 +func (rw *responseWriter) ReadFrom(r io.Reader) (int64, error) { + // WriteHeader wasn't called and is a CONNECT request, treat it as a success. + // otherwise, determine if the response should be compressed. + if rw.isConnect && !rw.wroteHeader && rw.statusCode == 0 { + rw.WriteHeader(http.StatusOK) + } + + rr, ok := rw.ResponseWriter.(io.ReaderFrom) + // sendfile can't be used anyway + if !ok { + return io.Copy(writerOnly{rw}, r) + } + + var ns int64 + // try to sniff the content type and determine if the response should be compressed + if !rw.wroteHeader && rw.config.MinLength > 0 { + var err error + ns, err = io.Copy(writerOnly{rw}, io.LimitReader(r, sniffLen)) + if err != nil || ns < sniffLen { + return ns, err + } + } + + // the response will be compressed, no sendfile support + if rw.w != nil { + nr, err := io.Copy(rw.w, r) + return nr + ns, err + } + nr, err := rr.ReadFrom(r) + return nr + ns, err +} + // Close writes any remaining buffered response and // deallocates any active resources. func (rw *responseWriter) Close() error { |