tools: make undici updater build wasm from src

- modify updater to include all files required to rebuild
  wasm from what's stored in the deps/undici directory
- modify updater to build wasm from source while updating

Signed-off-by: Michael Dawson <mdawson@devrus.com>
PR-URL: https://github.com/nodejs/node/pull/54128
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
This commit is contained in:
Michael Dawson 2024-07-31 01:27:39 +00:00 committed by Michael Dawson
parent a3ff3e8cd4
commit e9deab9915
28 changed files with 20601 additions and 31 deletions

13
deps/undici/src/.c8rc.json vendored Normal file
View File

@ -0,0 +1,13 @@
{
"all": true,
"reporter": [
"lcov",
"text",
"html",
"text-summary"
],
"include": [
"lib/**/*.js",
"index.js"
]
}

8
deps/undici/src/.dockerignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Ignore everything but the stuff following the `*` with the `!`
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file
*
!package.json
!lib
!deps
!build

9
deps/undici/src/.editorconfig vendored Normal file
View File

@ -0,0 +1,9 @@
# https://editorconfig.org/
root = true
[*]
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

86
deps/undici/src/.gitignore vendored Normal file
View File

@ -0,0 +1,86 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
# lock files
package-lock.json
yarn.lock
# IDE files
.idea
.vscode
*0x
*clinic*
# Fuzzing
corpus/
crash-*
fuzz-results-*.json
# Bundle output
undici-fetch.js
/test/imports/undici-import.js
# .npmrc has platform specific value for windows
.npmrc
.tap

13
deps/undici/src/.npmignore vendored Normal file
View File

@ -0,0 +1,13 @@
*
!lib/**/*
!index.js
!index-fetch.js
# The wasm files are stored as base64 strings in the corresponding .js files
lib/llhttp/llhttp_simd.wasm
lib/llhttp/llhttp.wasm
!types/**/*
!index.d.ts
!docs/docs/**/*
!scripts/strip-comments.js

6
deps/undici/src/CODE_OF_CONDUCT.md vendored Normal file
View File

@ -0,0 +1,6 @@
# Code of Conduct
Undici is committed to upholding the Node.js Code of Conduct.
The Node.js Code of Conduct document can be found at
https://github.com/nodejs/admin/blob/main/CODE_OF_CONDUCT.md

