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