Skip to content
Open
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
90 changes: 86 additions & 4 deletions deps/undici/src/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

* [Guides](#guides)
* [Update `llhttp`](#update-llhttp)
* [Update `milo`](#update-milo)
* [Lint](#lint)
* [Test](#test)
* [Coverage](#coverage)
Expand Down Expand Up @@ -59,7 +60,7 @@ npm i
> This requires [docker](https://www.docker.com/) installed on your machine.

```bash
npm run build:wasm
npm run build-wasm
```

#### Copy the sources to `undici`
Expand All @@ -83,13 +84,94 @@ cp src/native/api.h build/llhttp.h <your-path-to-undici>/deps/llhttp/include/
```bash
cd <your-path-to-undici>

npm run build:wasm
npm run build:llhttp
```

#### Commit the contents of lib/llhttp

Create a commit which includes all of the updated files in lib/llhttp.

<a id="update-milo"></a>
### Update `milo`

Milo is built from the upstream sources vendored in `deps/milo`, using its own
Dockerfile rather than a prebuilt npm package. Updating it is manual, like llhttp.
The standalone release CommonJS modules and their license are saved in `lib/milo`.

The current vendored release is 0.8.5 at commit
`2ec4642184f20cd1803e30650becc54bbd575c6c`.

#### Clone milo and checkout a release

```sh
git clone https://github.com/ShogunPanda/milo.git
cd milo
git checkout v0.8.5
```

#### Copy the sources into Undici

Replace the previous contents of `deps/milo` with the following files and
directories from the selected release, preserving their layout:

```sh
cp Dockerfile Makefile.toml rust-toolchain.toml LICENSE.md README.md CODE_OF_CONDUCT.md <your-path-to-undici>/deps/milo/
cp -R macros scripts <your-path-to-undici>/deps/milo/
mkdir -p <your-path-to-undici>/deps/milo/parser
cp parser/*.toml parser/*.lock parser/*.md <your-path-to-undici>/deps/milo/parser/
cp -R parser/src <your-path-to-undici>/deps/milo/parser/
```

Keep the Cargo manifests and all three lockfiles (`macros/Cargo.lock`,
`parser/Cargo.lock` and `scripts/Cargo.lock`), Rust binding generators and JavaScript
template. Preserve Undici's build adjustments: the Docker image digest, pinned
cargo-make version, Binaryen checksums and `--locked` Cargo builds. Update the
checksums for both Linux architectures whenever Binaryen is updated.
Do not copy `parser/tests`, `parser/examples`, `.git`, upstream workflows,
`target`, `dist`, or prebuilt npm packages. Use a clean checkout so no local build
outputs are included. When selecting a newer release, update the version and
full commit recorded above.

#### Build and copy the release artifacts

Docker is the only build tool required on the host. The upstream image installs
Rust, cargo-make and Binaryen, then runs `makers wasm` in an internal copy of the
read-only source checkout. See [milo's Docker build instructions](https://github.com/ShogunPanda/milo#building-webassembly-with-docker).

From Undici, build the vendored sources:

```sh
cd <your-path-to-undici>
npm run build:milo
```

`build/milo.js` follows those instructions, mounts `deps/milo` read-only, and
copies only these release artifacts:

```text
release/package-cjs/src/simd/index.js -> lib/milo/simd.js
release/package-cjs/src/no-simd/index.js -> lib/milo/no-simd.js
release/package-cjs/LICENSE.md -> lib/milo/LICENSE.md
```

Each JavaScript module already embeds its WASM binary in base64. Separate `.wasm`
files, unbundled modules, debug packages and package metadata are not copied.
Temporary Docker outputs are removed when the script finishes. The script does
not download or update milo's sources; Docker still downloads the image and build
dependencies as needed.

The shared-builtin CI job removes the bundled Milo modules and rebuilds them
before compiling Node.js, so that it cannot silently reuse prebuilt artifacts.
The npm package contains only the license and the two bundled JavaScript modules;
`lib/milo/binary`, `lib/milo/src` and separate WASM files are excluded.

#### Submit the update

Include the updated sources in `deps/milo`, generated files in `lib/milo` and
the documentation update in a manually prepared PR. This step prepares milo's
build inputs; it does not modify
the runtime parser, llhttp's build script or any workflows.

<a id="update-wpts"></a>
### Update `WPTs`

Expand Down Expand Up @@ -176,9 +258,9 @@ Use the "Create release PR" github action to generate a release PR.
If you are packaging `undici` for a distro, this might help if you would like to use
an unbundled version instead of bundling one in `libnode.so`.

To enable this, pass `EXTERNAL_PATH=/path/to/global/node_modules/undici` to `build/wasm.js`.
To enable this, pass `EXTERNAL_PATH=/path/to/global/node_modules/undici` to `build/llhttp.js`.
Pass this path with `loader.js` appended to `--shared-builtin-undici/undici-path` in Node.js's `configure.py`.
If building on a non-Alpine Linux distribution, you may need to also set the `WASM_CC`, `WASM_CFLAGS`, `WASM_LDFLAGS` and `WASM_LDLIBS` environment variables before running `build/wasm.js`.
If building on a non-Alpine Linux distribution, you may need to also set the `WASM_CC`, `WASM_CFLAGS`, `WASM_LDFLAGS` and `WASM_LDLIBS` environment variables before running `build/llhttp.js`.
Similarly, you can set the `WASM_OPT` environment variable to utilize your own `wasm-opt` optimizer.

<a id="benchmarks"></a>
Expand Down
28 changes: 25 additions & 3 deletions deps/undici/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,24 @@ Using [benchmark-http2.js](https://github.com/nodejs/undici/blob/main/benchmarks

Node.js includes a built-in `fetch()` implementation powered by undici starting from Node.js v18. However, there are important differences between using the built-in fetch and installing undici as a separate module.

### WebAssembly requirement

Undici's HTTP/1 parser requires WebAssembly. There is no alternative parser when
WebAssembly is unavailable, for example in Node.js configurations where
`--jitless` disables it. The existence of `fetch` does not imply that it can make
HTTP/1 requests in that environment.

When the HTTP/1 parser is needed without WebAssembly, Client and dispatcher
requests fail with an `Error` whose code is `ERR_WEBASSEMBLY_NOT_SUPPORTED`.
`fetch` rejects with a `TypeError` carrying that error in `error.cause`. Importing
Undici, accessing `fetch`, and using `Headers`, `FormData`, `Request`, or `Response`
do not themselves require the HTTP/1 parser.

The error is defined locally in Undici and does not depend on Node.js providing
that error code. For built-in fetch, this behavior depends on the bundled Undici
version. Node.js receives upstream fixes through its normal vendored Undici
update, rather than changes to the generated bundle alone.

### Built-in Fetch (Node.js v18+)

Node.js's built-in fetch is powered by a bundled version of undici:
Expand Down Expand Up @@ -773,14 +791,18 @@ and `undici.Agent`) which will enable the family autoselection algorithm when es

## Collaborators

* [__Daniele Belardi__](https://github.com/dnlup), <https://www.npmjs.com/~dnlup>
* [__Ethan Arrowood__](https://github.com/ethan-arrowood), <https://www.npmjs.com/~ethan_arrowood>
* [__Aras Abbasi__](https://github.com/Uzlopak)
* [__Carlos Fuentes__](https://github.com/metcoder95), <https://www.npmjs.com/~metcoder95>
* [__Ethan Arrowood__](https://github.com/Ethan-Arrowood), <https://www.npmjs.com/~ethan_arrowood>
* [__Matteo Collina__](https://github.com/mcollina), <https://www.npmjs.com/~matteo.collina>
* [__Matthew Aitken__](https://github.com/KhafraDev), <https://www.npmjs.com/~khaf>
* [__Mert Can Altin__](https://github.com/mertcanaltin), <https://www.npmjs.com/~mertcanaltin>
* [__Robert Nagy__](https://github.com/ronag), <https://www.npmjs.com/~ronag>
* [__Szymon Marczak__](https://github.com/szmarczak), <https://www.npmjs.com/~szmarczak>
* [__Trivikram Kamat__](https://github.com/trivikr), <https://www.npmjs.com/~trivikr>
* [__tsctx__](https://github.com/tsctx)

## Past Collaborators
* [__Szymon Marczak__](https://github.com/szmarczak), <https://www.npmjs.com/~szmarczak>
* [__Tomas Della Vedova__](https://github.com/delvedor), <https://www.npmjs.com/~delvedor>

### Releasers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ if (process.argv[2] === '--docker') {
cmd += ` --mount type=bind,source=${ROOT}/lib/llhttp,target=/home/node/build/lib/llhttp \
--mount type=bind,source=${ROOT}/build,target=/home/node/build/build \
--mount type=bind,source=${ROOT}/deps,target=/home/node/build/deps \
-t ${WASM_BUILDER_CONTAINER} node build/wasm.js`
-t ${WASM_BUILDER_CONTAINER} node build/llhttp.js`
console.log(`> ${cmd}\n\n`)
execSync(cmd, { stdio: 'inherit' })
process.exit(0) // eslint-disable-line n/no-process-exit
Expand Down
53 changes: 53 additions & 0 deletions deps/undici/src/build/milo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict'

const { execFileSync } = require('node:child_process')
const { chmod, mkdtemp, readFile, cp, rm, mkdir } = require('node:fs/promises')
const { resolve } = require('node:path')

const artifacts = {
'release/package-cjs/src/no-simd/index.js': 'no-simd.js',
'release/package-cjs/src/simd/index.js': 'simd.js',
'release/package-cjs/LICENSE.md': 'LICENSE.md'
}

function docker (...args) {
return execFileSync('docker', args, { stdio: 'inherit' })
}

async function buildMilo () {
// Setup some folders
const source = resolve(__dirname, '../deps/milo')
const destination = resolve(__dirname, '../lib/milo')
const temporary = await mkdtemp(resolve(__dirname, '../deps/.build-'))
const imageFile = resolve(temporary, 'id')

try {
await chmod(temporary, 0o777)
docker('build', '--iidfile', imageFile, source)

const image = (await readFile(imageFile, 'utf8')).trim()
if (!/^sha256:[a-f0-9]{64}$/.test(image)) {
throw new Error('Docker did not return a valid milo build image ID')
}

// Follow upstream's README: sources are read-only; only results are mounted writable.
const sourceMount = `type=bind,source=${source},target=/src,readonly`
const outputMount = `type=bind,source=${temporary},target=/output`
docker('run', '--rm', '--mount', sourceMount, '--mount', outputMount, image)

// Clean the destination directory and recreate it before copying artifacts.
await rm(destination, { recursive: true, force: true })
await mkdir(destination, { recursive: true })

// Copy artifacts from the temporary build output to the destination directory.
for (const [from, to] of Object.entries(artifacts)) {
await cp(resolve(temporary, from), resolve(destination, to))
}

console.log(`Milo release artifacts saved in ${destination}`)
} finally {
await rm(temporary, { recursive: true, force: true })
}
}

buildMilo()
76 changes: 76 additions & 0 deletions deps/undici/src/deps/milo/CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
36 changes: 36 additions & 0 deletions deps/undici/src/deps/milo/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
FROM ghcr.io/nodejs/wasm-builder@sha256:542fdbef9fa6eb003cc1eb89a9f3e6b967359471fdb29db4910c54474e70911d

USER root

ARG BINARYEN_VERSION=123
ARG RUST_TOOLCHAIN=nightly-2026-07-29
ARG CARGO_MAKE_VERSION=0.37.24

RUN set -eux; \
case "$(uname -m)" in \
x86_64) binaryen_arch=x86_64; binaryen_sha256=e959f2170af4c20c552e9de3a0253704d6a9d2766e8fdb88e4d6ac4bae9388fe ;; \
aarch64) binaryen_arch=aarch64; binaryen_sha256=4b6bd61ba6cd3b18c993b4657d93426c782f9b91b74be0d38018cd8be1319376 ;; \
*) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;; \
esac; \
wget -q "https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_VERSION}/binaryen-version_${BINARYEN_VERSION}-${binaryen_arch}-linux.tar.gz" -O /tmp/binaryen.tar.gz; \
echo "${binaryen_sha256} /tmp/binaryen.tar.gz" | sha256sum -c -; \
tar -xzf /tmp/binaryen.tar.gz -C /tmp; \
install -m 0755 "/tmp/binaryen-version_${BINARYEN_VERSION}/bin/wasm-opt" /usr/local/bin/wasm-opt; \
rm -rf /tmp/binaryen.tar.gz "/tmp/binaryen-version_${BINARYEN_VERSION}"

USER node

RUN set -eux; \
rustup toolchain install "${RUST_TOOLCHAIN}" --profile minimal; \
rustup target add wasm32-unknown-unknown --toolchain "${RUST_TOOLCHAIN}"; \
rustup component add rust-src --toolchain "${RUST_TOOLCHAIN}"; \
cargo +"${RUST_TOOLCHAIN}" install cargo-make --version "${CARGO_MAKE_VERSION}" --locked

ENV PATH="/home/node/.cargo/bin:${PATH}"
ENV RUSTUP_TOOLCHAIN=${RUST_TOOLCHAIN}

WORKDIR /workspace/parser

# Build from an internal copy so Cargo and the build tasks cannot modify the
# read-only source mount. Only the generated WASM artifacts are written out.
CMD ["sh", "-ec", "cp -a /src /tmp/milo && cd /tmp/milo/parser && makers wasm && mkdir -p /output && cp -a /tmp/milo/dist/wasm/. /output/"]
7 changes: 7 additions & 0 deletions deps/undici/src/deps/milo/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ISC License

Copyright (c) 2023, and above Paolo Insogna, NearForm and other contributors

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Loading
Loading