213
deps/undici/src/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,213 @@
# Contributing to Undici
* [Guides](#guides)
* [Update `llhttp`](#update-llhttp)
* [Lint](#lint)
* [Test](#test)
* [Coverage](#coverage)
* [Releases](#releases)
* [Update `WPTs`](#update-wpts)
* [Building for externally shared node builtins](#external-builds)
* [Benchmarks](#benchmarks
* [Documentation](#documentation)
* [Developer's Certificate of Origin 1.1](#developers-certificate-of-origin)
* [Moderation Policy](#moderation-policy)
<a id="guides"></a>
## Guides
This is a collection of guides on how to run and update `undici`, and how to run different parts of the project.
<a id="update-llhttp"></a>
### Update `llhttp`
The HTTP parser used by `undici` is a WebAssembly build of [`llhttp`](https://github.com/nodejs/llhttp).
While the project itself provides a way to compile targeting WebAssembly, at the moment we embed the sources
directly and compile the module in `undici`.
The `deps/llhttp/include` folder contains the C header files, while the `deps/llhttp/src` folder contains
the C source files needed to compile the module.
The `lib/llhttp` folder contains the `.js` transpiled assets required to implement a parser.
The following are the steps required to perform an update.
#### Clone the [llhttp](https://github.com/nodejs/llhttp) project
```bash
git clone git@github.com:nodejs/llhttp.git
cd llhttp
```
#### Checkout a `llhttp` release
```bash
git checkout <tag>
```
#### Install the `llhttp` dependencies
```bash
npm i
```
#### Run the wasm build script
> This requires [docker](https://www.docker.com/) installed on your machine.
```bash
npm run build-wasm
```
#### Copy the sources to `undici`
```bash
cp build/wasm/*.js <your-path-to-undici>/lib/llhttp/
cp build/wasm/*.js.map <your-path-to-undici>/lib/llhttp/
cp build/wasm/*.d.ts <your-path-to-undici>/lib/llhttp/
cp src/native/api.c src/native/http.c build/c/llhttp.c <your-path-to-undici>/deps/llhttp/src/
cp src/native/api.h build/llhttp.h <your-path-to-undici>/deps/llhttp/include/
```
#### Build the WebAssembly module in `undici`
> This requires [docker](https://www.docker.com/) installed on your machine.
```bash
cd <your-path-to-undici>
npm run build:wasm
```
#### Commit the contents of lib/llhttp
Create a commit which includes all of the updated files in lib/llhttp.
<a id="update-wpts"></a>
### Update `WPTs`
`undici` runs a subset of the [`web-platform-tests`](https://github.com/web-platform-tests/wpt).
### Requirements:
- [Node core utils](https://github.com/nodejs/node-core-utils) setup with credentials.
To update every test, run the following commands. Typically you would only need to update the tests in a specific directory.
```bash
git node wpt resources
git node wpt interfaces
git node wpt common
git node wpt fetch
git node wpt FileAPI
git node wpt xhr
git node wpt websockets
git node wpt mimesniff
git node wpt storage
git node wpt service-workers
git node wpt eventsource
```
#### Run the tests
Run the tests to ensure that any new failures are marked as such.
You can mark tests as failing in their corresponding [status](./test/wpt/status) file.
```bash
npm run test:wpt
```
<a id="lint"></a>
### Lint
```bash
npm run lint
```
<a id="test"></a>
### Test
```bash
npm run test
```
<a id="coverage"></a>
### Coverage
```bash
npm run coverage
```
<a id="releases"></a>
### Issuing Releases
Release is automatic on commit to main which bumps the package.json version field.
Use the "Create release PR" github action to generate a release PR.
<a id="external-builds"></a>
### Building for externally shared node builtins
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`.
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`.
<a id="benchmarks"></a>
### Benchmarks
```bash
cd benchmarks && npm i && npm run bench
```
The benchmarks will be available at `http://localhost:3042`.
<a id="documentation"></a>
### Documentation
```bash
cd docs && npm i && npm run serve
```
The documentation will be available at `http://localhost:3000`.
<a id="developers-certificate-of-origin"></a>
## Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
* (a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
* (b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
* (c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
* (d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
<a id="moderation-policy"></a>
### Moderation Policy
The [Node.js Moderation Policy] applies to this project.
[Node.js Moderation Policy]: https://github.com/nodejs/admin/blob/main/Moderation-Policy.md

136
deps/undici/src/GOVERNANCE.md vendored Normal file
View File

@ -0,0 +1,136 @@
### Undici Working Group
The Node.js Undici project is governed by a Working Group (WG)
that is responsible for high-level guidance of the project.
The WG has final authority over this project including:
* Technical direction
* Project governance and process (including this policy)
* Contribution policy
* GitHub repository hosting
* Conduct guidelines
* Maintaining the list of additional Collaborators
For the current list of WG members, see the project
[README.md](./README.md#collaborators).
### Collaborators
The undici GitHub repository is
maintained by the WG and additional Collaborators who are added by the
WG on an ongoing basis.
Individuals making significant and valuable contributions are made
Collaborators and given commit-access to the project. These
individuals are identified by the WG and their addition as
Collaborators is discussed during the WG meeting.
_Note:_ If you make a significant contribution and are not considered
for commit-access log an issue or contact a WG member directly and it
will be brought up in the next WG meeting.
Modifications of the contents of the undici repository are
made on
a collaborative basis. Anybody with a GitHub account may propose a
modification via pull request and it will be considered by the project
Collaborators. All pull requests must be reviewed and accepted by a
Collaborator with sufficient expertise who is able to take full
responsibility for the change. In the case of pull requests proposed
by an existing Collaborator, an additional Collaborator is required
for sign-off. Consensus should be sought if additional Collaborators
participate and there is disagreement around a particular
modification. See _Consensus Seeking Process_ below for further detail
on the consensus model used for governance.
Collaborators may opt to elevate significant or controversial
modifications, or modifications that have not found consensus to the
WG for discussion by assigning the ***WG-agenda*** tag to a pull
request or issue. The WG should serve as the final arbiter where
required.
For the current list of Collaborators, see the project
[README.md](./README.md#collaborators). The list shall be in an
alphabetical order.
### WG Membership
WG seats are not time-limited. There is no fixed size of the WG.
However, the expected target is between 6 and 12, to ensure adequate
coverage of important areas of expertise, balanced with the ability to
make decisions efficiently.
There is no specific set of requirements or qualifications for WG
membership beyond these rules.
The WG may add additional members to the WG by unanimous consensus.
A WG member may be removed from the WG by voluntary resignation, or by
unanimous consensus of all other WG members.
Changes to WG membership should be posted in the agenda, and may be
suggested as any other agenda item (see "WG Meetings" below).
If an addition or removal is proposed during a meeting, and the full
WG is not in attendance to participate, then the addition or removal
is added to the agenda for the subsequent meeting. This is to ensure
that all members are given the opportunity to participate in all
membership decisions. If a WG member is unable to attend a meeting
where a planned membership decision is being made, then their consent
is assumed.
No more than 1/3 of the WG members may be affiliated with the same
employer. If removal or resignation of a WG member, or a change of
employment by a WG member, creates a situation where more than 1/3 of
the WG membership shares an employer, then the situation must be
immediately remedied by the resignation or removal of one or more WG
members affiliated with the over-represented employer(s).
### WG Meetings
The WG meets occasionally on Zoom. A designated moderator
approved by the WG runs the meeting. Each meeting should be
published to YouTube.
Items are added to the WG agenda that are considered contentious or
are modifications of governance, contribution policy, WG membership,
or release process.
The intention of the agenda is not to approve or review all patches;
that should happen continuously on GitHub and be handled by the larger
group of Collaborators.
Any community member or contributor can ask that something be added to
the next meeting's agenda by logging a GitHub Issue. Any Collaborator,
WG member or the moderator can add the item to the agenda by adding
the ***WG-agenda*** tag to the issue.
Prior to each WG meeting the moderator will share the Agenda with
members of the WG. WG members can add any items they like to the
agenda at the beginning of each meeting. The moderator and the WG
cannot veto or remove items.
The WG may invite persons or representatives from certain projects to
participate in a non-voting capacity.
The moderator is responsible for summarizing the discussion of each
agenda item and sends it as a pull request after the meeting.
### Consensus Seeking Process
The WG follows a
[Consensus
Seeking](http://en.wikipedia.org/wiki/Consensus-seeking_decision-making)
decision-making model.
When an agenda item has appeared to reach a consensus the moderator
will ask "Does anyone object?" as a final call for dissent from the
consensus.
If an agenda item cannot reach a consensus a WG member can call for
either a closing vote or a vote to table the issue to the next
meeting. The call for a vote must be seconded by a majority of the WG
or else the discussion will continue. Simple majority wins.
Note that changes to WG membership require a majority consensus. See
"WG Membership" above.

33
deps/undici/src/MAINTAINERS.md vendored Normal file
View File

@ -0,0 +1,33 @@
# Maintainers
This document details any and all processes relevant to project maintainers. Maintainers should feel empowered to contribute back to this document with any process changes they feel improve the overall experience for themselves and other maintainers.
## Labels
Maintainers are encouraged to use the extensive and detailed list of labels for easier repo management.
* Generally, all issues should be labelled. The most general labels are `bug`, `enhancement`, and `Status: help-wanted`.
* Issues specific to a certain aspect of the project should be labeled using one of the specificity labels listed below. For example, a bug in the `Client` class should have the `Client` and `bug` label assigned.
* Specificity labels:
* `Agent`
* `Client`
* `Docs`
* `Performance`
* `Pool`
* `Tests`
* `Types`
* Any `question` or `usage help` issues should be converted into Q&A Discussions
* `Status:` labels should be added to all open issues indicating their relative development status.
* Status labels:
* `Status: blocked`
* `Status: help-wanted`
* `Status: in-progress`
* `Status: wontfix`
* Issues and/or pull requests with an agreed upon semver status can be assigned the appropriate `semver-` label.
* Semver labels:
* `semver-major`
* `semver-minor`
* `semver-patch`
* Issues with a low-barrier of entry should be assigned the `good first issue` label.
* Do not use the `invalid` label, instead use `bug` or `Status: wontfix`.
* Duplicate issues should initially be assigned the `duplicate` label.

2
deps/undici/src/SECURITY.md vendored Normal file
View File

@ -0,0 +1,2 @@
If you believe you have found a security issue in the software in this
repository, please consult https://github.com/nodejs/node/blob/HEAD/SECURITY.md.

25
deps/undici/src/build/Dockerfile vendored Normal file
View File

@ -0,0 +1,25 @@
FROM node:22-alpine3.19@sha256:075a5cc188c3c9a49acacd481a9e8a3c9abf4223f02c658e37fdb8e9fe2c4664
ARG UID=1000
ARG GID=1000
ARG BINARYEN_VERSION=116
RUN apk add -U clang lld wasi-sdk
RUN mkdir /home/node/undici
WORKDIR /home/node/undici
RUN wget https://github.com/WebAssembly/binaryen/releases/download/version_$BINARYEN_VERSION/binaryen-version_$BINARYEN_VERSION-x86_64-linux.tar.gz && \
tar -zxvf binaryen-version_$BINARYEN_VERSION-x86_64-linux.tar.gz binaryen-version_$BINARYEN_VERSION/bin/wasm-opt && \
mv binaryen-version_$BINARYEN_VERSION/bin/wasm-opt ./ && \
rm binaryen-version_$BINARYEN_VERSION-x86_64-linux.tar.gz && \
rm -rf binaryen-version_$BINARYEN_VERSION && \
chmod +x ./wasm-opt
COPY package.json .
COPY build build
COPY deps deps
COPY lib lib
USER node

124
deps/undici/src/build/wasm.js vendored Normal file
View File

@ -0,0 +1,124 @@
'use strict'
const { execSync } = require('node:child_process')
const { writeFileSync, readFileSync } = require('node:fs')
const { join, resolve } = require('node:path')
const ROOT = resolve(__dirname, '../')
const WASM_SRC = resolve(__dirname, '../deps/llhttp')
const WASM_OUT = resolve(__dirname, '../lib/llhttp')
const DOCKERFILE = resolve(__dirname, './Dockerfile')
// These are defined by build environment
const WASM_CC = process.env.WASM_CC || 'clang'
let WASM_CFLAGS = process.env.WASM_CFLAGS || '--sysroot=/usr/share/wasi-sysroot -target wasm32-unknown-wasi'
let WASM_LDFLAGS = process.env.WASM_LDFLAGS || ''
const WASM_LDLIBS = process.env.WASM_LDLIBS || ''
// For compatibility with Node.js' `configure --shared-builtin-undici/undici-path ...`
const EXTERNAL_PATH = process.env.EXTERNAL_PATH
// These are relevant for undici and should not be overridden
WASM_CFLAGS += ' -Ofast -fno-exceptions -fvisibility=hidden -mexec-model=reactor'
WASM_LDFLAGS += ' -Wl,-error-limit=0 -Wl,-O3 -Wl,--lto-O3 -Wl,--strip-all'
WASM_LDFLAGS += ' -Wl,--allow-undefined -Wl,--export-dynamic -Wl,--export-table'
WASM_LDFLAGS += ' -Wl,--export=malloc -Wl,--export=free -Wl,--no-entry'
const WASM_OPT_FLAGS = '-O4 --converge --strip-debug --strip-dwarf --strip-producers'
const writeWasmChunk = (path, dest) => {
const base64 = readFileSync(join(WASM_OUT, path)).toString('base64')
writeFileSync(join(WASM_OUT, dest), `'use strict'
const { Buffer } = require('node:buffer')
module.exports = Buffer.from('${base64}', 'base64')
`)
}
let platform = process.env.WASM_PLATFORM
if (!platform && process.argv[2]) {
platform = execSync('docker info -f "{{.OSType}}/{{.Architecture}}"').toString().trim()
}
if (process.argv[2] === '--rm') {
const cmd = 'docker image rm llhttp_wasm_builder'
console.log(`> ${cmd}\n\n`)
try {
execSync(cmd, { stdio: 'inherit' })
} catch (e) {}
process.exit(0)
}
if (process.argv[2] === '--prebuild') {
const cmd = `docker build --platform=${platform.toString().trim()} -t llhttp_wasm_builder -f ${DOCKERFILE} ${ROOT}`
console.log(`> ${cmd}\n\n`)
execSync(cmd, { stdio: 'inherit' })
process.exit(0)
}
if (process.argv[2] === '--docker') {
let cmd = `docker run --rm -it --platform=${platform.toString().trim()}`
if (process.platform === 'linux') {
cmd += ` --user ${process.getuid()}:${process.getegid()}`
}
cmd += ` --mount type=bind,source=${ROOT}/lib/llhttp,target=/home/node/undici/lib/llhttp llhttp_wasm_builder node build/wasm.js`
console.log(`> ${cmd}\n\n`)
execSync(cmd, { stdio: 'inherit' })
process.exit(0)
}
const hasApk = (function () {
try { execSync('command -v apk'); return true } catch (error) { return false }
})()
const hasOptimizer = (function () {
try { execSync('./wasm-opt --version'); return true } catch (error) { return false }
})()
if (hasApk) {
// Gather information about the tools used for the build
const buildInfo = execSync('apk info -v').toString()
if (!buildInfo.includes('wasi-sdk')) {
console.log('Failed to generate build environment information')
process.exit(-1)
}
console.log(buildInfo)
}
// Build wasm binary
execSync(`${WASM_CC} ${WASM_CFLAGS} ${WASM_LDFLAGS} \
${join(WASM_SRC, 'src')}/*.c \
-I${join(WASM_SRC, 'include')} \
-o ${join(WASM_OUT, 'llhttp.wasm')} \
${WASM_LDLIBS}`, { stdio: 'inherit' })
if (hasOptimizer) {
execSync(`./wasm-opt ${WASM_OPT_FLAGS} -o ${join(WASM_OUT, 'llhttp.wasm')} ${join(WASM_OUT, 'llhttp.wasm')}`, { stdio: 'inherit' })
}
writeWasmChunk('llhttp.wasm', 'llhttp-wasm.js')
// Build wasm simd binary
execSync(`${WASM_CC} ${WASM_CFLAGS} -msimd128 ${WASM_LDFLAGS} \
${join(WASM_SRC, 'src')}/*.c \
-I${join(WASM_SRC, 'include')} \
-o ${join(WASM_OUT, 'llhttp_simd.wasm')} \
${WASM_LDLIBS}`, { stdio: 'inherit' })
if (hasOptimizer) {
execSync(`./wasm-opt ${WASM_OPT_FLAGS} --enable-simd -o ${join(WASM_OUT, 'llhttp_simd.wasm')} ${join(WASM_OUT, 'llhttp_simd.wasm')}`, { stdio: 'inherit' })
}
writeWasmChunk('llhttp_simd.wasm', 'llhttp_simd-wasm.js')
// For compatibility with Node.js' `configure --shared-builtin-undici/undici-path ...`
if (EXTERNAL_PATH) {
writeFileSync(join(ROOT, 'loader.js'), `
'use strict'
globalThis.__UNDICI_IS_NODE__ = true
module.exports = require('node:module').createRequire('${EXTERNAL_PATH}/loader.js')('./index-fetch.js')
delete globalThis.__UNDICI_IS_NODE__
`)
}

View File

@ -0,0 +1,815 @@
#ifndef INCLUDE_LLHTTP_H_
#define INCLUDE_LLHTTP_H_
#define LLHTTP_VERSION_MAJOR 8
#define LLHTTP_VERSION_MINOR 1
#define LLHTTP_VERSION_PATCH 0
#ifndef LLHTTP_STRICT_MODE
# define LLHTTP_STRICT_MODE 0
#endif
#ifndef INCLUDE_LLHTTP_ITSELF_H_
#define INCLUDE_LLHTTP_ITSELF_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef struct llhttp__internal_s llhttp__internal_t;
struct llhttp__internal_s {
int32_t _index;
void* _span_pos0;
void* _span_cb0;
int32_t error;
const char* reason;
const char* error_pos;
void* data;
void* _current;
uint64_t content_length;
uint8_t type;
uint8_t method;
uint8_t http_major;
uint8_t http_minor;
uint8_t header_state;
uint8_t lenient_flags;
uint8_t upgrade;
uint8_t finish;
uint16_t flags;
uint16_t status_code;
uint8_t initial_message_completed;
void* settings;
};
int llhttp__internal_init(llhttp__internal_t* s);
int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* INCLUDE_LLHTTP_ITSELF_H_ */
#ifndef LLLLHTTP_C_HEADERS_
#define LLLLHTTP_C_HEADERS_
#ifdef __cplusplus
extern "C" {
#endif
enum llhttp_errno {
HPE_OK = 0,
HPE_INTERNAL = 1,
HPE_STRICT = 2,
HPE_CR_EXPECTED = 25,
HPE_LF_EXPECTED = 3,
HPE_UNEXPECTED_CONTENT_LENGTH = 4,
HPE_UNEXPECTED_SPACE = 30,
HPE_CLOSED_CONNECTION = 5,
HPE_INVALID_METHOD = 6,
HPE_INVALID_URL = 7,
HPE_INVALID_CONSTANT = 8,
HPE_INVALID_VERSION = 9,
HPE_INVALID_HEADER_TOKEN = 10,
HPE_INVALID_CONTENT_LENGTH = 11,
HPE_INVALID_CHUNK_SIZE = 12,
HPE_INVALID_STATUS = 13,
HPE_INVALID_EOF_STATE = 14,
HPE_INVALID_TRANSFER_ENCODING = 15,
HPE_CB_MESSAGE_BEGIN = 16,
HPE_CB_HEADERS_COMPLETE = 17,
HPE_CB_MESSAGE_COMPLETE = 18,
HPE_CB_CHUNK_HEADER = 19,
HPE_CB_CHUNK_COMPLETE = 20,
HPE_PAUSED = 21,
HPE_PAUSED_UPGRADE = 22,
HPE_PAUSED_H2_UPGRADE = 23,
HPE_USER = 24,
HPE_CB_URL_COMPLETE = 26,
HPE_CB_STATUS_COMPLETE = 27,
HPE_CB_METHOD_COMPLETE = 32,
HPE_CB_VERSION_COMPLETE = 33,
HPE_CB_HEADER_FIELD_COMPLETE = 28,
HPE_CB_HEADER_VALUE_COMPLETE = 29,
HPE_CB_CHUNK_EXTENSION_NAME_COMPLETE = 34,
HPE_CB_CHUNK_EXTENSION_VALUE_COMPLETE = 35,
HPE_CB_RESET = 31
};
typedef enum llhttp_errno llhttp_errno_t;
enum llhttp_flags {
F_CONNECTION_KEEP_ALIVE = 0x1,
F_CONNECTION_CLOSE = 0x2,
F_CONNECTION_UPGRADE = 0x4,
F_CHUNKED = 0x8,
F_UPGRADE = 0x10,
F_CONTENT_LENGTH = 0x20,
F_SKIPBODY = 0x40,
F_TRAILING = 0x80,
F_TRANSFER_ENCODING = 0x200
};
typedef enum llhttp_flags llhttp_flags_t;
enum llhttp_lenient_flags {
LENIENT_HEADERS = 0x1,
LENIENT_CHUNKED_LENGTH = 0x2,
LENIENT_KEEP_ALIVE = 0x4,
LENIENT_TRANSFER_ENCODING = 0x8,
LENIENT_VERSION = 0x10
};
typedef enum llhttp_lenient_flags llhttp_lenient_flags_t;
enum llhttp_type {
HTTP_BOTH = 0,
HTTP_REQUEST = 1,
HTTP_RESPONSE = 2
};
typedef enum llhttp_type llhttp_type_t;
enum llhttp_finish {
HTTP_FINISH_SAFE = 0,
HTTP_FINISH_SAFE_WITH_CB = 1,
HTTP_FINISH_UNSAFE = 2
};
typedef enum llhttp_finish llhttp_finish_t;
enum llhttp_method {
HTTP_DELETE = 0,
HTTP_GET = 1,
HTTP_HEAD = 2,
HTTP_POST = 3,
HTTP_PUT = 4,
HTTP_CONNECT = 5,
HTTP_OPTIONS = 6,
HTTP_TRACE = 7,
HTTP_COPY = 8,
HTTP_LOCK = 9,
HTTP_MKCOL = 10,
HTTP_MOVE = 11,
HTTP_PROPFIND = 12,
HTTP_PROPPATCH = 13,
HTTP_SEARCH = 14,
HTTP_UNLOCK = 15,
HTTP_BIND = 16,
HTTP_REBIND = 17,
HTTP_UNBIND = 18,
HTTP_ACL = 19,
HTTP_REPORT = 20,
HTTP_MKACTIVITY = 21,
HTTP_CHECKOUT = 22,
HTTP_MERGE = 23,
HTTP_MSEARCH = 24,
HTTP_NOTIFY = 25,
HTTP_SUBSCRIBE = 26,
HTTP_UNSUBSCRIBE = 27,
HTTP_PATCH = 28,
HTTP_PURGE = 29,
HTTP_MKCALENDAR = 30,
HTTP_LINK = 31,
HTTP_UNLINK = 32,
HTTP_SOURCE = 33,
HTTP_PRI = 34,
HTTP_DESCRIBE = 35,
HTTP_ANNOUNCE = 36,
HTTP_SETUP = 37,
HTTP_PLAY = 38,
HTTP_PAUSE = 39,
HTTP_TEARDOWN = 40,
HTTP_GET_PARAMETER = 41,
HTTP_SET_PARAMETER = 42,
HTTP_REDIRECT = 43,
HTTP_RECORD = 44,
HTTP_FLUSH = 45
};
typedef enum llhttp_method llhttp_method_t;
enum llhttp_status {
HTTP_STATUS_CONTINUE = 100,
HTTP_STATUS_SWITCHING_PROTOCOLS = 101,
HTTP_STATUS_PROCESSING = 102,
HTTP_STATUS_EARLY_HINTS = 103,
HTTP_STATUS_RESPONSE_IS_STALE = 110,
HTTP_STATUS_REVALIDATION_FAILED = 111,
HTTP_STATUS_DISCONNECTED_OPERATION = 112,
HTTP_STATUS_HEURISTIC_EXPIRATION = 113,
HTTP_STATUS_MISCELLANEOUS_WARNING = 199,
HTTP_STATUS_OK = 200,
HTTP_STATUS_CREATED = 201,
HTTP_STATUS_ACCEPTED = 202,
HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
HTTP_STATUS_NO_CONTENT = 204,
HTTP_STATUS_RESET_CONTENT = 205,
HTTP_STATUS_PARTIAL_CONTENT = 206,
HTTP_STATUS_MULTI_STATUS = 207,
HTTP_STATUS_ALREADY_REPORTED = 208,
HTTP_STATUS_TRANSFORMATION_APPLIED = 214,
HTTP_STATUS_IM_USED = 226,
HTTP_STATUS_MISCELLANEOUS_PERSISTENT_WARNING = 299,
HTTP_STATUS_MULTIPLE_CHOICES = 300,
HTTP_STATUS_MOVED_PERMANENTLY = 301,
HTTP_STATUS_FOUND = 302,
HTTP_STATUS_SEE_OTHER = 303,
HTTP_STATUS_NOT_MODIFIED = 304,
HTTP_STATUS_USE_PROXY = 305,
HTTP_STATUS_SWITCH_PROXY = 306,
HTTP_STATUS_TEMPORARY_REDIRECT = 307,
HTTP_STATUS_PERMANENT_REDIRECT = 308,
HTTP_STATUS_BAD_REQUEST = 400,
HTTP_STATUS_UNAUTHORIZED = 401,
HTTP_STATUS_PAYMENT_REQUIRED = 402,
HTTP_STATUS_FORBIDDEN = 403,
HTTP_STATUS_NOT_FOUND = 404,
HTTP_STATUS_METHOD_NOT_ALLOWED = 405,
HTTP_STATUS_NOT_ACCEPTABLE = 406,
HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
HTTP_STATUS_REQUEST_TIMEOUT = 408,
HTTP_STATUS_CONFLICT = 409,
HTTP_STATUS_GONE = 410,
HTTP_STATUS_LENGTH_REQUIRED = 411,
HTTP_STATUS_PRECONDITION_FAILED = 412,
HTTP_STATUS_PAYLOAD_TOO_LARGE = 413,
HTTP_STATUS_URI_TOO_LONG = 414,
HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416,
HTTP_STATUS_EXPECTATION_FAILED = 417,
HTTP_STATUS_IM_A_TEAPOT = 418,
HTTP_STATUS_PAGE_EXPIRED = 419,
HTTP_STATUS_ENHANCE_YOUR_CALM = 420,
HTTP_STATUS_MISDIRECTED_REQUEST = 421,
HTTP_STATUS_UNPROCESSABLE_ENTITY = 422,
HTTP_STATUS_LOCKED = 423,
HTTP_STATUS_FAILED_DEPENDENCY = 424,
HTTP_STATUS_TOO_EARLY = 425,
HTTP_STATUS_UPGRADE_REQUIRED = 426,
HTTP_STATUS_PRECONDITION_REQUIRED = 428,
HTTP_STATUS_TOO_MANY_REQUESTS = 429,
HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL = 430,
HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
HTTP_STATUS_LOGIN_TIMEOUT = 440,
HTTP_STATUS_NO_RESPONSE = 444,
HTTP_STATUS_RETRY_WITH = 449,
HTTP_STATUS_BLOCKED_BY_PARENTAL_CONTROL = 450,
HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
HTTP_STATUS_CLIENT_CLOSED_LOAD_BALANCED_REQUEST = 460,
HTTP_STATUS_INVALID_X_FORWARDED_FOR = 463,
HTTP_STATUS_REQUEST_HEADER_TOO_LARGE = 494,
HTTP_STATUS_SSL_CERTIFICATE_ERROR = 495,
HTTP_STATUS_SSL_CERTIFICATE_REQUIRED = 496,
HTTP_STATUS_HTTP_REQUEST_SENT_TO_HTTPS_PORT = 497,
HTTP_STATUS_INVALID_TOKEN = 498,
HTTP_STATUS_CLIENT_CLOSED_REQUEST = 499,
HTTP_STATUS_INTERNAL_SERVER_ERROR = 500,
HTTP_STATUS_NOT_IMPLEMENTED = 501,
HTTP_STATUS_BAD_GATEWAY = 502,
HTTP_STATUS_SERVICE_UNAVAILABLE = 503,
HTTP_STATUS_GATEWAY_TIMEOUT = 504,
HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505,
HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506,
HTTP_STATUS_INSUFFICIENT_STORAGE = 507,
HTTP_STATUS_LOOP_DETECTED = 508,
HTTP_STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509,
HTTP_STATUS_NOT_EXTENDED = 510,
HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511,
HTTP_STATUS_WEB_SERVER_UNKNOWN_ERROR = 520,
HTTP_STATUS_WEB_SERVER_IS_DOWN = 521,
HTTP_STATUS_CONNECTION_TIMEOUT = 522,
HTTP_STATUS_ORIGIN_IS_UNREACHABLE = 523,
HTTP_STATUS_TIMEOUT_OCCURED = 524,
HTTP_STATUS_SSL_HANDSHAKE_FAILED = 525,
HTTP_STATUS_INVALID_SSL_CERTIFICATE = 526,
HTTP_STATUS_RAILGUN_ERROR = 527,
HTTP_STATUS_SITE_IS_OVERLOADED = 529,
HTTP_STATUS_SITE_IS_FROZEN = 530,
HTTP_STATUS_IDENTITY_PROVIDER_AUTHENTICATION_ERROR = 561,
HTTP_STATUS_NETWORK_READ_TIMEOUT = 598,
HTTP_STATUS_NETWORK_CONNECT_TIMEOUT = 599
};
typedef enum llhttp_status llhttp_status_t;
#define HTTP_ERRNO_MAP(XX) \
XX(0, OK, OK) \
XX(1, INTERNAL, INTERNAL) \
XX(2, STRICT, STRICT) \
XX(25, CR_EXPECTED, CR_EXPECTED) \
XX(3, LF_EXPECTED, LF_EXPECTED) \
XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \
XX(30, UNEXPECTED_SPACE, UNEXPECTED_SPACE) \
XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \
XX(6, INVALID_METHOD, INVALID_METHOD) \
XX(7, INVALID_URL, INVALID_URL) \
XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \
XX(9, INVALID_VERSION, INVALID_VERSION) \
XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \
XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \
XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \
XX(13, INVALID_STATUS, INVALID_STATUS) \
XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \
XX(15, INVALID_TRANSFER_ENCODING, INVALID_TRANSFER_ENCODING) \
XX(16, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \
XX(17, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \
XX(18, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \
XX(19, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \
XX(20, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \
XX(21, PAUSED, PAUSED) \
XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \
XX(23, PAUSED_H2_UPGRADE, PAUSED_H2_UPGRADE) \
XX(24, USER, USER) \
XX(26, CB_URL_COMPLETE, CB_URL_COMPLETE) \
XX(27, CB_STATUS_COMPLETE, CB_STATUS_COMPLETE) \
XX(32, CB_METHOD_COMPLETE, CB_METHOD_COMPLETE) \
XX(33, CB_VERSION_COMPLETE, CB_VERSION_COMPLETE) \
XX(28, CB_HEADER_FIELD_COMPLETE, CB_HEADER_FIELD_COMPLETE) \
XX(29, CB_HEADER_VALUE_COMPLETE, CB_HEADER_VALUE_COMPLETE) \
XX(34, CB_CHUNK_EXTENSION_NAME_COMPLETE, CB_CHUNK_EXTENSION_NAME_COMPLETE) \
XX(35, CB_CHUNK_EXTENSION_VALUE_COMPLETE, CB_CHUNK_EXTENSION_VALUE_COMPLETE) \
XX(31, CB_RESET, CB_RESET) \
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
XX(30, MKCALENDAR, MKCALENDAR) \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
XX(33, SOURCE, SOURCE) \
#define RTSP_METHOD_MAP(XX) \
XX(1, GET, GET) \
XX(3, POST, POST) \
XX(6, OPTIONS, OPTIONS) \
XX(35, DESCRIBE, DESCRIBE) \
XX(36, ANNOUNCE, ANNOUNCE) \
XX(37, SETUP, SETUP) \
XX(38, PLAY, PLAY) \
XX(39, PAUSE, PAUSE) \
XX(40, TEARDOWN, TEARDOWN) \
XX(41, GET_PARAMETER, GET_PARAMETER) \
XX(42, SET_PARAMETER, SET_PARAMETER) \
XX(43, REDIRECT, REDIRECT) \
XX(44, RECORD, RECORD) \
XX(45, FLUSH, FLUSH) \
#define HTTP_ALL_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
XX(30, MKCALENDAR, MKCALENDAR) \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
XX(33, SOURCE, SOURCE) \
XX(34, PRI, PRI) \
XX(35, DESCRIBE, DESCRIBE) \
XX(36, ANNOUNCE, ANNOUNCE) \
XX(37, SETUP, SETUP) \
XX(38, PLAY, PLAY) \
XX(39, PAUSE, PAUSE) \
XX(40, TEARDOWN, TEARDOWN) \
XX(41, GET_PARAMETER, GET_PARAMETER) \
XX(42, SET_PARAMETER, SET_PARAMETER) \
XX(43, REDIRECT, REDIRECT) \
XX(44, RECORD, RECORD) \
XX(45, FLUSH, FLUSH) \
#define HTTP_STATUS_MAP(XX) \
XX(100, CONTINUE, CONTINUE) \
XX(101, SWITCHING_PROTOCOLS, SWITCHING_PROTOCOLS) \
XX(102, PROCESSING, PROCESSING) \
XX(103, EARLY_HINTS, EARLY_HINTS) \
XX(110, RESPONSE_IS_STALE, RESPONSE_IS_STALE) \
XX(111, REVALIDATION_FAILED, REVALIDATION_FAILED) \
XX(112, DISCONNECTED_OPERATION, DISCONNECTED_OPERATION) \
XX(113, HEURISTIC_EXPIRATION, HEURISTIC_EXPIRATION) \
XX(199, MISCELLANEOUS_WARNING, MISCELLANEOUS_WARNING) \
XX(200, OK, OK) \
XX(201, CREATED, CREATED) \
XX(202, ACCEPTED, ACCEPTED) \
XX(203, NON_AUTHORITATIVE_INFORMATION, NON_AUTHORITATIVE_INFORMATION) \
XX(204, NO_CONTENT, NO_CONTENT) \
XX(205, RESET_CONTENT, RESET_CONTENT) \
XX(206, PARTIAL_CONTENT, PARTIAL_CONTENT) \
XX(207, MULTI_STATUS, MULTI_STATUS) \
XX(208, ALREADY_REPORTED, ALREADY_REPORTED) \
XX(214, TRANSFORMATION_APPLIED, TRANSFORMATION_APPLIED) \
XX(226, IM_USED, IM_USED) \
XX(299, MISCELLANEOUS_PERSISTENT_WARNING, MISCELLANEOUS_PERSISTENT_WARNING) \
XX(300, MULTIPLE_CHOICES, MULTIPLE_CHOICES) \
XX(301, MOVED_PERMANENTLY, MOVED_PERMANENTLY) \
XX(302, FOUND, FOUND) \
XX(303, SEE_OTHER, SEE_OTHER) \
XX(304, NOT_MODIFIED, NOT_MODIFIED) \
XX(305, USE_PROXY, USE_PROXY) \
XX(306, SWITCH_PROXY, SWITCH_PROXY) \
XX(307, TEMPORARY_REDIRECT, TEMPORARY_REDIRECT) \
XX(308, PERMANENT_REDIRECT, PERMANENT_REDIRECT) \
XX(400, BAD_REQUEST, BAD_REQUEST) \
XX(401, UNAUTHORIZED, UNAUTHORIZED) \
XX(402, PAYMENT_REQUIRED, PAYMENT_REQUIRED) \
XX(403, FORBIDDEN, FORBIDDEN) \
XX(404, NOT_FOUND, NOT_FOUND) \
XX(405, METHOD_NOT_ALLOWED, METHOD_NOT_ALLOWED) \
XX(406, NOT_ACCEPTABLE, NOT_ACCEPTABLE) \
XX(407, PROXY_AUTHENTICATION_REQUIRED, PROXY_AUTHENTICATION_REQUIRED) \
XX(408, REQUEST_TIMEOUT, REQUEST_TIMEOUT) \
XX(409, CONFLICT, CONFLICT) \
XX(410, GONE, GONE) \
XX(411, LENGTH_REQUIRED, LENGTH_REQUIRED) \
XX(412, PRECONDITION_FAILED, PRECONDITION_FAILED) \
XX(413, PAYLOAD_TOO_LARGE, PAYLOAD_TOO_LARGE) \
XX(414, URI_TOO_LONG, URI_TOO_LONG) \
XX(415, UNSUPPORTED_MEDIA_TYPE, UNSUPPORTED_MEDIA_TYPE) \
XX(416, RANGE_NOT_SATISFIABLE, RANGE_NOT_SATISFIABLE) \
XX(417, EXPECTATION_FAILED, EXPECTATION_FAILED) \
XX(418, IM_A_TEAPOT, IM_A_TEAPOT) \
XX(419, PAGE_EXPIRED, PAGE_EXPIRED) \
XX(420, ENHANCE_YOUR_CALM, ENHANCE_YOUR_CALM) \
XX(421, MISDIRECTED_REQUEST, MISDIRECTED_REQUEST) \
XX(422, UNPROCESSABLE_ENTITY, UNPROCESSABLE_ENTITY) \
XX(423, LOCKED, LOCKED) \
XX(424, FAILED_DEPENDENCY, FAILED_DEPENDENCY) \
XX(425, TOO_EARLY, TOO_EARLY) \
XX(426, UPGRADE_REQUIRED, UPGRADE_REQUIRED) \
XX(428, PRECONDITION_REQUIRED, PRECONDITION_REQUIRED) \
XX(429, TOO_MANY_REQUESTS, TOO_MANY_REQUESTS) \
XX(430, REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL, REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL) \
XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, REQUEST_HEADER_FIELDS_TOO_LARGE) \
XX(440, LOGIN_TIMEOUT, LOGIN_TIMEOUT) \
XX(444, NO_RESPONSE, NO_RESPONSE) \
XX(449, RETRY_WITH, RETRY_WITH) \
XX(450, BLOCKED_BY_PARENTAL_CONTROL, BLOCKED_BY_PARENTAL_CONTROL) \
XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, UNAVAILABLE_FOR_LEGAL_REASONS) \
XX(460, CLIENT_CLOSED_LOAD_BALANCED_REQUEST, CLIENT_CLOSED_LOAD_BALANCED_REQUEST) \
XX(463, INVALID_X_FORWARDED_FOR, INVALID_X_FORWARDED_FOR) \
XX(494, REQUEST_HEADER_TOO_LARGE, REQUEST_HEADER_TOO_LARGE) \
XX(495, SSL_CERTIFICATE_ERROR, SSL_CERTIFICATE_ERROR) \
XX(496, SSL_CERTIFICATE_REQUIRED, SSL_CERTIFICATE_REQUIRED) \
XX(497, HTTP_REQUEST_SENT_TO_HTTPS_PORT, HTTP_REQUEST_SENT_TO_HTTPS_PORT) \
XX(498, INVALID_TOKEN, INVALID_TOKEN) \
XX(499, CLIENT_CLOSED_REQUEST, CLIENT_CLOSED_REQUEST) \
XX(500, INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR) \
XX(501, NOT_IMPLEMENTED, NOT_IMPLEMENTED) \
XX(502, BAD_GATEWAY, BAD_GATEWAY) \
XX(503, SERVICE_UNAVAILABLE, SERVICE_UNAVAILABLE) \
XX(504, GATEWAY_TIMEOUT, GATEWAY_TIMEOUT) \
XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP_VERSION_NOT_SUPPORTED) \
XX(506, VARIANT_ALSO_NEGOTIATES, VARIANT_ALSO_NEGOTIATES) \
XX(507, INSUFFICIENT_STORAGE, INSUFFICIENT_STORAGE) \
XX(508, LOOP_DETECTED, LOOP_DETECTED) \
XX(509, BANDWIDTH_LIMIT_EXCEEDED, BANDWIDTH_LIMIT_EXCEEDED) \
XX(510, NOT_EXTENDED, NOT_EXTENDED) \
XX(511, NETWORK_AUTHENTICATION_REQUIRED, NETWORK_AUTHENTICATION_REQUIRED) \
XX(520, WEB_SERVER_UNKNOWN_ERROR, WEB_SERVER_UNKNOWN_ERROR) \
XX(521, WEB_SERVER_IS_DOWN, WEB_SERVER_IS_DOWN) \
XX(522, CONNECTION_TIMEOUT, CONNECTION_TIMEOUT) \
XX(523, ORIGIN_IS_UNREACHABLE, ORIGIN_IS_UNREACHABLE) \
XX(524, TIMEOUT_OCCURED, TIMEOUT_OCCURED) \
XX(525, SSL_HANDSHAKE_FAILED, SSL_HANDSHAKE_FAILED) \
XX(526, INVALID_SSL_CERTIFICATE, INVALID_SSL_CERTIFICATE) \
XX(527, RAILGUN_ERROR, RAILGUN_ERROR) \
XX(529, SITE_IS_OVERLOADED, SITE_IS_OVERLOADED) \
XX(530, SITE_IS_FROZEN, SITE_IS_FROZEN) \
XX(561, IDENTITY_PROVIDER_AUTHENTICATION_ERROR, IDENTITY_PROVIDER_AUTHENTICATION_ERROR) \
XX(598, NETWORK_READ_TIMEOUT, NETWORK_READ_TIMEOUT) \
XX(599, NETWORK_CONNECT_TIMEOUT, NETWORK_CONNECT_TIMEOUT) \
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LLLLHTTP_C_HEADERS_ */
#ifndef INCLUDE_LLHTTP_API_H_
#define INCLUDE_LLHTTP_API_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#if defined(__wasm__)
#define LLHTTP_EXPORT __attribute__((visibility("default")))
#else
#define LLHTTP_EXPORT
#endif
typedef llhttp__internal_t llhttp_t;
typedef struct llhttp_settings_s llhttp_settings_t;
typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length);
typedef int (*llhttp_cb)(llhttp_t*);
struct llhttp_settings_s {
/* Possible return values 0, -1, `HPE_PAUSED` */
llhttp_cb on_message_begin;
/* Possible return values 0, -1, HPE_USER */
llhttp_data_cb on_url;
llhttp_data_cb on_status;
llhttp_data_cb on_method;
llhttp_data_cb on_version;
llhttp_data_cb on_header_field;
llhttp_data_cb on_header_value;
llhttp_data_cb on_chunk_extension_name;
llhttp_data_cb on_chunk_extension_value;
/* Possible return values:
* 0 - Proceed normally
* 1 - Assume that request/response has no body, and proceed to parsing the
* next message
* 2 - Assume absence of body (as above) and make `llhttp_execute()` return
* `HPE_PAUSED_UPGRADE`
* -1 - Error
* `HPE_PAUSED`
*/
llhttp_cb on_headers_complete;
/* Possible return values 0, -1, HPE_USER */
llhttp_data_cb on_body;
/* Possible return values 0, -1, `HPE_PAUSED` */
llhttp_cb on_message_complete;
llhttp_cb on_url_complete;
llhttp_cb on_status_complete;
llhttp_cb on_method_complete;
llhttp_cb on_version_complete;
llhttp_cb on_header_field_complete;
llhttp_cb on_header_value_complete;
llhttp_cb on_chunk_extension_name_complete;
llhttp_cb on_chunk_extension_value_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
* Possible return values 0, -1, `HPE_PAUSED`
*/
llhttp_cb on_chunk_header;
llhttp_cb on_chunk_complete;
llhttp_cb on_reset;
};
/* Initialize the parser with specific type and user settings.
*
* NOTE: lifetime of `settings` has to be at least the same as the lifetime of
* the `parser` here. In practice, `settings` has to be either a static
* variable or be allocated with `malloc`, `new`, etc.
*/
LLHTTP_EXPORT
void llhttp_init(llhttp_t* parser, llhttp_type_t type,
const llhttp_settings_t* settings);
LLHTTP_EXPORT
llhttp_t* llhttp_alloc(llhttp_type_t type);
LLHTTP_EXPORT
void llhttp_free(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_type(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_http_major(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_http_minor(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_method(llhttp_t* parser);
LLHTTP_EXPORT
int llhttp_get_status_code(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_upgrade(llhttp_t* parser);
/* Reset an already initialized parser back to the start state, preserving the
* existing parser type, callback settings, user data, and lenient flags.
*/
LLHTTP_EXPORT
void llhttp_reset(llhttp_t* parser);
/* Initialize the settings object */
LLHTTP_EXPORT
void llhttp_settings_init(llhttp_settings_t* settings);
/* Parse full or partial request/response, invoking user callbacks along the
* way.
*
* If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing
* interrupts, and such errno is returned from `llhttp_execute()`. If
* `HPE_PAUSED` was used as a errno, the execution can be resumed with
* `llhttp_resume()` call.
*
* In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE`
* is returned after fully parsing the request/response. If the user wishes to
* continue parsing, they need to invoke `llhttp_resume_after_upgrade()`.
*
* NOTE: if this function ever returns a non-pause type error, it will continue
* to return the same error upon each successive call up until `llhttp_init()`
* is called.
*/
LLHTTP_EXPORT
llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);
/* This method should be called when the other side has no further bytes to
* send (e.g. shutdown of readable side of the TCP connection.)
*
* Requests without `Content-Length` and other messages might require treating
* all incoming bytes as the part of the body, up to the last byte of the
* connection. This method will invoke `on_message_complete()` callback if the
* request was terminated safely. Otherwise a error code would be returned.
*/
LLHTTP_EXPORT
llhttp_errno_t llhttp_finish(llhttp_t* parser);
/* Returns `1` if the incoming message is parsed until the last byte, and has
* to be completed by calling `llhttp_finish()` on EOF
*/
LLHTTP_EXPORT
int llhttp_message_needs_eof(const llhttp_t* parser);
/* Returns `1` if there might be any other messages following the last that was
* successfully parsed.
*/
LLHTTP_EXPORT
int llhttp_should_keep_alive(const llhttp_t* parser);
/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set
* appropriate error reason.
*
* Important: do not call this from user callbacks! User callbacks must return
* `HPE_PAUSED` if pausing is required.
*/
LLHTTP_EXPORT
void llhttp_pause(llhttp_t* parser);
/* Might be called to resume the execution after the pause in user's callback.
* See `llhttp_execute()` above for details.
*
* Call this only if `llhttp_execute()` returns `HPE_PAUSED`.
*/
LLHTTP_EXPORT
void llhttp_resume(llhttp_t* parser);
/* Might be called to resume the execution after the pause in user's callback.
* See `llhttp_execute()` above for details.
*
* Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`
*/
LLHTTP_EXPORT
void llhttp_resume_after_upgrade(llhttp_t* parser);
/* Returns the latest return error */
LLHTTP_EXPORT
llhttp_errno_t llhttp_get_errno(const llhttp_t* parser);
/* Returns the verbal explanation of the latest returned error.
*
* Note: User callback should set error reason when returning the error. See
* `llhttp_set_error_reason()` for details.
*/
LLHTTP_EXPORT
const char* llhttp_get_error_reason(const llhttp_t* parser);
/* Assign verbal description to the returned error. Must be called in user
* callbacks right before returning the errno.
*
* Note: `HPE_USER` error code might be useful in user callbacks.
*/
LLHTTP_EXPORT
void llhttp_set_error_reason(llhttp_t* parser, const char* reason);
/* Returns the pointer to the last parsed byte before the returned error. The
* pointer is relative to the `data` argument of `llhttp_execute()`.
*
* Note: this method might be useful for counting the number of parsed bytes.
*/
LLHTTP_EXPORT
const char* llhttp_get_error_pos(const llhttp_t* parser);
/* Returns textual name of error code */
LLHTTP_EXPORT
const char* llhttp_errno_name(llhttp_errno_t err);
/* Returns textual name of HTTP method */
LLHTTP_EXPORT
const char* llhttp_method_name(llhttp_method_t method);
/* Returns textual name of HTTP status */
LLHTTP_EXPORT
const char* llhttp_status_name(llhttp_status_t status);
/* Enables/disables lenient header value parsing (disabled by default).
*
* Lenient parsing disables header value token checks, extending llhttp's
* protocol support to highly non-compliant clients/server. No
* `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when
* lenient parsing is "on".
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_headers(llhttp_t* parser, int enabled);
/* Enables/disables lenient handling of conflicting `Transfer-Encoding` and
* `Content-Length` headers (disabled by default).
*
* Normally `llhttp` would error when `Transfer-Encoding` is present in
* conjunction with `Content-Length`. This error is important to prevent HTTP
* request smuggling, but may be less desirable for small number of cases
* involving legacy servers.
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled);
/* Enables/disables lenient handling of `Connection: close` and HTTP/1.0
* requests responses.
*
* Normally `llhttp` would error on (in strict mode) or discard (in loose mode)
* the HTTP request/response after the request/response with `Connection: close`
* and `Content-Length`. This is important to prevent cache poisoning attacks,
* but might interact badly with outdated and insecure clients. With this flag
* the extra request/response will be parsed normally.
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled);
/* Enables/disables lenient handling of `Transfer-Encoding` header.
*
* Normally `llhttp` would error when a `Transfer-Encoding` has `chunked` value
* and another value after it (either in a single header or in multiple
* headers whose value are internally joined using `, `).
* This is mandated by the spec to reliably determine request body size and thus
* avoid request smuggling.
* With this flag the extra value will be parsed normally.
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* INCLUDE_LLHTTP_API_H_ */
#endif /* INCLUDE_LLHTTP_H_ */

462
deps/undici/src/deps/llhttp/src/api.c vendored Normal file
View File

@ -0,0 +1,462 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "llhttp.h"
#define CALLBACK_MAYBE(PARSER, NAME) \
do { \
const llhttp_settings_t* settings; \
settings = (const llhttp_settings_t*) (PARSER)->settings; \
if (settings == NULL || settings->NAME == NULL) { \
err = 0; \
break; \
} \
err = settings->NAME((PARSER)); \
} while (0)
#define SPAN_CALLBACK_MAYBE(PARSER, NAME, START, LEN) \
do { \
const llhttp_settings_t* settings; \
settings = (const llhttp_settings_t*) (PARSER)->settings; \
if (settings == NULL || settings->NAME == NULL) { \
err = 0; \
break; \
} \
err = settings->NAME((PARSER), (START), (LEN)); \
if (err == -1) { \
err = HPE_USER; \
llhttp_set_error_reason((PARSER), "Span callback error in " #NAME); \
} \
} while (0)
void llhttp_init(llhttp_t* parser, llhttp_type_t type,
const llhttp_settings_t* settings) {
llhttp__internal_init(parser);
parser->type = type;
parser->settings = (void*) settings;
}
#if defined(__wasm__)
extern int wasm_on_message_begin(llhttp_t * p);
extern int wasm_on_url(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_status(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_header_field(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_header_value(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_headers_complete(llhttp_t * p, int status_code,
uint8_t upgrade, int should_keep_alive);
extern int wasm_on_body(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_message_complete(llhttp_t * p);
static int wasm_on_headers_complete_wrap(llhttp_t* p) {
return wasm_on_headers_complete(p, p->status_code, p->upgrade,
llhttp_should_keep_alive(p));
}
const llhttp_settings_t wasm_settings = {
wasm_on_message_begin,
wasm_on_url,
wasm_on_status,
NULL,
NULL,
wasm_on_header_field,
wasm_on_header_value,
NULL,
NULL,
wasm_on_headers_complete_wrap,
wasm_on_body,
wasm_on_message_complete,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
llhttp_t* llhttp_alloc(llhttp_type_t type) {
llhttp_t* parser = malloc(sizeof(llhttp_t));
llhttp_init(parser, type, &wasm_settings);
return parser;
}
void llhttp_free(llhttp_t* parser) {
free(parser);
}
#endif // defined(__wasm__)
/* Some getters required to get stuff from the parser */
uint8_t llhttp_get_type(llhttp_t* parser) {
return parser->type;
}
uint8_t llhttp_get_http_major(llhttp_t* parser) {
return parser->http_major;
}
uint8_t llhttp_get_http_minor(llhttp_t* parser) {
return parser->http_minor;
}
uint8_t llhttp_get_method(llhttp_t* parser) {
return parser->method;
}
int llhttp_get_status_code(llhttp_t* parser) {
return parser->status_code;
}
uint8_t llhttp_get_upgrade(llhttp_t* parser) {
return parser->upgrade;
}
void llhttp_reset(llhttp_t* parser) {
llhttp_type_t type = parser->type;
const llhttp_settings_t* settings = parser->settings;
void* data = parser->data;
uint8_t lenient_flags = parser->lenient_flags;
llhttp__internal_init(parser);
parser->type = type;
parser->settings = (void*) settings;
parser->data = data;
parser->lenient_flags = lenient_flags;
}
llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) {
return llhttp__internal_execute(parser, data, data + len);
}
void llhttp_settings_init(llhttp_settings_t* settings) {
memset(settings, 0, sizeof(*settings));
}
llhttp_errno_t llhttp_finish(llhttp_t* parser) {
int err;
/* We're in an error state. Don't bother doing anything. */
if (parser->error != 0) {
return 0;
}
switch (parser->finish) {
case HTTP_FINISH_SAFE_WITH_CB:
CALLBACK_MAYBE(parser, on_message_complete);
if (err != HPE_OK) return err;
/* FALLTHROUGH */
case HTTP_FINISH_SAFE:
return HPE_OK;
case HTTP_FINISH_UNSAFE:
parser->reason = "Invalid EOF state";
return HPE_INVALID_EOF_STATE;
default:
abort();
}
}
void llhttp_pause(llhttp_t* parser) {
if (parser->error != HPE_OK) {
return;
}
parser->error = HPE_PAUSED;
parser->reason = "Paused";
}
void llhttp_resume(llhttp_t* parser) {
if (parser->error != HPE_PAUSED) {
return;
}
parser->error = 0;
}
void llhttp_resume_after_upgrade(llhttp_t* parser) {
if (parser->error != HPE_PAUSED_UPGRADE) {
return;
}
parser->error = 0;
}
llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) {
return parser->error;
}
const char* llhttp_get_error_reason(const llhttp_t* parser) {
return parser->reason;
}
void llhttp_set_error_reason(llhttp_t* parser, const char* reason) {
parser->reason = reason;
}
const char* llhttp_get_error_pos(const llhttp_t* parser) {
return parser->error_pos;
}
const char* llhttp_errno_name(llhttp_errno_t err) {
#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return "HPE_" #NAME;
switch (err) {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
default: abort();
}
#undef HTTP_ERRNO_GEN
}
const char* llhttp_method_name(llhttp_method_t method) {
#define HTTP_METHOD_GEN(NUM, NAME, STRING) case HTTP_##NAME: return #STRING;
switch (method) {
HTTP_ALL_METHOD_MAP(HTTP_METHOD_GEN)
default: abort();
}
#undef HTTP_METHOD_GEN
}
const char* llhttp_status_name(llhttp_status_t status) {
#define HTTP_STATUS_GEN(NUM, NAME, STRING) case HTTP_STATUS_##NAME: return #STRING;
switch (status) {
HTTP_STATUS_MAP(HTTP_STATUS_GEN)
default: abort();
}
#undef HTTP_STATUS_GEN
}
void llhttp_set_lenient_headers(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_HEADERS;
} else {
parser->lenient_flags &= ~LENIENT_HEADERS;
}
}
void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_CHUNKED_LENGTH;
} else {
parser->lenient_flags &= ~LENIENT_CHUNKED_LENGTH;
}
}
void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_KEEP_ALIVE;
} else {
parser->lenient_flags &= ~LENIENT_KEEP_ALIVE;
}
}
void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_TRANSFER_ENCODING;
} else {
parser->lenient_flags &= ~LENIENT_TRANSFER_ENCODING;
}
}
/* Callbacks */
int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_message_begin);
return err;
}
int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_url, p, endp - p);
return err;
}
int llhttp__on_url_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_url_complete);
return err;
}
int llhttp__on_status(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_status, p, endp - p);
return err;
}
int llhttp__on_status_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_status_complete);
return err;
}
int llhttp__on_method(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_method, p, endp - p);
return err;
}
int llhttp__on_method_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_method_complete);
return err;
}
int llhttp__on_version(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_version, p, endp - p);
return err;
}
int llhttp__on_version_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_version_complete);
return err;
}
int llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_header_field, p, endp - p);
return err;
}
int llhttp__on_header_field_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_header_field_complete);
return err;
}
int llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_header_value, p, endp - p);
return err;
}
int llhttp__on_header_value_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_header_value_complete);
return err;
}
int llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_headers_complete);
return err;
}
int llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_message_complete);
return err;
}
int llhttp__on_body(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_body, p, endp - p);
return err;
}
int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_chunk_header);
return err;
}
int llhttp__on_chunk_extension_name(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_chunk_extension_name, p, endp - p);
return err;
}
int llhttp__on_chunk_extension_name_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_chunk_extension_name_complete);
return err;
}
int llhttp__on_chunk_extension_value(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_chunk_extension_value, p, endp - p);
return err;
}
int llhttp__on_chunk_extension_value_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_chunk_extension_value_complete);
return err;
}
int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_chunk_complete);
return err;
}
int llhttp__on_reset(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_reset);
return err;
}
/* Private */
void llhttp__debug(llhttp_t* s, const char* p, const char* endp,
const char* msg) {
if (p == endp) {
fprintf(stderr, "p=%p type=%d flags=%02x next=null debug=%s\n", s, s->type,
s->flags, msg);
} else {
fprintf(stderr, "p=%p type=%d flags=%02x next=%02x debug=%s\n", s,
s->type, s->flags, *p, msg);
}
}

