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 #include <stdint.h>
11 #include <stddef.h>
12 
13 #include <zephyr/sys/iterable_sections.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 struct http_resource_desc {
20 	const char *resource;
21 	void *detail;
22 };
23 
24 /**
25  * @brief Define a static HTTP resource
26  *
27  * A static HTTP resource is one that is known prior to system initialization. In contrast,
28  * dynamic resources may be discovered upon system initialization. Dynamic resources may also be
29  * inserted, or removed by events originating internally or externally to the system at runtime.
30  *
31  * @note The @p _resource is the URL without the associated protocol, host, or URL parameters. E.g.
32  * the resource for `http://www.foo.com/bar/baz.html#param1=value1` would be `/bar/baz.html`. It
33  * is often referred to as the "path" of the URL. Every `(service, resource)` pair should be
34  * unique. The @p _resource must be non-NULL.
35  *
36  * @param _name Name of the resource.
37  * @param _service Name of the associated service.
38  * @param _resource Pathname-like string identifying the resource.
39  * @param _detail Implementation-specific detail associated with the resource.
40  */
41 #define HTTP_RESOURCE_DEFINE(_name, _service, _resource, _detail)                                  \
42 	const STRUCT_SECTION_ITERABLE_ALTERNATE(http_resource_desc_##_service, http_resource_desc, \
43 						_name) = {                                         \
44 		.resource = _resource,                                                             \
45 		.detail = (_detail),                                                               \
46 	}
47 
48 struct http_service_desc {
49 	const char *host;
50 	uint16_t *port;
51 	void *detail;
52 	size_t concurrent;
53 	size_t backlog;
54 	struct http_resource_desc *res_begin;
55 	struct http_resource_desc *res_end;
56 };
57 
58 #define __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, _res_begin,   \
59 				_res_end)                                                          \
60 	static const STRUCT_SECTION_ITERABLE(http_service_desc, _name) = {                         \
61 		.host = _host,                                                                     \
62 		.port = (uint16_t *)(_port),                                                       \
63 		.detail = (void *)(_detail),                                                       \
64 		.concurrent = (_concurrent),                                                       \
65 		.backlog = (_backlog),                                                             \
66 		.res_begin = (_res_begin),                                                         \
67 		.res_end = (_res_end),                                                             \
68 	}
69 
70 /**
71  * @brief Define an HTTP service without static resources.
72  *
73  * @note The @p _host parameter must be non-`NULL`. It is used to specify an IP address either in
74  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host.
75  *
76  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
77  * number to use for the service. If the specified port number is zero, then an ephemeral port
78  * number will be used and the actual port number assigned will be written back to memory. For
79  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
80  *
81  * @param _name Name of the service.
82  * @param _host IP address or hostname associated with the service.
83  * @param[inout] _port Pointer to port associated with the service.
84  * @param _concurrent Maximum number of concurrent clients.
85  * @param _backlog Maximum number queued connections.
86  * @param _detail Implementation-specific detail associated with the service.
87  */
88 #define HTTP_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail)             \
89 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, NULL, NULL)
90 
91 /**
92  * @brief Define an HTTP service with static resources.
93  *
94  * @note The @p _host parameter must be non-`NULL`. It is used to specify an IP address either in
95  * IPv4 or IPv6 format a fully-qualified hostname or a virtual host.
96  *
97  * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
98  * number to use for the service. If the specified port number is zero, then an ephemeral port
99  * number will be used and the actual port number assigned will be written back to memory. For
100  * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
101  *
102  * @param _name Name of the service.
103  * @param _host IP address or hostname associated with the service.
104  * @param[inout] _port Pointer to port associated with the service.
105  * @param _concurrent Maximum number of concurrent clients.
106  * @param _backlog Maximum number queued connections.
107  * @param _detail Implementation-specific detail associated with the service.
108  */
109 #define HTTP_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail)                   \
110 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[];      \
111 	extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[];        \
112 	__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail,               \
113 				&_CONCAT(_http_resource_desc_##_name, _list_start)[0],             \
114 				&_CONCAT(_http_resource_desc_##_name, _list_end)[0])
115 
116 /**
117  * @brief Count the number of HTTP services.
118  *
119  * @param[out] _dst Pointer to location where result is written.
120  */
121 #define HTTP_SERVICE_COUNT(_dst) STRUCT_SECTION_COUNT(http_service_desc, _dst)
122 
123 /**
124  * @brief Count HTTP service static resources.
125  *
126  * @param _service Pointer to a service.
127  */
128 #define HTTP_SERVICE_RESOURCE_COUNT(_service) ((_service)->res_end - (_service)->res_begin)
129 
130 /**
131  * @brief Iterate over all HTTP services.
132  *
133  * @param _it Name of iterator (of type @ref http_service_desc)
134  */
135 #define HTTP_SERVICE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_service_desc, _it)
136 
137 /**
138  * @brief Iterate over static HTTP resources associated with a given @p _service.
139  *
140  * @note This macro requires that @p _service is defined with @ref HTTP_SERVICE_DEFINE.
141  *
142  * @param _service Name of HTTP service
143  * @param _it Name of iterator (of type @ref http_resource_desc)
144  */
145 #define HTTP_RESOURCE_FOREACH(_service, _it)                                                       \
146 	STRUCT_SECTION_FOREACH_ALTERNATE(http_resource_desc_##_service, http_resource_desc, _it)
147 
148 /**
149  * @brief Iterate over all static resources associated with @p _service .
150  *
151  * @note This macro is suitable for a @p _service defined with either @ref HTTP_SERVICE_DEFINE
152  * or @ref HTTP_SERVICE_DEFINE_EMPTY.
153  *
154  * @param _service Pointer to HTTP service
155  * @param _it Name of iterator (of type @ref http_resource_desc)
156  */
157 #define HTTP_SERVICE_FOREACH_RESOURCE(_service, _it)                                               \
158 	for (struct http_resource_desc *_it = (_service)->res_begin; ({                            \
159 		     __ASSERT(_it <= (_service)->res_end, "unexpected list end location");         \
160 		     _it < (_service)->res_end;                                                    \
161 	     });                                                                                   \
162 	     _it++)
163 
164 #ifdef __cplusplus
165 }
166 #endif
167 
168 #endif /* ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_ */
169