lib: add WebSocket client

fixup

add test

lint

fixup

update doc/node.1

PR-URL: https://github.com/nodejs/node/pull/49830
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
This commit is contained in:
Khafra 2023-09-28 09:01:30 -04:00 committed by GitHub
parent a4fdb1abe0
commit e28dbe1c2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 72 additions and 20 deletions

View File

@ -361,5 +361,6 @@ module.exports = {
WritableStream: 'readable',
WritableStreamDefaultWriter: 'readable',
WritableStreamDefaultController: 'readable',
WebSocket: 'readable',
},
};

View File

@ -738,6 +738,14 @@ added: v12.3.0
Enable experimental WebAssembly module support.
### `--experimental-websocket`
<!-- YAML
added: REPLACEME
-->
Enable experimental [`WebSocket`][] support.
### `--force-context-aware`
<!-- YAML
@ -2248,6 +2256,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`
@ -2715,6 +2724,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

View File

@ -1018,6 +1018,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
@ -1052,6 +1063,7 @@ A browser-compatible implementation of [`WritableStreamDefaultWriter`][].
[ECMAScript module]: esm.md
[Navigator API]: https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object
[Web Crypto API]: webcrypto.md
[`--experimental-websocket`]: cli.md#--experimental-websocket
[`--no-experimental-global-customevent`]: cli.md#--no-experimental-global-customevent
[`--no-experimental-global-webcrypto`]: cli.md#--no-experimental-global-webcrypto
[`AbortController`]: https://developer.mozilla.org/en-US/docs/Web/API/AbortController
@ -1085,6 +1097,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

View File

@ -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.
.

View File

@ -78,7 +78,7 @@ function prepareExecution(options) {
setupTraceCategoryState();
setupInspectorHooks();
setupWarningHandler();
setupFetch();
setupUndici();
setupWebCrypto();
setupCustomEvent();
setupCodeCoverage();
@ -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;
}
@ -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,
@ -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

View File

@ -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,

View File

@ -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;

View File

@ -123,6 +123,7 @@ const webIdlExposedWindow = new Set([
'Headers',
'Request',
'Response',
'WebSocket',
]);
const nodeGlobals = new Set([

View File

@ -370,6 +370,9 @@ if (global.ReadableStream) {
global.DecompressionStream,
);
}
if (global.WebSocket) {
knownGlobals.push(WebSocket);
}
function allowGlobals(...allowlist) {
knownGlobals = knownGlobals.concat(allowlist);

View File

@ -0,0 +1,7 @@
// Flags: --experimental-websocket
'use strict';
require('../common');
const assert = require('assert');
assert.strictEqual(typeof WebSocket, 'function');