150
deps/undici/src/deps/llhttp/src/http.c vendored Normal file
View File

@ -0,0 +1,150 @@
#include <stdio.h>
#ifndef LLHTTP__TEST
# include "llhttp.h"
#else
# define llhttp_t llparse_t
#endif /* */
int llhttp_message_needs_eof(const llhttp_t* parser);
int llhttp_should_keep_alive(const llhttp_t* parser);
int llhttp__before_headers_complete(llhttp_t* parser, const char* p,
const char* endp) {
/* Set this here so that on_headers_complete() callbacks can see it */
if ((parser->flags & F_UPGRADE) &&
(parser->flags & F_CONNECTION_UPGRADE)) {
/* For responses, "Upgrade: foo" and "Connection: upgrade" are
* mandatory only when it is a 101 Switching Protocols response,
* otherwise it is purely informational, to announce support.
*/
parser->upgrade =
(parser->type == HTTP_REQUEST || parser->status_code == 101);
} else {
parser->upgrade = (parser->method == HTTP_CONNECT);
}
return 0;
}
/* Return values:
* 0 - No body, `restart`, message_complete
* 1 - CONNECT request, `restart`, message_complete, and pause
* 2 - chunk_size_start
* 3 - body_identity
* 4 - body_identity_eof
* 5 - invalid transfer-encoding for request
*/
int llhttp__after_headers_complete(llhttp_t* parser, const char* p,
const char* endp) {
int hasBody;
hasBody = parser->flags & F_CHUNKED || parser->content_length > 0;
if (parser->upgrade && (parser->method == HTTP_CONNECT ||
(parser->flags & F_SKIPBODY) || !hasBody)) {
/* Exit, the rest of the message is in a different protocol. */
return 1;
}
if (parser->flags & F_SKIPBODY) {
return 0;
} else if (parser->flags & F_CHUNKED) {
/* chunked encoding - ignore Content-Length header, prepare for a chunk */
return 2;
} else if (parser->flags & F_TRANSFER_ENCODING) {
if (parser->type == HTTP_REQUEST &&
(parser->lenient_flags & LENIENT_CHUNKED_LENGTH) == 0 &&
(parser->lenient_flags & LENIENT_TRANSFER_ENCODING) == 0) {
/* RFC 7230 3.3.3 */
/* If a Transfer-Encoding header field
* is present in a request and the chunked transfer coding is not
* the final encoding, the message body length cannot be determined
* reliably; the server MUST respond with the 400 (Bad Request)
* status code and then close the connection.
*/
return 5;
} else {
/* RFC 7230 3.3.3 */
/* If a Transfer-Encoding header field is present in a response and
* the chunked transfer coding is not the final encoding, the
* message body length is determined by reading the connection until
* it is closed by the server.
*/
return 4;
}
} else {
if (!(parser->flags & F_CONTENT_LENGTH)) {
if (!llhttp_message_needs_eof(parser)) {
/* Assume content-length 0 - read the next */
return 0;
} else {
/* Read body until EOF */
return 4;
}
} else if (parser->content_length == 0) {
/* Content-Length header given but zero: Content-Length: 0\r\n */
return 0;
} else {
/* Content-Length header given and non-zero */
return 3;
}
}
}
int llhttp__after_message_complete(llhttp_t* parser, const char* p,
const char* endp) {
int should_keep_alive;
should_keep_alive = llhttp_should_keep_alive(parser);
parser->finish = HTTP_FINISH_SAFE;
parser->flags = 0;
/* NOTE: this is ignored in loose parsing mode */
return should_keep_alive;
}
int llhttp_message_needs_eof(const llhttp_t* parser) {
if (parser->type == HTTP_REQUEST) {
return 0;
}
/* See RFC 2616 section 4.4 */
if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
parser->status_code == 204 || /* No Content */
parser->status_code == 304 || /* Not Modified */
(parser->flags & F_SKIPBODY)) { /* response to a HEAD request */
return 0;
}
/* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */
if ((parser->flags & F_TRANSFER_ENCODING) &&
(parser->flags & F_CHUNKED) == 0) {
return 1;
}
if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) {
return 0;
}
return 1;
}
int llhttp_should_keep_alive(const llhttp_t* parser) {
if (parser->http_major > 0 && parser->http_minor > 0) {
/* HTTP/1.1 */
if (parser->flags & F_CONNECTION_CLOSE) {
return 0;
}
} else {
/* HTTP/1.0 or earlier */
if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
return 0;
}
}
return !llhttp_message_needs_eof(parser);
}

