hendriknielaender/http2.zig
๐ HTTP/2 server for zig
main.tar.gz
WARNING
Still work in progress.
Add http2.zig to your build.zig.zon
:
.{
.name = "my-project",
.version = "1.0.0",
.dependencies = .{
.http2 = .{
.url = "https://github.com/hendriknielaender/http2.zig/archive/main.tar.gz",
.hash = "1220...", // Use `zig fetch` to get the hash
},
},
}
Import in your build.zig
:
const http2_module = b.dependency("http2", .{
.target = target,
.optimize = optimize,
}).module("http2");
exe.root_module.addImport("http2", http2_module);
const std = @import("std");
const http2 = @import("http2");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const address = try std.net.Address.resolveIp("127.0.0.1", 9001);
var listener = try address.listen(.{ .reuse_address = true });
defer listener.deinit();
std.debug.print("HTTP/2 server listening on 127.0.0.1:9001\\n", .{});
while (true) {
var conn = listener.accept() catch continue;
defer conn.stream.close();
// Create HTTP/2 connection
var server_conn = http2.Connection(
std.io.AnyReader,
std.io.AnyWriter
).init(
allocator,
conn.stream.reader().any(),
conn.stream.writer().any(),
true // is_server
) catch continue;
defer server_conn.deinit();
// Handle HTTP/2 protocol
server_conn.handle_connection() catch |err| {
std.debug.print("Connection error: {any}\\n", .{err});
};
}
}
http2.zig/
โโโ src/
โ โโโ http2.zig # Main entry point and public API
โ โโโ connection.zig # HTTP/2 connection with SIMD optimizations
โ โโโ stream.zig # Individual stream with compile-time budgeting
โ โโโ frame.zig # Frame parsing and serialization
โ โโโ hpack.zig # HPACK header compression
โ โโโ worker_pool.zig # libxev-based async worker pool
โ โโโ memory_budget.zig # Compile-time memory budgeting
โ โโโ budget_assertions.zig # Compile-time memory budget enforcement
โ โโโ error.zig # Error definitions and handling
โ โโโ tls.zig # TLS integration layer
โโโ benchmarks/
โ โโโ server.zig # High-performance benchmark server
โ โโโ bench.sh # Automated benchmark testing
โโโ example/
โ โโโ hello-world/ # Complete working example
โโโ docs/ # Documentation and guides
Connection
The heart of http2.zig - manages the HTTP/2 connection lifecycle with SIMD optimizations:
const Connection = http2.Connection(ReaderType, WriterType);
// Initialize server-side connection with memory budgeting
var memory_pool = try http2.memory_budget.StaticMemoryPool.init(allocator);
var conn = try Connection.init(allocator, reader, writer, true);
// Process HTTP/2 frames with hardware acceleration
try conn.handle_connection();
WorkerPool
High-performance async worker pool with libxev integration:
// Initialize worker pool with memory budgeting
var worker_pool = try http2.worker_pool.WorkerPool.init(allocator, &memory_pool);
try worker_pool.start();
// Submit connection work for async processing
try worker_pool.submitConnectionWork(connection);
Stream
Represents individual HTTP/2 streams with compile-time memory budgeting:
// Create stream with compile-time window size configuration
const MyStream = http2.Stream(16, 1000); // 64KB window, 1000 max streams
var stream = try MyStream.init(allocator, conn, stream_id);
// Send response with static buffers (no runtime allocation)
try stream.send_headers(headers, true); // end_stream = true
Frame
Type-safe frame processing with zero-copy parsing:
// Read incoming frame
var frame = try conn.receive_frame();
defer frame.deinit(allocator);
// Process by type
switch (frame.header.frame_type) {
FrameTypes.FRAME_TYPE_HEADERS => try handle_headers(frame),
FrameTypes.FRAME_TYPE_DATA => try handle_data(frame),
// ...
}
High-concurrency performance with 99%+ success rate:
# Run benchmark against server
cd benchmarks && make benchmark
# Results (18,411 req/sec with 99.01% success rate)
Total requests: 18606
Successful responses: 18422
Failed requests: 184
Success rate: 99.01%
http2.zig implements the complete HTTP/2 specification:
Current status: 146/168 tests passing (87%)
# Run conformance tests
h2spec http2 -h 127.0.0.1 -p 3000 -S
Key achievements:
The remaining 22 failing tests are primarily:
const MyHandler = struct {
pub fn handle_stream(stream: *http2.Stream, headers: []const http2.Header) !void {
// Custom request processing
if (std.mem.eql(u8, headers[0].value, "/api/data")) {
try stream.send_headers(&.{
.{ .name = ":status", .value = "200" },
.{ .name = "content-type", .value = "application/json" },
}, false);
try stream.send_data("{\"message\": \"Hello HTTP/2!\"}", true);
}
}
};
// Graceful error handling
conn.handle_connection() catch |err| switch (err) {
error.ProtocolError => {
// Client sent invalid HTTP/2 - GOAWAY already sent
std.log.warn("Protocol violation from client", .{});
},
error.ConnectionResetByPeer => {
// Normal client disconnect
std.log.info("Client disconnected", .{});
},
else => return err, // Propagate unexpected errors
};
// TLS-enabled HTTP/2 server
const tls_conn = try std.crypto.tls.Server.init(socket, cert, key);
var http2_conn = try http2.Connection(...).init(
allocator,
tls_conn.reader().any(),
tls_conn.writer().any(),
true
);
# Debug build
zig build
# Release build
zig build -Doptimize=ReleaseFast
# Run example
zig build run
# Unit tests
zig build test
# H2spec conformance tests (requires h2spec)
zig build test-h2spec
# Benchmark tests
cd benchmarks && make benchmark
We welcome contributions! Please see our Contributing Guide.
Areas for contribution:
MIT License - see LICENSE for details.