Skip to content

Commit

Permalink
lib: add WebSocket client
Browse files Browse the repository at this point in the history
fixup

add test

lint

fixup

update doc/node.1

PR-URL: #49830
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
  • Loading branch information
KhafraDev authored and targos committed Nov 11, 2023
1 parent 5bca8fe commit a01050d
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 20 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,5 +360,6 @@ module.exports = {
WritableStream: 'readable',
WritableStreamDefaultWriter: 'readable',
WritableStreamDefaultController: 'readable',
WebSocket: 'readable',
},
};
10 changes: 10 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,14 @@ added: v12.3.0

Enable experimental WebAssembly module support.

### `--experimental-websocket`

<!-- YAML
added: REPLACEME
-->

Enable experimental [`WebSocket`][] support.

### `--force-context-aware`

<!-- YAML
Expand Down Expand Up @@ -2220,6 +2228,7 @@ Node.js options that are allowed are:
* `--experimental-vm-modules`
* `--experimental-wasi-unstable-preview1`
* `--experimental-wasm-modules`
* `--experimental-websocket`
* `--force-context-aware`
* `--force-fips`
* `--force-node-api-uncaught-exceptions-policy`
Expand Down Expand Up @@ -2687,6 +2696,7 @@ done
[`NODE_OPTIONS`]: #node_optionsoptions
[`NO_COLOR`]: https://no-color.org
[`SlowBuffer`]: buffer.md#class-slowbuffer
[`WebSocket`]: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
[`YoungGenerationSizeFromSemiSpaceSize`]: https://chromium.googlesource.com/v8/v8.git/+/refs/tags/10.3.129/src/heap/heap.cc#328
[`dns.lookup()`]: dns.md#dnslookuphostname-options-callback
[`dns.setDefaultResultOrder()`]: dns.md#dnssetdefaultresultorderorder
Expand Down
13 changes: 13 additions & 0 deletions doc/api/globals.md
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,17 @@ The object that acts as the namespace for all W3C
[WebAssembly][webassembly-org] related functionality. See the
[Mozilla Developer Network][webassembly-mdn] for usage and compatibility.

## `WebSocket`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental.
A browser-compatible implementation of [`WebSocket`][]. Enable this API
with the [`--experimental-websocket`][] CLI flag.

## Class: `WritableStream`

