Skip to content

[🐛 Bug]: Router returns 500 Internal Server Error on WebSocket CDP connections when behind HTTP/2 reverse proxy (regression in 4.42.0) #3134

Description

@shkomio86

Description

Starting with Selenium Grid 4.42.0, the Router fails to handle WebSocket upgrade requests for CDP (/session/{id}/se/cdp) when deployed behind a reverse proxy that uses HTTP/2 (e.g., Envoy/Contour). The same setup works correctly with 4.41.0.

Environment

  • Selenium Grid version: 4.42.0-20260303 and 4.43.0-20260404 (both affected)
  • Last working version: 4.41.0-20260222
  • Deployment: Kubernetes (Helm chart), isolated components mode
  • Reverse proxy: Contour (Envoy-based) with enableWebsockets: true
  • Client: Playwright 1.60.0 (uses ws library internally)
  • OS: Linux (amd64), AWS EKS

Steps to Reproduce

  1. Deploy Selenium Grid 4.42.0+ in Kubernetes with isolated components
  2. Place an HTTP/2-capable reverse proxy (Envoy/Contour/nginx with HTTP/2) in front of the Router
  3. Create a session via the external URL (HTTPS)
  4. Attempt a WebSocket connection to /session/{sessionId}/se/cdp through the proxy

Expected Behavior

WebSocket upgrade succeeds with 101 Switching Protocols, and the CDP connection is established (as it does with 4.41.0).

Actual Behavior

Router returns 500 Internal Server Error with:

org.openqa.selenium.json.JsonException: Expected to read a START_MAP but instead have: END. Last 0 characters read:
  at org.openqa.selenium.json.JsonInput.beginObject(JsonInput.java:363)
  at org.openqa.selenium.remote.NewSessionPayload.isW3C(NewSessionPayload.java:306)
  at org.openqa.selenium.remote.NewSessionPayload.<init>(NewSessionPayload.java:64)
  at org.openqa.selenium.grid.data.SessionRequest.<init>(SessionRequest.java:63)
  at org.openqa.selenium.grid.sessionqueue.NewSessionQueue.lambda$new$1(NewSessionQueue.java:67)
  ...
  at org.openqa.selenium.grid.router.Router.execute(Router.java:89)

Root Cause Analysis

The stack trace shows the WebSocket upgrade request to /session/{id}/se/cdp is being incorrectly routed to NewSessionQueue (the POST /session handler) instead of the WebSocket handler.

This happens because:

  1. The client connects via HTTPS to the proxy, which negotiates HTTP/2 (ALPN)
  2. In HTTP/2, there are no Connection: Upgrade or Upgrade: websocket headers — WebSocket upgrades use the extended CONNECT method (RFC 8441)
  3. When Envoy forwards the request to the Router (HTTP/1.1 backend), the WebSocket upgrade headers may not be properly reconstructed
  4. The Router's new WebSocket routing code (introduced in 4.42 via PR #17146 - transparent TCP tunnel) apparently requires these headers to identify WebSocket requests
  5. Without the headers, the Router falls through to the session queue handler, which tries to parse an empty request body as JSON → JsonException

In 4.41.0, the Router matched WebSocket requests by URL path pattern (/session/{id}/se/cdp), which works regardless of headers.

Verification

Version Result
4.41.0-20260222 ✅ Works — WebSocket CDP connections succeed
4.42.0-20260303 ❌ Fails — 500 Internal Server Error
4.43.0-20260404 ❌ Fails — 500 Internal Server Error

All three versions were tested on the same cluster with the same proxy configuration.

Workaround

Pin Selenium Grid to version 4.41.0.

Suggested Fix

The Router should identify WebSocket requests by URL path pattern (e.g., /session/{id}/se/cdp) in addition to checking for Upgrade: websocket headers. This ensures compatibility with HTTP/2 proxies that may not forward traditional WebSocket upgrade headers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions