1.. _http_server_interface:
2
3HTTP Server
4###########
5
6.. contents::
7    :local:
8    :depth: 2
9
10Overview
11********
12
13Zephyr provides an HTTP server library, which allows to register HTTP services
14and HTTP resources associated with those services. The server creates a listening
15socket for every registered service, and handles incoming client connections.
16It's possible to communicate over a plain TCP socket (HTTP) or a TLS socket (HTTPS).
17Both, HTTP/1.1 (RFC 2616) and HTTP/2 (RFC 9113) protocol versions are supported.
18
19The server operation is generally transparent for the application, running in a
20background thread. The application can control the server activity with
21respective API functions.
22
23Certain resource types (for example dynamic resource) provide resource-specific
24application callbacks, allowing the server to interact with the application (for
25instance provide resource content, or process request payload).
26
27Currently, the following resource types are supported:
28
29* Static resources - content defined compile-time, cannot be modified at runtime
30  (:c:enumerator:`HTTP_RESOURCE_TYPE_STATIC`).
31
32* Static file system resources - the path at which the filesystem is mounted,
33  and the URL at which the filesystem is made available are fixed at build time,
34  but the content within the filesystem can be changed dynamically. This means that
35  the files can be created, modified or deleted by some other code outside the HTTP
36  server (:c:enumerator:`HTTP_RESOURCE_TYPE_STATIC_FS`).
37
38* Dynamic resources - content provided at runtime by respective application
39  callback (:c:enumerator:`HTTP_RESOURCE_TYPE_DYNAMIC`).
40
41* Websocket resources - allowing to establish Websocket connections with the
42  server (:c:enumerator:`HTTP_RESOURCE_TYPE_WEBSOCKET`).
43
44Zephyr provides a sample demonstrating HTTP(s) server operation and various
45resource types usage. See :zephyr:code-sample:`sockets-http-server` for more
46information.
47
48Server Setup
49************
50
51A few prerequisites are needed in order to enable HTTP server functionality in
52the application.
53
54First of all, the HTTP server has to be enabled in applications configuration file
55with :kconfig:option:`CONFIG_HTTP_SERVER` Kconfig option:
56
57.. code-block:: cfg
58    :caption: ``prj.conf``
59
60    CONFIG_HTTP_SERVER=y
61
62All HTTP services and HTTP resources are placed in a dedicated linker section.
63The linker section for services is predefined locally, however the application
64is responsible for defining linker sections for resources associated with
65respective services. Linker section names for resources should be prefixed with
66``http_resource_desc_``, appended with the service name.
67
68Linker sections for resources should be defined in a linker file. For example,
69for a service named ``my_service``, the linker section shall be defined as follows:
70
71.. code-block:: c
72    :caption: ``sections-rom.ld``
73
74    #include <zephyr/linker/iterable_sections.h>
75
76    ITERABLE_SECTION_ROM(http_resource_desc_my_service, Z_LINK_ITERABLE_SUBALIGN)
77
78Finally, the linker file and linker section have to be added to your application
79using CMake:
80
81.. code-block:: cmake
82    :caption: ``CMakeLists.txt``
83
84    zephyr_linker_sources(SECTIONS sections-rom.ld)
85    zephyr_linker_section(NAME http_resource_desc_my_service
86                          KVMA RAM_REGION GROUP RODATA_REGION
87                          SUBALIGN ${CONFIG_LINKER_ITERABLE_SUBALIGN})
88
89.. note::
90
91    You need to define a separate linker section for each HTTP service
92    registered in the system.
93
94Sample Usage
95************
96
97Services
98========
99
100The application needs to define an HTTP service (or multiple services), with
101the same name as used for the linker section with :c:macro:`HTTP_SERVICE_DEFINE`
102macro:
103
104.. code-block:: c
105
106    #include <zephyr/net/http/service.h>
107
108    static uint16_t http_service_port = 80;
109
110    HTTP_SERVICE_DEFINE(my_service, "0.0.0.0", &http_service_port, 1, 10, NULL, NULL);
111
112Alternatively, an HTTPS service can be defined with
113:c:macro:`HTTPS_SERVICE_DEFINE`:
114
115.. code-block:: c
116
117    #include <zephyr/net/http/service.h>
118    #include <zephyr/net/tls_credentials.h>
119
120    #define HTTP_SERVER_CERTIFICATE_TAG 1
121
122    static uint16_t https_service_port = 443;
123    static const sec_tag_t sec_tag_list[] = {
124        HTTP_SERVER_CERTIFICATE_TAG,
125    };
126
127    HTTPS_SERVICE_DEFINE(my_service, "0.0.0.0", &https_service_port, 1, 10,
128                         NULL, NULL, sec_tag_list, sizeof(sec_tag_list));
129
130The ``_res_fallback`` parameter can be used when defining an HTTP/HTTPS service to
131specify a fallback resource which will be used if no other resource matches the
132URL. This can be used for example to serve an index page for all unknown paths
133(useful for a single-page app which handles routing in the frontend), or for a
134customised 404 response.
135
136.. code-block:: c
137
138    static int default_handler(struct http_client_ctx *client, enum http_data_status status,
139		       const struct http_request_ctx *request_ctx,
140		       struct http_response_ctx *response_ctx, void *user_data)
141    {
142        static const char response_404[] = "Oops, page not found!";
143
144        if (status == HTTP_SERVER_DATA_FINAL) {
145            response_ctx->status = 404;
146            response_ctx->body = response_404;
147            response_ctx->body_len = sizeof(response_404) - 1;
148            response_ctx->final_chunk = true;
149        }
150
151        return 0;
152    }
153
154    static struct http_resource_detail_dynamic default_detail = {
155        .common = {
156            .type = HTTP_RESOURCE_TYPE_DYNAMIC,
157            .bitmask_of_supported_http_methods = BIT(HTTP_GET),
158        },
159        .cb = default_handler,
160        .user_data = NULL,
161    };
162
163    /* Register a fallback resource to handle any unknown path */
164    HTTP_SERVICE_DEFINE(my_service, "0.0.0.0", &http_service_port, 1, 10, NULL, &default_detail);
165
166.. note::
167
168    HTTPS services rely on TLS credentials being registered in the system.
169    See :ref:`sockets_tls_credentials_subsys` for information on how to
170    configure TLS credentials in the system.
171
172Once HTTP(s) service is defined, resources can be registered for it with
173:c:macro:`HTTP_RESOURCE_DEFINE` macro.
174
175Application can enable resource wildcard support by enabling
176:kconfig:option:`CONFIG_HTTP_SERVER_RESOURCE_WILDCARD` option. When this
177option is set, then it is possible to match several incoming HTTP requests
178with just one resource handler. The `fnmatch()
179<https://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html>`__
180POSIX API function is used to match the pattern in the URL paths.
181
182Example:
183
184.. code-block:: c
185
186    HTTP_RESOURCE_DEFINE(my_resource, my_service, "/foo*", &resource_detail);
187
188This would match all URLs that start with a string ``foo``. See
189`POSIX.2 chapter 2.13
190<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13>`__
191for pattern matching syntax description.
192
193Static resources
194================
195
196Static resource content is defined build-time and is immutable. The following
197example shows how gzip compressed webpage can be defined as a static resource
198in the application:
199
200.. code-block:: c
201
202    static const uint8_t index_html_gz[] = {
203        #include "index.html.gz.inc"
204    };
205
206    struct http_resource_detail_static index_html_gz_resource_detail = {
207        .common = {
208            .type = HTTP_RESOURCE_TYPE_STATIC,
209            .bitmask_of_supported_http_methods = BIT(HTTP_GET),
210            .content_encoding = "gzip",
211        },
212        .static_data = index_html_gz,
213        .static_data_len = sizeof(index_html_gz),
214    };
215
216    HTTP_RESOURCE_DEFINE(index_html_gz_resource, my_service, "/",
217                         &index_html_gz_resource_detail);
218
219The resource content and content encoding is application specific. For the above
220example, a gzip compressed webpage can be generated during build, by adding the
221following code to the application's ``CMakeLists.txt`` file:
222
223.. code-block:: cmake
224    :caption: ``CMakeLists.txt``
225
226    set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/)
227    set(source_file_index src/index.html)
228    generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.gz.inc --gzip)
229
230where ``src/index.html`` is the location of the webpage to be compressed.
231
232Static filesystem resources
233===========================
234
235Static filesystem resource content is defined build-time and is immutable. Note that only
236``GET`` operation is supported, user is not able to upload files to the filesystem. The following
237example shows how the path can be defined as a static resource in the application:
238
239.. code-block:: c
240
241    struct http_resource_detail_static_fs static_fs_resource_detail = {
242        .common = {
243            .type                              = HTTP_RESOURCE_TYPE_STATIC_FS,
244            .bitmask_of_supported_http_methods = BIT(HTTP_GET),
245        },
246        .fs_path = "/lfs1/www",
247    };
248
249    HTTP_RESOURCE_DEFINE(static_fs_resource, my_service, "*", &static_fs_resource_detail);
250
251All files located in /lfs1/www are made available to the client. If a file is
252gzipped, .gz must be appended to the file name (e.g. index.html.gz), then the
253server delivers index.html.gz when the client requests index.html and adds gzip
254content-encoding to the HTTP header.
255
256The content type is evaluated based on the file extension. The server supports
257.html, .js, .css, .jpg, .png and .svg. More content types can be provided with the
258:c:macro:`HTTP_SERVER_CONTENT_TYPE` macro. All other files are provided with the
259content type text/html.
260
261.. code-block:: c
262
263    HTTP_SERVER_CONTENT_TYPE(json, "application/json")
264
265Dynamic resources
266=================
267
268For dynamic resource, a resource callback is registered to exchange data between
269the server and the application.
270
271The following example code shows how to register a dynamic resource with a simple
272resource handler, which echoes received data back to the client:
273
274.. code-block:: c
275
276    static int dyn_handler(struct http_client_ctx *client, enum http_data_status status,
277                           const struct http_request_ctx *request_ctx,
278                           struct http_response_ctx *response_ctx, void *user_data)
279    {
280    #define MAX_TEMP_PRINT_LEN 32
281        static char print_str[MAX_TEMP_PRINT_LEN];
282        enum http_method method = client->method;
283        static size_t processed;
284
285        __ASSERT_NO_MSG(buffer != NULL);
286
287        if (status == HTTP_SERVER_DATA_ABORTED) {
288            LOG_DBG("Transaction aborted after %zd bytes.", processed);
289            processed = 0;
290            return 0;
291        }
292
293        processed += request_ctx->data_len;
294
295        snprintf(print_str, sizeof(print_str), "%s received (%zd bytes)",
296                 http_method_str(method), request_ctx->data_len);
297        LOG_HEXDUMP_DBG(request_ctx->data, request_ctx->data_len, print_str);
298
299        if (status == HTTP_SERVER_DATA_FINAL) {
300            LOG_DBG("All data received (%zd bytes).", processed);
301            processed = 0;
302        }
303
304        /* Echo data back to client */
305        response_ctx->body = request_ctx->data;
306        response_ctx->body_len = request_ctx->data_len;
307        response_ctx->final_chunk = (status == HTTP_SERVER_DATA_FINAL);
308
309        return 0;
310    }
311
312    struct http_resource_detail_dynamic dyn_resource_detail = {
313        .common = {
314            .type = HTTP_RESOURCE_TYPE_DYNAMIC,
315            .bitmask_of_supported_http_methods =
316                BIT(HTTP_GET) | BIT(HTTP_POST),
317        },
318        .cb = dyn_handler,
319        .user_data = NULL,
320    };
321
322    HTTP_RESOURCE_DEFINE(dyn_resource, my_service, "/dynamic",
323                         &dyn_resource_detail);
324
325
326The resource callback may be called multiple times for a single request, hence
327the application should be able to keep track of the received data progress.
328
329The ``status`` field informs the application about the progress in passing
330request payload from the server to the application. As long as the status
331reports :c:enumerator:`HTTP_SERVER_DATA_MORE`, the application should expect
332more data to be provided in a consecutive callback calls.
333Once all request payload has been passed to the application, the server reports
334:c:enumerator:`HTTP_SERVER_DATA_FINAL` status. In case of communication errors
335during request processing (for example client closed the connection before
336complete payload has been received), the server reports
337:c:enumerator:`HTTP_SERVER_DATA_ABORTED`. Either of the two events indicate that
338the application shall reset any progress recorded for the resource, and await
339a new request to come. The server guarantees that the resource can only be
340accessed by single client at a time.
341
342The ``request_ctx`` parameter is used to pass request data to the application:
343
344* The ``data`` and ``data_len`` fields pass request data to the application.
345
346* The ``headers``, ``header_count`` and ``headers_status`` fields pass request
347  headers to the application, if
348  :kconfig:option:`CONFIG_HTTP_SERVER_CAPTURE_HEADERS` is enabled.
349
350The ``response_ctx`` field is used by the application to pass response data to
351the HTTP server:
352
353* The ``status`` field allows the application to send an HTTP response code. If
354  not populated, the response code will be 200 by default.
355
356* The ``headers`` and ``header_count`` fields can be used for the application to
357  send any arbitrary HTTP headers. If not populated, only Transfer-Encoding and
358  Content-Type are sent by default. The callback may override the Content-Type
359  if desired.
360
361* The ``body`` and ``body_len`` fields are used to send body data.
362
363* The ``final_chunk`` field is used to indicate that the application has no more
364  response data to send.
365
366Headers and/or response codes may only be sent in the first populated
367``response_ctx``, after which only further body data is allowed in subsequent
368callbacks.
369
370The server will call the resource callback until it provided all request data
371to the application, and the application reports there is no more data to include
372in the reply.
373
374Websocket resources
375===================
376
377Websocket resources register an application callback, which is called when a
378Websocket connection upgrade takes place. The callback is provided with a socket
379descriptor corresponding to the underlying TCP/TLS connection. Once called,
380the application takes full control over the socket, i. e. is responsible to
381release it when done.
382
383.. code-block:: c
384
385    static int ws_socket;
386    static uint8_t ws_recv_buffer[1024];
387
388    int ws_setup(int sock, struct http_request_ctx *request_ctx, void *user_data)
389    {
390        ws_socket = sock;
391        return 0;
392    }
393
394    struct http_resource_detail_websocket ws_resource_detail = {
395        .common = {
396            .type = HTTP_RESOURCE_TYPE_WEBSOCKET,
397            /* We need HTTP/1.1 Get method for upgrading */
398            .bitmask_of_supported_http_methods = BIT(HTTP_GET),
399        },
400        .cb = ws_setup,
401        .data_buffer = ws_recv_buffer,
402        .data_buffer_len = sizeof(ws_recv_buffer),
403        .user_data = NULL, /* Fill this for any user specific data */
404    };
405
406    HTTP_RESOURCE_DEFINE(ws_resource, my_service, "/", &ws_resource_detail);
407
408The above minimalistic example shows how to register a Websocket resource with
409a simple callback, used only to store the socket descriptor provided. Further
410processing of the Websocket connection is application-specific, hence outside
411of scope of this guide. See :zephyr:code-sample:`sockets-http-server` for an
412example Websocket-based echo service implementation.
413
414Accessing request headers
415=========================
416
417The application can register an interest in any specific HTTP request headers.
418These headers are then stored for each incoming request, and can be accessed
419from within a dynamic resource callback. Request headers are only included in
420the first callback for a given request, and are not passed to any subsequent
421callbacks.
422
423This feature must first be enabled with
424:kconfig:option:`CONFIG_HTTP_SERVER_CAPTURE_HEADERS` Kconfig option.
425
426Then the application can register headers to be captured, and read the values
427from within the dynamic resource callback:
428
429.. code-block:: c
430
431    HTTP_SERVER_REGISTER_HEADER_CAPTURE(capture_user_agent, "User-Agent");
432
433    static int dyn_handler(struct http_client_ctx *client, enum http_data_status status,
434                           uint8_t *buffer, size_t len, void *user_data)
435    {
436        size_t header_count = client->header_capture_ctx.count;
437        const struct http_header *headers = client->header_capture_ctx.headers;
438
439        LOG_INF("Captured %d headers with request", header_count);
440
441        for (uint32_t i = 0; i < header_count; i++) {
442            LOG_INF("Header: '%s: %s'", headers[i].name, headers[i].value);
443        }
444
445        return 0;
446    }
447
448API Reference
449*************
450
451.. doxygengroup:: http_service
452.. doxygengroup:: http_server
453