PlusWeb
An Express-style HTTP framework in C++17, on a libuv event loop and the llhttp parser.
One event loop handles every connection, requests resolve through a segment trie keyed on method and path, and no connection went unanswered at any concurrency tested — including the 512 where Express left 264 waiting.
- C++17
- libuv
- llhttp
- CMake
- MIT
mounting rewrites the path, so the sub-router never knows where it was attached.
01 — the parts that are mine
An HTTP framework that starts at the socket.
Express hands you app.get(path, handler) and hides everything under it. I
wanted to know what stands between that call and a file descriptor, so I wrote the whole
path: accept, parse, route, run the middleware chain, serialize, write, and hold the
connection open for the next request.
- 4.8×
- 91.9k
- 6.5 MB
- 55%
02 — against Express, on one box
Add routes to Express and it slows down. This one doesn’t.
Same machine, same handlers, the same load pointed at both. Go from five routes to ten thousand and Express falls from 19,000 requests a second to 355. This one barely moves — and it holds those routes in 6.5 MB of memory where the Express cluster needs 97.7 MB.
03 — run it
Write the routes. Send a request.
Write the handlers and the router rebuilds as you type. Underneath it is
src/trie.cpp itself, compiled for the browser — the method is the
first segment of the key, a literal child always beats a parameter, and nothing backtracks.
send a path
try , ,
the trie these build
- GET /health
- GET /users
- GET /users/new
- GET /users/:id
- POST /users
- DELETE /users/:id
The route lines are compiled by the real router; handler names are decoration.