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 <stdint.h>
23 #include <stddef.h>
24 
25 #include <zephyr/sys/util_macro.h>
26 #include <zephyr/sys/iterable_sections.h>
27 #include <zephyr/net/tls_credentials.h>
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 /** HTTP resource description */
34 struct http_resource_desc {
35 	/** Resource name */
36 	const char *resource;
37 	/** Detail associated with this resource */
38 	void *detail;
39 };
40 
41 /**
42  * @brief Define a static HTTP resource
43  *
44  * A static HTTP resource is one that is known prior to system initialization. In contrast,
45  * dynamic resources may be discovered upon system initialization. Dynamic resources may also be
46  * inserted, or removed by events originating internally or externally to the system at runtime.
47  *
48  * @note The @p _resource is the URL without the associated protocol, host, or URL parameters. E.g.
49  * the resource for `http://www.foo.com/bar/baz.html#param1=value1` would be `/bar/baz.html`. It
50  * is often referred to as the "path" of the URL. Every `(service, resource)` pair should be
51  * unique. The @p _resource must be non-NULL.
52  *
53  * @param _name Name of the resource.
54  * @param _service Name of the associated service.
55  * @param _resource Pathname-like string identifying the resource.
56  * @param _detail Implementation-specific detail associated with the resource.
57  */
58 #define HTTP_RESOURCE_DEFINE(_name, _service, _resource, _detail)                                  \
59 	const STRUCT_SECTION_ITERABLE_ALTERNATE(http_resource_desc_##_service, http_resource_desc, \
60 						_name) = {                                         \
61 		.resource = _resource,                                                             \
62 		.detail = (void *)(_detail),                                                       \
63 	}
64 
65 /** @cond INTERNAL_HIDDEN */
66 
67 struct http_service_desc {
68 	const char *host;
69 	uint16_t *port;
70 	void *detail;
71 	size_t concurrent;
72 	size_t backlog;
73 	struct http_resource_desc *res_begin;
74 	struct http_resource_desc *res_end;
75 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
76 	const sec_tag_t *sec_tag_list;
77 	size_t sec_tag_list_size;
78 #endif
79 };
80 
81 #define __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, _res_begin,   \
82 				_res_end, ...)                                                     \
83 	const STRUCT_SECTION_ITERABLE(http_service_desc, _name) = {				   \
84 		.host = _host,                                                                     \
85 		.port = (uint16_t *)(_port),                                                       \
86 		.detail = (void *)(_detail),                                                       \
87 		.concurrent = (_concurrent),                                                       \
88 		.backlog = (_backlog),                                                             \
89 		.res_begin = (_res_begin),                                                         \
90 		.res_end = (_res_end),                                                             \
91 		COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS,                                        \
92 			    (.sec_tag_list = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (NULL),  \
93 							 (GET_ARG_N(1, __VA_ARGS__))),), ())       \
94 		COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS,                                        \
95 			    (.sec_tag_list_size = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (0),\
96 					     (GET_ARG_N(1, GET_ARGS_LESS_N(1, __VA_ARGS__))))), ())\
97 	}
98 
99 /** @endcond */
100 
101 /**
102  * @brief Define an HTTP service without static resources.
103  *
104  * @note The @p _host parameter is used to specify an IP address either in
105  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
106  * port will listen on all addresses.
107  *
108  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
109  * number to use for the service. If the specified port number is zero, then an ephemeral port
110  * number will be used and the actual port number assigned will be written back to memory. For
111  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
112  *
113  * @param _name Name of the service.
114  * @param _host IP address or hostname associated with the service.
115  * @param[inout] _port Pointer to port associated with the service.
116  * @param _concurrent Maximum number of concurrent clients.
117  * @param _backlog Maximum number queued connections.
118  * @param _detail Implementation-specific detail associated with the service.
119  */
120 #define HTTP_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail)             \
121 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, NULL, NULL)
122 
123 /**
124  * @brief Define an HTTPS service without static resources.
125  *
126  * @note The @p _host parameter is used to specify an IP address either in
127  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
128  * port will listen on all addresses.
129  *
130  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
131  * number to use for the service. If the specified port number is zero, then an ephemeral port
132  * number will be used and the actual port number assigned will be written back to memory. For
133  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
134  *
135  * @param _name Name of the service.
136  * @param _host IP address or hostname associated with the service.
137  * @param[inout] _port Pointer to port associated with the service.
138  * @param _concurrent Maximum number of concurrent clients.
139  * @param _backlog Maximum number queued connections.
140  * @param _detail Implementation-specific detail associated with the service.
141  * @param _sec_tag_list TLS security tag list used to setup a HTTPS socket.
142  * @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket.
143  */
144 #define HTTPS_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail,          \
145 				   _sec_tag_list, _sec_tag_list_size)                            \
146 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, NULL, NULL, \
147 				_sec_tag_list, _sec_tag_list_size);				 \
148 	BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS),				 \
149 		     "TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)")
150 
151 /**
152  * @brief Define an HTTP service with static resources.
153  *
154  * @note The @p _host parameter is used to specify an IP address either in
155  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
156  * port will listen on all addresses.
157  *
158  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
159  * number to use for the service. If the specified port number is zero, then an ephemeral port
160  * number will be used and the actual port number assigned will be written back to memory. For
161  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
162  *
163  * @param _name Name of the service.
164  * @param _host IP address or hostname associated with the service.
165  * @param[inout] _port Pointer to port associated with the service.
166  * @param _concurrent Maximum number of concurrent clients.
167  * @param _backlog Maximum number queued connections.
168  * @param _detail Implementation-specific detail associated with the service.
169  */
170 #define HTTP_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail)                   \
171 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[];      \
172 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[];        \
173 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail,               \
174 				&_CONCAT(_http_resource_desc_##_name, _list_start)[0],             \
175 				&_CONCAT(_http_resource_desc_##_name, _list_end)[0])
176 
177 /**
178  * @brief Define an HTTPS service with static resources.
179  *
180  * @note The @p _host parameter is used to specify an IP address either in
181  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
182  * port will listen on all addresses.
183  *
184  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
185  * number to use for the service. If the specified port number is zero, then an ephemeral port
186  * number will be used and the actual port number assigned will be written back to memory. For
187  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
188  *
189  * @param _name Name of the service.
190  * @param _host IP address or hostname associated with the service.
191  * @param[inout] _port Pointer to port associated with the service.
192  * @param _concurrent Maximum number of concurrent clients.
193  * @param _backlog Maximum number queued connections.
194  * @param _detail Implementation-specific detail associated with the service.
195  * @param _sec_tag_list TLS security tag list used to setup a HTTPS socket.
196  * @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket.
197  */
198 #define HTTPS_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail,              \
199 			     _sec_tag_list, _sec_tag_list_size)                                \
200 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[];  \
201 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[];    \
202 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail,           \
203 				&_CONCAT(_http_resource_desc_##_name, _list_start)[0],         \
204 				&_CONCAT(_http_resource_desc_##_name, _list_end)[0],           \
205 				_sec_tag_list, _sec_tag_list_size);                            \
206 	BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS),                               \
207 		     "TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)")
208 
209 /**
210  * @brief Count the number of HTTP services.
211  *
212  * @param[out] _dst Pointer to location where result is written.
213  */
214 #define HTTP_SERVICE_COUNT(_dst) STRUCT_SECTION_COUNT(http_service_desc, _dst)
215 
216 /**
217  * @brief Count HTTP service static resources.
218  *
219  * @param _service Pointer to a service.
220  */
221 #define HTTP_SERVICE_RESOURCE_COUNT(_service) ((_service)->res_end - (_service)->res_begin)
222 
223 /**
224  * @brief Iterate over all HTTP services.
225  *
226  * @param _it Name of http_service_desc iterator
227  */
228 #define HTTP_SERVICE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_service_desc, _it)
229 
230 /**
231  * @brief Iterate over static HTTP resources associated with a given @p _service.
232  *
233  * @note This macro requires that @p _service is defined with @ref HTTP_SERVICE_DEFINE.
234  *
235  * @param _service Name of HTTP service
236  * @param _it Name of iterator (of type @ref http_resource_desc)
237  */
238 #define HTTP_RESOURCE_FOREACH(_service, _it)                                                       \
239 	STRUCT_SECTION_FOREACH_ALTERNATE(http_resource_desc_##_service, http_resource_desc, _it)
240 
241 /**
242  * @brief Iterate over all static resources associated with @p _service .
243  *
244  * @note This macro is suitable for a @p _service defined with either @ref HTTP_SERVICE_DEFINE
245  * or @ref HTTP_SERVICE_DEFINE_EMPTY.
246  *
247  * @param _service Pointer to HTTP service
248  * @param _it Name of iterator (of type @ref http_resource_desc)
249  */
250 #define HTTP_SERVICE_FOREACH_RESOURCE(_service, _it)                                               \
251 	for (struct http_resource_desc *_it = (_service)->res_begin; ({                            \
252 		     __ASSERT(_it <= (_service)->res_end, "unexpected list end location");         \
253 		     _it < (_service)->res_end;                                                    \
254 	     });                                                                                   \
255 	     _it++)
256 
257 #ifdef __cplusplus
258 }
259 #endif
260 
261 /**
262  * @}
263  */
264 
265 #endif /* ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_ */
266