<!-- YAML
Expand Down Expand Up @@ -999,6 +1010,7 @@ A browser-compatible implementation of [`WritableStreamDefaultWriter`][].
[CommonJS module]: modules.md
[ECMAScript module]: esm.md
[Web Crypto API]: webcrypto.md
[`--experimental-websocket`]: cli.md#--experimental-websocket
[`--no-experimental-fetch`]: cli.md#--no-experimental-fetch
[`--no-experimental-global-customevent`]: cli.md#--no-experimental-global-customevent
[`--no-experimental-global-webcrypto`]: cli.md#--no-experimental-global-webcrypto
Expand Down Expand Up @@ -1033,6 +1045,7 @@ A browser-compatible implementation of [`WritableStreamDefaultWriter`][].
[`TransformStream`]: webstreams.md#class-transformstream
[`URLSearchParams`]: url.md#class-urlsearchparams
[`URL`]: url.md#class-url
[`WebSocket`]: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
[`WritableStreamDefaultController`]: webstreams.md#class-writablestreamdefaultcontroller
[`WritableStreamDefaultWriter`]: webstreams.md#class-writablestreamdefaultwriter
[`WritableStream`]: webstreams.md#class-writablestream
Expand Down
3 changes: 3 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ Use this flag to enable ShadowRealm support.
.It Fl -experimental-test-coverage
Enable code coverage in the test runner.
.
.It Fl -experimental-websocket
Enable experimental support for the WebSocket API.
.
.It Fl -no-experimental-fetch
Disable experimental support for the Fetch API.
.
Expand Down
48 changes: 28 additions & 20 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ function prepareExecution(options) {
setupTraceCategoryState();
setupInspectorHooks();
setupWarningHandler();
setupFetch();
setupUndici();
setupWebCrypto();
setupCustomEvent();
setupCodeCoverage();
Expand Down Expand Up @@ -262,9 +262,9 @@ function setupWarningHandler() {
}

// https://fetch.spec.whatwg.org/
function setupFetch() {
if (getEmbedderOptions().noBrowserGlobals ||
getOptionValue('--no-experimental-fetch')) {
// https://websockets.spec.whatwg.org/
function setupUndici() {
if (getEmbedderOptions().noBrowserGlobals) {
return;
}

Expand All @@ -278,12 +278,6 @@ function setupFetch() {
return undici;
}

async function fetch(input, init = undefined) {
return lazyUndici().fetch(input, init);
}

defineOperation(globalThis, 'fetch', fetch);

function lazyInterface(name) {
return {
configurable: true,
Expand All @@ -297,17 +291,31 @@ function setupFetch() {
};
}

ObjectDefineProperties(globalThis, {
FormData: lazyInterface('FormData'),
Headers: lazyInterface('Headers'),
Request: lazyInterface('Request'),
Response: lazyInterface('Response'),
});
if (!getOptionValue('--no-experimental-fetch')) {
async function fetch(input, init = undefined) {
return lazyUndici().fetch(input, init);
}

// The WebAssembly Web API: https://webassembly.github.io/spec/web-api
internalBinding('wasm_web_api').setImplementation((streamState, source) => {
require('internal/wasm_web_api').wasmStreamingCallback(streamState, source);
});
defineOperation(globalThis, 'fetch', fetch);

ObjectDefineProperties(globalThis, {
FormData: lazyInterface('FormData'),
Headers: lazyInterface('Headers'),
Request: lazyInterface('Request'),
Response: lazyInterface('Response'),
});

// The WebAssembly Web API: https://webassembly.github.io/spec/web-api
internalBinding('wasm_web_api').setImplementation((streamState, source) => {
require('internal/wasm_web_api').wasmStreamingCallback(streamState, source);
});
}

if (getOptionValue('--experimental-websocket')) {
ObjectDefineProperties(globalThis, {
WebSocket: lazyInterface('WebSocket'),
});
}
}

// TODO(aduh95): move this to internal/bootstrap/web/* when the CLI flag is
Expand Down
5 changes: 5 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,11 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
&EnvironmentOptions::experimental_fetch,
kAllowedInEnvvar,
true);
AddOption("--experimental-websocket",
"experimental WebSocket API",
&EnvironmentOptions::experimental_websocket,
kAllowedInEnvvar,
true);
AddOption("--experimental-global-customevent",
"expose experimental CustomEvent on the global scope",
&EnvironmentOptions::experimental_global_customevent,
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class EnvironmentOptions : public Options {
std::string dns_result_order;
bool enable_source_maps = false;
bool experimental_fetch = true;
bool experimental_websocket = false;
bool experimental_global_customevent = true;
bool experimental_global_web_crypto = true;
bool experimental_https_modules = false;
Expand Down
1 change: 1 addition & 0 deletions test/common/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ const webIdlExposedWindow = new Set([
'Headers',
'Request',
'Response',
'WebSocket',
]);

const nodeGlobals = new Set([
Expand Down
3 changes: 3 additions & 0 deletions test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,9 @@ if (global.ReadableStream) {
global.DecompressionStream,
);
}
if (global.WebSocket) {
knownGlobals.push(WebSocket);
}

function allowGlobals(...allowlist) {
knownGlobals = knownGlobals.concat(allowlist);
Expand Down
7 changes: 7 additions & 0 deletions test/parallel/test-websocket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Flags: --experimental-websocket
'use strict';

require('../common');
const assert = require('assert');

assert.strictEqual(typeof WebSocket, 'function');

0 comments on commit a01050d

Please sign in to comment.