* feat: add net.WebSocket
Add a WHATWG-compatible WebSocket client to the net module, backed by
Chromium's network stack via NetworkContext::CreateWebSocket(). This
gives main-process code a WebSocket that goes through the session's
proxy configuration, certificate verification, and cookie store, with
the same drop-in API shape as the browser/Node global WebSocket.
The implementation has two pieces:
- shell/browser/api/electron_api_web_socket.{h,cc}: a gin-wrapped object
that implements network.mojom.{WebSocketHandshakeClient, WebSocketClient,
WebSocketAuthenticationHandler}, drives the mojo data pipes with
back-pressure on both sides, reassembles fragmented frames, tracks
bufferedAmount, and emits low-level events.
- lib/browser/api/net-websocket.ts: a class WebSocket extends EventTarget
that implements the WHATWG surface (addEventListener, on{open,message,
error,close}, readyState, bufferedAmount, protocol, extensions,
binaryType, send(), close(), CONNECTING/OPEN/CLOSING/CLOSED) plus
Electron-specific options (headers, origin, useSessionCookies, session,
partition).
binaryType supports 'nodebuffer' (default), 'arraybuffer', and 'blob'.
useSessionCookies defaults to false, matching net.request(). The Origin
header defaults to the http(s) equivalent of the WebSocket URL's origin
so that the connection looks first-party for SameSite cookie purposes;
it can be overridden with the origin option.
Main process only for now; webRequest interception is a known follow-up.
* fix: address review findings and migrate WebSocketWrapper to gin::Wrappable
Migrate WebSocketWrapper from gin_helper::DeprecatedWrappable to
gin::Wrappable (cppgc-based, electron/electron#47922):
- Add kElectronWebSocket wrappable pointer tag.
- Replace Pin()/Unpin() with gin_helper::SelfKeepAlive, cleared on teardown.
- Replace base::WeakPtrFactory with gin::WeakCellFactory + gin::WrapPersistent
for callbacks; add Trace() to visit the weak cell.
- Annotate mojo::Receiver/Remote fields with GC_PLUGIN_IGNORE (browser process
doesn't need execution-context tracking), matching UtilityProcessWrapper.
- Public constructor for cppgc::MakeGarbageCollected; Create() returns T*.
Spec and correctness fixes:
- Drop the unused WebSocketAuthenticationHandler. The 'login' event it emitted
was never bridged to the WHATWG-only TS surface, leaving the mojo
OnAuthRequired callback orphaned and the connection hung on a 401/407
challenge until V8 GC. Pass NullRemote() so the network service fails the
challenge fast (matching WebSocketConnectorImpl). Drop the 'authenticated
proxies' claim from the docs.
- Serialize the send queue so a Blob send (which must read asynchronously)
doesn't let a later string/ArrayBuffer send overtake it on the wire.
- Set readyState to CLOSED before dispatching the 'error' event, per the
WebSocket spec ordering rules.
- Stop nulling the wrapper on close so bufferedAmount reflects untransmitted
bytes (it must not reset to zero) and continues to count post-close sends.
- Use WebIDL [Clamp] semantics for the close() code argument.
- Disable permessage-deflate on the test ws server; it isn't the subject under
test and ws@7's deflate close path can race a server-initiated close.
* chore: correct copyright holder in new files
* fix: address review feedback
- Track all bytes queued in the JS send chain (not just Blob reads) so
bufferedAmount is accurate while a non-Blob send is waiting behind an
asynchronous Blob read.
- Surface the network failure message and net error in CloseEvent.reason
for connection failures (the WHATWG 'error' Event has no payload). Failure
reasons from the network service already embed the net error name; only
append it for internally-generated failures.
- Emit a Node Buffer from the C++ side via electron::Buffer::Copy() instead
of a raw ArrayBuffer, avoiding a TS-side wrap on the default 'nodebuffer'
path.
- Drop the redundant disconnect handler on the WebSocket remote; the
WebSocketClient receiver and the remote terminate at the same WebSocketImpl
in the network process.
* chore: remove accidentally committed lock file
6.3 KiB
Class: WebSocket extends EventTarget
Create WebSocket connections from the main process using Chromium's native networking library
Process: Main
net.WebSocket is a drop-in replacement for the WHATWG WebSocket
interface that routes the connection through Chromium's network stack rather
than Node.js. Use it when you want a main-process WebSocket connection that:
- Uses the system or session proxy configuration (PAC, WPAD).
- Validates TLS certificates against the platform trust store and the session's certificate verification policy.
- Honors session-level configuration (custom CA, host resolution rules, etc.).
- Sends the session's cookies (when
useSessionCookiesis enabled).
The class implements the standard WebSocket interface
(an EventTarget), so
code written against the browser or Node.js global WebSocket works without
changes:
const { app, net } = require('electron')
app.whenReady().then(() => {
const ws = new net.WebSocket('wss://echo.websocket.events')
ws.onopen = () => ws.send('hello')
ws.onmessage = (event) => {
console.log('received', event.data)
ws.close()
}
})
net.WebSocket can only be used after the application emits the ready event.
new WebSocket(url[, protocols])
urlstring - The URL to connect to. The scheme must bews:orwss:(http:andhttps:are accepted and rewritten to their WebSocket equivalents, as in the browser).protocolsstring | string[] | WebSocketOptions (optional) - One or more WebSocket subprotocols, or an Electron-specific options object.
Passing an options object as the second argument is an Electron extension; the
two-argument form new net.WebSocket(url, protocols) is fully compatible with
the WHATWG constructor.
Static Properties
WebSocket.CONNECTING Readonly
An Integer constant equal to 0, the readyState value while the opening
handshake is in progress.
WebSocket.OPEN Readonly
An Integer constant equal to 1, the readyState value once the connection
is established.
WebSocket.CLOSING Readonly
An Integer constant equal to 2, the readyState value while the closing
handshake is in progress.
WebSocket.CLOSED Readonly
An Integer constant equal to 3, the readyState value once the connection
is closed.
Instance Properties
ws.url Readonly
A string representing the resolved URL of the connection.
ws.readyState Readonly
An Integer representing the current state of the connection: one of
WebSocket.CONNECTING (0), WebSocket.OPEN (1), WebSocket.CLOSING
(2), or WebSocket.CLOSED (3).
ws.bufferedAmount Readonly
An Integer representing the number of bytes of application data that have
been queued via send() but not yet handed off to the network.
ws.protocol Readonly
A string containing the subprotocol selected by the server. The empty string
until the connection is open or if the server did not select a subprotocol.
ws.extensions Readonly
A string containing the extensions negotiated by the server (for example
permessage-deflate).
ws.binaryType
A string controlling how incoming binary messages are exposed on the
message event. Can be nodebuffer, arraybuffer, or blob. The default is
nodebuffer.
'nodebuffer' is an Electron extension that delivers binary messages as
Buffer objects, which is generally
the most convenient representation in the main process. Set binaryType to
'arraybuffer' or 'blob' for behavior identical to the renderer
WebSocket.
ws.onopen
A Function | null event handler for the open event. Equivalent to calling
addEventListener('open', ...).
ws.onmessage
A Function | null event handler for the message event. Equivalent to
calling addEventListener('message', ...).
ws.onerror
A Function | null event handler for the error event. Equivalent to calling
addEventListener('error', ...).
ws.onclose
A Function | null event handler for the close event. Equivalent to calling
addEventListener('close', ...).
Instance Methods
ws.send(data)
datastring | ArrayBufferLike | ArrayBufferView | Blob - The data to send. Strings are sent as text frames; everything else is sent as a binary frame.
Enqueues data to be transmitted to the server. Throws an
InvalidStateError DOMException if readyState is CONNECTING.
ws.close([code][, reason])
codeInteger (optional) - The WebSocket close code. Must be1000or in the range3000–4999.reasonstring (optional) - A human-readable close reason. Must encode to no more than 123 bytes of UTF-8.
Closes the connection. Calling close() while still CONNECTING aborts the
handshake.
Events
net.WebSocket is an EventTarget,
not an EventEmitter. Listen with addEventListener() or the corresponding
on* event handler property:
open- Emitted when the connection is established and the opening handshake has completed. After this event,protocolandextensionsreflect the values negotiated with the server.message- Emitted with aMessageEventwhen a message arrives.event.datais astringfor text frames, or aBuffer,ArrayBuffer, orBlob(perbinaryType) for binary frames.error- Emitted when the connection fails. Always followed by acloseevent.close- Emitted with aCloseEvent(code,reason,wasClean) when the connection is closed for any reason. When the connection fails (for example, the handshake is rejected or the network is unreachable),codeis1006and Electron setsreasonto a short description of the underlying network error so that the failure is diagnosable without a debugger attached.