18232
deps/undici/src/deps/llhttp/src/llhttp.c vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
deps/undici/src/lib/llhttp/llhttp.wasm vendored Executable file

Binary file not shown.

BIN
deps/undici/src/lib/llhttp/llhttp_simd.wasm vendored Executable file

Binary file not shown.

View File

@ -0,0 +1,60 @@
> undici@6.19.5 prebuild:wasm
> node build/wasm.js --prebuild
> docker build --platform=linux/x86_64 -t llhttp_wasm_builder -f /home/midawson/test-undici/io.js/deps/undici/src/build/Dockerfile /home/midawson/test-undici/io.js/deps/undici/src
> undici@6.19.5 build:wasm
> node build/wasm.js --docker
> docker run --rm -it --platform=linux/x86_64 --user 1003:1003 --mount type=bind,source=/home/midawson/test-undici/io.js/deps/undici/src/lib/llhttp,target=/home/node/undici/lib/llhttp llhttp_wasm_builder node build/wasm.js
alpine-baselayout-3.4.3-r2
alpine-baselayout-data-3.4.3-r2
alpine-keys-2.4-r1
apk-tools-2.14.0-r5
binutils-2.41-r0
busybox-1.36.1-r15
busybox-binsh-1.36.1-r15
ca-certificates-bundle-20230506-r0
clang17-17.0.5-r0
clang17-headers-17.0.5-r0
clang17-libs-17.0.5-r0
fortify-headers-1.1-r3
gcc-13.2.1_git20231014-r0
gmp-6.3.0-r0
isl26-0.26-r1
jansson-2.14-r4
libatomic-13.2.1_git20231014-r0
libc-utils-0.7.2-r5
libcrypto3-3.1.4-r5
libffi-3.4.4-r3
libgcc-13.2.1_git20231014-r0
libgomp-13.2.1_git20231014-r0
libssl3-3.1.4-r5
libstdc++-13.2.1_git20231014-r0
libstdc++-dev-13.2.1_git20231014-r0
libxml2-2.11.8-r0
lld-17.0.5-r0
lld-libs-17.0.5-r0
llvm17-libs-17.0.5-r0
llvm17-linker-tools-17.0.5-r0
mpc1-1.3.1-r1
mpfr4-4.2.1-r0
musl-1.2.4_git20230717-r4
musl-dev-1.2.4_git20230717-r4
musl-utils-1.2.4_git20230717-r4
scanelf-1.3.7-r2
scudo-malloc-17.0.5-r0
ssl_client-1.36.1-r15
wasi-compiler-rt-17.0.5-r1
wasi-libc-0.20231012-r0
wasi-libcxx-17.0.5-r0
wasi-sdk-20-r3
xz-libs-5.4.5-r0
zlib-1.3.1-r0
zstd-libs-1.5.5-r8

