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 	static 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 must be non-`NULL`. It is used to specify an IP address either in
105  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host.
106  *
107  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
108  * number to use for the service. If the specified port number is zero, then an ephemeral port
109  * number will be used and the actual port number assigned will be written back to memory. For
110  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
111  *
112  * @param _name Name of the service.
113  * @param _host IP address or hostname associated with the service.
114  * @param[inout] _port Pointer to port associated with the service.
115  * @param _concurrent Maximum number of concurrent clients.
116  * @param _backlog Maximum number queued connections.
117  * @param _detail Implementation-specific detail associated with the service.
118  */
119 #define HTTP_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail)             \
120 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, NULL, NULL)
121 
122 /**
123  * @brief Define an HTTPS service without static resources.
124  *
125  * @note The @p _host parameter must be non-`NULL`. It is used to specify an IP address either in
126  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host.
127  *
128  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
129  * number to use for the service. If the specified port number is zero, then an ephemeral port
130  * number will be used and the actual port number assigned will be written back to memory. For
131  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
132  *
133  * @param _name Name of the service.
134  * @param _host IP address or hostname associated with the service.
135  * @param[inout] _port Pointer to port associated with the service.
136  * @param _concurrent Maximum number of concurrent clients.
137  * @param _backlog Maximum number queued connections.
138  * @param _detail Implementation-specific detail associated with the service.
139  * @param _sec_tag_list TLS security tag list used to setup a HTTPS socket.
140  * @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket.
141  */
142 #define HTTPS_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail,          \
143 				   _sec_tag_list, _sec_tag_list_size)                            \
144 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, NULL, NULL, \
145 				_sec_tag_list, _sec_tag_list_size);				 \
146 	BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS),				 \
147 		     "TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)")
148 
149 /**
150  * @brief Define an HTTP service with static resources.
151  *
152  * @note The @p _host parameter must be non-`NULL`. It is used to specify an IP address either in
153  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host.
154  *
155  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
156  * number to use for the service. If the specified port number is zero, then an ephemeral port
157  * number will be used and the actual port number assigned will be written back to memory. For
158  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
159  *
160  * @param _name Name of the service.
161  * @param _host IP address or hostname associated with the service.
162  * @param[inout] _port Pointer to port associated with the service.
163  * @param _concurrent Maximum number of concurrent clients.
164  * @param _backlog Maximum number queued connections.
165  * @param _detail Implementation-specific detail associated with the service.
166  */
167 #define HTTP_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail)                   \
168 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[];      \
169 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[];        \
170 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail,               \
171 				&_CONCAT(_http_resource_desc_##_name, _list_start)[0],             \
172 				&_CONCAT(_http_resource_desc_##_name, _list_end)[0])
173 
174 /**
175  * @brief Define an HTTPS service with static resources.
176  *
177  * @note The @p _host parameter must be non-`NULL`. It is used to specify an IP address either in
178  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host.
179  *
180  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
181  * number to use for the service. If the specified port number is zero, then an ephemeral port
182  * number will be used and the actual port number assigned will be written back to memory. For
183  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
184  *
185  * @param _name Name of the service.
186  * @param _host IP address or hostname associated with the service.
187  * @param[inout] _port Pointer to port associated with the service.
188  * @param _concurrent Maximum number of concurrent clients.
189  * @param _backlog Maximum number queued connections.
190  * @param _detail Implementation-specific detail associated with the service.
191  * @param _sec_tag_list TLS security tag list used to setup a HTTPS socket.
192  * @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket.
193  */
194 #define HTTPS_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail,              \
195 			     _sec_tag_list, _sec_tag_list_size)                                \
196 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[];  \
197 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[];    \
198 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail,           \
199 				&_CONCAT(_http_resource_desc_##_name, _list_start)[0],         \
200 				&_CONCAT(_http_resource_desc_##_name, _list_end)[0],           \
201 				_sec_tag_list, _sec_tag_list_size);                            \
202 	BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS),                               \
203 		     "TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)")
204 
205 /**
206  * @brief Count the number of HTTP services.
207  *
208  * @param[out] _dst Pointer to location where result is written.
209  */
210 #define HTTP_SERVICE_COUNT(_dst) STRUCT_SECTION_COUNT(http_service_desc, _dst)
211 
212 /**
213  * @brief Count HTTP service static resources.
214  *
215  * @param _service Pointer to a service.
216  */
217 #define HTTP_SERVICE_RESOURCE_COUNT(_service) ((_service)->res_end - (_service)->res_begin)
218 
219 /**
220  * @brief Iterate over all HTTP services.
221  *
222  * @param _it Name of http_service_desc iterator
223  */
224 #define HTTP_SERVICE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_service_desc, _it)
225 
226 /**
227  * @brief Iterate over static HTTP resources associated with a given @p _service.
228  *
229  * @note This macro requires that @p _service is defined with @ref HTTP_SERVICE_DEFINE.
230  *
231  * @param _service Name of HTTP service
232  * @param _it Name of iterator (of type @ref http_resource_desc)
233  */
234 #define HTTP_RESOURCE_FOREACH(_service, _it)                                                       \
235 	STRUCT_SECTION_FOREACH_ALTERNATE(http_resource_desc_##_service, http_resource_desc, _it)
236 
237 /**
238  * @brief Iterate over all static resources associated with @p _service .
239  *
240  * @note This macro is suitable for a @p _service defined with either @ref HTTP_SERVICE_DEFINE
241  * or @ref HTTP_SERVICE_DEFINE_EMPTY.
242  *
243  * @param _service Pointer to HTTP service
244  * @param _it Name of iterator (of type @ref http_resource_desc)
245  */
246 #define HTTP_SERVICE_FOREACH_RESOURCE(_service, _it)                                               \
247 	for (struct http_resource_desc *_it = (_service)->res_begin; ({                            \
248 		     __ASSERT(_it <= (_service)->res_end, "unexpected list end location");         \
249 		     _it < (_service)->res_end;                                                    \
250 	     });                                                                                   \
251 	     _it++)
252 
253 #ifdef __cplusplus
254 }
255 #endif
256 
257 /**
258  * @}
259  */
260 
261 #endif /* ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_ */
262