Skip to content

Commit

Permalink
lib,src: use Response URL as WebAssembly location
Browse files Browse the repository at this point in the history
As per Section 3 of the WebAssembly Web API spec.

PR-URL: #42842
Refs: #42701
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
  • Loading branch information
tniessen authored and targos committed Apr 28, 2022
1 parent 7b70144 commit ad82694
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 1 deletion.
4 changes: 4 additions & 0 deletions lib/internal/bootstrap/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ function setupFetch() {
throw new ERR_WEBASSEMBLY_RESPONSE('body has already been used');
}

if (response.url) {
streamState.setURL(response.url);
}

// Pass all data from the response body to the WebAssembly compiler.
for await (const chunk of response.body) {
streamState.push(chunk);
Expand Down
12 changes: 12 additions & 0 deletions src/node_wasm_web_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Local<Function> WasmStreamingObject::Initialize(Environment* env) {
t->InstanceTemplate()->SetInternalFieldCount(
WasmStreamingObject::kInternalFieldCount);

env->SetProtoMethod(t, "setURL", SetURL);
env->SetProtoMethod(t, "push", Push);
env->SetProtoMethod(t, "finish", Finish);
env->SetProtoMethod(t, "abort", Abort);
Expand Down Expand Up @@ -75,6 +76,17 @@ void WasmStreamingObject::New(const FunctionCallbackInfo<Value>& args) {
new WasmStreamingObject(env, args.This());
}

void WasmStreamingObject::SetURL(const FunctionCallbackInfo<Value>& args) {
WasmStreamingObject* obj;
ASSIGN_OR_RETURN_UNWRAP(&obj, args.Holder());
CHECK(obj->streaming_);

CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsString());
Utf8Value url(Environment::GetCurrent(args)->isolate(), args[0]);
obj->streaming_->SetUrl(url.out(), url.length());
}

void WasmStreamingObject::Push(const FunctionCallbackInfo<Value>& args) {
WasmStreamingObject* obj;
ASSIGN_OR_RETURN_UNWRAP(&obj, args.Holder());
Expand Down
1 change: 1 addition & 0 deletions src/node_wasm_web_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class WasmStreamingObject final : public BaseObject {

private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetURL(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Push(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Finish(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Abort(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down
Binary file added test/fixtures/crash.wasm
Binary file not shown.
1 change: 1 addition & 0 deletions test/fixtures/crash.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(module (func (export "crash") unreachable))
23 changes: 22 additions & 1 deletion test/parallel/test-wasm-web-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async function testRequest(handler) {
const server = createServer((_, res) => handler(res)).unref().listen(0);
await events.once(server, 'listening');
const { port } = server.address();
return fetch(`http://127.0.0.1:${port}/`);
return fetch(`http://127.0.0.1:${port}/foo.wasm`);
}

// Runs the given function both with the promise itself and as a continuation
Expand Down Expand Up @@ -223,4 +223,25 @@ function testCompileStreamingRejectionUsingFetch(responseCallback, rejection) {
name: 'TypeError',
message: /terminated/
});

// Test "Developer-Facing Display Conventions" described in the WebAssembly
// Web API specification.
await testCompileStreaming(() => testRequest((res) => {
// Respond with a WebAssembly module that only exports a single function,
// which only contains an 'unreachable' instruction.
res.setHeader('Content-Type', 'application/wasm');
res.end(fixtures.readSync('crash.wasm'));
}), async (modPromise) => {
// Call the WebAssembly function and check that the error stack contains the
// correct "WebAssembly location" as per the specification.
const mod = await modPromise;
const instance = new WebAssembly.Instance(mod);
assert.throws(() => instance.exports.crash(), (err) => {
const stack = err.stack.split(/\n/g);
assert.strictEqual(stack[0], 'RuntimeError: unreachable');
assert.match(stack[1],
/^\s*at http:\/\/127\.0\.0\.1:\d+\/foo\.wasm:wasm-function\[0\]:0x22$/);
return true;
});
});
})().then(common.mustCall());

0 comments on commit ad82694

Please sign in to comment.