Line data Source code
1 1 : /*
2 : * Copyright (c) 2022 Meta
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : #ifndef ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_
8 : #define ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_
9 :
10 : /**
11 : * @file service.h
12 : *
13 : * @brief HTTP service API
14 : *
15 : * @defgroup http_service HTTP service API
16 : * @since 3.4
17 : * @version 0.1.0
18 : * @ingroup networking
19 : * @{
20 : */
21 :
22 : #include "zephyr/net/http/server.h"
23 : #include <stdint.h>
24 : #include <stddef.h>
25 :
26 : #include <zephyr/sys/util_macro.h>
27 : #include <zephyr/sys/iterable_sections.h>
28 : #include <zephyr/net/tls_credentials.h>
29 :
30 : #ifdef __cplusplus
31 : extern "C" {
32 : #endif
33 :
34 : /** HTTP resource description */
35 1 : struct http_resource_desc {
36 : /** Resource name */
37 1 : const char *resource;
38 : /** Detail associated with this resource */
39 1 : void *detail;
40 : };
41 :
42 : /**
43 : * @brief Define a static HTTP resource
44 : *
45 : * A static HTTP resource is one that is known prior to system initialization. In contrast,
46 : * dynamic resources may be discovered upon system initialization. Dynamic resources may also be
47 : * inserted, or removed by events originating internally or externally to the system at runtime.
48 : *
49 : * @note The @p _resource is the URL without the associated protocol, host, or URL parameters. E.g.
50 : * the resource for `http://www.foo.com/bar/baz.html#param1=value1` would be `/bar/baz.html`. It
51 : * is often referred to as the "path" of the URL. Every `(service, resource)` pair should be
52 : * unique. The @p _resource must be non-NULL.
53 : *
54 : * @param _name Name of the resource.
55 : * @param _service Name of the associated service.
56 : * @param _resource Pathname-like string identifying the resource.
57 : * @param _detail Implementation-specific detail associated with the resource.
58 : */
59 1 : #define HTTP_RESOURCE_DEFINE(_name, _service, _resource, _detail) \
60 : const STRUCT_SECTION_ITERABLE_ALTERNATE(http_resource_desc_##_service, http_resource_desc, \
61 : _name) = { \
62 : .resource = _resource, \
63 : .detail = (void *)(_detail), \
64 : }
65 :
66 : /** @cond INTERNAL_HIDDEN */
67 :
68 : struct http_service_runtime_data {
69 : int num_clients;
70 : };
71 :
72 : struct http_service_desc;
73 :
74 : /** Custom socket creation function type */
75 : typedef int (*http_socket_create_fn)(const struct http_service_desc *svc, int af, int proto);
76 :
77 : /** HTTP service configuration */
78 : struct http_service_config {
79 : /** Custom socket creation for the service if needed */
80 : http_socket_create_fn socket_create;
81 : /* If any more service-specific configuration is needed, it can be added here. */
82 : };
83 :
84 : struct http_service_desc {
85 : const char *host;
86 : uint16_t *port;
87 : int *fd;
88 : void *detail;
89 : size_t concurrent;
90 : size_t backlog;
91 : struct http_service_runtime_data *data;
92 : struct http_resource_desc *res_begin;
93 : struct http_resource_desc *res_end;
94 : struct http_resource_detail *res_fallback;
95 : const struct http_service_config *config;
96 : #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
97 : const sec_tag_t *sec_tag_list;
98 : size_t sec_tag_list_size;
99 : #endif
100 : };
101 :
102 : #define __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, \
103 : _res_fallback, _res_begin, _res_end, _config, ...) \
104 : BUILD_ASSERT(_concurrent <= CONFIG_HTTP_SERVER_MAX_CLIENTS, \
105 : "can't accept more then MAX_CLIENTS"); \
106 : BUILD_ASSERT(_backlog > 0, "backlog can't be 0"); \
107 : static int _name##_fd = -1; \
108 : static struct http_service_runtime_data _name##_data = {0}; \
109 : const STRUCT_SECTION_ITERABLE(http_service_desc, _name) = { \
110 : .host = _host, \
111 : .port = (uint16_t *)(_port), \
112 : .fd = &_name##_fd, \
113 : .detail = (void *)(_detail), \
114 : .concurrent = (_concurrent), \
115 : .backlog = (_backlog), \
116 : .data = &_name##_data, \
117 : .res_begin = (_res_begin), \
118 : .res_end = (_res_end), \
119 : .res_fallback = (_res_fallback), \
120 : .config = (_config), \
121 : COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS, \
122 : (.sec_tag_list = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (NULL), \
123 : (GET_ARG_N(1, __VA_ARGS__))),), ()) \
124 : COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS, \
125 : (.sec_tag_list_size = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (0),\
126 : (GET_ARG_N(1, GET_ARGS_LESS_N(1, __VA_ARGS__))))), ())\
127 : }
128 :
129 : /** @endcond */
130 :
131 : /**
132 : * @brief Define an HTTP service without static resources.
133 : *
134 : * @note The @p _host parameter is used to specify an IP address either in
135 : * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
136 : * port will listen on all addresses.
137 : *
138 : * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
139 : * number to use for the service. If the specified port number is zero, then an ephemeral port
140 : * number will be used and the actual port number assigned will be written back to memory. For
141 : * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
142 : *
143 : * @param _name Name of the service.
144 : * @param _host IP address or hostname associated with the service.
145 : * @param[inout] _port Pointer to port associated with the service.
146 : * @param _concurrent Maximum number of concurrent clients. (max. CONFIG_HTTP_SERVER_MAX_CLIENTS)
147 : * @param _backlog Maximum number of queued connections. (min. 1)
148 : * @param _detail User-defined detail associated with the service.
149 : * @param _res_fallback Fallback resource to be served if no other resource matches path
150 : * @param _config Pointer to http_service_config structure (can be NULL for default behavior)
151 : */
152 : #define HTTP_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail, \
153 1 : _res_fallback, _config) \
154 : __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, \
155 : _res_fallback, NULL, NULL, _config)
156 :
157 : /**
158 : * @brief Define an HTTPS service without static resources.
159 : *
160 : * @note The @p _host parameter is used to specify an IP address either in
161 : * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
162 : * port will listen on all addresses.
163 : *
164 : * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
165 : * number to use for the service. If the specified port number is zero, then an ephemeral port
166 : * number will be used and the actual port number assigned will be written back to memory. For
167 : * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
168 : *
169 : * @param _name Name of the service.
170 : * @param _host IP address or hostname associated with the service.
171 : * @param[inout] _port Pointer to port associated with the service.
172 : * @param _concurrent Maximum number of concurrent clients. (max. CONFIG_HTTP_SERVER_MAX_CLIENTS)
173 : * @param _backlog Maximum number of queued connections. (min. 1)
174 : * @param _detail User-defined detail associated with the service.
175 : * @param _res_fallback Fallback resource to be served if no other resource matches path
176 : * @param _config Pointer to http_service_config structure (can be NULL for default behavior)
177 : * @param _sec_tag_list TLS security tag list used to setup a HTTPS socket.
178 : * @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket.
179 : */
180 : #define HTTPS_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail, \
181 1 : _res_fallback, _config, _sec_tag_list, _sec_tag_list_size) \
182 : __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, \
183 : _res_fallback, NULL, NULL, _config, \
184 : _sec_tag_list, _sec_tag_list_size); \
185 : BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS), \
186 : "TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)")
187 :
188 : /**
189 : * @brief Define an HTTP service with static resources.
190 : *
191 : * @note The @p _host parameter is used to specify an IP address either in
192 : * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
193 : * port will listen on all addresses.
194 : *
195 : * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
196 : * number to use for the service. If the specified port number is zero, then an ephemeral port
197 : * number will be used and the actual port number assigned will be written back to memory. For
198 : * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
199 : *
200 : * @param _name Name of the service.
201 : * @param _host IP address or hostname associated with the service.
202 : * @param[inout] _port Pointer to port associated with the service.
203 : * @param _concurrent Maximum number of concurrent clients. (max. CONFIG_HTTP_SERVER_MAX_CLIENTS)
204 : * @param _backlog Maximum number of queued connections. (min. 1)
205 : * @param _detail User-defined detail associated with the service.
206 : * @param _res_fallback Fallback resource to be served if no other resource matches path
207 : * @param _config Pointer to http_service_config structure (can be NULL for default behavior)
208 : */
209 : #define HTTP_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail, _res_fallback, \
210 1 : _config) \
211 : extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[]; \
212 : extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[]; \
213 : __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, \
214 : _res_fallback, \
215 : &_CONCAT(_http_resource_desc_##_name, _list_start)[0], \
216 : &_CONCAT(_http_resource_desc_##_name, _list_end)[0], _config);
217 :
218 : /**
219 : * @brief Define an HTTPS service with static resources.
220 : *
221 : * @note The @p _host parameter is used to specify an IP address either in
222 : * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
223 : * port will listen on all addresses.
224 : *
225 : * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
226 : * number to use for the service. If the specified port number is zero, then an ephemeral port
227 : * number will be used and the actual port number assigned will be written back to memory. For
228 : * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
229 : *
230 : * @param _name Name of the service.
231 : * @param _host IP address or hostname associated with the service.
232 : * @param[inout] _port Pointer to port associated with the service.
233 : * @param _concurrent Maximum number of concurrent clients. (max. CONFIG_HTTP_SERVER_MAX_CLIENTS)
234 : * @param _backlog Maximum number of queued connections. (min. 1)
235 : * @param _detail User-defined detail associated with the service.
236 : * @param _res_fallback Fallback resource to be served if no other resource matches path
237 : * @param _config Pointer to http_service_config structure (can be NULL for default behavior)
238 : * @param _sec_tag_list TLS security tag list used to setup a HTTPS socket.
239 : * @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket.
240 : */
241 : #define HTTPS_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail, \
242 1 : _res_fallback, _config, _sec_tag_list, _sec_tag_list_size) \
243 : extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[]; \
244 : extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[]; \
245 : __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, \
246 : _res_fallback, \
247 : &_CONCAT(_http_resource_desc_##_name, _list_start)[0], \
248 : &_CONCAT(_http_resource_desc_##_name, _list_end)[0], _config, \
249 : _sec_tag_list, _sec_tag_list_size); \
250 : BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS), \
251 : "TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)")
252 :
253 : /**
254 : * @brief Count the number of HTTP services.
255 : *
256 : * @param[out] _dst Pointer to location where result is written.
257 : */
258 1 : #define HTTP_SERVICE_COUNT(_dst) STRUCT_SECTION_COUNT(http_service_desc, _dst)
259 :
260 : /**
261 : * @brief Count HTTP service static resources.
262 : *
263 : * @param _service Pointer to a service.
264 : */
265 1 : #define HTTP_SERVICE_RESOURCE_COUNT(_service) ((_service)->res_end - (_service)->res_begin)
266 :
267 : /**
268 : * @brief Iterate over all HTTP services.
269 : *
270 : * @param _it Name of http_service_desc iterator
271 : */
272 1 : #define HTTP_SERVICE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_service_desc, _it)
273 :
274 : /**
275 : * @brief Iterate over static HTTP resources associated with a given @p _service.
276 : *
277 : * @note This macro requires that @p _service is defined with @ref HTTP_SERVICE_DEFINE.
278 : *
279 : * @param _service Name of HTTP service
280 : * @param _it Name of iterator (of type @ref http_resource_desc)
281 : */
282 1 : #define HTTP_RESOURCE_FOREACH(_service, _it) \
283 : STRUCT_SECTION_FOREACH_ALTERNATE(http_resource_desc_##_service, http_resource_desc, _it)
284 :
285 : /**
286 : * @brief Iterate over all static resources associated with @p _service .
287 : *
288 : * @note This macro is suitable for a @p _service defined with either @ref HTTP_SERVICE_DEFINE
289 : * or @ref HTTP_SERVICE_DEFINE_EMPTY.
290 : *
291 : * @param _service Pointer to HTTP service
292 : * @param _it Name of iterator (of type @ref http_resource_desc)
293 : */
294 1 : #define HTTP_SERVICE_FOREACH_RESOURCE(_service, _it) \
295 : for (struct http_resource_desc *_it = (_service)->res_begin; ({ \
296 : __ASSERT(_it <= (_service)->res_end, "unexpected list end location"); \
297 : _it < (_service)->res_end; \
298 : }); \
299 : _it++)
300 :
301 : #ifdef __cplusplus
302 : }
303 : #endif
304 :
305 : /**
306 : * @}
307 : */
308 :
309 : #endif /* ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_ */
|