Skip to content

fix(sandbox): relay WebSocket frames after HTTP 101 Switching Protocols#1

Open
davidpeden3 wants to merge 1 commit intomainfrom
fix/websocket-101-upgrade-relay
Open

fix(sandbox): relay WebSocket frames after HTTP 101 Switching Protocols#1
davidpeden3 wants to merge 1 commit intomainfrom
fix/websocket-101-upgrade-relay

Conversation

@davidpeden3
Copy link
Copy Markdown
Owner

Summary

Fixes the egress proxy dropping WebSocket frames after a successful HTTP CONNECT + 101 Switching Protocols response. The L7 REST relay treated 101 as a generic 1xx informational response, forwarding headers then returning to the HTTP parsing loop — which blocks or drops the subsequent WebSocket/upgraded protocol frames.

Related Issue

Changes

  • provider.rs: Added RelayOutcome enum with Reusable, Consumed, and Upgraded { overflow } variants to replace the bool return from relay methods
  • rest.rs: Detect 101 before the generic 1xx handler in relay_response(), forward headers to client, capture overflow bytes, return Upgraded outcome. Updated relay_http_request_with_resolver to return RelayOutcome. Updated all tests for new return type.
  • relay.rs: relay_rest() and relay_passthrough_with_credentials() switch to tokio::io::copy_bidirectional on Upgraded outcome, forwarding any overflow bytes first

Testing

  • All 322 existing tests pass
  • New test relay_response_101_switching_protocols_returns_overflow validates 101 detection, header forwarding, and overflow capture
  • End-to-end tested: built patched binary, deployed to K3s sandbox on two machines, verified WebSocket frames relay through the proxy (OpenClaw node successfully paired with remote gateway through fully sandboxed proxy)

Checklist

  • Conventional commit format
  • DCO sign-off
  • Tests pass (cargo test --package openshell-sandbox)
  • No unrelated changes

The L7 REST proxy treats 101 Switching Protocols as a generic 1xx
informational response via is_bodiless_response(), forwarding the
headers and returning to the HTTP parsing loop. After a 101, the
connection has been upgraded (e.g. to WebSocket) and subsequent bytes
are protocol frames, not HTTP requests. The relay loop either blocks
or silently drops them.

This patch:
- Adds RelayOutcome::Upgraded variant to signal protocol upgrades
- Detects 101 responses before the generic 1xx handler in
  relay_response(), capturing any overflow bytes read past the headers
- Switches relay_rest() and relay_passthrough_with_credentials() to
  raw bidirectional TCP copy (tokio::io::copy_bidirectional) after
  receiving an Upgraded outcome
- Adds a test verifying 101 response handling and overflow capture

This enables WebSocket connections (OpenClaw node meshes, Discord/Slack
bots) to work from inside fully sandboxed environments.

Fixes: NVIDIA#652
Related: NVIDIA/NemoClaw#409

Signed-off-by: David Peden <davidpeden3@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant