diff --git a/examples/README.md b/.github/examples/README.md
similarity index 100%
rename from examples/README.md
rename to .github/examples/README.md
diff --git a/examples/basic/server.js b/.github/examples/basic/server.js
similarity index 100%
rename from examples/basic/server.js
rename to .github/examples/basic/server.js
diff --git a/examples/cors/server.js b/.github/examples/cors/server.js
similarity index 100%
rename from examples/cors/server.js
rename to .github/examples/cors/server.js
diff --git a/examples/error-handling/server.js b/.github/examples/error-handling/server.js
similarity index 100%
rename from examples/error-handling/server.js
rename to .github/examples/error-handling/server.js
diff --git a/examples/middleware/server.js b/.github/examples/middleware/server.js
similarity index 100%
rename from examples/middleware/server.js
rename to .github/examples/middleware/server.js
diff --git a/examples/rest-api/server.js b/.github/examples/rest-api/server.js
similarity index 100%
rename from examples/rest-api/server.js
rename to .github/examples/rest-api/server.js
diff --git a/examples/validation/server.js b/.github/examples/validation/server.js
similarity index 100%
rename from examples/validation/server.js
rename to .github/examples/validation/server.js
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 9a8ea48..eba214c 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -6,43 +6,12 @@ on:
workflow_dispatch:
jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - name: Setup Bun
- uses: oven-sh/setup-bun@v2
- with:
- bun-version: latest
-
- - name: Setup Rust
- uses: dtolnay/rust-toolchain@stable
-
- - name: Install dependencies
- run: bun install
-
- - name: Build
- run: bun run build:release
-
- - name: Test
- run: bun run test
-
publish:
- needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - name: Setup Bun
- uses: oven-sh/setup-bun@v2
- with:
- bun-version: latest
-
- - name: Setup Rust
- uses: dtolnay/rust-toolchain@stable
-
- - name: Setup Node.js (for npm publish)
+ - name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
@@ -50,10 +19,7 @@ jobs:
scope: "@http-native"
- name: Install dependencies
- run: bun install
-
- - name: Build (release)
- run: bun run build:release
+ run: npm install
- name: Publish to npm
run: npm publish --access public
diff --git a/noslop/AGENTS.md b/noslop/AGENTS.md
deleted file mode 100644
index e69de29..0000000
diff --git a/noslop/CLAUDE.md b/noslop/CLAUDE.md
deleted file mode 100644
index e69de29..0000000
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..2d4febb
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,20 @@
+{
+ "name": "@http-native/core",
+ "version": "0.0.2",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@http-native/core",
+ "version": "0.0.2",
+ "dependencies": {
+ "@http-native/core": "^0.0.1"
+ }
+ },
+ "node_modules/@http-native/core": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/@http-native/core/-/core-0.0.1.tgz",
+ "integrity": "sha512-NGdf6gxui1gtcQJ86zSAwuCRMUsIr5C7BBdkD/8SWDP2NJ90cGboOvM6zH3S+QZlKmkKYFmfSBKRspTioKM9Xw=="
+ }
+ }
+}
diff --git a/package.json b/package.json
index 941aa2c..73431da 100644
--- a/package.json
+++ b/package.json
@@ -1,16 +1,23 @@
{
"name": "@http-native/core",
- "version": "0.1.0",
+ "version": "0.0.3",
"type": "module",
"publishConfig": {
"access": "public"
},
+ "bin": {
+ "http-native": "./src/cli.js"
+ },
+ "files": [
+ "src"
+ ],
"exports": {
".": {
"types": "./src/index.d.ts",
"default": "./src/index.js"
},
"./cors": "./src/cors.js",
+ "./hot": "./src/hot.js",
"./session": "./src/session.js",
"./validate": "./src/validate.js",
"./http-server.config": "./src/http-server.config.js"
@@ -18,6 +25,8 @@
"scripts": {
"build": "bun scripts/build-native.mjs",
"build:release": "bun scripts/build-native.mjs --release",
+ "dev:hot": "HTTP_NATIVE_HOT_RELOAD=1 bun test/app.ts",
+ "dev": "bun src/hot.js",
"test": "bun run build && bun test/test.js",
"bench": "bun run build:release && bun bench/run.js",
"bench:http-native:static": "bun run build:release && bun bench/run.js http-native static 3001",
@@ -44,5 +53,8 @@
"bench:xitca:opt": "bun bench/run.js xitca opt 3023",
"bench:monoio:opt": "bun bench/run.js monoio opt 3024",
"bench:zig:opt": "bun bench/run.js zig opt 3025"
+ },
+ "dependencies": {
+ "@http-native/core": "^0.0.1"
}
}
diff --git a/readme.md b/readme.md
index e918ce6..0830b01 100644
--- a/readme.md
+++ b/readme.md
@@ -1,91 +1,54 @@
-
+
+# @http-native/core
-Http-native
+A fast, Express-like HTTP framework for JavaScript powered by a Rust native module via napi-rs.
-Http native is a express like server framework for Javascript that uses the Node-compatible framework with Rust native module way, where the rust binary is evoked through napi-rs or something faster.
+## Install
-You can also import the default server tuning config and override it before `listen()`:
-
-```js
-import httpServerConfig from "http-native/http-server.config";
+```sh
+npm install @http-native/core
```
-Rust handler (http) <-> (javascript logic)
-
-The rust server handles all the http, while the core javascript logic is run sperately (EXREMELY fast)
-
-Extrat performance features:
-
- 1) Ahead of time constant data indentification. (If the data in the route's logic isn't manipulated at runtime we directly store it in rust so we don't envoke the javascript logic)
-
- 2) Faster than bun.server() aswell as fastify.
-
- 3) Default async handling (Yes rust handles the async for you.)
-
-So start by just writing
+## Usage
```js
-import { createApp } from "../src/index.js";
-
-const db = {
- async getUser(id) {
- return {
- id,
- name: "Ada wong",
- role: "admin",
- };
- },
-};
+import { createApp } from "@http-native/core";
const app = createApp();
-app.use(async (req, res, next) => {
- res.header("x-powered-by", "http-native");
- await next();
+app.get("/", async (req, res) => {
+ res.json({ ok: true });
});
-app.get("/", (req, res) => {
- res.json({
- ok: true,
- engine: "rust",
- bridge: "napi-rs",
- });
+app.get("/user/:id", async (req, res) => {
+ res.json({ id: req.params.id });
});
-app.get("/users/:id", async (req, res) => {
- const user = await db.getUser(req.params.id);
- res.json(user);
+app.error(async (error, req, res) => {
+ res.status(500).json({ error: error.message });
});
-const server = await app.listen({
- port: 3001,
- serverConfig: {
- ...httpServerConfig,
- maxHeaderBytes: 32 * 1024,
- },
-});
+const server = await app.listen().port(8190);
+console.log(`Listening on ${server.url}`);
```
-Runtime optimization reporting:
+## Imports
```js
-console.log(server.optimizations.summary());
-console.log(server.optimizations.snapshot());
+import { createApp } from "@http-native/core";
+import cors from "@http-native/core/cors";
+import { validate } from "@http-native/core/validate";
+import httpServerConfig from "@http-native/core/http-server.config";
```
-Pass `opt: { notify: true }` to `listen()` if you want runtime logs when a route is already native static or looks stable enough to cache later.
-
-
-This architecture is designed to outperform previous iterations and provide top-tier performance on par with or exceeding `bun.serve()`.
-Run tests via `test.js` and use the benchmark suite to validate performance gains.
-
-
-Since this is designed to be a core library, please ensure strict adherence to API stability and zero-allocation principles where possible.
-
-Remeber nadhi u moron this will be a library so don't go around doing shit.
+## Optimizations
+```js
+const server = await app.listen().port(8190).opt({ devComments: true });
-bump action
+console.log(server.optimizations.summary());
+console.log(server.optimizations.snapshot());
+```
diff --git a/rust-native/Cargo.lock b/rust-native/Cargo.lock
index d640ca7..548e3bf 100644
--- a/rust-native/Cargo.lock
+++ b/rust-native/Cargo.lock
@@ -25,6 +25,28 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+[[package]]
+name = "aws-lc-rs"
+version = "1.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc"
+dependencies = [
+ "aws-lc-sys",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-lc-sys"
+version = "0.39.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399"
+dependencies = [
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+]
+
[[package]]
name = "base64"
version = "0.22.1"
@@ -70,12 +92,33 @@ version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
+[[package]]
+name = "cc"
+version = "1.2.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+[[package]]
+name = "cmake"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
+dependencies = [
+ "cc",
+]
+
[[package]]
name = "convert_case"
version = "0.11.0"
@@ -157,6 +200,18 @@ version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
[[package]]
name = "flume"
version = "0.11.1"
@@ -178,6 +233,12 @@ dependencies = [
"percent-encoding",
]
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
[[package]]
name = "futures"
version = "0.3.32"
@@ -298,6 +359,18 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
+]
+
[[package]]
name = "hermit-abi"
version = "0.5.2"
@@ -320,18 +393,21 @@ dependencies = [
"anyhow",
"base64",
"bytes",
- "getrandom",
+ "getrandom 0.2.17",
"hmac",
"httparse",
"itoa",
"json5",
"memchr",
"monoio",
+ "monoio-rustls",
"napi",
"napi-build",
"napi-derive",
"parking_lot",
"rustc-hash",
+ "rustls",
+ "rustls-pemfile",
"serde",
"serde_json",
"sha2",
@@ -463,6 +539,16 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.4",
+ "libc",
+]
+
[[package]]
name = "js-sys"
version = "0.3.91"
@@ -571,6 +657,15 @@ dependencies = [
"windows-sys 0.48.0",
]
+[[package]]
+name = "monoio-io-wrapper"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bcfaa76e5daf87cc4d31b4d1b6bc93c12db59c19df50b9200afdbde42077655"
+dependencies = [
+ "monoio",
+]
+
[[package]]
name = "monoio-macros"
version = "0.1.0"
@@ -582,13 +677,26 @@ dependencies = [
"syn",
]
+[[package]]
+name = "monoio-rustls"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e31f422825bd7fb19957af6eaf89d7234ba143fcc0e515f5a2f526e332d1875"
+dependencies = [
+ "bytes",
+ "monoio",
+ "monoio-io-wrapper",
+ "rustls",
+ "thiserror",
+]
+
[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
- "getrandom",
+ "getrandom 0.2.17",
]
[[package]]
@@ -794,6 +902,12 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
[[package]]
name = "redox_syscall"
version = "0.5.18"
@@ -803,12 +917,71 @@ dependencies = [
"bitflags 2.11.0",
]
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.17",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
[[package]]
name = "rustc-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+[[package]]
+name = "rustls"
+version = "0.23.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
+dependencies = [
+ "aws-lc-rs",
+ "log",
+ "once_cell",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
+dependencies = [
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
+dependencies = [
+ "aws-lc-rs",
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
[[package]]
name = "rustversion"
version = "1.0.22"
@@ -881,6 +1054,12 @@ dependencies = [
"digest",
]
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
[[package]]
name = "slab"
version = "0.4.12"
@@ -946,6 +1125,26 @@ dependencies = [
"syn",
]
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "threadpool"
version = "1.8.1"
@@ -989,6 +1188,12 @@ version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
[[package]]
name = "url"
version = "2.5.8"
@@ -1019,6 +1224,15 @@ version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+[[package]]
+name = "wasip2"
+version = "1.0.2+wasi-0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
+dependencies = [
+ "wit-bindgen",
+]
+
[[package]]
name = "wasm-bindgen"
version = "0.2.114"
@@ -1209,6 +1423,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+[[package]]
+name = "wit-bindgen"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+
[[package]]
name = "writeable"
version = "0.6.2"
@@ -1259,6 +1479,12 @@ dependencies = [
"synstructure",
]
+[[package]]
+name = "zeroize"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
+
[[package]]
name = "zerotrie"
version = "0.2.3"
diff --git a/rust-native/Cargo.toml b/rust-native/Cargo.toml
index 296ef3b..d320e70 100644
--- a/rust-native/Cargo.toml
+++ b/rust-native/Cargo.toml
@@ -18,9 +18,12 @@ rustc-hash = "2"
getrandom = "0.2"
hmac = "0.12"
monoio = { version = "0.2", features = ["sync", "legacy"] }
+monoio-rustls = "0.4"
napi = { version = "3", default-features = false, features = ["napi8"] }
napi-derive = "3"
parking_lot = "0.12"
+rustls = "0.23"
+rustls-pemfile = "2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sha2 = "0.10"
diff --git a/rust-native/src/lib.rs b/rust-native/src/lib.rs
index 7c82b9a..e8509d4 100644
--- a/rust-native/src/lib.rs
+++ b/rust-native/src/lib.rs
@@ -6,13 +6,17 @@ pub mod session;
use anyhow::{anyhow, Context, Result};
use memchr::memmem;
use monoio::io::{AsyncReadRent, AsyncWriteRent, AsyncWriteRentExt};
-use monoio::net::{ListenerOpts, TcpListener, TcpStream};
+use monoio::net::{ListenerOpts, TcpListener};
+use monoio_rustls::TlsAcceptor;
use napi::bindgen_prelude::{Buffer, Function, Promise};
use napi::threadsafe_function::ThreadsafeFunction;
use napi::{Error, Status};
use napi_derive::napi;
+use rustls::pki_types::{CertificateDer, PrivateKeyDer};
+use rustls::ServerConfig as RustlsServerConfig;
use std::borrow::Cow;
use std::cell::RefCell;
+use std::io::BufReader;
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::atomic::{AtomicBool, Ordering};
use std::rc::Rc;
@@ -23,7 +27,7 @@ use crate::analyzer::{
DynamicFastPathResponse, DynamicValueSourceKind, JsonTemplateKind, JsonValueTemplate,
TextSegment,
};
-use crate::manifest::{HttpServerConfigInput, ManifestInput};
+use crate::manifest::{HttpServerConfigInput, ManifestInput, TlsConfigInput};
use crate::router::{ExactStaticRoute, MatchedRoute, Router};
// ─── Constants ──────────────────────────
@@ -341,6 +345,8 @@ pub fn start_server(
let server_config =
Arc::new(HttpServerConfig::from_manifest(&manifest).map_err(to_napi_error)?);
let router = Arc::new(Router::from_manifest(&manifest).map_err(to_napi_error)?);
+ let tls_acceptor = build_tls_acceptor(&manifest).map_err(to_napi_error)?;
+ let tls_enabled = tls_acceptor.is_some();
// Build session store if session config is present in manifest
let session_store: Option> = manifest.session.as_ref().map(|cfg| {
@@ -380,6 +386,7 @@ pub fn start_server(
let thread_config = Arc::clone(&server_config);
let thread_shutdown = Arc::clone(&shutdown_flag);
let thread_session_store = session_store.clone();
+ let thread_tls_acceptor = tls_acceptor.clone();
let thread_options = NativeListenOptions {
host: options.host.clone(),
port: options.port,
@@ -405,6 +412,7 @@ pub fn start_server(
thread_router,
thread_dispatcher,
thread_config,
+ thread_tls_acceptor,
thread_shutdown,
thread_session_store,
)
@@ -464,7 +472,11 @@ pub fn start_server(
Ok(NativeServerHandle {
host: host.clone(),
port,
- url: format!("http://{host}:{port}"),
+ url: if tls_enabled {
+ format!("https://{host}:{port}")
+ } else {
+ format!("http://{host}:{port}")
+ },
shutdown: Mutex::new(Some(ShutdownHandle {
flag: shutdown_flag,
wake_addrs,
@@ -516,6 +528,7 @@ async fn run_server(
router: Arc,
dispatcher: Arc,
server_config: Arc,
+ tls_acceptor: Option,
shutdown_flag: Arc,
session_store: Option>,
) -> Result<()> {
@@ -524,6 +537,7 @@ async fn run_server(
let router: Rc> = Rc::new(router);
let dispatcher: Rc> = Rc::new(dispatcher);
let server_config: Rc> = Rc::new(server_config);
+ let tls_acceptor: Option> = tls_acceptor.map(Rc::new);
let session_store: Option>> =
session_store.map(Rc::new);
@@ -553,6 +567,7 @@ async fn run_server(
let router = Rc::clone(&router);
let dispatcher = Rc::clone(&dispatcher);
let server_config = Rc::clone(&server_config);
+ let tls_acceptor = tls_acceptor.clone();
let session_store = session_store.clone();
active_connections.set(active_connections.get() + 1);
@@ -560,9 +575,25 @@ async fn run_server(
let conn_counter = &active_connections as *const std::cell::Cell;
monoio::spawn(async move {
- if let Err(error) =
- handle_connection(stream, router, dispatcher, server_config, session_store).await
- {
+ let connection_result = if let Some(acceptor) = tls_acceptor.as_ref() {
+ match acceptor.accept(stream).await {
+ Ok(tls_stream) => {
+ handle_connection(
+ tls_stream,
+ router,
+ dispatcher,
+ server_config,
+ session_store,
+ )
+ .await
+ }
+ Err(error) => Err(anyhow!("TLS accept failed: {error}")),
+ }
+ } else {
+ handle_connection(stream, router, dispatcher, server_config, session_store)
+ .await
+ };
+ if let Err(error) = connection_result {
eprintln!("[http-native] connection error: {error}");
}
// Safety: single-threaded — pointer is always valid while server runs
@@ -611,13 +642,16 @@ const TIMEOUT_BODY_READ: Duration = Duration::from_secs(60);
// ─── Connection Handler with Buffer Pool
-async fn handle_connection(
- mut stream: TcpStream,
+async fn handle_connection(
+ mut stream: S,
router: Rc>,
dispatcher: Rc>,
server_config: Rc>,
session_store: Option>>,
-) -> Result<()> {
+) -> Result<()>
+where
+ S: AsyncReadRent + AsyncWriteRent + Unpin,
+{
let mut buffer = acquire_buffer();
let result = handle_connection_inner(
@@ -634,14 +668,17 @@ async fn handle_connection(
result
}
-async fn handle_connection_inner(
- stream: &mut TcpStream,
+async fn handle_connection_inner(
+ stream: &mut S,
buffer: &mut Vec,
router: &Router,
dispatcher: &JsDispatcher,
server_config: &HttpServerConfig,
session_store: Option<&session::SessionStore>,
-) -> Result<()> {
+) -> Result<()>
+where
+ S: AsyncReadRent + AsyncWriteRent + Unpin,
+{
let mut is_first_request = true;
loop {
@@ -1767,11 +1804,14 @@ fn build_response_bytes_fast(
// ─── Response Writing ───────────────────
-async fn write_exact_static_response(
- stream: &mut TcpStream,
+async fn write_exact_static_response(
+ stream: &mut S,
static_route: &ExactStaticRoute,
keep_alive: bool,
-) -> Result<()> {
+) -> Result<()>
+where
+ S: AsyncWriteRent + Unpin,
+{
let response = if keep_alive {
static_route.keep_alive_response.clone()
} else {
@@ -1984,8 +2024,8 @@ fn extract_session_trailer(dispatch_bytes: &[u8], start_offset: usize) -> Option
})
}
-async fn write_dynamic_dispatch_response(
- stream: &mut TcpStream,
+async fn write_dynamic_dispatch_response(
+ stream: &mut S,
dispatcher: &JsDispatcher,
request: Buffer,
keep_alive: bool,
@@ -1995,7 +2035,10 @@ async fn write_dynamic_dispatch_response(
session_store: Option<&session::SessionStore>,
session_id: Option<[u8; session::SESSION_ID_BYTES]>,
is_new_session: bool,
-) -> Result<()> {
+) -> Result<()>
+where
+ S: AsyncWriteRent + Unpin,
+{
match dispatcher.dispatch(request).await {
Ok(response) => {
match build_http_response_from_dispatch(response.as_ref(), keep_alive) {
@@ -2450,6 +2493,61 @@ fn bind_listener(
.with_context(|| format!("failed to bind TCP listener on {bind_addr}"))
}
+fn build_tls_acceptor(manifest: &ManifestInput) -> Result