HTTP Server
Overview
Zephyr provides an HTTP server library, which allows to register HTTP services and HTTP resources associated with those services. The server creates a listening socket for every registered service, and handles incoming client connections. It’s possible to communicate over a plain TCP socket (HTTP) or a TLS socket (HTTPS). Both, HTTP/1.1 (RFC 2616) and HTTP/2 (RFC 9113) protocol versions are supported.
The server operation is generally transparent for the application, running in a background thread. The application can control the server activity with respective API functions.
Certain resource types (for example dynamic resource) provide resource-specific application callbacks, allowing the server to interact with the application (for instance provide resource content, or process request payload).
Currently, the following resource types are supported:
Static resources - content defined compile-time, cannot be modified at runtime (
HTTP_RESOURCE_TYPE_STATIC
).Dynamic resources - content provided at runtime by respective application callback (
HTTP_RESOURCE_TYPE_DYNAMIC
).Websocket resources - allowing to establish Websocket connections with the server (
HTTP_RESOURCE_TYPE_WEBSOCKET
).
Zephyr provides a sample demonstrating HTTP(s) server operation and various resource types usage. See HTTP Server for more information.
Server Setup
A few prerequisites are needed in order to enable HTTP server functionality in the application.
First of all, the HTTP server has to be enabled in applications configuration file
with CONFIG_HTTP_SERVER
Kconfig option:
CONFIG_HTTP_SERVER=y
All HTTP services and HTTP resources are placed in a dedicated linker section.
The linker section for services is predefined locally, however the application
is responsible for defining linker sections for resources associated with
respective services. Linker section names for resources should be prefixed with
http_resource_desc_
, appended with the service name.
Linker sections for resources should be defined in a linker file. For example,
for a service named my_service
, the linker section shall be defined as follows:
#include <zephyr/linker/iterable_sections.h>
ITERABLE_SECTION_ROM(http_resource_desc_my_service, Z_LINK_ITERABLE_SUBALIGN)
Finally, the linker file and linker section have to be added to your application using CMake:
zephyr_linker_sources(SECTIONS sections-rom.ld)
zephyr_linker_section(NAME http_resource_desc_my_service
KVMA RAM_REGION GROUP RODATA_REGION
SUBALIGN Z_LINK_ITERABLE_SUBALIGN)
Note
You need to define a separate linker section for each HTTP service registered in the system.
Sample Usage
Services
The application needs to define an HTTP service (or multiple services), with
the same name as used for the linker section with HTTP_SERVICE_DEFINE
macro:
#include <zephyr/net/http/service.h>
static uint16_t http_service_port = 80;
HTTP_SERVICE_DEFINE(my_service, "0.0.0.0", &http_service_port, 1, 10, NULL);
Alternatively, an HTTPS service can be defined with with
HTTPS_SERVICE_DEFINE
:
#include <zephyr/net/http/service.h>
#include <zephyr/net/tls_credentials.h>
#define HTTP_SERVER_CERTIFICATE_TAG 1
static uint16_t https_service_port = 443;
static const sec_tag_t sec_tag_list[] = {
HTTP_SERVER_CERTIFICATE_TAG,
};
HTTPS_SERVICE_DEFINE(my_service, "0.0.0.0", &https_service_port, 1, 10,
NULL, sec_tag_list, sizeof(sec_tag_list));
Note
HTTPS services rely on TLS credentials being registered in the system. See TLS credentials subsystem for information on how to configure TLS credentials in the system.
Once HTTP(s) service is defined, resources can be registered for it with
HTTP_RESOURCE_DEFINE
macro.
Static resources
Static resource content is defined build-time and is immutable. The following example shows how gzip compressed webpage can be defined as a static resource in the application:
static const uint8_t index_html_gz[] = {
#include "index.html.gz.inc"
};
struct http_resource_detail_static index_html_gz_resource_detail = {
.common = {
.type = HTTP_RESOURCE_TYPE_STATIC,
.bitmask_of_supported_http_methods = BIT(HTTP_GET),
.content_encoding = "gzip",
},
.static_data = index_html_gz,
.static_data_len = sizeof(index_html_gz),
};
HTTP_RESOURCE_DEFINE(index_html_gz_resource, my_service, "/",
&index_html_gz_resource_detail);
The resource content and content encoding is application specific. For the above
example, a gzip compressed webpage can be generated during build, by adding the
following code to the application’s CMakeLists.txt
file:
set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/)
set(source_file_index src/index.html)
generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.gz.inc --gzip)
where src/index.html
is the location of the webpage to be compressed.
Dynamic resources
For dynamic resource, a resource callback is registered to exchange data between the server and the application. The application defines a resource buffer used to pass the request payload data from the server, and to provide response payload to the server. The following example code shows how to register a dynamic resource with a simple resource handler, which echoes received data back to the client:
static uint8_t recv_buffer[1024];
static int dyn_handler(struct http_client_ctx *client,
enum http_data_status status, uint8_t *buffer,
size_t len, void *user_data)
{
#define MAX_TEMP_PRINT_LEN 32
static char print_str[MAX_TEMP_PRINT_LEN];
enum http_method method = client->method;
static size_t processed;
__ASSERT_NO_MSG(buffer != NULL);
if (status == HTTP_SERVER_DATA_ABORTED) {
LOG_DBG("Transaction aborted after %zd bytes.", processed);
processed = 0;
return 0;
}
processed += len;
snprintf(print_str, sizeof(print_str), "%s received (%zd bytes)",
http_method_str(method), len);
LOG_HEXDUMP_DBG(buffer, len, print_str);
if (status == HTTP_SERVER_DATA_FINAL) {
LOG_DBG("All data received (%zd bytes).", processed);
processed = 0;
}
/* This will echo data back to client as the buffer and recv_buffer
* point to same area.
*/
return len;
}
struct http_resource_detail_dynamic dyn_resource_detail = {
.common = {
.type = HTTP_RESOURCE_TYPE_DYNAMIC,
.bitmask_of_supported_http_methods =
BIT(HTTP_GET) | BIT(HTTP_POST),
},
.cb = dyn_handler,
.data_buffer = recv_buffer,
.data_buffer_len = sizeof(recv_buffer),
.user_data = NULL,
};
HTTP_RESOURCE_DEFINE(dyn_resource, my_service, "/dynamic",
&dyn_resource_detail);
The resource callback may be called multiple times for a single request, hence the application should be able to keep track of the received data progress.
The status
field informs the application about the progress in passing
request payload from the server to the application. As long as the status
reports HTTP_SERVER_DATA_MORE
, the application should expect
more data to be provided in a consecutive callback calls.
Once all request payload has been passed to the application, the server reports
HTTP_SERVER_DATA_FINAL
status. In case of communication errors
during request processing (for example client closed the connection before
complete payload has been received), the server reports
HTTP_SERVER_DATA_ABORTED
. Either of the two events indicate that
the application shall reset any progress recorded for the resource, and await
a new request to come. The server guarantees that the resource can only be
accessed by single client at a time.
The resource callback returns the number of bytes to be replied in the response payload to the server (provided in the resource data buffer). In case there is no more data to be included in the response, the callback should return 0.
The server will call the resource callback until it provided all request data to the application, and the application reports there is no more data to include in the reply.
Websocket resources
Websocket resources register an application callback, which is is called when a Websocket connection upgrade takes place. The callback is provided with a socket descriptor corresponding to the underlying TCP/TLS connection. Once called, the application takes full control over the socket, i. e. is responsible to release it when done.
static int ws_socket;
static uint8_t ws_recv_buffer[1024];
int ws_setup(int sock, void *user_data)
{
ws_socket = sock;
return 0;
}
struct http_resource_detail_websocket ws_resource_detail = {
.common = {
.type = HTTP_RESOURCE_TYPE_WEBSOCKET,
/* We need HTTP/1.1 Get method for upgrading */
.bitmask_of_supported_http_methods = BIT(HTTP_GET),
},
.cb = ws_setup,
.data_buffer = ws_recv_buffer,
.data_buffer_len = sizeof(ws_recv_buffer),
.user_data = NULL, /* Fill this for any user specific data */
};
HTTP_RESOURCE_DEFINE(ws_resource, my_service, "/", &ws_resource_detail);
The above minimalistic example shows how to register a Websocket resource with a simple callback, used only to store the socket descriptor provided. Further processing of the Websocket connection is application-specific, hence outside of scope of this guide. See HTTP Server for an example Websocket-based echo service implementation.
API Reference
- group http_service
Defines
-
HTTP_RESOURCE_DEFINE(_name, _service, _resource, _detail)
Define a static HTTP resource.
A static HTTP resource is one that is known prior to system initialization. In contrast, dynamic resources may be discovered upon system initialization. Dynamic resources may also be inserted, or removed by events originating internally or externally to the system at runtime.
Note
The
_resource
is the URL without the associated protocol, host, or URL parameters. E.g. the resource for#param1=value1
would be/bar/baz.html
. It is often referred to as the “path” of the URL. Every(service, resource)
pair should be unique. The_resource
must be non-NULL.- Parameters:
_name – Name of the resource.
_service – Name of the associated service.
_resource – Pathname-like string identifying the resource.
_detail – Implementation-specific detail associated with the resource.
-
HTTP_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail)
Define an HTTP service without static resources.
Note
The
_host
parameter must be non-NULL
. It is used to specify an IP address either in IPv4 or IPv6 format a fully-qualified hostname or a virtual host.Note
The
_port
parameter must be non-NULL
. It points to a location that specifies the port number to use for the service. If the specified port number is zero, then an ephemeral port number will be used and the actual port number assigned will be written back to memory. For ephemeral port numbers, the memory pointed to by_port
must be writeable.- Parameters:
_name – Name of the service.
_host – IP address or hostname associated with the service.
_port – [inout] Pointer to port associated with the service.
_concurrent – Maximum number of concurrent clients.
_backlog – Maximum number queued connections.
_detail – Implementation-specific detail associated with the service.
-
HTTPS_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail, _sec_tag_list, _sec_tag_list_size)
Define an HTTPS service without static resources.
Note
The
_host
parameter must be non-NULL
. It is used to specify an IP address either in IPv4 or IPv6 format a fully-qualified hostname or a virtual host.Note
The
_port
parameter must be non-NULL
. It points to a location that specifies the port number to use for the service. If the specified port number is zero, then an ephemeral port number will be used and the actual port number assigned will be written back to memory. For ephemeral port numbers, the memory pointed to by_port
must be writeable.- Parameters:
_name – Name of the service.
_host – IP address or hostname associated with the service.
_port – [inout] Pointer to port associated with the service.
_concurrent – Maximum number of concurrent clients.
_backlog – Maximum number queued connections.
_detail – Implementation-specific detail associated with the service.
_sec_tag_list – TLS security tag list used to setup a HTTPS socket.
_sec_tag_list_size – TLS security tag list size used to setup a HTTPS socket.
-
HTTP_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail)
Define an HTTP service with static resources.
Note
The
_host
parameter must be non-NULL
. It is used to specify an IP address either in IPv4 or IPv6 format a fully-qualified hostname or a virtual host.Note
The
_port
parameter must be non-NULL
. It points to a location that specifies the port number to use for the service. If the specified port number is zero, then an ephemeral port number will be used and the actual port number assigned will be written back to memory. For ephemeral port numbers, the memory pointed to by_port
must be writeable.- Parameters:
_name – Name of the service.
_host – IP address or hostname associated with the service.
_port – [inout] Pointer to port associated with the service.
_concurrent – Maximum number of concurrent clients.
_backlog – Maximum number queued connections.
_detail – Implementation-specific detail associated with the service.
-
HTTPS_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail, _sec_tag_list, _sec_tag_list_size)
Define an HTTPS service with static resources.
Note
The
_host
parameter must be non-NULL
. It is used to specify an IP address either in IPv4 or IPv6 format a fully-qualified hostname or a virtual host.Note
The
_port
parameter must be non-NULL
. It points to a location that specifies the port number to use for the service. If the specified port number is zero, then an ephemeral port number will be used and the actual port number assigned will be written back to memory. For ephemeral port numbers, the memory pointed to by_port
must be writeable.- Parameters:
_name – Name of the service.
_host – IP address or hostname associated with the service.
_port – [inout] Pointer to port associated with the service.
_concurrent – Maximum number of concurrent clients.
_backlog – Maximum number queued connections.
_detail – Implementation-specific detail associated with the service.
_sec_tag_list – TLS security tag list used to setup a HTTPS socket.
_sec_tag_list_size – TLS security tag list size used to setup a HTTPS socket.
-
HTTP_SERVICE_COUNT(_dst)
Count the number of HTTP services.
- Parameters:
_dst – [out] Pointer to location where result is written.
-
HTTP_SERVICE_RESOURCE_COUNT(_service)
Count HTTP service static resources.
- Parameters:
_service – Pointer to a service.
-
HTTP_SERVICE_FOREACH(_it)
Iterate over all HTTP services.
- Parameters:
_it – Name of http_service_desc iterator
-
HTTP_RESOURCE_FOREACH(_service, _it)
Iterate over static HTTP resources associated with a given
_service
.Note
This macro requires that
_service
is defined with HTTP_SERVICE_DEFINE.- Parameters:
_service – Name of HTTP service
_it – Name of iterator (of type http_resource_desc)
-
HTTP_SERVICE_FOREACH_RESOURCE(_service, _it)
Iterate over all static resources associated with
_service
.Note
This macro is suitable for a
_service
defined with either HTTP_SERVICE_DEFINE or HTTP_SERVICE_DEFINE_EMPTY.- Parameters:
_service – Pointer to HTTP service
_it – Name of iterator (of type http_resource_desc)
-
struct http_resource_desc
- #include <service.h>
HTTP resource description.
-
HTTP_RESOURCE_DEFINE(_name, _service, _resource, _detail)
- group http_server
Typedefs
-
typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client, enum http_data_status status, uint8_t *data_buffer, size_t data_len, void *user_data)
Callback used when data is received.
Data to be sent to client can be specified.
- Param client:
HTTP context information for this client connection.
- Param status:
HTTP data status, indicate whether more data is expected or not.
- Param data_buffer:
Data received.
- Param data_len:
Amount of data received.
- Param user_data:
User specified data.
- Return:
>0 amount of data to be sent to client, let server to call this function again when new data is received. 0 nothing to sent to client, close the connection <0 error, close the connection.
-
typedef int (*http_resource_websocket_cb_t)(int ws_socket, void *user_data)
Callback used when a Websocket connection is setup.
The application will need to handle all functionality related to the connection like reading and writing websocket data, and closing the connection.
- Param ws_socket:
A socket for the Websocket data.
- Param user_data:
User specified data.
- Return:
0 Accepting the connection, HTTP server library will no longer handle data to/from the socket and it is application responsibility to send and receive data to/from the supplied socket. <0 error, close the connection.
Enums
-
enum http_resource_type
HTTP server resource type.
Values:
-
enumerator HTTP_RESOURCE_TYPE_STATIC
Static resource, cannot be modified on runtime.
-
enumerator HTTP_RESOURCE_TYPE_DYNAMIC
Dynamic resource, server interacts with the application via registered http_resource_dynamic_cb_t.
-
enumerator HTTP_RESOURCE_TYPE_WEBSOCKET
Websocket resource, application takes control over Websocket connection after and upgrade.
-
enumerator HTTP_RESOURCE_TYPE_STATIC
-
enum http_data_status
Indicates the status of the currently processed piece of data.
Values:
-
enumerator HTTP_SERVER_DATA_ABORTED = -1
Transaction aborted, data incomplete.
-
enumerator HTTP_SERVER_DATA_MORE = 0
Transaction incomplete, more data expected.
-
enumerator HTTP_SERVER_DATA_FINAL = 1
Final data fragment in current transaction.
-
enumerator HTTP_SERVER_DATA_ABORTED = -1
Functions
-
int http_server_start(void)
Start the HTTP2 server.
The server runs in a background thread. Once started, the server will create a server socket for all HTTP services registered in the system and accept connections from clients (see HTTP_SERVICE_DEFINE).
-
int http_server_stop(void)
Stop the HTTP2 server.
All server sockets are closed and the server thread is suspended.
-
struct http_resource_detail
- #include <server.h>
Representation of a server resource, common for all resource types.
Public Members
-
uint32_t bitmask_of_supported_http_methods
Bitmask of supported HTTP methods (http_method).
-
enum http_resource_type type
Resource type.
-
int path_len
Length of the URL path.
-
const char *content_encoding
Content encoding of the resource.
-
const char *content_type
Content type of the resource.
-
uint32_t bitmask_of_supported_http_methods
-
struct http_resource_detail_static
- #include <server.h>
Representation of a static server resource.
Public Members
-
struct http_resource_detail common
Common resource details.
-
const void *static_data
Content of the static resource.
-
size_t static_data_len
Size of the static resource.
-
struct http_resource_detail common
-
struct http_resource_detail_dynamic
- #include <server.h>
Representation of a dynamic server resource.
Public Members
-
struct http_resource_detail common
Common resource details.
-
http_resource_dynamic_cb_t cb
Resource callback used by the server to interact with the application.
-
uint8_t *data_buffer
Data buffer used to exchanged data between server and the, application.
-
size_t data_buffer_len
Length of the data in the data buffer.
-
struct http_client_ctx *holder
A pointer to the client currently processing resource, used to prevent concurrent access to the resource from multiple clients.
-
void *user_data
A pointer to the user data registered by the application.
-
struct http_resource_detail common
-
struct http_resource_detail_websocket
- #include <server.h>
Representation of a websocket server resource.
Public Members
-
struct http_resource_detail common
Common resource details.
-
int ws_sock
Websocket socket value.
-
http_resource_websocket_cb_t cb
Resource callback used by the server to interact with the application.
-
uint8_t *data_buffer
Data buffer used to exchanged data between server and the, application.
-
size_t data_buffer_len
Length of the data in the data buffer.
-
void *user_data
A pointer to the user data registered by the application.
-
struct http_resource_detail common
-
struct http_stream_ctx
- #include <server.h>
HTTP/2 stream representation.
-
struct http_frame
- #include <server.h>
HTTP/2 frame representation.
-
struct http_client_ctx
- #include <server.h>
Representation of an HTTP client connected to the server.
Public Members
-
int fd
Socket descriptor associated with the server.
-
unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE]
Client data buffer.
-
unsigned char *cursor
Cursor indicating currently processed byte.
-
size_t data_len
Data left to process in the buffer.
-
int window_size
Connection-level window size.
-
enum http_server_state server_state
Server state for the associated client.
-
struct http_frame current_frame
Currently processed HTTP/2 frame.
-
struct http_resource_detail *current_detail
Currently processed resource detail.
-
struct http_hpack_header_buf header_field
HTTP/2 header parser context.
-
struct http_stream_ctx streams[HTTP_SERVER_MAX_STREAMS]
HTTP/2 streams context.
-
struct http_parser_settings parser_settings
HTTP/1 parser configuration.
-
struct http_parser parser
HTTP/1 parser context.
-
unsigned char url_buffer[HTTP_SERVER_MAX_URL_LENGTH]
Request URL.
-
unsigned char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN]
Request content type.
-
unsigned char header_buffer[HTTP_SERVER_MAX_HEADER_LEN]
Temp buffer for currently processed header (HTTP/1 only).
-
size_t content_len
Request content length.
-
enum http_method method
Request method.
-
enum http1_parser_state parser_state
HTTP/1 parser state.
-
int http1_frag_data_len
Length of the payload length in the currently processed request fragment (HTTP/1 only).
-
struct k_work_delayable inactivity_timer
Client inactivity timer.
The client connection is closed by the server when it expires.
-
bool headers_sent
Flag indicating that headers were sent in the reply.
-
bool preface_sent
Flag indicating that HTTP2 preface was sent.
-
bool has_upgrade_header
Flag indicating that upgrade header was present in the request.
-
bool http2_upgrade
Flag indicating HTTP/2 upgrade takes place.
-
bool websocket_upgrade
Flag indicating Websocket upgrade takes place.
-
bool websocket_sec_key_next
Flag indicating Websocket key is being processed.
-
int fd
-
typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client, enum http_data_status status, uint8_t *data_buffer, size_t data_len, void *user_data)