aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules/caddyhttp/reverseproxy/reverseproxy.go
diff options
context:
space:
mode:
authorWeidiDeng <[email protected]>2024-12-07 04:23:27 +0800
committerMatthew Holt <[email protected]>2024-12-20 09:37:21 -0700
commit030b6051f11e6ff6e5a936c6e4da2389aa0d0660 (patch)
tree6fa9e28306abc4a94beb679020e8630f0533a787 /modules/caddyhttp/reverseproxy/reverseproxy.go
parente4623e72aa83340f0af2d2a82c3c46fcae7f8c92 (diff)
downloadcaddy-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.go19
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