TestProxyWebSocketXForwardedFor verifies that for WebSocket Upgrade requests, the proxy middleware appends c.RealIP() to any existing X-Forwarded-For chain, mirroring net/http/httputil.(*ProxyRequest).SetXForwarded used by the HTTP path. Regression guard for the previous "set only if empty" behavio
(t *testing.T)
| 1174 | // the proxy's own peer IP from the chain whenever upstream proxies had already |
| 1175 | // added entries. |
| 1176 | func TestProxyWebSocketXForwardedFor(t *testing.T) { |
| 1177 | tests := []struct { |
| 1178 | name string |
| 1179 | incomingXFF []string // nil = no incoming X-Forwarded-For header at all |
| 1180 | wantPrefix string // expected join of entries preceding the appended proxy RealIP |
| 1181 | }{ |
| 1182 | { |
| 1183 | name: "no incoming XFF, only proxy RealIP is set", |
| 1184 | incomingXFF: nil, |
| 1185 | wantPrefix: "", |
| 1186 | }, |
| 1187 | { |
| 1188 | name: "single-line single-entry XFF is preserved with proxy RealIP appended", |
| 1189 | incomingXFF: []string{"203.0.113.1"}, |
| 1190 | wantPrefix: "203.0.113.1", |
| 1191 | }, |
| 1192 | { |
| 1193 | name: "single-line comma-separated XFF is preserved with proxy RealIP appended", |
| 1194 | incomingXFF: []string{"203.0.113.1, 10.0.0.5"}, |
| 1195 | wantPrefix: "203.0.113.1, 10.0.0.5", |
| 1196 | }, |
| 1197 | { |
| 1198 | name: "multi-line XFF (multiple header occurrences) is joined with proxy RealIP appended", |
| 1199 | incomingXFF: []string{"203.0.113.1", "10.0.0.5"}, |
| 1200 | wantPrefix: "203.0.113.1, 10.0.0.5", |
| 1201 | }, |
| 1202 | } |
| 1203 | |
| 1204 | for _, tt := range tests { |
| 1205 | t.Run(tt.name, func(t *testing.T) { |
| 1206 | // Buffered so the upstream handler never blocks before the client reads. |
| 1207 | headerCh := make(chan http.Header, 1) |
| 1208 | |
| 1209 | upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 1210 | wsHandler := func(conn *websocket.Conn) { |
| 1211 | headerCh <- conn.Request().Header.Clone() |
| 1212 | defer conn.Close() |
| 1213 | var msg string |
| 1214 | if err := websocket.Message.Receive(conn, &msg); err == nil { |
| 1215 | _ = websocket.Message.Send(conn, msg) |
| 1216 | } |
| 1217 | } |
| 1218 | websocket.Server{Handler: wsHandler}.ServeHTTP(w, r) |
| 1219 | })) |
| 1220 | defer upstream.Close() |
| 1221 | |
| 1222 | tgtURL, _ := url.Parse(upstream.URL) |
| 1223 | e := echo.New() |
| 1224 | e.Use(ProxyWithConfig(ProxyConfig{Balancer: NewRandomBalancer([]*ProxyTarget{{URL: tgtURL}})})) |
| 1225 | proxySrv := httptest.NewServer(e) |
| 1226 | defer proxySrv.Close() |
| 1227 | |
| 1228 | proxyWSURL, _ := url.Parse(proxySrv.URL) |
| 1229 | proxyWSURL.Scheme = "ws" |
| 1230 | |
| 1231 | origin, _ := url.Parse(proxySrv.URL) |
| 1232 | cfg := &websocket.Config{ |
| 1233 | Location: proxyWSURL, |
nothing calls this directly
no test coverage detected
searching dependent graphs…