diff options
author | WeidiDeng <[email protected]> | 2024-12-07 04:23:27 +0800 |
---|---|---|
committer | Matthew Holt <[email protected]> | 2024-12-20 09:37:21 -0700 |
commit | 030b6051f11e6ff6e5a936c6e4da2389aa0d0660 (patch) | |
tree | 6fa9e28306abc4a94beb679020e8630f0533a787 /modules/caddyhttp/reverseproxy/reverseproxy.go | |
parent | e4623e72aa83340f0af2d2a82c3c46fcae7f8c92 (diff) | |
download | caddy-030b6051f11e6ff6e5a936c6e4da2389aa0d0660.tar.gz caddy-030b6051f11e6ff6e5a936c6e4da2389aa0d0660.zip |
reverseproxy: Rewrite requests and responses for websocket over http2 (#6567)
* reverse proxy: rewrite requests and responses for websocket over http2
* delete protocol pseudo-header
* modify cloned requests
* set request variable to track if it's a h2 websocket
* use request bodu
* rewrite request body
* use WebSocket instead of Websocket in the headers
* use logger check for zap loggers
* fix lint
Diffstat (limited to 'modules/caddyhttp/reverseproxy/reverseproxy.go')
-rw-r--r-- | modules/caddyhttp/reverseproxy/reverseproxy.go | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go index ba9e5f3fc..907b47b0a 100644 --- a/modules/caddyhttp/reverseproxy/reverseproxy.go +++ b/modules/caddyhttp/reverseproxy/reverseproxy.go @@ -17,6 +17,8 @@ package reverseproxy import ( "bytes" "context" + "crypto/rand" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -412,6 +414,23 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht return caddyhttp.Error(http.StatusInternalServerError, fmt.Errorf("preparing request for upstream round-trip: %v", err)) } + // websocket over http2, assuming backend doesn't support this, the request will be modified to http1.1 upgrade + // TODO: once we can reliably detect backend support this, it can be removed for those backends + if r.ProtoMajor == 2 && r.Method == http.MethodConnect && r.Header.Get(":protocol") != "" { + clonedReq.Header.Del(":protocol") + // keep the body for later use. http1.1 upgrade uses http.NoBody + caddyhttp.SetVar(clonedReq.Context(), "h2_websocket_body", clonedReq.Body) + clonedReq.Body = http.NoBody + clonedReq.Method = http.MethodGet + clonedReq.Header.Set("Upgrade", r.Header.Get(":protocol")) + clonedReq.Header.Set("Connection", "Upgrade") + key := make([]byte, 16) + _, randErr := rand.Read(key) + if randErr != nil { + return randErr + } + clonedReq.Header["Sec-WebSocket-Key"] = []string{base64.StdEncoding.EncodeToString(key)} + } // we will need the original headers and Host value if // header operations are configured; this is so that each |