zephyr/include/zephyr/net/http/service.h
Matt Rodgers b7091ed439 net: http_server: serve resources only for their defined services
Ensure that HTTP resources can only be served to a client connected on
the specific service(s) that the resource was registered against using
the HTTP_RESOURCE_DEFINE macro.

This allows different resources to be registered to different services,
for example to make some resources only available via an HTTPS service
and not via unencrypted HTTP.

Signed-off-by: Matt Rodgers <mrodgers@witekio.com>
2025-01-09 14:13:57 +01:00

268 lines
12 KiB
C

/*
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_
#define ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_
/**
* @file service.h
*
* @brief HTTP service API
*
* @defgroup http_service HTTP service API
* @since 3.4
* @version 0.1.0
* @ingroup networking
* @{
*/
#include <stdint.h>
#include <stddef.h>
#include <zephyr/sys/util_macro.h>
#include <zephyr/sys/iterable_sections.h>
#include <zephyr/net/tls_credentials.h>
#ifdef __cplusplus
extern "C" {
#endif
/** HTTP resource description */
struct http_resource_desc {
/** Resource name */
const char *resource;
/** Detail associated with this resource */
void *detail;
};
/**
* @brief Define a static HTTP resource
*
* A static HTTP resource is one that is known prior to system initialization. In contrast,
* dynamic resources may be discovered upon system initialization. Dynamic resources may also be
* inserted, or removed by events originating internally or externally to the system at runtime.
*
* @note The @p _resource is the URL without the associated protocol, host, or URL parameters. E.g.
* the resource for `http://www.foo.com/bar/baz.html#param1=value1` would be `/bar/baz.html`. It
* is often referred to as the "path" of the URL. Every `(service, resource)` pair should be
* unique. The @p _resource must be non-NULL.
*
* @param _name Name of the resource.
* @param _service Name of the associated service.
* @param _resource Pathname-like string identifying the resource.
* @param _detail Implementation-specific detail associated with the resource.
*/
#define HTTP_RESOURCE_DEFINE(_name, _service, _resource, _detail) \
const STRUCT_SECTION_ITERABLE_ALTERNATE(http_resource_desc_##_service, http_resource_desc, \
_name) = { \
.resource = _resource, \
.detail = (void *)(_detail), \
}
/** @cond INTERNAL_HIDDEN */
struct http_service_desc {
const char *host;
uint16_t *port;
int *fd;
void *detail;
size_t concurrent;
size_t backlog;
struct http_resource_desc *res_begin;
struct http_resource_desc *res_end;
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
const sec_tag_t *sec_tag_list;
size_t sec_tag_list_size;
#endif
};
#define __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, _res_begin, \
_res_end, ...) \
static int _name##_fd = -1; \
const STRUCT_SECTION_ITERABLE(http_service_desc, _name) = { \
.host = _host, \
.port = (uint16_t *)(_port), \
.fd = &_name##_fd, \
.detail = (void *)(_detail), \
.concurrent = (_concurrent), \
.backlog = (_backlog), \
.res_begin = (_res_begin), \
.res_end = (_res_end), \
COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS, \
(.sec_tag_list = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (NULL), \
(GET_ARG_N(1, __VA_ARGS__))),), ()) \
COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS, \
(.sec_tag_list_size = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (0),\
(GET_ARG_N(1, GET_ARGS_LESS_N(1, __VA_ARGS__))))), ())\
}
/** @endcond */
/**
* @brief Define an HTTP service without static resources.
*
* @note The @p _host parameter is used to specify an IP address either in
* IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
* port will listen on all addresses.
*
* @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
* number to use for the service. If the specified port number is zero, then an ephemeral port
* number will be used and the actual port number assigned will be written back to memory. For
* ephemeral port numbers, the memory pointed to by @p _port must be writeable.
*
* @param _name Name of the service.
* @param _host IP address or hostname associated with the service.
* @param[inout] _port Pointer to port associated with the service.
* @param _concurrent Maximum number of concurrent clients.
* @param _backlog Maximum number queued connections.
* @param _detail Implementation-specific detail associated with the service.
*/
#define HTTP_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail) \
__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, NULL, NULL)
/**
* @brief Define an HTTPS service without static resources.
*
* @note The @p _host parameter is used to specify an IP address either in
* IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
* port will listen on all addresses.
*
* @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
* number to use for the service. If the specified port number is zero, then an ephemeral port
* number will be used and the actual port number assigned will be written back to memory. For
* ephemeral port numbers, the memory pointed to by @p _port must be writeable.
*
* @param _name Name of the service.
* @param _host IP address or hostname associated with the service.
* @param[inout] _port Pointer to port associated with the service.
* @param _concurrent Maximum number of concurrent clients.
* @param _backlog Maximum number queued connections.
* @param _detail Implementation-specific detail associated with the service.
* @param _sec_tag_list TLS security tag list used to setup a HTTPS socket.
* @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket.
*/
#define HTTPS_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail, \
_sec_tag_list, _sec_tag_list_size) \
__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, NULL, NULL, \
_sec_tag_list, _sec_tag_list_size); \
BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS), \
"TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)")
/**
* @brief Define an HTTP service with static resources.
*
* @note The @p _host parameter is used to specify an IP address either in
* IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
* port will listen on all addresses.
*
* @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
* number to use for the service. If the specified port number is zero, then an ephemeral port
* number will be used and the actual port number assigned will be written back to memory. For
* ephemeral port numbers, the memory pointed to by @p _port must be writeable.
*
* @param _name Name of the service.
* @param _host IP address or hostname associated with the service.
* @param[inout] _port Pointer to port associated with the service.
* @param _concurrent Maximum number of concurrent clients.
* @param _backlog Maximum number queued connections.
* @param _detail Implementation-specific detail associated with the service.
*/
#define HTTP_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail) \
extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[]; \
extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[]; \
__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, \
&_CONCAT(_http_resource_desc_##_name, _list_start)[0], \
&_CONCAT(_http_resource_desc_##_name, _list_end)[0])
/**
* @brief Define an HTTPS service with static resources.
*
* @note The @p _host parameter is used to specify an IP address either in
* IPv4 or IPv6 format a fully-qualified hostname or a virtual host. If left NULL, the listening
* port will listen on all addresses.
*
* @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
* number to use for the service. If the specified port number is zero, then an ephemeral port
* number will be used and the actual port number assigned will be written back to memory. For
* ephemeral port numbers, the memory pointed to by @p _port must be writeable.
*
* @param _name Name of the service.
* @param _host IP address or hostname associated with the service.
* @param[inout] _port Pointer to port associated with the service.
* @param _concurrent Maximum number of concurrent clients.
* @param _backlog Maximum number queued connections.
* @param _detail Implementation-specific detail associated with the service.
* @param _sec_tag_list TLS security tag list used to setup a HTTPS socket.
* @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket.
*/
#define HTTPS_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail, \
_sec_tag_list, _sec_tag_list_size) \
extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[]; \
extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[]; \
__z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, \
&_CONCAT(_http_resource_desc_##_name, _list_start)[0], \
&_CONCAT(_http_resource_desc_##_name, _list_end)[0], \
_sec_tag_list, _sec_tag_list_size); \
BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS), \
"TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)")
/**
* @brief Count the number of HTTP services.
*
* @param[out] _dst Pointer to location where result is written.
*/
#define HTTP_SERVICE_COUNT(_dst) STRUCT_SECTION_COUNT(http_service_desc, _dst)
/**
* @brief Count HTTP service static resources.
*
* @param _service Pointer to a service.
*/
#define HTTP_SERVICE_RESOURCE_COUNT(_service) ((_service)->res_end - (_service)->res_begin)
/**
* @brief Iterate over all HTTP services.
*
* @param _it Name of http_service_desc iterator
*/
#define HTTP_SERVICE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_service_desc, _it)
/**
* @brief Iterate over static HTTP resources associated with a given @p _service.
*
* @note This macro requires that @p _service is defined with @ref HTTP_SERVICE_DEFINE.
*
* @param _service Name of HTTP service
* @param _it Name of iterator (of type @ref http_resource_desc)
*/
#define HTTP_RESOURCE_FOREACH(_service, _it) \
STRUCT_SECTION_FOREACH_ALTERNATE(http_resource_desc_##_service, http_resource_desc, _it)
/**
* @brief Iterate over all static resources associated with @p _service .
*
* @note This macro is suitable for a @p _service defined with either @ref HTTP_SERVICE_DEFINE
* or @ref HTTP_SERVICE_DEFINE_EMPTY.
*
* @param _service Pointer to HTTP service
* @param _it Name of iterator (of type @ref http_resource_desc)
*/
#define HTTP_SERVICE_FOREACH_RESOURCE(_service, _it) \
for (struct http_resource_desc *_it = (_service)->res_begin; ({ \
__ASSERT(_it <= (_service)->res_end, "unexpected list end location"); \
_it < (_service)->res_end; \
}); \
_it++)
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_ */