water_http
http framework meant to be the fastest and easiest http framework by using the power of rust macros and it`s provide stable workload over os systems and all the important features for servers
Features
- very slight and easy to use
- blazingly fast with very advanced concepts and services to provide, you can see Benchmarks repository
- very simple and familiar constructor
- support both protocols http2 and http1 with all existed features and more
- support all http encoding algorithms with custom encoding for low levels like
- brotli
- zstd
- gzip
- deflate
- lz4
- snappy
- bzip2
- custom encoding algorithms for low level of programming
- provide simple routing structure with many patterns of write
- very fast http parsing algorithms which archived http 1 parsing with 1 micro second
- can handle millions of requests in given seconds
- support videos streaming for web pages videos
- provide easy approaches for saving and downloading files from and to the server
- support tls or ssl implementation for secure connections without any confusing
- naming routes and redirecting to these routes by their names using one single method
- multi pattern ways to generate your code and very easy approaches
- support controlling low actions like block custom ip addresses from connecting your server or strict your service to custom ip addresses
- thresholding actions like the threshold the maximum size of using compressing algorithms when sending response back considering clients encoding support
Nice Information
- we need to understand that http request is based on another protocols like tcp (http1 and htt2) or udp (http3) and what framework is basically do is to read incoming bytes into certain bytes buffer which located on ram memory so when the framework uses the same bytes which read by the OS as much as possible that would make the framework better because at this logic we had zero additional memory allocations and that`s what water_http framework is meant to be
- when we need to serve requests in better pattern we need to understand one thing ( less memory allocations leads to better performance ) so water http used another way of serving post request in http 1 protocol and it`s allocating one buffer for each connection and reusing the same allocated buffer for each http request instead of using new buffer for each http request
- we are using IncomingRequest struct for parsing Http requests which it self-developed struct for using the same buffer bytes to handling request and also single bytes iteration with zero allocations
- we used the power of rust macros to makes code very easy to build and use /
Installation
for start building your own web server app you need to follow the steps
- install water_http by
- using shell
cargo add water_http - using cargo.toml file
= "[last_version]"
- using shell
- install tokio by
- using shell
cargo add tokio --features=full - using cargo.toml file
= { = "[last_version]", = ["full"] }
- using shell
Concepts
-
water http built with concepts of controllers tree let`s say we have
-MainController __ child 1 Controller | child 2 controller
child 1 and child2 controller are both depends on MainController prefix if he has one and also could depend on MainController middleware if apply_parents_middlewares was set to true
-
the context has shared public object of type generic ,so we could parse anything to children controllers also we need to specify what is the maxy headers count ( which means how many headers we would read from incoming request ) and the max query count ( which means how many queries we could request using path ) for example : http://example.com/post?id=1&name=2 in this example we have two queries in the path (id,name)
so to init these for controllers we could use InitControllerRoot macro
use HashMap;
use InitControllersRoot;
type MainHolderType = ;
InitControllersRoot!
so after initializing our controllers root we could build our controllers
Note : we are specifying headers length and queries length for two purpose
1- for providing security and refuse all malicious big load requests
2- to allocate memory on the stack which need known sized bytes so that we could make the app significantly faster
Some Tips
- if you need to trace debugging hints you could use feature debugging
by running shell
cargo run --features debugging - if you need to count speed of parsing bytes to http 1 protocol as request you could use feature "count_connection_parsing_speed"
cargo run --features count_connection_parsing_speed
- if you need to run one of the examples files
cargo run example public_files_serving
- to set the framework to auto handle content encoding when sending back response
use ;
- to enable using tls
use ServerConfigurations;
Note: you could choose your needed file from examples folder
🚀 Benchmarking
Water_http is now officially included in TechEmpower Framework Benchmarks, the most trusted and widely recognized benchmarking organization for web frameworks.
Benchmarking results for water_http will appear in the next official round, but you can already view and test it manually through the TechEmpower repository.
Current status:
✔️ water_http has been approved and merged into the TechEmpower project
✔️ Source and benchmark implementation are publicly available
⏳ Official numbers will be published in the upcoming round
🔍 You can manually inspect or run the benchmark now: https://github.com/TechEmpower/FrameworkBenchmarks
This marks a major milestone for water_http, showcasing its speed, stability, and production-grade performance.
Starting
-
firstly you need to define Controllers Root as we explain in Concepts
-
create controller using
water_http::WaterControllermacro
use WaterController;
/// we use crate key word because this macro will
/// encapsulate everything inside new mod
/// and holder is the type that we defined in the previous step
WaterController!
- now inside main fn in rust we will create configurations and run the server app
async
Basic Example
use HashMap;
use ServerConfigurations;
use ;
type MainHolderType = ;
InitControllersRoot!
async
WaterController!
Notes :
- water_http use tokio runtime for multithreading tasks
- using WaterController macro need to have (name,holder,function) in order arrangement but the following properties no needs for that
- you may need to install cmake and clang compiler for compiling
- in linux make sure to have build-essential and cmake and you sometime gcc to do install any of them
sudo apt-get install build-essential cmake
- if you want to create fn which take context as parameter
you would need to parse parameters as following
use HttpContext;
type MainHolderType = crateMainHolderType;
async
or you could use also
use HttpContext;
type MainHolderType = crateMainHolderType;
async
Writing Responses
- using sender
functions_builder!
and there is alot of functions that facilitate sending responses like sending json or file from public directory
functions_builder!
- using context sending methods
functions_builder!
- using water_http macros
functions_builder!
also you could use response!(context json -> jsonValue ); to send json response
Writing Controllers Functions styles
use WaterController;
// you can use one style to make it your default and favorite one
// my personal favorite one is
// method -> path -> function_name(context) async {
// function body
// }
WaterController!
// notice that writing methods like POST,post,Post,posT,POst
// it would give the same result cause the framework has auto under table requests handler
Full Code example
use HashMap;
use ;
use ;
use HttpSenderTrait;
InitControllersRoot!
type MainHolderType = CHolder;
async
// you can use one style to make it your default and favorite one
// my personal favorite one is
// method -> path -> function_name(context) async {
// function body
// }
WaterController!
// notice that writing methods like POST,post,Post,posT,POst
// it would give the same result cause the framework has auto under table requests handler
functions_builder!
// to generate normal function without helper
// pub async fn fn_name<'context, MainHolderType: Send + 'static, const header_length: usize, const query_length: usize>
// (context: &mut water_http::server::HttpContext<'context, MainHolderType, header_length, query_length>) {
// }
// so we created water_http::functions_builder macro to help you create functions in fast and easy way
🚀 The fast_build! Macro (Easy & Rapid Prototyping)
When you need to spin up a structured server with full routing support instantly, water_http offers the fast_build! macro. It eliminates boilerplate entirely, automatically managing controller root initializations, server configurations, and setup hooks behind the scenes for an incredibly fast and straightforward development cycle.
Feature Variants & Syntax Flexibility
The fast_build! macro adapts to your architecture natively. Whether you need a minimal single-file endpoint or a complex tree of controllers with shared multi-threaded state, fast_build! handles it effortlessly.
1. The Ultra-Fast Bare Minimum
Great for simple microservices. Bypasses structure configuration overhead and assumes default bindings automatically.
use fast_build;
fast_build!
⏳ The LazyResponse Architecture (Deferred Payload Pipeline)
In standard server configurations, writing a response immediately pushes byte chunks down into the active socket stream. While fast for simple handlers, immediate execution strips away the ability to modify or abort responses during deep controller routing traversals or middleware execution phases.
water_http solves this with LazyResponse. A lazy response defers payload assembly and socket writes until the final microsecond of the connection cycle. It holds the payload in a non-allocating, deferred structure until the entire controller tree validation finishes, ensuring all headers, state changes, and interceptors have had their absolute final say before committing to a network transmit.
Key Advantages
- Perfect Middleware Compatibility: Parent interceptors can safely override, augment, or drop down-tree handlers because no bytes have physically touched the socket yet.
- Dynamic Header Mutation: Append or alter headers anywhere along the pipeline route without triggering pre-mature chunk transmission errors.
- Early-Exit Guarantees: Instantly stop expensive nested database/serialization logic if an upper-tier interceptor completely overrides the response context.
Code Example: Cascade Interception & Lazy Deferral
The example below demonstrates how multiple nested controllers handle LazyResponse contexts, and how parent interceptors seamlessly intercept and rewrite down-tree executions when apply_parents_interceptors -> (true) is configured.
use ServerConfigurations;
use ;
type MainHolderType = u8;
InitControllersRoot!
// =============================================================================
// ROOT CONTROLLER
// =============================================================================
WaterController!
// =============================================================================
// SECONDARY NESTED CONTROLLER
// =============================================================================
WaterController!
// =============================================================================
// THIRD NESTED CONTROLLER (INHERITING PARENT PIPELINES)
// =============================================================================
WaterController!
⚡ The mini Engine (Zero-Overhead Hyper-Performance)
For deployment environments where every single CPU cycle, byte of memory, and nano-second matters, water_http provides a dedicated mini engine.
It is designed specifically to serve ultra-tiny services with absolute zero runtime overhead. By bypassing traditional macro routers, allocations, and controller hierarchies, mini gives you direct, raw, bare-metal access to the underlying socket ring-buffers using stack-allocated const-generics.
Key Highlights
- Strictly Zero Heap Allocation: Memory layout is completely determined at compile time.
- No Routing Overhead: Requests drop straight into a single, lightning-fast direct callback handler.
- Bare-Metal Context Control: Uses direct raw static pointer structures (
CtxPtr) instead of heavy abstraction layers.
Code Example
use ;
use ServerConfigurations;
async
⚠️ Current Architecture Limitations
While water_http is engineered for extreme raw performance, certain feature combinations are explicitly restricted due to fundamental architectural trade-offs.
1. io_uring is Restricted to Plaintext HTTP/1.x Only
The high-performance asynchronous io_uring completion-based engine is strictly scoped to plaintext HTTP/1.x. It is deliberately not supported alongside TLS or HTTP/2 for the following system-level reasons:
-
TLS Devalues
io_uring(System Call Optimization Defeat): The core purpose of utilizingio_uringis to eliminate runtime system calls (read/write) by sharing submission and completion queues directly with the kernel. When using TLS, encrypted data must constantly be brought back up to user-space cryptographic libraries (likerustlsoropenssl) for decryption and processing before the server can even understand the HTTP payload. This user-space memory thrashing and parsing overhead completely negates the syscall-limitation benefits thatio_uringprovides, making it functionally useless for encrypted streams. -
HTTP/2 Requires a Separate From-Scratch Architecture: HTTP/2 shifts the network paradigm to a highly multiplexed, single-connection stream framework. Mapping asynchronous, independent kernel completion events back to a heavily stateful, multiplexed frame system requires an entirely custom I/O architecture built from scratch specifically for that purpose.
🛠️ Fallback Behavior: When your server configurations enable TLS/SSL or require HTTP/2 features,
water_httptransparently shifts routing traffic to its highly optimized, stable epoll/Tokio-driven runtime network backend, ensuring 100% feature reliability.
2. Strict Path-Based Routing (No Method Multiplexing)
To achieve absolute maximum routing throughput and eliminate pointer-chasing overhead during requests, water_http utilizes an ultra-lean, highly optimized map to resolve route handlers. Consequently, the router matches strictly by the URI path string, introducing a strict design rule:
No Shared Paths Across HTTP Methods: You cannot bind multiple HTTP methods (such as a GET and a POST) to the exact same path string (e.g., /api/data). If paths overlap, one handler will overwrite the other in the map.
The Performance Payload: By removing multi-method conditional branching and nested lookups inside the hot path of the router, path lookup achieves near-constant time complexity, keeping route resolution lightning fast.
💡 Recommended Design Pattern: If you need to handle multiple actions on a single resource, use explicit, high-performance RESTful paths (e.g., GET /api/data_get and POST /api/data_post) or distinct action-based prefixes.