Skip to content

Commit 4a880ef

Browse files
authored
[browser] detect and assert engine features (#88846)
1 parent 24f5cbb commit 4a880ef

File tree

5 files changed

+50
-2
lines changed

5 files changed

+50
-2
lines changed

src/mono/wasm/runtime/http.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,26 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
import { wrap_as_cancelable_promise } from "./cancelable-promise";
5-
import { Module, loaderHelpers } from "./globals";
5+
import { ENVIRONMENT_IS_NODE, Module, loaderHelpers } from "./globals";
66
import { MemoryViewType, Span } from "./marshal";
77
import type { VoidPtr } from "./types/emscripten";
88

9+
10+
function verifyEnvironment() {
11+
if (typeof globalThis.fetch !== "function" || typeof globalThis.AbortController !== "function") {
12+
const message = ENVIRONMENT_IS_NODE
13+
? "Please install `node-fetch` and `node-abort-controller` npm packages to enable HTTP client support."
14+
: "This browser doesn't support fetch API. Please use a modern browser.";
15+
throw new Error(message);
16+
}
17+
}
18+
919
export function http_wasm_supports_streaming_response(): boolean {
1020
return typeof Response !== "undefined" && "body" in Response.prototype && typeof ReadableStream === "function";
1121
}
1222

1323
export function http_wasm_create_abort_controler(): AbortController {
24+
verifyEnvironment();
1425
return new AbortController();
1526
}
1627

@@ -38,6 +49,7 @@ export function http_wasm_fetch_bytes(url: string, header_names: string[], heade
3849
}
3950

4051
export function http_wasm_fetch(url: string, header_names: string[], header_values: string[], option_names: string[], option_values: any[], abort_controller: AbortController, body: string | Uint8Array | null): Promise<ResponseExtension> {
52+
verifyEnvironment();
4153
mono_assert(url && typeof url === "string", "expected url string");
4254
mono_assert(header_names && header_values && Array.isArray(header_names) && Array.isArray(header_values) && header_names.length === header_values.length, "expected headerNames and headerValues arrays");
4355
mono_assert(option_names && option_values && Array.isArray(option_names) && Array.isArray(option_values) && option_names.length === option_values.length, "expected headerNames and headerValues arrays");

src/mono/wasm/runtime/loader/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33

44
import type { DotnetHostBuilder } from "../types";
55
import { mono_exit } from "./exit";
6+
import { verifyEnvironment } from "./polyfills";
67
import { HostBuilder, createEmscripten } from "./run";
78

89
// export external API
910
const dotnet: DotnetHostBuilder = new HostBuilder();
1011
const exit = mono_exit;
1112
const legacyEntrypoint = createEmscripten;
1213

14+
verifyEnvironment();
15+
1316
export { dotnet, exit };
1417
export default legacyEntrypoint;

src/mono/wasm/runtime/loader/polyfills.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
import MonoWasmThreads from "consts:monoWasmThreads";
15

26
import type { DotnetModuleInternal } from "../types/internal";
37
import { INTERNAL, ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, loaderHelpers, ENVIRONMENT_IS_WEB } from "./globals";
@@ -14,6 +18,19 @@ const URLPolyfill = class URL {
1418
}
1519
};
1620

21+
export function verifyEnvironment() {
22+
mono_assert(ENVIRONMENT_IS_SHELL || typeof globalThis.URL === "function", "This browser/engine doesn't support URL API. Please use a modern version.");
23+
mono_assert(typeof globalThis.BigInt64Array === "function", "This browser/engine doesn't support BigInt64Array API. Please use a modern version.");
24+
if (MonoWasmThreads) {
25+
mono_assert(!ENVIRONMENT_IS_SHELL && !ENVIRONMENT_IS_NODE, "This build of dotnet is multi-threaded, it doesn't support shell environments like V8 or NodeJS.");
26+
mono_assert(globalThis.SharedArrayBuffer !== undefined, "SharedArrayBuffer is not enabled on this page. Please use a modern browser and set Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy http headers. See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements");
27+
mono_assert(typeof globalThis.EventTarget === "function", "This browser/engine doesn't support EventTarget API. Please use a modern version.");
28+
}
29+
30+
// TODO detect other (WASM) features that are required for the runtime
31+
// See https://github.com/dotnet/runtime/issues/84574
32+
}
33+
1734
export async function detect_features_and_polyfill(module: DotnetModuleInternal): Promise<void> {
1835

1936
const scriptUrlQuery =/* webpackIgnore: true */import.meta.url;

src/mono/wasm/runtime/loader/worker.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
14
import { MonoConfig } from "../types";
25
import { MonoConfigInternal } from "../types/internal";
36
import { deep_merge_config, normalizeConfig } from "./config";

src/mono/wasm/runtime/web-socket.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import MonoWasmThreads from "consts:monoWasmThreads";
55

66
import { prevent_timer_throttling } from "./scheduling";
77
import { Queue } from "./queue";
8-
import { createPromiseController } from "./globals";
8+
import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, createPromiseController } from "./globals";
99
import { setI32, localHeapViewU8 } from "./memory";
1010
import { VoidPtr } from "./types/emscripten";
1111
import { PromiseController } from "./types/internal";
@@ -26,7 +26,20 @@ let mono_wasm_web_socket_close_warning = false;
2626
const ws_send_buffer_blocking_threshold = 65536;
2727
const emptyBuffer = new Uint8Array();
2828

29+
function verifyEnvironment() {
30+
if (ENVIRONMENT_IS_SHELL) {
31+
throw new Error("WebSockets are not supported in shell JS engine.");
32+
}
33+
if (typeof globalThis.WebSocket !== "function") {
34+
const message = ENVIRONMENT_IS_NODE
35+
? "Please install `ws` npm package to enable networking support."
36+
: "This browser doesn't support WebSocket API. Please use a modern browser.";
37+
throw new Error(message);
38+
}
39+
}
40+
2941
export function ws_wasm_create(uri: string, sub_protocols: string[] | null, receive_status_ptr: VoidPtr, onClosed: (code: number, reason: string) => void): WebSocketExtension {
42+
verifyEnvironment();
3043
mono_assert(uri && typeof uri === "string", () => `ERR12: Invalid uri ${typeof uri}`);
3144

3245
const ws = new globalThis.WebSocket(uri, sub_protocols || undefined) as WebSocketExtension;

0 commit comments

Comments
 (0)