aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules/caddyhttp/encode
diff options
context:
space:
mode:
Diffstat (limited to 'modules/caddyhttp/encode')
-rw-r--r--modules/caddyhttp/encode/caddyfile.go36
-rw-r--r--modules/caddyhttp/encode/encode.go30
-rw-r--r--modules/caddyhttp/encode/encode_test.go2
3 files changed, 48 insertions, 20 deletions
diff --git a/modules/caddyhttp/encode/caddyfile.go b/modules/caddyhttp/encode/caddyfile.go
index e8ea4b807..8b8657080 100644
--- a/modules/caddyhttp/encode/caddyfile.go
+++ b/modules/caddyhttp/encode/caddyfile.go
@@ -57,21 +57,7 @@ func (enc *Encode) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
d.Next() // consume directive name
prefer := []string{}
- for _, arg := range d.RemainingArgs() {
- mod, err := caddy.GetModule("http.encoders." + arg)
- if err != nil {
- return d.Errf("finding encoder module '%s': %v", mod, err)
- }
- encoding, ok := mod.New().(Encoding)
- if !ok {
- return d.Errf("module %s is not an HTTP encoding", mod)
- }
- if enc.EncodingsRaw == nil {
- enc.EncodingsRaw = make(caddy.ModuleMap)
- }
- enc.EncodingsRaw[arg] = caddyconfig.JSON(encoding, nil)
- prefer = append(prefer, arg)
- }
+ remainingArgs := d.RemainingArgs()
responseMatchers := make(map[string]caddyhttp.ResponseMatcher)
for d.NextBlock(0) {
@@ -111,6 +97,26 @@ func (enc *Encode) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
}
}
+ if len(prefer) == 0 && len(remainingArgs) == 0 {
+ remainingArgs = []string{"zstd", "gzip"}
+ }
+
+ for _, arg := range remainingArgs {
+ mod, err := caddy.GetModule("http.encoders." + arg)
+ if err != nil {
+ return d.Errf("finding encoder module '%s': %v", mod, err)
+ }
+ encoding, ok := mod.New().(Encoding)
+ if !ok {
+ return d.Errf("module %s is not an HTTP encoding", mod)
+ }
+ if enc.EncodingsRaw == nil {
+ enc.EncodingsRaw = make(caddy.ModuleMap)
+ }
+ enc.EncodingsRaw[arg] = caddyconfig.JSON(encoding, nil)
+ prefer = append(prefer, arg)
+ }
+
// use the order in which the encoders were defined.
enc.Prefer = prefer
diff --git a/modules/caddyhttp/encode/encode.go b/modules/caddyhttp/encode/encode.go
index f0d56a90d..597772ccc 100644
--- a/modules/caddyhttp/encode/encode.go
+++ b/modules/caddyhttp/encode/encode.go
@@ -156,7 +156,7 @@ func (enc *Encode) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyh
if _, ok := enc.writerPools[encName]; !ok {
continue // encoding not offered
}
- w = enc.openResponseWriter(encName, w)
+ w = enc.openResponseWriter(encName, w, r.Method == http.MethodConnect)
defer w.(*responseWriter).Close()
// to comply with RFC 9110 section 8.8.3(.3), we modify the Etag when encoding
@@ -201,14 +201,14 @@ func (enc *Encode) addEncoding(e Encoding) error {
// openResponseWriter creates a new response writer that may (or may not)
// encode the response with encodingName. The returned response writer MUST
// be closed after the handler completes.
-func (enc *Encode) openResponseWriter(encodingName string, w http.ResponseWriter) *responseWriter {
+func (enc *Encode) openResponseWriter(encodingName string, w http.ResponseWriter, isConnect bool) *responseWriter {
var rw responseWriter
- return enc.initResponseWriter(&rw, encodingName, w)
+ return enc.initResponseWriter(&rw, encodingName, w, isConnect)
}
// initResponseWriter initializes the responseWriter instance
// allocated in openResponseWriter, enabling mid-stack inlining.
-func (enc *Encode) initResponseWriter(rw *responseWriter, encodingName string, wrappedRW http.ResponseWriter) *responseWriter {
+func (enc *Encode) initResponseWriter(rw *responseWriter, encodingName string, wrappedRW http.ResponseWriter, isConnect bool) *responseWriter {
if rww, ok := wrappedRW.(*caddyhttp.ResponseWriterWrapper); ok {
rw.ResponseWriter = rww
} else {
@@ -216,6 +216,7 @@ func (enc *Encode) initResponseWriter(rw *responseWriter, encodingName string, w
}
rw.encodingName = encodingName
rw.config = enc
+ rw.isConnect = isConnect
return rw
}
@@ -230,6 +231,7 @@ type responseWriter struct {
config *Encode
statusCode int
wroteHeader bool
+ isConnect bool
}
// WriteHeader stores the status to write when the time comes
@@ -245,6 +247,14 @@ func (rw *responseWriter) WriteHeader(status int) {
rw.Header().Add("Vary", "Accept-Encoding")
}
+ // write status immediately if status is 2xx and the request is CONNECT
+ // since it means the response is successful.
+ // see: https://github.com/caddyserver/caddy/issues/6733#issuecomment-2525058845
+ if rw.isConnect && 200 <= status && status <= 299 {
+ rw.ResponseWriter.WriteHeader(status)
+ rw.wroteHeader = true
+ }
+
// write status immediately when status code is informational
// see: https://caddy.community/t/disappear-103-early-hints-response-with-encode-enable-caddy-v2-7-6/23081/5
if 100 <= status && status <= 199 {
@@ -260,6 +270,12 @@ func (enc *Encode) Match(rw *responseWriter) bool {
// FlushError is an alternative Flush returning an error. It delays the actual Flush of the underlying
// ResponseWriterWrapper until headers were written.
func (rw *responseWriter) FlushError() error {
+ // WriteHeader wasn't called and is a CONNECT request, treat it as a success.
+ // otherwise, wait until header is written.
+ if rw.isConnect && !rw.wroteHeader && rw.statusCode == 0 {
+ rw.WriteHeader(http.StatusOK)
+ }
+
if !rw.wroteHeader {
// flushing the underlying ResponseWriter will write header and status code,
// but we need to delay that until we can determine if we must encode and
@@ -288,6 +304,12 @@ func (rw *responseWriter) Write(p []byte) (int, error) {
return 0, nil
}
+ // 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)
+ }
+
// sniff content-type and determine content-length
if !rw.wroteHeader && rw.config.MinLength > 0 {
var gtMinLength bool
diff --git a/modules/caddyhttp/encode/encode_test.go b/modules/caddyhttp/encode/encode_test.go
index d76945498..83effa58c 100644
--- a/modules/caddyhttp/encode/encode_test.go
+++ b/modules/caddyhttp/encode/encode_test.go
@@ -9,7 +9,7 @@ import (
func BenchmarkOpenResponseWriter(b *testing.B) {
enc := new(Encode)
for n := 0; n < b.N; n++ {
- enc.openResponseWriter("test", nil)
+ enc.openResponseWriter("test", nil, false)
}
}