8000 Add HTTP CONNECT proxy support for WebSocket connections by dominicletz · Pull Request #148 · dominicletz/websockex · GitHub
[go: up one dir, main page]

Add HTTP CONNECT proxy support for WebSocket connections - #148

Merged
dominicletz merged 3 commits into
masterfrom
cursor/http-connect-proxy-b57e
Oct 29, 2026
Merged

dominicletz merged 3 commits into
masterfrom
cursor/http-connect-proxy-b57e

Conversation

@dominicletz
@dominicletz dominicletz commented Oct 29, 2026 •
Copy link
Copy Markdown
Owner

Summary

Adds an HTTP CONNECT proxy option for ws:// and wss:// connections. This was split out of #145 so the half-close work can land on its own.

  • proxy: accepts a URL ("http://localhost:8080" or "http://user:p%40ss@proxy.test:8080") or a map with :host, :port, and optional :username / :password.
  • The client connects to the proxy, sends CONNECT, and on 200 uses that socket for the WebSocket. wss:// upgrades the tunnel with TLS and sets server_name_indication to the target host, so the default peer verification from Verify TLS peers by default #144 still checks the destination certificate.
  • Proxy basic auth is sent when credentials are present. :socket_options apply to the TCP connection to the proxy.
WebSockex.start_link(url, module, state, proxy: "http://localhost:8080")

WebSockex.start_link(url, module, state,
  proxy: %{host: "proxy.example.com", port: 8080, username: "user", password: "secret"}
)

Tests

Connection tests cover URL credential parsing, ws:// tunneling (including Proxy-Authorization), refusing to dial the target directly when a proxy is set, socket_options on the proxy connect, and hostname verification through a tunnel.

On Elixir 1.18.4 / OTP 27, mix format --check-formatted and mix compile --warn 10000 ings-as-errors pass. mix test has the same pre-existing failure as master: open_socket rejects a hostname mismatch with supplied cacerts expects {:tls_alert, {:bad_certificate, _}}, and OTP 27 reports {:tls_alert, {:handshake_failure, _}}. The new proxy tests pass.

If CONNECT or the TLS upgrade fails after the TCP connection to the proxy succeeds, that proxy socket is not closed.

Open in Web Open in Cursor 

Note

Medium Risk
Changes core connection and TLS upgrade paths and sends proxy credentials on the wire; failed CONNECT/TLS steps may leave the proxy TCP socket open per the PR note.

Reviewed by Cursor Bugbot for commit 8621d6e. Configure here.

chgeuer and others added 2 commits October 29, 2026 21:53
This enables WebSocket connections through HTTP CONNECT proxies, which is
essential for scenarios like:
- Corporate proxy environments
- MITM proxy debugging/inspection
- Network traffic analysis

Changes to Conn module:
- Add :proxy option to connection_option type (accepts URL string or map)
- New open_socket/1 clause for SSL connections with proxy:
  1. Connect to proxy via plain TCP
  2. Send HTTP CONNECT request to establish tunnel
  3. Wait for 200 OK response
  4. Upgrade TCP socket to SSL over the tunnel
- Add helper functions:
  - parse_proxy_option/1 - handles URL strings and maps
  - send_connect_request/2 - sends HTTP CONNECT to proxy
  - receive_connect_response/3 - parses proxy response
  - parse_connect_headers/2 - consumes response headers

Usage:
  WebSockex.start_link(url, module, state,
    proxy: "http://localhost:8080"
  )

Or with a map:
  WebSockex.start_link(url, module, state,
    proxy: %{host: "proxy.example.com", port: 8080}
  )
Tunnel plain ws:// connections, send proxy basic auth, honor socket
options on the proxy connect, and set TLS SNI to the target host when
upgrading the tunnel. Cover the proxy path with connection tests.

Co-authored-by: Dominic Letz <dominicletz@users.noreply.github.com>
@cursor cursor Bot left a comment •
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix prepared fixes for all 3 issues found in the latest run.

  • ✅ Fixed: Proxy socket leak on failure
    • After the proxy TCP connect succeeds, CONNECT, response, and TLS-upgrade failures now close that socket before returning the error.
  • ✅ Fixed: IPv6 CONNECT target is malformed
    • CONNECT request-target and Host now bracket IPv6 literals, so a target such as ::1 is sent as [::1]:port.
  • ✅ Fixed: Invalid proxy config fails open
    • Unparseable proxy URLs and configs missing host or port now return an error from new/2 and open_socket/1 instead of dialing the target directly.

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 8621d6e. Configure here.

Comment thread lib/websockex/conn.ex
{:ok, Map.put(conn, :socket, socket)}
else
{:error, error} -> {:error, %WebSockex.ConnError{original: error}}
end
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proxy socket leak on failure

High Severity

After the TCP connection to the proxy succeeds, failures during CONNECT, the response read, or the TLS upgrade return an error without closing that socket. Reconnects plus auth, timeout, or handshake failures can leak file descriptors until the VM cannot open new connections.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8621d6e. Configure here.

Comment thread lib/websockex/conn.ex

request = [
"CONNECT #{host_port} HTTP/1.1\r\n",
"Host: #{host_port}\r\n",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IPv6 CONNECT target is malformed

Medium Severity

The CONNECT request formats the target as host colon port. URI.parse stores IPv6 hosts without brackets, so the request line is invalid and standards-compliant proxies reject tunnels to IPv6 destinations.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8621d6e. Configure here.

Comment thread lib/websockex/conn.ex Outdated
end
end

defp parse_proxy_option(_), do: nil
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid proxy config fails open

Medium Severity

Unparseable proxy URLs and maps missing host or port become nil. open_socket then dials the WebSocket target directly, so a misconfigured proxy option silently bypasses the intended proxy.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8621d6e. Configure here.

Close the proxy TCP socket when CONNECT, the response read, or the TLS
upgrade fails so reconnects cannot leak descriptors. Bracket IPv6 literals
in the CONNECT request-target and Host header. Reject invalid proxy
options instead of dialing the WebSocket target directly.
@dominicletz
dominicletz merged commit 3c39bcb into master Oct 29, 2026
2 checks passed
@dominicletz
dominicletz deleted the cursor/http-connect-proxy-b57e branch October 29, 2026 22:41
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.

3 participants

0