Coroutine-per-connection HTTP/1.1 server using LEV async I/O, with
keep-alive, chunked transfer encoding, response compression (gzip/deflate),
and optional TLS with SNI support. Runs inside a lev.run() event loop.
| Name | Signature |
|---|---|
server:process_request | server:process_request(client, client_ip, count, redis_module) -> connection_state, err |
server:serve | server:serve() -> nil, err |
server:configure | server:configure(config) -> ok, err |
new | new(config, handle) -> server, err |
server:process_request(
client,client_ip,count,redis_module) ->connection_state,err
Process a single HTTP request on an accepted connection
Reads one HTTP/1.1 request from client, invokes self.handle, sends
the response, and returns the connection disposition string.
Return values:
"keep-alive" — request handled; the connection may be reused
"close" — response sent with Connection: close; caller must close
nil, err — fatal read/write error; caller must close the connection
count is the number of requests handled on this connection. When it
reaches cfg.requests_per_connection the response is sent with Connection: close.
The context table passed to self.handle contains:
logger — the server logger
client — the LEV TCP socket (for proxying)
cfg — a snapshot of the server config
redis_module — async Redis module for store injection
If handle returns all-nil values the request is assumed to have been
proxied directly on the socket and the connection is kept alive without
writing a response.
server:serve() ->
nil,err
Start accepting connections in a coroutine-per-connection event loop
Enters the LEV event loop, binds the configured address/port, then accepts connections. Each connection is handled in a spawned coroutine.
For each accepted connection:
Performs the TLS handshake if cfg.ssl is set
Calls process_request in a keep-alive loop until the client closes
or cfg.requests_per_connection is reached
Closes the socket
The connection_limit setting controls the maximum number of concurrent
connections (default 64).
server:configure(
config) ->ok,err
Apply configuration and validate TLS cert/key paths
Merges config into the server's current configuration table and
updates the logger level. If config.ssl is present, validates that
cert/key files exist. TLS identities are pre-parsed once before the
accept loop, while the handshake itself still happens per-connection
inside starttls().
The ssl field format:
ssl = {
default = { cert = "path/to/cert.pem", key = "path/to/key.pem" },
hosts = {
["example.com"] = { cert = "...", key = "..." },
},
}
Returns nil, err if a certificate or key file cannot be found.
new(
config,handle) ->server,err
Create a new HTTP server instance
Creates and configures an HTTP server. The handle function is called
for each request with (method, query, args, headers, body, context) and
must return content, status, response_headers.
The config table may override these defaults:
ip — bind address (default: "127.0.0.1")
port — listen port (default: 8080)
backlog — listen backlog (default: 256)
connection_limit — max concurrent connections (default: 64)
requests_per_connection — requests before connection closes (default: 512)
max_body_size — max request body in bytes (default: 5 MB)
request_line_limit — max header/request line (default: 8 KB)
keepalive_idle_timeout — keep-alive idle timeout (default: 15)
request_header_timeout — header read timeout (default: 10)
request_body_timeout — body read timeout (default: 30)
tls_handshake_timeout — TLS handshake timeout (default: 10)
ssl — TLS configuration (see below)
compression — compression settings table
log_level — log level (default: "access")
log_headers — request headers to log
TLS configuration (ssl field):
{
default = { cert = "path/to/cert", key = "path/to/key" },
hosts = {
["domain.com"] = { cert = "...", key = "..." },
},
}
The server uses a coroutine-per-connection model: each accepted
connection is handled in a spawned coroutine within lev.run().
local server = require("http.server")
local srv, err = server.new(
{
ip = "0.0.0.0",
port = 8443,
ssl = {
default = {
cert = "/etc/tls/cert.pem",
key = "/etc/tls/key.pem",
},
},
},
function(method, query, args, headers, body, ctx)
return "Hello!", 200, { ["content-type"] = "text/plain" }
end
)
if not srv then error(err) end
srv:serve() -- blocks forever