HTTP
Provides high-performance HTTP/1.1 server functionality built on libevpl.
The libevpl HTTP server is very minimalist in its current form, but it allows HTTP to be transmitted over arbitrary supported protocols possibly with zero-copy transfer.
Overview
libevpl’s HTTP support provides:
- HTTP/1.0 and HTTP/1.1 server - Handle GET, POST, PUT, DELETE, HEAD requests, at whichever version the request claims
- Streaming - Support for chunked transfer encoding and content-length
- Zero-copy - Use iovecs for efficient data transfer
- Header manipulation - Add custom request/response headers
- Multiple protocols - Run HTTP over TCP, XLIO, or RDMA
Supported methods: GET, HEAD, POST, PUT, DELETE
What the library decides for you
Message framing belongs to the library, not the application: it is the only part that knows both what the peer asked for and what is about to reach the wire. Specifically —
Dateis added to every response (RFC 9110 §6.6.1 makes it a MUST on 2xx, 3xx and 4xx). Do not add one; two would be a malformed message.Hostis added to every client request that does not already carry one (RFC 9112 §3.2 makes it a MUST on HTTP/1.1). Add one only to override the authority the endpoint implies.- The framing headers are chosen from the status and the request’s version, not only from what the application asked for. A 1xx or 204 response carries neither
Content-LengthnorTransfer-Encoding(RFC 9110 §8.6 and RFC 9112 §6.1); a chunked response to an HTTP/1.0 request is sent close-delimited instead, because that version has no chunked coding to decode. - The content of a response to HEAD, and of a 1xx, 204 or 304, is suppressed: the header fields a GET would have returned are still sent, and the octets are not (RFC 9112 §6.3).
- A status that is not a status — outside 100..599 — is answered
500with the original logged, since it cannot be put on the wire at all.
A conformance suite for all of this lives in src/http/tests; see src/http/tests/CONFORMANCE.md.
Types
struct evpl_http_agent
Opaque structure representing an HTTP agent (per event loop).
struct evpl_http_server
Opaque structure representing an HTTP server attached to a listener.
struct evpl_http_request
Opaque structure representing an individual HTTP request/response.
enum evpl_http_notify_type
HTTP event notifications:
| Type | Description |
|---|---|
EVPL_HTTP_NOTIFY_RECEIVE_DATA | Request body data available |
EVPL_HTTP_NOTIFY_RECEIVE_COMPLETE | Request fully received |
EVPL_HTTP_NOTIFY_WANT_DATA | Server ready for more response data |
EVPL_HTTP_NOTIFY_RESPONSE_COMPLETE | Response fully sent |
EVPL_HTTP_NOTIFY_RESPONSE_HEADERS | Client: status line and response headers received |
EVPL_HTTP_NOTIFY_FAILED | The request is over and will not complete |
Exactly one of RECEIVE_COMPLETE (client), RESPONSE_COMPLETE (server) or FAILED reaches a given request, so FAILED is where an application releases whatever it attached to one. Every request still outstanding on a connection gets it when the connection goes down, so a caller is never left waiting on a completion that can no longer happen. evpl_http_request_status() carries the reason:
| Reason | Meaning |
|---|---|
EVPL_HTTP_ERROR_CONN_LOST | The connection was lost before the request completed |
EVPL_HTTP_ERROR_BAD_RESPONSE | Client: the peer’s response could not be parsed |
The request is freed as soon as the callback returns, so nothing may reference it afterwards.
enum evpl_http_request_type
HTTP request methods:
EVPL_HTTP_REQUEST_TYPE_GETEVPL_HTTP_REQUEST_TYPE_HEADEVPL_HTTP_REQUEST_TYPE_POSTEVPL_HTTP_REQUEST_TYPE_PUTEVPL_HTTP_REQUEST_TYPE_DELETEEVPL_HTTP_REQUEST_TYPE_UNKNOWN
Callback Types
evpl_http_notify_callback_t
typedef void (*evpl_http_notify_callback_t)(
struct evpl *evpl,
struct evpl_http_agent *agent,
struct evpl_http_request *request,
enum evpl_http_notify_type notify_type,
enum evpl_http_request_type request_type,
const char *uri,
void *notify_data,
void *private_data);
Callback invoked for HTTP events on a specific request.
Parameters:
evpl- Event loopagent- HTTP agentrequest- HTTP requestnotify_type- Type of notificationrequest_type- HTTP method (GET, POST, etc.)uri- Request URInotify_data- Request-specific data (from dispatch callback)private_data- User context (from dispatch callback)
evpl_http_dispatch_callback_t
typedef void (*evpl_http_dispatch_callback_t)(
struct evpl *evpl,
struct evpl_http_agent *agent,
struct evpl_http_request *request,
evpl_http_notify_callback_t *notify_callback,
void **notify_data,
void *private_data);
Callback invoked when a new HTTP request arrives (routing/dispatch).
Parameters:
evpl- Event loopagent- HTTP agentrequest- New HTTP requestnotify_callback- [OUT] Set notification callback for this requestnotify_data- [OUT] Set request-specific contextprivate_data- Server context
Functions
Agent Management
evpl_http_init
struct evpl_http_agent *evpl_http_init(struct evpl *evpl);
Create an HTTP agent for an event loop.
Parameters:
evpl- Event loop
Returns: HTTP agent, or NULL on failure
Note: One agent per event loop.
evpl_http_destroy
void evpl_http_destroy(struct evpl_http_agent *agent);
Destroy an HTTP agent. All servers must be detached first.
Parameters:
agent- Agent to destroy
Server Management
evpl_http_attach
struct evpl_http_server *evpl_http_attach(
struct evpl_http_agent *agent,
struct evpl_listener *listener,
evpl_http_dispatch_callback_t dispatch_callback,
void *private_data);
Attach an HTTP server to a listener.
Parameters:
agent- HTTP agentlistener- Network listenerdispatch_callback- Request dispatch callbackprivate_data- Server context
Returns: HTTP server handle, or NULL on failure
evpl_http_server_destroy
void evpl_http_server_destroy(
struct evpl_http_agent *agent,
struct evpl_http_server *server);
Detach and destroy an HTTP server.
Parameters:
agent- HTTP agentserver- Server to destroy
Request Information
evpl_http_request_type
enum evpl_http_request_type evpl_http_request_type(
struct evpl_http_request *request);
Get the HTTP method of a request.
Returns: Request type enum
evpl_http_request_type_to_string
const char *evpl_http_request_type_to_string(
struct evpl_http_request *request);
Get the HTTP method as a string.
Returns: Method string (“GET”, “POST”, etc.)
evpl_http_request_url
const char *evpl_http_request_url(
struct evpl_http_request *request,
int *len);
Get the request URI.
Parameters:
request- HTTP requestlen- [OUT] URI length (optional, can beNULL)
Returns: URI string
evpl_http_request_header
const char *evpl_http_request_header(
struct evpl_http_request *request,
const char *name);
Get a request header value.
Parameters:
request- HTTP requestname- Header name (case-insensitive)
Returns: Header value, or NULL if not present
evpl_http_request_header_iterate
typedef void (*evpl_http_request_header_cb_t)(
const char *name,
const char *value,
void *private_data);
void evpl_http_request_header_iterate(
struct evpl_http_request *request,
evpl_http_request_header_cb_t callback,
void *private_data);
Invoke callback once for every header on the request, in the order the headers were received. Use this when the set of header names isn’t known up front — for example, when canonicalizing headers for signature verification.
The name and value pointers passed to the callback are owned by the request and remain valid for the duration of the call only; copy them if they need to outlive the callback.
Parameters:
request- HTTP requestcallback- Function to invoke for each headerprivate_data- Opaque pointer forwarded tocallback
Request Body
evpl_http_request_get_data_avail
uint64_t evpl_http_request_get_data_avail(
struct evpl_http_request *request);
Get the number of bytes available to read from request body.
Returns: Available bytes
evpl_http_request_get_datav
int evpl_http_request_get_datav(
struct evpl *evpl,
struct evpl_http_request *request,
struct evpl_iovec *iov,
int length);
Read request body data into iovecs.
Parameters:
evpl- Event looprequest- HTTP requestiov- [OUT] Iovec to receive datalength- Maximum bytes to read
Returns: Number of bytes read
Response Headers
evpl_http_request_add_header
int evpl_http_request_add_header(
struct evpl_http_request *request,
const char *name,
const char *value);
Add a header to the outbound block — response headers on a server connection, request headers on a client one.
Parameters:
request- HTTP requestname- Header namevalue- Header value
Returns: 0, or -1 with the header not added if either:
- it would push the block past the configured
http_max_header_size, or - the name is not a token (RFC 9110 §5.1), or the value contains CR or LF, which §5.5 calls “invalid and dangerous” and puts outside the field-value grammar. A CRLF in a value ends the field, so everything after it would be read as further fields and then as content — one message becoming two, the second chosen by whoever supplied the value. Worth testing the return wherever a value comes from outside the program.
Response Body
evpl_http_server_set_response_length
void evpl_http_server_set_response_length(
struct evpl_http_request *request,
uint64_t content_length);
Set the response Content-Length.
Parameters:
request- HTTP requestcontent_length- Response body size in bytes
Note: Call before sending data.
evpl_http_server_set_response_chunked
void evpl_http_server_set_response_chunked(
struct evpl_http_request *request);
Enable chunked transfer encoding for the response.
Parameters:
request- HTTP request
Use case: When response size is not known in advance.
evpl_http_request_add_datav
void evpl_http_request_add_datav(
struct evpl_http_request *request,
struct evpl_iovec *iov,
int niov);
Add response body data.
Parameters:
request- HTTP requestiov- Iovecs containing response dataniov- Number of iovecs
evpl_http_server_dispatch_default
void evpl_http_server_dispatch_default(
struct evpl_http_request *request,
int status);
Send a default response with a status code.
Parameters:
request- HTTP requeststatus- HTTP status code (200, 404, 500, etc.)
Use case: Quick responses for errors or simple status pages.
Client Connections
evpl_http_client_connect
struct evpl_http_conn *evpl_http_client_connect(
struct evpl_http_agent *agent,
enum evpl_protocol_id protocol_id,
struct evpl_endpoint *endpoint,
enum evpl_http_version version,
void *private_data);
Open a client connection. The handle belongs to the caller until evpl_http_client_close.
evpl_http_client_close
void evpl_http_client_close(
struct evpl_http_agent *agent,
struct evpl_http_conn *conn);
Release a client connection.
The handle stays valid even after the peer has gone away: a dropped connection is retired but not freed, so the pointer its owner holds never becomes stale at a moment the owner cannot observe. Every request outstanding on it is completed with EVPL_HTTP_NOTIFY_FAILED when that happens, which is how the owner learns.
Calling this on a connection whose peer has already gone is therefore fine, and is how such a connection is finally released. Dispatching a request on one is also safe: it completes immediately with EVPL_HTTP_NOTIFY_FAILED, before evpl_http_request_dispatch returns.
The handle must not be used afterwards.
See Also
- Binds & Connections API - Underlying network I/O
- Memory API - Buffer management
- Threading API - Multi-threaded servers
- Examples - Complete HTTP server examples (coming soon)