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
88.. note::
89
90    You need to define a separate linker section for each HTTP service
91    registered in the system.
92
93Sample Usage
94************
95
96Services
97========
98
99The application needs to define an HTTP service (or multiple services), with
100the same name as used for the linker section with :c:macro:`HTTP_SERVICE_DEFINE`
101macro:
102
103.. code-block:: c
104
105    #include <zephyr/net/http/service.h>
106
107    static uint16_t http_service_port = 80;
108
109    HTTP_SERVICE_DEFINE(my_service, "0.0.0.0", &http_service_port, 1, 10, NULL, NULL, NULL);
110
111Alternatively, an HTTPS service can be defined with
112:c:macro:`HTTPS_SERVICE_DEFINE`:
113
114.. code-block:: c
115
116    #include <zephyr/net/http/service.h>
117    #include <zephyr/net/tls_credentials.h>
118
119    #define HTTP_SERVER_CERTIFICATE_TAG 1
120
121    static uint16_t https_service_port = 443;
122    static const sec_tag_t sec_tag_list[] = {
123        HTTP_SERVER_CERTIFICATE_TAG,
124    };
125
126    HTTPS_SERVICE_DEFINE(my_service, "0.0.0.0", &https_service_port, 1, 10,
127                         NULL, NULL, NULL, sec_tag_list, sizeof(sec_tag_list));
128
129Per-service configuration
130=========================
131
132HTTP services support individual service configuration,
133for now it includes only socket creation through
134the ``http_service_config`` structure. This allows applications to customize
135socket creation behavior, for example to set specific socket options or use
136custom socket types.
137
138To use custom socket creation:
139
140.. code-block:: c
141
142    static int my_socket_create(const struct http_service_desc *svc, int af, int proto)
143    {
144        int fd;
145
146        /* Create socket with custom parameters */
147        fd = zsock_socket(af, SOCK_STREAM, proto);
148        if (fd < 0) {
149            return fd;
150        }
151
152        /* Set custom socket options */
153        /* Add any other custom socket configuration */
154
155        return fd;
156    }
157
158    static const struct http_service_config my_service_config = {
159        .socket_create = my_socket_create,
160    };
161
162    static uint16_t http_service_port = 80;
163
164    HTTP_SERVICE_DEFINE(my_service, "0.0.0.0", &http_service_port, 1, 10,
165                        NULL, NULL, &my_service_config);
166
167The custom socket creation function receives:
168- ``svc``: Pointer to the service descriptor
169- ``af``: Address family (AF_INET or AF_INET6)
170- ``proto``: Protocol (IPPROTO_TCP or IPPROTO_TLS_1_2 for HTTPS)
171
172The function should return the socket file descriptor on success, or a negative error code on failure.
173
174If no custom configuration is needed, simply pass ``NULL`` for the config parameter:
175
176.. code-block:: c
177
178    HTTP_SERVICE_DEFINE(my_service, "0.0.0.0", &http_service_port, 1, 10,
179                        NULL, NULL, NULL);
180
181Fallback Resources
182==================
183
184The ``_res_fallback`` parameter can be used when defining an HTTP/HTTPS service to
185specify a fallback resource which will be used if no other resource matches the
186URL. This can be used for example to serve an index page for all unknown paths
187(useful for a single-page app which handles routing in the frontend), or for a
188customised 404 response.
189
190.. code-block:: c
191
192    static int default_handler(struct http_client_ctx *client, enum http_data_status status,
193		       const struct http_request_ctx *request_ctx,
194		       struct http_response_ctx *response_ctx, void *user_data)
195    {
196        static const char response_404[] = "Oops, page not found!";
197
198        if (status == HTTP_SERVER_DATA_FINAL) {
199            response_ctx->status = 404;
200            response_ctx->body = response_404;
201            response_ctx->body_len = sizeof(response_404) - 1;
202            response_ctx->final_chunk = true;
203        }
204
205        return 0;
206    }
207
208    static struct http_resource_detail_dynamic default_detail = {
209        .common = {
210            .type = HTTP_RESOURCE_TYPE_DYNAMIC,
211            .bitmask_of_supported_http_methods = BIT(HTTP_GET),
212        },
213        .cb = default_handler,
214        .user_data = NULL,
215    };
216
217    /* Register a fallback resource to handle any unknown path */
218    HTTP_SERVICE_DEFINE(my_service, "0.0.0.0", &http_service_port, 1, 10, NULL, &default_detail, NULL);
219
220.. note::
221
222    HTTPS services rely on TLS credentials being registered in the system.
223    See :ref:`sockets_tls_credentials_subsys` for information on how to
224    configure TLS credentials in the system.
225
226Once HTTP(s) service is defined, resources can be registered for it with
227:c:macro:`HTTP_RESOURCE_DEFINE` macro.
228
229Application can enable resource wildcard support by enabling
230:kconfig:option:`CONFIG_HTTP_SERVER_RESOURCE_WILDCARD` option. When this
231option is set, then it is possible to match several incoming HTTP requests
232with just one resource handler. The `fnmatch()
233<https://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html>`__
234POSIX API function is used to match the pattern in the URL paths.
235
236Example:
237
238.. code-block:: c
239
240    HTTP_RESOURCE_DEFINE(my_resource, my_service, "/foo*", &resource_detail);
241
242This would match all URLs that start with a string ``foo``. See
243`POSIX.2 chapter 2.13
244<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13>`__
245for pattern matching syntax description.
246
247Static resources
248================
249
250Static resource content is defined build-time and is immutable. The following
251example shows how gzip compressed webpage can be defined as a static resource
252in the application:
253
254.. code-block:: c
255
256    static const uint8_t index_html_gz[] = {
257        #include "index.html.gz.inc"
258    };
259
260    struct http_resource_detail_static index_html_gz_resource_detail = {
261        .common = {
262            .type = HTTP_RESOURCE_TYPE_STATIC,
263            .bitmask_of_supported_http_methods = BIT(HTTP_GET),
264            .content_encoding = "gzip",
265        },
266        .static_data = index_html_gz,
267        .static_data_len = sizeof(index_html_gz),
268    };
269
270    HTTP_RESOURCE_DEFINE(index_html_gz_resource, my_service, "/",
271                         &index_html_gz_resource_detail);
272
273The resource content and content encoding is application specific. For the above
274example, a gzip compressed webpage can be generated during build, by adding the
275following code to the application's ``CMakeLists.txt`` file:
276
277.. code-block:: cmake
278    :caption: ``CMakeLists.txt``
279
280    set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/)
281    set(source_file_index src/index.html)
282    generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.gz.inc --gzip)
283
284where ``src/index.html`` is the location of the webpage to be compressed.
285
286Static filesystem resources
287===========================
288
289Static filesystem resource content is defined build-time and is immutable. Note that only
290``GET`` operation is supported, user is not able to upload files to the filesystem. The following
291example shows how the path can be defined as a static resource in the application:
292
293.. code-block:: c
294
295    struct http_resource_detail_static_fs static_fs_resource_detail = {
296        .common = {
297            .type                              = HTTP_RESOURCE_TYPE_STATIC_FS,
298            .bitmask_of_supported_http_methods = BIT(HTTP_GET),
299        },
300        .fs_path = "/lfs1/www",
301    };
302
303    HTTP_RESOURCE_DEFINE(static_fs_resource, my_service, "*", &static_fs_resource_detail);
304
305All files located in /lfs1/www are made available to the client. If a file is
306gzipped, .gz must be appended to the file name (e.g. index.html.gz), then the
307server delivers index.html.gz when the client requests index.html and adds gzip
308content-encoding to the HTTP header.
309
310The content type is evaluated based on the file extension. The server supports
311.html, .js, .css, .jpg, .png and .svg. More content types can be provided with the
312:c:macro:`HTTP_SERVER_CONTENT_TYPE` macro. All other files are provided with the
313content type text/html.
314
315.. code-block:: c
316
317    HTTP_SERVER_CONTENT_TYPE(json, "application/json")
318
319When serving files from a static filesystem, the response chunk size can be configured
320using the :kconfig:option:`CONFIG_HTTP_SERVER_STATIC_FS_RESPONSE_SIZE` Kconfig option.
321This determines the size of individual chunks when transmitting file content to clients.
322
323Dynamic resources
324=================
325
326For dynamic resource, a resource callback is registered to exchange data between
327the server and the application.
328
329The following example code shows how to register a dynamic resource with a simple
330resource handler, which echoes received data back to the client:
331
332.. code-block:: c
333
334    static int dyn_handler(struct http_client_ctx *client, enum http_data_status status,
335                           const struct http_request_ctx *request_ctx,
336                           struct http_response_ctx *response_ctx, void *user_data)
337    {
338    #define MAX_TEMP_PRINT_LEN 32
339        static char print_str[MAX_TEMP_PRINT_LEN];
340        enum http_method method = client->method;
341        static size_t processed;
342
343        __ASSERT_NO_MSG(buffer != NULL);
344
345        if (status == HTTP_SERVER_DATA_ABORTED) {
346            LOG_DBG("Transaction aborted after %zd bytes.", processed);
347            processed = 0;
348            return 0;
349        }
350
351        processed += request_ctx->data_len;
352
353        snprintf(print_str, sizeof(print_str), "%s received (%zd bytes)",
354                 http_method_str(method), request_ctx->data_len);
355        LOG_HEXDUMP_DBG(request_ctx->data, request_ctx->data_len, print_str);
356
357        if (status == HTTP_SERVER_DATA_FINAL) {
358            LOG_DBG("All data received (%zd bytes).", processed);
359            processed = 0;
360        }
361
362        /* Echo data back to client */
363        response_ctx->body = request_ctx->data;
364        response_ctx->body_len = request_ctx->data_len;
365        response_ctx->final_chunk = (status == HTTP_SERVER_DATA_FINAL);
366
367        return 0;
368    }
369
370    struct http_resource_detail_dynamic dyn_resource_detail = {
371        .common = {
372            .type = HTTP_RESOURCE_TYPE_DYNAMIC,
373            .bitmask_of_supported_http_methods =
374                BIT(HTTP_GET) | BIT(HTTP_POST),
375        },
376        .cb = dyn_handler,
377        .user_data = NULL,
378    };
379
380    HTTP_RESOURCE_DEFINE(dyn_resource, my_service, "/dynamic",
381                         &dyn_resource_detail);
382
383
384The resource callback may be called multiple times for a single request, hence
385the application should be able to keep track of the received data progress.
386
387The ``status`` field informs the application about the progress in passing
388request payload from the server to the application. As long as the status
389reports :c:enumerator:`HTTP_SERVER_DATA_MORE`, the application should expect
390more data to be provided in a consecutive callback calls.
391Once all request payload has been passed to the application, the server reports
392:c:enumerator:`HTTP_SERVER_DATA_FINAL` status. In case of communication errors
393during request processing (for example client closed the connection before
394complete payload has been received), the server reports
395:c:enumerator:`HTTP_SERVER_DATA_ABORTED`. Either of the two events indicate that
396the application shall reset any progress recorded for the resource, and await
397a new request to come. The server guarantees that the resource can only be
398accessed by single client at a time.
399
400The ``request_ctx`` parameter is used to pass request data to the application:
401
402* The ``data`` and ``data_len`` fields pass request data to the application.
403
404* The ``headers``, ``header_count`` and ``headers_status`` fields pass request
405  headers to the application, if
406  :kconfig:option:`CONFIG_HTTP_SERVER_CAPTURE_HEADERS` is enabled.
407
408The ``response_ctx`` field is used by the application to pass response data to
409the HTTP server:
410
411* The ``status`` field allows the application to send an HTTP response code. If
412  not populated, the response code will be 200 by default.
413
414* The ``headers`` and ``header_count`` fields can be used for the application to
415  send any arbitrary HTTP headers. If not populated, only Transfer-Encoding and
416  Content-Type are sent by default. The callback may override the Content-Type
417  if desired.
418
419* The ``body`` and ``body_len`` fields are used to send body data.
420
421* The ``final_chunk`` field is used to indicate that the application has no more
422  response data to send.
423
424Headers and/or response codes may only be sent in the first populated
425``response_ctx``, after which only further body data is allowed in subsequent
426callbacks.
427
428The server will call the resource callback until it provided all request data
429to the application, and the application reports there is no more data to include
430in the reply.
431
432Websocket resources
433===================
434
435Websocket resources register an application callback, which is called when a
436Websocket connection upgrade takes place. The callback is provided with a socket
437descriptor corresponding to the underlying TCP/TLS connection. Once called,
438the application takes full control over the socket, i. e. is responsible to
439release it when done.
440
441.. code-block:: c
442
443    static int ws_socket;
444    static uint8_t ws_recv_buffer[1024];
445
446    int ws_setup(int sock, struct http_request_ctx *request_ctx, void *user_data)
447    {
448        ws_socket = sock;
449        return 0;
450    }
451
452    struct http_resource_detail_websocket ws_resource_detail = {
453        .common = {
454            .type = HTTP_RESOURCE_TYPE_WEBSOCKET,
455            /* We need HTTP/1.1 Get method for upgrading */
456            .bitmask_of_supported_http_methods = BIT(HTTP_GET),
457        },
458        .cb = ws_setup,
459        .data_buffer = ws_recv_buffer,
460        .data_buffer_len = sizeof(ws_recv_buffer),
461        .user_data = NULL, /* Fill this for any user specific data */
462    };
463
464    HTTP_RESOURCE_DEFINE(ws_resource, my_service, "/", &ws_resource_detail);
465
466The above minimalistic example shows how to register a Websocket resource with
467a simple callback, used only to store the socket descriptor provided. Further
468processing of the Websocket connection is application-specific, hence outside
469of scope of this guide. See :zephyr:code-sample:`sockets-http-server` for an
470example Websocket-based echo service implementation.
471
472Accessing request headers
473=========================
474
475The application can register an interest in any specific HTTP request headers.
476These headers are then stored for each incoming request, and can be accessed
477from within a dynamic resource callback. Request headers are only included in
478the first callback for a given request, and are not passed to any subsequent
479callbacks.
480
481This feature must first be enabled with
482:kconfig:option:`CONFIG_HTTP_SERVER_CAPTURE_HEADERS` Kconfig option.
483
484Then the application can register headers to be captured, and read the values
485from within the dynamic resource callback:
486
487.. code-block:: c
488
489    HTTP_SERVER_REGISTER_HEADER_CAPTURE(capture_user_agent, "User-Agent");
490
491    static int dyn_handler(struct http_client_ctx *client, enum http_data_status status,
492                           uint8_t *buffer, size_t len, void *user_data)
493    {
494        size_t header_count = client->header_capture_ctx.count;
495        const struct http_header *headers = client->header_capture_ctx.headers;
496
497        LOG_INF("Captured %d headers with request", header_count);
498
499        for (uint32_t i = 0; i < header_count; i++) {
500            LOG_INF("Header: '%s: %s'", headers[i].name, headers[i].value);
501        }
502
503        return 0;
504    }
505
506API Reference
507*************
508
509.. doxygengroup:: http_service
510.. doxygengroup:: http_server
511