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