summaryrefslogtreecommitdiff
path: root/lib/internal/wasm_web_api.js
blob: 9c21864fa5699854acaef416cf77aa0b69b45346 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
'use strict';

const {
  PromiseResolve,
} = primordials;
const {
  ERR_INVALID_ARG_TYPE,
  ERR_WEBASSEMBLY_RESPONSE,
} = require('internal/errors').codes;

let undici;
function lazyUndici() {
  return undici ??= require('internal/deps/undici/undici');
}

// This is essentially an implementation of a v8::WasmStreamingCallback, except
// that it is implemented in JavaScript because the fetch() implementation is
// difficult to use from C++. See lib/internal/process/pre_execution.js and
// src/node_wasm_web_api.cc that interact with this function.
function wasmStreamingCallback(streamState, source) {
  (async () => {
    const response = await PromiseResolve(source);
    if (!(response instanceof lazyUndici().Response)) {
      throw new ERR_INVALID_ARG_TYPE(
        'source', ['Response', 'Promise resolving to Response'], response);
    }

    const contentType = response.headers.get('Content-Type');
    if (contentType !== 'application/wasm') {
      throw new ERR_WEBASSEMBLY_RESPONSE(
        `has unsupported MIME type '${contentType}'`);
    }

    if (!response.ok) {
      throw new ERR_WEBASSEMBLY_RESPONSE(
        `has status code ${response.status}`);
    }

    if (response.bodyUsed !== false) {
      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.
    const { body } = response;
    if (body != null) {
      for await (const chunk of body) {
        streamState.push(chunk);
      }
    }
  })().then(() => {
    // No error occurred. Tell the implementation that the stream has ended.
    streamState.finish();
  }, (err) => {
    // An error occurred, either because the given object was not a valid
    // and usable Response or because a network error occurred.
    streamState.abort(err);
  });
}

module.exports = {
  wasmStreamingCallback,
};