Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ FetchContent_Declare(llhttp
URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v8.1.0.tar.gz"
EXCLUDE_FROM_ALL)
FetchContent_Declare(UrlLib
GIT_REPOSITORY https://github.com/BabylonJS/UrlLib.git
GIT_TAG 0c991337a1160ba7a2d062bf8e342d0a66f48dc9
# Repoint upstream after BabylonJS/UrlLib#38 merges.
GIT_REPOSITORY https://github.com/bkaradzic-microsoft/UrlLib.git
GIT_TAG 85e8f026d8cb54fd6ed298b6c0be9bdadb67dcc8
EXCLUDE_FROM_ALL)
FetchContent_Declare(quickjs-ng
GIT_REPOSITORY https://github.com/quickjs-ng/quickjs.git
Expand Down
6 changes: 5 additions & 1 deletion Core/Node-API-JSI/Include/napi/napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2368,7 +2368,11 @@ ObjectWrap<T>::DefineClass(napi_env env,
descriptor.setProperty(rt, "set", jsi::Function::createFromHostFunction(rt, name, 0,
[env, setter{p.instanceSetter}, data{p.data}](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value {
T* nativeObject{Unwrap(env, thisVal.getObject(rt))};
(nativeObject->*setter)({env, thisVal, args, count, nullptr, data}, {env, {rt, args[0]}});
try {
(nativeObject->*setter)({env, thisVal, args, count, nullptr, data}, {env, {rt, args[0]}});
} catch (const Error& error) {
throw jsi::JSError(rt, jsi::Value{rt, static_cast<const jsi::Object&>(error.Value())});
}
return {};
}));
}
Expand Down
39 changes: 34 additions & 5 deletions Polyfills/XMLHttpRequest/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,47 @@
Minimal implementation of XMLHttpRequest required to support the Babylon.js RequestFile method. Under the hood, XMLHttpRequest is implemented using various platform-specific APIs in the UrlLib dependency.

## Event listening
We do not support `onload`-style event listeners. Instead, you should listen to events using `addEventListener`. At the moment, we only support the following events:
Events can be observed with `addEventListener` or the corresponding
`onreadystatechange`, `onload`, `onerror`, `onloadend`, and `onabort` properties. Handlers receive
an event whose `target` and `currentTarget` are the request, and run with the request as `this`.
`readystatechange` dispatches an `Event`; `load`, `error`, `abort`, and `loadend` dispatch
`ProgressEvent` instances (`lengthComputable === false`, `loaded === total === 0`).
Missing constructors are installed without replacing host-provided ones.
Both registration styles share registration order, retain handlers across requests, and
observe removals or property reassignment before a listener's turn. Duplicate
`addEventListener` registrations are ignored. Primitive property assignments clear the
handler; non-callable objects are retained by identity but are not invoked.
Callbacks are owned by JavaScript so a handler capturing its own XHR does not keep an
otherwise unreachable request alive. Exceptions are reported to the runtime's
unhandled-exception handler without preventing later listeners from running.
`stopImmediatePropagation()` skips later listeners on the same request, including
when called through `Event.prototype`; `stopPropagation()` does not.
At the moment, we only support the following events:
* `loadend`
* `readystatechange`
* `error` (fired on a transport failure or a non-`2xx` HTTP response, before `loadend`)
* `load` (fired after any completed HTTP response, including non-`2xx` responses)
* `error` (fired on a transport failure, before `loadend`)
* `abort` (fired when an active request is aborted, before `loadend`)

Active `abort()` dispatches `readystatechange`, `abort`, and `loadend` synchronously,
with status 0 and an empty response, then returns to `UNSENT`. A request opened from
one of those callbacks is preserved. Abort before send is inert; abort after completion
clears the response without events. Unlike the previous implementation, cancellation
raises `abort`, not `error`; completed non-`2xx` responses raise `load`, not `error`.

Reopening preserves `responseType`. If validating or opening a replacement fails, the
previous response or active request remains intact. Response bodies and headers are
only exposed after successful transport completion; they are not read from an active
worker. Changing `responseType`, changing request headers, or sending again while a
send is active throws.

## Local files
Unlike the web, XMLHttpRequest supports loading local files using two schemes:
* `file:///` allows you to load from an absolute path
* `app:///` allows you to load from a relative path, either the current program or package depending on platform

## Other things to be aware of:
* Only `GET` requests are currently supported
* Only `GET` requests are supported on all platforms; `POST` support depends on the UrlLib backend
* For `readyState`, we only support `UNSENT`, `OPENED`, and `DONE`

## Transport-error diagnostics (non-standard)
Expand All @@ -26,6 +55,6 @@ tell a DNS failure from a refused connection or a missing local asset:
* `errorDetail` -- the full normalized `"<domain>:<symbol>(<code>): <detail>"` string

Both are empty strings unless the request failed at the transport layer, and are populated only
on backends that expose the detail (Apple, Linux) -- empty on Windows/Android until those
backends populate `UrlLib`'s accessors. Browsers do not expose these properties, so
on backends that expose the detail (Apple, Linux, Android) -- empty on Windows until that
backend populates `UrlLib`'s accessors. Browsers do not expose these properties, so
spec-conformant code is unaffected.
Loading
Loading