Skip to content

Commit 7633125

Browse files
authored
fix: force HTTP1 for upstream connections for WS and WSS backends (#8699)
* force HTTP1 for upstream connections for WS and WSS backends Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com> * use different clusters for mixed upstream protocols Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com> * update Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com> * fix lint Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com> --------- Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com>
1 parent 00d0895 commit 7633125

18 files changed

Lines changed: 1045 additions & 6 deletions

internal/gatewayapi/route.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2477,11 +2477,15 @@ func (t *Translator) processBackendDestinationSetting(
24772477
protocol ir.AppProtocol,
24782478
) *ir.DestinationSetting {
24792479
var dstAddrType *ir.DestinationAddressType
2480+
forceHTTP1Upstream := false
24802481

24812482
addrTypeMap := make(map[ir.DestinationAddressType]int)
24822483
backend := t.GetBackend(backendNamespace, string(backendRef.Name))
24832484
for _, ap := range backend.Spec.AppProtocols {
24842485
protocol = backendAppProtocolToIRAppProtocol(ap, protocol)
2486+
// For WebSocket backends, force HTTP/1.1 upstream to ensure Envoy can establish a successful connection,
2487+
// as WebSocket over HTTP/2 is not widely supported by upstreams and can lead to connection failures.
2488+
forceHTTP1Upstream = forceHTTP1Upstream || isWebSocketBackendAppProtocol(ap)
24852489
}
24862490

24872491
ds := &ir.DestinationSetting{Name: name}
@@ -2490,6 +2494,7 @@ func (t *Translator) processBackendDestinationSetting(
24902494
if backend.Spec.Type != nil && *backend.Spec.Type == egv1a1.BackendTypeDynamicResolver {
24912495
ds.IsDynamicResolver = true
24922496
ds.Protocol = protocol
2497+
ds.ForceHTTP1Upstream = forceHTTP1Upstream
24932498
return ds
24942499
}
24952500

@@ -2532,6 +2537,7 @@ func (t *Translator) processBackendDestinationSetting(
25322537
ds.Endpoints = dstEndpoints
25332538
ds.AddressType = dstAddrType
25342539
ds.Protocol = protocol
2540+
ds.ForceHTTP1Upstream = forceHTTP1Upstream
25352541

25362542
if backend.Spec.Fallback != nil {
25372543
// set only the secondary priority, the backend defaults to a primary priority if unset.
@@ -2564,13 +2570,24 @@ func backendAppProtocolToIRAppProtocol(ap egv1a1.AppProtocolType, defaultProtoco
25642570
switch ap {
25652571
case egv1a1.AppProtocolTypeH2C:
25662572
return ir.HTTP2
2573+
case egv1a1.AppProtocolTypeWS, egv1a1.AppProtocolTypeWSS:
2574+
return ir.HTTP
25672575
case "grpc":
25682576
return ir.GRPC
25692577
default:
25702578
return defaultProtocol
25712579
}
25722580
}
25732581

2582+
func isWebSocketBackendAppProtocol(ap egv1a1.AppProtocolType) bool {
2583+
switch ap {
2584+
case egv1a1.AppProtocolTypeWS, egv1a1.AppProtocolTypeWSS:
2585+
return true
2586+
default:
2587+
return false
2588+
}
2589+
}
2590+
25742591
func getStatPattern(routeContext RouteContext, parentRef *RouteParentContext, controllerName string) string {
25752592
var pattern string
25762593
var envoyProxy *egv1a1.EnvoyProxy
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
gateways:
2+
- apiVersion: gateway.networking.k8s.io/v1
3+
kind: Gateway
4+
metadata:
5+
namespace: envoy-gateway
6+
name: gateway-1
7+
spec:
8+
gatewayClassName: envoy-gateway-class
9+
listeners:
10+
- name: http
11+
protocol: HTTP
12+
port: 80
13+
allowedRoutes:
14+
namespaces:
15+
from: All
16+
httpRoutes:
17+
- apiVersion: gateway.networking.k8s.io/v1
18+
kind: HTTPRoute
19+
metadata:
20+
namespace: default
21+
name: httproute-ws
22+
spec:
23+
parentRefs:
24+
- namespace: envoy-gateway
25+
name: gateway-1
26+
rules:
27+
- matches:
28+
- path:
29+
value: "/ws"
30+
backendRefs:
31+
- group: gateway.envoyproxy.io
32+
kind: Backend
33+
name: backend-ws
34+
- apiVersion: gateway.networking.k8s.io/v1
35+
kind: HTTPRoute
36+
metadata:
37+
namespace: default
38+
name: httproute-wss
39+
spec:
40+
parentRefs:
41+
- namespace: envoy-gateway
42+
name: gateway-1
43+
rules:
44+
- matches:
45+
- path:
46+
value: "/wss"
47+
backendRefs:
48+
- group: gateway.envoyproxy.io
49+
kind: Backend
50+
name: backend-wss
51+
- apiVersion: gateway.networking.k8s.io/v1
52+
kind: HTTPRoute
53+
metadata:
54+
namespace: default
55+
name: httproute-h2c
56+
spec:
57+
parentRefs:
58+
- namespace: envoy-gateway
59+
name: gateway-1
60+
rules:
61+
- matches:
62+
- path:
63+
value: "/h2c"
64+
backendRefs:
65+
- group: gateway.envoyproxy.io
66+
kind: Backend
67+
name: backend-h2c
68+
backends:
69+
- apiVersion: gateway.envoyproxy.io/v1alpha1
70+
kind: Backend
71+
metadata:
72+
name: backend-ws
73+
namespace: default
74+
spec:
75+
appProtocols:
76+
- gateway.envoyproxy.io/ws
77+
endpoints:
78+
- ip:
79+
address: 10.244.0.28
80+
port: 3000
81+
- apiVersion: gateway.envoyproxy.io/v1alpha1
82+
kind: Backend
83+
metadata:
84+
name: backend-wss
85+
namespace: default
86+
spec:
87+
appProtocols:
88+
- gateway.envoyproxy.io/wss
89+
endpoints:
90+
- fqdn:
91+
hostname: websocket.example.com
92+
port: 443
93+
tls:
94+
wellKnownCACertificates: System
95+
sni: websocket.example.com
96+
- apiVersion: gateway.envoyproxy.io/v1alpha1
97+
kind: Backend
98+
metadata:
99+
name: backend-h2c
100+
namespace: default
101+
spec:
102+
appProtocols:
103+
- gateway.envoyproxy.io/h2c
104+
endpoints:
105+
- fqdn:
106+
hostname: primary.foo.com
107+
port: 3000

0 commit comments

Comments
 (0)