diff options
author | WeidiDeng <[email protected]> | 2024-12-12 02:15:01 +0800 |
---|---|---|
committer | GitHub <[email protected]> | 2024-12-11 11:15:01 -0700 |
commit | bcaa8aaf114629031d10dcef0ca7680ae8163e32 (patch) | |
tree | 5f9c5921347eb6cddd11fffbc5c108066783ac3c /modules/caddyhttp/encode/encode.go | |
parent | d0e209e1da6cd6d7d61e83b851f2913ee31454f8 (diff) | |
download | caddy-bcaa8aaf114629031d10dcef0ca7680ae8163e32.tar.gz caddy-bcaa8aaf114629031d10dcef0ca7680ae8163e32.zip |
encode: write status immediate for success response for CONNECT requests (#6738)
* encode: write status immediate for success response for CONNECT requests
* fix compile
* fix test
* fix lint
* treat first write and flush for encode response writer to CONNECT request as success if status is not set explicitly
Diffstat (limited to 'modules/caddyhttp/encode/encode.go')
-rw-r--r-- | modules/caddyhttp/encode/encode.go | 30 |
1 files changed, 26 insertions, 4 deletions
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 |