12
deps/undici/src/package-lock.json generated vendored
View File

@ -2575,9 +2575,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001647",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001647.tgz",
"integrity": "sha512-n83xdNiyeNcHpzWY+1aFbqCK7LuLfBricc4+alSQL2Xb6OR3XpnQAmlDG+pQcdTfiHRuLcQ96VOfrPSGiNJYSg==",
"version": "1.0.30001649",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001649.tgz",
"integrity": "sha512-fJegqZZ0ZX8HOWr6rcafGr72+xcgJKI9oWfDW5DrD7ExUtgZC7a7R7ZYmZqplh7XDocFdGeIFn7roAxhOeYrPQ==",
"dev": true,
"funding": [
{
@ -3202,9 +3202,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz",
"integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==",
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz",
"integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==",
"dev": true,
"license": "ISC"
},

View File

@ -0,0 +1,15 @@
'use strict'
const { rmSync } = require('node:fs')
const { resolve } = require('node:path')
if (process.env.NODE_V8_COVERAGE) {
if (process.env.NODE_V8_COVERAGE.endsWith('/tmp')) {
rmSync(resolve(__dirname, process.env.NODE_V8_COVERAGE, '..'), { recursive: true, force: true })
} else {
rmSync(resolve(__dirname, process.env.NODE_V8_COVERAGE), { recursive: true, force: true })
}
} else {
console.log(resolve(__dirname, 'coverage'))
rmSync(resolve(__dirname, '../coverage'), { recursive: true, force: true })
}

View File

@ -0,0 +1,3 @@
/* istanbul ignore file */
require('https-pem/install')

View File

@ -0,0 +1,28 @@
const fs = require('node:fs')
const path = require('node:path')
const packageJSONPath = path.join(__dirname, '..', 'package.json')
const packageJSONRaw = fs.readFileSync(packageJSONPath, 'utf-8')
const packageJSON = JSON.parse(packageJSONRaw)
const licensePath = path.join(__dirname, '..', 'LICENSE')
const licenseRaw = fs.readFileSync(licensePath, 'utf-8')
const packageTypesJSON = {
name: 'undici-types',
version: packageJSON.version,
description: 'A stand-alone types package for Undici',
homepage: packageJSON.homepage,
bugs: packageJSON.bugs,
repository: packageJSON.repository,
license: packageJSON.license,
types: 'index.d.ts',
files: ['*.d.ts'],
contributors: packageJSON.contributors
}
const packageTypesPath = path.join(__dirname, '..', 'types', 'package.json')
const licenseTypesPath = path.join(__dirname, '..', 'types', 'LICENSE')
fs.writeFileSync(packageTypesPath, JSON.stringify(packageTypesJSON, null, 2))
fs.writeFileSync(licenseTypesPath, licenseRaw)

View File

@ -0,0 +1,12 @@
'use strict'
const { platform } = require('node:os')
const { writeFileSync } = require('node:fs')
const { resolve } = require('node:path')
if (platform() === 'win32') {
writeFileSync(
resolve(__dirname, '.npmrc'),
'script-shell = "C:\\windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"\n'
)
}

73
deps/undici/src/scripts/release.js vendored Normal file
View File

@ -0,0 +1,73 @@
'use strict'
// Called from .github/workflows
const generateReleaseNotes = async ({ github, owner, repo, versionTag, defaultBranch }) => {
const { data: releases } = await github.rest.repos.listReleases({
owner,
repo
})
const previousRelease = releases.find((r) => r.tag_name.startsWith('v6'))
const { data: { body } } = await github.rest.repos.generateReleaseNotes({
owner,
repo,
tag_name: versionTag,
target_commitish: defaultBranch,
previous_tag_name: previousRelease?.tag_name
})
const bodyWithoutReleasePr = body.split('\n')
.filter((line) => !line.includes('[Release] v'))
.join('\n')
return bodyWithoutReleasePr
}
const generatePr = async ({ github, context, defaultBranch, versionTag }) => {
const { owner, repo } = context.repo
const releaseNotes = await generateReleaseNotes({ github, owner, repo, versionTag, defaultBranch })
await github.rest.pulls.create({
owner,
repo,
head: `release/${versionTag}`,
base: defaultBranch,
title: `[Release] ${versionTag}`,
body: releaseNotes
})
}
const release = async ({ github, context, defaultBranch, versionTag }) => {
const { owner, repo } = context.repo
const releaseNotes = await generateReleaseNotes({ github, owner, repo, versionTag, defaultBranch })
await github.rest.repos.createRelease({
owner,
repo,
tag_name: versionTag,
target_commitish: defaultBranch,
name: versionTag,
body: releaseNotes,
draft: false,
prerelease: false,
generate_release_notes: false
})
try {
await github.rest.git.deleteRef({
owner,
repo,
ref: `heads/release/${versionTag}`
})
} catch (err) {
console.log("Couldn't delete release PR ref")
console.log(err)
}
}
module.exports = {
generatePr,
release
}

View File

@ -0,0 +1,15 @@
/* istanbul ignore file */
const [major, minor, patch] = process.versions.node.split('.').map(v => Number(v))
const required = process.argv.pop().split('.').map(v => Number(v))
const badMajor = major < required[0]
const badMinor = major === required[0] && minor < required[1]
const badPatch = major === required[0] && minor === required[1] && patch < required[2]
if (badMajor || badMinor || badPatch) {
console.log(`Required Node.js >=${required.join('.')}, got ${process.versions.node}`)
console.log('Skipping')
} else {
process.exit(1)
}

10
deps/undici/undici.js vendored
View File

@ -13194,11 +13194,5 @@ module.exports.EventSource = require_eventsource().EventSource;
module.exports.EnvHttpProxyAgent = EnvHttpProxyAgent;
module.exports.getGlobalDispatcher = getGlobalDispatcher;
module.exports.setGlobalDispatcher = setGlobalDispatcher;
/*! Bundled license information:
undici/lib/web/fetch/body.js:
(*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> *)
undici/lib/web/websocket/frame.js:
(*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> *)
*/
/*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
/*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> */

View File

@ -5,9 +5,10 @@
# This script must be in the tools directory when it runs because it uses the
# script source file path to determine directories to work in.
set -ex
set -e
ROOT=$(cd "$(dirname "$0")/../.." && pwd)
DEPS_DIR="$ROOT/deps"
[ -z "$NODE" ] && NODE="$ROOT/out/Release/node"
[ -x "$NODE" ] || NODE=$(command -v node)
NPM="$ROOT/deps/npm/bin/npm-cli.js"
@ -15,29 +16,74 @@ NPM="$ROOT/deps/npm/bin/npm-cli.js"
# shellcheck disable=SC1091
. "$ROOT/tools/dep_updaters/utils.sh"
NEW_VERSION=$("$NODE" "$NPM" view undici dist-tags.latest)
CURRENT_VERSION=$("$NODE" -p "require('./deps/undici/src/package.json').version")
NEW_VERSION="$("$NODE" --input-type=module <<'EOF'
const res = await fetch('https://api.github.com/repos/nodejs/undici/releases/latest',
process.env.GITHUB_TOKEN && {
headers: {
"Authorization": `Bearer ${process.env.GITHUB_TOKEN}`
},
});
if (!res.ok) throw new Error(`FetchError: ${res.status} ${res.statusText}`, { cause: res });
const { tag_name } = await res.json();
console.log(tag_name.replace('v', ''));
EOF
)"
CURRENT_VERSION=$("$NODE" -p "require('$DEPS_DIR/undici/src/package.json').version")
echo "$CURRENT_VERSION"
echo "$NEW_VERSION"
# This function exit with 0 if new version and current version are the same
compare_dependency_version "undici" "$NEW_VERSION" "$CURRENT_VERSION"
cd "$( dirname "$0" )/../.." || exit
rm -rf deps/undici/src
rm -f deps/undici/undici.js
WORKSPACE=$(mktemp -d 2> /dev/null || mktemp -d -t 'tmp')
echo "$WORKSPACE"
cleanup () {
EXIT_CODE=$?
[ -d "$WORKSPACE" ] && rm -rf "$WORKSPACE"
exit $EXIT_CODE
}
trap cleanup INT TERM EXIT
UNDICI_ZIP="undici-$NEW_VERSION"
cd "$WORKSPACE"
echo "Fetching UNDICI source archive..."
curl -sL -o "$UNDICI_ZIP.zip" "https://github.com/nodejs/undici/archive/refs/tags/v$NEW_VERSION.zip"
log_and_verify_sha256sum "undici" "$UNDICI_ZIP.zip"
echo "Unzipping..."
unzip "$UNDICI_ZIP.zip" -d "src"
mv "src/$UNDICI_ZIP" "$DEPS_DIR/undici/src"
rm "$UNDICI_ZIP.zip"
cd "$ROOT"
(
rm -rf undici-tmp
mkdir undici-tmp
cd undici-tmp || exit
cd "$DEPS_DIR/undici/src"
"$NODE" "$NPM" init --yes
# remove components we don't need to keep in nodejs/deps
rm -rf .husky || true
rm -rf .github || true
rm -rf test
rm -rf benchmarks
rm -rf docs-tmp
mv docs docs-tmp
mkdir docs
mv docs-tmp/docs docs/docs
rm -rf docs-tmp
"$NODE" "$NPM" install --global-style --no-bin-links --ignore-scripts "undici@$NEW_VERSION"
cd node_modules/undici
"$NODE" "$NPM" install --no-bin-link --ignore-scripts
"$NODE" "$NPM" run build:node
"$NODE" "$NPM" prune --production
rm node_modules/.package-lock.json
# Rebuild components from source
rm lib/llhttp/llhttp*.*
"$NODE" "$NPM" install --no-bin-link --ignore-scripts
"$NODE" "$NPM" run build:wasm > lib/llhttp/wasm_build_env.txt
"$NODE" "$NPM" run build:node
"$NODE" "$NPM" prune --production
)
# update version information in src/undici_version.h
@ -50,12 +96,9 @@ cat > "$ROOT/src/undici_version.h" <<EOF
#endif // SRC_UNDICI_VERSION_H_
EOF
mv undici-tmp/node_modules/undici deps/undici/src
mv deps/undici/src/undici-fetch.js deps/undici/undici.js
cp deps/undici/src/LICENSE deps/undici/LICENSE
rm -rf undici-tmp/
# Update the version number on maintaining-dependencies.md
# and print the new version as the last line of the script as we need
# to add it to $GITHUB_ENV variable