aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules/caddyhttp/encode/encode.go
diff options
context:
space:
mode:
authorWeidiDeng <[email protected]>2024-12-19 08:59:26 +0800
committerWeidiDeng <[email protected]>2024-12-19 08:59:26 +0800
commit1e1daf909d6440fb508ff9309b2debe00b6ae1cf (patch)
treeb4eb3dc3182b4451dad1731df7757f08fe1afb83 /modules/caddyhttp/encode/encode.go
parent6790c0e38abcc534c4b3365b6e438148001fd6df (diff)
downloadcaddy-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.go43
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 {