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