LCOV - code coverage report
Current view: top level - zephyr/net/http - server.h Hit Total Coverage
Test: new.info Lines: 95 101 94.1 %
Date: 2024-12-22 00:14:23

          Line data    Source code
       1           1 : /*
       2             :  * Copyright (c) 2023, Emna Rekik
       3             :  * Copyright (c) 2024 Nordic Semiconductor ASA
       4             :  *
       5             :  * SPDX-License-Identifier: Apache-2.0
       6             :  */
       7             : 
       8             : #ifndef ZEPHYR_INCLUDE_NET_HTTP_SERVER_H_
       9             : #define ZEPHYR_INCLUDE_NET_HTTP_SERVER_H_
      10             : 
      11             : /**
      12             :  * @file server.h
      13             :  *
      14             :  * @brief HTTP server API
      15             :  *
      16             :  * @defgroup http_server HTTP server API
      17             :  * @since 3.7
      18             :  * @version 0.1.0
      19             :  * @ingroup networking
      20             :  * @{
      21             :  */
      22             : 
      23             : #include <stdint.h>
      24             : 
      25             : #include <zephyr/kernel.h>
      26             : #include <zephyr/net/http/parser.h>
      27             : #include <zephyr/net/http/hpack.h>
      28             : #include <zephyr/net/http/status.h>
      29             : #include <zephyr/net/socket.h>
      30             : #include <zephyr/sys/iterable_sections.h>
      31             : 
      32             : #ifdef __cplusplus
      33             : extern "C" {
      34             : #endif
      35             : 
      36             : /** @cond INTERNAL_HIDDEN */
      37             : 
      38             : #if defined(CONFIG_HTTP_SERVER)
      39             : #define HTTP_SERVER_CLIENT_BUFFER_SIZE   CONFIG_HTTP_SERVER_CLIENT_BUFFER_SIZE
      40             : #define HTTP_SERVER_MAX_STREAMS          CONFIG_HTTP_SERVER_MAX_STREAMS
      41             : #define HTTP_SERVER_MAX_CONTENT_TYPE_LEN CONFIG_HTTP_SERVER_MAX_CONTENT_TYPE_LENGTH
      42             : #define HTTP_SERVER_MAX_URL_LENGTH       CONFIG_HTTP_SERVER_MAX_URL_LENGTH
      43             : #define HTTP_SERVER_MAX_HEADER_LEN       CONFIG_HTTP_SERVER_MAX_HEADER_LEN
      44             : #else
      45             : #define HTTP_SERVER_CLIENT_BUFFER_SIZE   0
      46             : #define HTTP_SERVER_MAX_STREAMS          0
      47             : #define HTTP_SERVER_MAX_CONTENT_TYPE_LEN 0
      48             : #define HTTP_SERVER_MAX_URL_LENGTH       0
      49             : #define HTTP_SERVER_MAX_HEADER_LEN       0
      50             : #endif
      51             : 
      52             : #if defined(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)
      53             : #define HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE CONFIG_HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE
      54             : #define HTTP_SERVER_CAPTURE_HEADER_COUNT       CONFIG_HTTP_SERVER_CAPTURE_HEADER_COUNT
      55             : #else
      56             : #define HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE 0
      57             : #define HTTP_SERVER_CAPTURE_HEADER_COUNT       0
      58             : #endif
      59             : 
      60             : #define HTTP2_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
      61             : 
      62             : /** @endcond */
      63             : 
      64             : /**
      65             :  *  @brief HTTP server resource type.
      66             :  */
      67           1 : enum http_resource_type {
      68             :         /** Static resource, cannot be modified on runtime. */
      69             :         HTTP_RESOURCE_TYPE_STATIC,
      70             : 
      71             :         /** serves static gzipped files from a filesystem */
      72             :         HTTP_RESOURCE_TYPE_STATIC_FS,
      73             : 
      74             :         /** Dynamic resource, server interacts with the application via registered
      75             :          *  @ref http_resource_dynamic_cb_t.
      76             :          */
      77             :         HTTP_RESOURCE_TYPE_DYNAMIC,
      78             : 
      79             :         /** Websocket resource, application takes control over Websocket connection
      80             :          *  after and upgrade.
      81             :          */
      82             :         HTTP_RESOURCE_TYPE_WEBSOCKET,
      83             : };
      84             : 
      85             : /**
      86             :  * @brief Representation of a server resource, common for all resource types.
      87             :  */
      88           1 : struct http_resource_detail {
      89             :         /** Bitmask of supported HTTP methods (@ref http_method). */
      90           1 :         uint32_t bitmask_of_supported_http_methods;
      91             : 
      92             :         /** Resource type. */
      93           1 :         enum http_resource_type type;
      94             : 
      95             :         /** Length of the URL path. */
      96           1 :         int path_len;
      97             : 
      98             :         /** Content encoding of the resource. */
      99           1 :         const char *content_encoding;
     100             : 
     101             :         /** Content type of the resource. */
     102           1 :         const char *content_type;
     103             : };
     104             : 
     105             : /** @cond INTERNAL_HIDDEN */
     106             : BUILD_ASSERT(NUM_BITS(
     107             :              sizeof(((struct http_resource_detail *)0)->bitmask_of_supported_http_methods))
     108             :              >= (HTTP_METHOD_END_VALUE - 1));
     109             : /** @endcond */
     110             : 
     111             : /**
     112             :  * @brief Representation of a static server resource.
     113             :  */
     114           1 : struct http_resource_detail_static {
     115             :         /** Common resource details. */
     116           1 :         struct http_resource_detail common;
     117             : 
     118             :         /** Content of the static resource. */
     119           1 :         const void *static_data;
     120             : 
     121             :         /** Size of the static resource. */
     122           1 :         size_t static_data_len;
     123             : };
     124             : 
     125             : /** @cond INTERNAL_HIDDEN */
     126             : /* Make sure that the common is the first in the struct. */
     127             : BUILD_ASSERT(offsetof(struct http_resource_detail_static, common) == 0);
     128             : /** @endcond */
     129             : 
     130             : /**
     131             :  * @brief Representation of a static filesystem server resource.
     132             :  */
     133           1 : struct http_resource_detail_static_fs {
     134             :         /** Common resource details. */
     135           1 :         struct http_resource_detail common;
     136             : 
     137             :         /** Path in the local filesystem */
     138           1 :         const char *fs_path;
     139             : };
     140             : 
     141             : /** @cond INTERNAL_HIDDEN */
     142             : /* Make sure that the common is the first in the struct. */
     143             : BUILD_ASSERT(offsetof(struct http_resource_detail_static_fs, common) == 0);
     144             : /** @endcond */
     145             : 
     146           0 : struct http_content_type {
     147           0 :         const char *extension;
     148           0 :         size_t extension_len;
     149           0 :         const char *content_type;
     150             : };
     151             : 
     152           0 : #define HTTP_SERVER_CONTENT_TYPE(_extension, _content_type)                                        \
     153             :         const STRUCT_SECTION_ITERABLE(http_content_type, _extension) = {                           \
     154             :                 .extension = STRINGIFY(_extension),                                                \
     155             :                 .extension_len = sizeof(STRINGIFY(_extension)) - 1,                                \
     156             :                 .content_type = _content_type,                                                     \
     157             :         };
     158             : 
     159           0 : #define HTTP_SERVER_CONTENT_TYPE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_content_type, _it)
     160             : 
     161             : struct http_client_ctx;
     162             : 
     163             : /** Indicates the status of the currently processed piece of data.  */
     164           1 : enum http_data_status {
     165             :         /** Transaction aborted, data incomplete. */
     166             :         HTTP_SERVER_DATA_ABORTED = -1,
     167             :         /** Transaction incomplete, more data expected. */
     168             :         HTTP_SERVER_DATA_MORE = 0,
     169             :         /** Final data fragment in current transaction. */
     170             :         HTTP_SERVER_DATA_FINAL = 1,
     171             : };
     172             : 
     173             : /** @brief Status of captured request headers */
     174           1 : enum http_header_status {
     175             :         HTTP_HEADER_STATUS_OK,      /**< All available headers were successfully captured. */
     176             :         HTTP_HEADER_STATUS_DROPPED, /**< One or more headers were dropped due to lack of space. */
     177             :         HTTP_HEADER_STATUS_NONE,    /**< No header status is available. */
     178             : };
     179             : 
     180             : /** @brief HTTP header representation */
     181           1 : struct http_header {
     182           1 :         const char *name;  /**< Pointer to header name NULL-terminated string. */
     183           1 :         const char *value; /**< Pointer to header value NULL-terminated string. */
     184             : };
     185             : 
     186             : /** @brief HTTP request context */
     187           1 : struct http_request_ctx {
     188           1 :         uint8_t *data;                          /**< HTTP request data */
     189           1 :         size_t data_len;                        /**< Length of HTTP request data */
     190           1 :         struct http_header *headers;            /**< Array of HTTP request headers */
     191           1 :         size_t header_count;                    /**< Array length of HTTP request headers */
     192           1 :         enum http_header_status headers_status; /**< Status of HTTP request headers */
     193             : };
     194             : 
     195             : /** @brief HTTP response context */
     196           1 : struct http_response_ctx {
     197           1 :         enum http_status status;           /**< HTTP status code to include in response */
     198           1 :         const struct http_header *headers; /**< Array of HTTP headers */
     199           1 :         size_t header_count;               /**< Length of headers array */
     200           1 :         const uint8_t *body;               /**< Pointer to body data */
     201           1 :         size_t body_len;                   /**< Length of body data */
     202           1 :         bool final_chunk; /**< Flag set to true when the application has no more data to send */
     203             : };
     204             : 
     205             : /**
     206             :  * @typedef http_resource_dynamic_cb_t
     207             :  * @brief Callback used when data is received. Data to be sent to client
     208             :  *        can be specified.
     209             :  *
     210             :  * @param client HTTP context information for this client connection.
     211             :  * @param status HTTP data status, indicate whether more data is expected or not.
     212             :  * @param request_ctx Request context structure containing HTTP request data that was received.
     213             :  * @param response_ctx Response context structure for application to populate with response data.
     214             :  * @param user_data User specified data.
     215             :  *
     216             :  * @return 0 success, server can send any response data provided in the response_ctx.
     217             :  *         <0 error, close the connection.
     218             :  */
     219           1 : typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client,
     220             :                                           enum http_data_status status,
     221             :                                           const struct http_request_ctx *request_ctx,
     222             :                                           struct http_response_ctx *response_ctx,
     223             :                                           void *user_data);
     224             : 
     225             : /**
     226             :  * @brief Representation of a dynamic server resource.
     227             :  */
     228           1 : struct http_resource_detail_dynamic {
     229             :         /** Common resource details. */
     230           1 :         struct http_resource_detail common;
     231             : 
     232             :         /** Resource callback used by the server to interact with the
     233             :          *  application.
     234             :          */
     235           1 :         http_resource_dynamic_cb_t cb;
     236             : 
     237             :         /** A pointer to the client currently processing resource, used to
     238             :          *  prevent concurrent access to the resource from multiple clients.
     239             :          */
     240           1 :         struct http_client_ctx *holder;
     241             : 
     242             :         /** A pointer to the user data registered by the application.  */
     243           1 :         void *user_data;
     244             : };
     245             : 
     246             : /** @cond INTERNAL_HIDDEN */
     247             : BUILD_ASSERT(offsetof(struct http_resource_detail_dynamic, common) == 0);
     248             : /** @endcond */
     249             : 
     250             : /**
     251             :  * @typedef http_resource_websocket_cb_t
     252             :  * @brief Callback used when a Websocket connection is setup. The application
     253             :  *        will need to handle all functionality related to the connection like
     254             :  *        reading and writing websocket data, and closing the connection.
     255             :  *
     256             :  * @param ws_socket A socket for the Websocket data.
     257             :  * @param user_data User specified data.
     258             :  *
     259             :  * @return  0 Accepting the connection, HTTP server library will no longer
     260             :  *            handle data to/from the socket and it is application responsibility
     261             :  *            to send and receive data to/from the supplied socket.
     262             :  *         <0 error, close the connection.
     263             :  */
     264           1 : typedef int (*http_resource_websocket_cb_t)(int ws_socket,
     265             :                                             void *user_data);
     266             : 
     267             : /** @brief Representation of a websocket server resource */
     268           1 : struct http_resource_detail_websocket {
     269             :         /** Common resource details. */
     270           1 :         struct http_resource_detail common;
     271             : 
     272             :         /** Websocket socket value */
     273           1 :         int ws_sock;
     274             : 
     275             :         /** Resource callback used by the server to interact with the
     276             :          *  application.
     277             :          */
     278           1 :         http_resource_websocket_cb_t cb;
     279             : 
     280             :         /** Data buffer used to exchanged data between server and the,
     281             :          *  application.
     282             :          */
     283           1 :         uint8_t *data_buffer;
     284             : 
     285             :         /** Length of the data in the data buffer. */
     286           1 :         size_t data_buffer_len;
     287             : 
     288             :         /** A pointer to the user data registered by the application.  */
     289           1 :         void *user_data;
     290             : };
     291             : 
     292             : /** @cond INTERNAL_HIDDEN */
     293             : BUILD_ASSERT(offsetof(struct http_resource_detail_websocket, common) == 0);
     294             : /** @endcond */
     295             : 
     296             : /** @cond INTERNAL_HIDDEN */
     297             : 
     298             : enum http2_stream_state {
     299             :         HTTP2_STREAM_IDLE,
     300             :         HTTP2_STREAM_RESERVED_LOCAL,
     301             :         HTTP2_STREAM_RESERVED_REMOTE,
     302             :         HTTP2_STREAM_OPEN,
     303             :         HTTP2_STREAM_HALF_CLOSED_LOCAL,
     304             :         HTTP2_STREAM_HALF_CLOSED_REMOTE,
     305             :         HTTP2_STREAM_CLOSED
     306             : };
     307             : 
     308             : enum http_server_state {
     309             :         HTTP_SERVER_FRAME_HEADER_STATE,
     310             :         HTTP_SERVER_PREFACE_STATE,
     311             :         HTTP_SERVER_REQUEST_STATE,
     312             :         HTTP_SERVER_FRAME_DATA_STATE,
     313             :         HTTP_SERVER_FRAME_HEADERS_STATE,
     314             :         HTTP_SERVER_FRAME_SETTINGS_STATE,
     315             :         HTTP_SERVER_FRAME_PRIORITY_STATE,
     316             :         HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE,
     317             :         HTTP_SERVER_FRAME_CONTINUATION_STATE,
     318             :         HTTP_SERVER_FRAME_PING_STATE,
     319             :         HTTP_SERVER_FRAME_RST_STREAM_STATE,
     320             :         HTTP_SERVER_FRAME_GOAWAY_STATE,
     321             :         HTTP_SERVER_FRAME_PADDING_STATE,
     322             :         HTTP_SERVER_DONE_STATE,
     323             : };
     324             : 
     325             : enum http1_parser_state {
     326             :         HTTP1_INIT_HEADER_STATE,
     327             :         HTTP1_WAITING_HEADER_STATE,
     328             :         HTTP1_RECEIVING_HEADER_STATE,
     329             :         HTTP1_RECEIVED_HEADER_STATE,
     330             :         HTTP1_RECEIVING_DATA_STATE,
     331             :         HTTP1_MESSAGE_COMPLETE_STATE,
     332             : };
     333             : 
     334             : #define HTTP_SERVER_INITIAL_WINDOW_SIZE 65536
     335             : #define HTTP_SERVER_WS_MAX_SEC_KEY_LEN 32
     336             : 
     337             : /** @endcond */
     338             : 
     339             : /** @brief HTTP/2 stream representation. */
     340           1 : struct http2_stream_ctx {
     341           1 :         int stream_id; /**< Stream identifier. */
     342           1 :         enum http2_stream_state stream_state; /**< Stream state. */
     343           1 :         int window_size; /**< Stream-level window size. */
     344             : 
     345             :         /** Currently processed resource detail. */
     346           1 :         struct http_resource_detail *current_detail;
     347             : 
     348             :         /** Flag indicating that headers were sent in the reply. */
     349           1 :         bool headers_sent : 1;
     350             : 
     351             :         /** Flag indicating that END_STREAM flag was sent. */
     352           1 :         bool end_stream_sent : 1;
     353             : };
     354             : 
     355             : /** @brief HTTP/2 frame representation. */
     356           1 : struct http2_frame {
     357           1 :         uint32_t length; /**< Frame payload length. */
     358           1 :         uint32_t stream_identifier; /**< Stream ID the frame belongs to. */
     359           1 :         uint8_t type; /**< Frame type. */
     360           1 :         uint8_t flags; /**< Frame flags. */
     361           1 :         uint8_t padding_len; /**< Frame padding length. */
     362             : };
     363             : 
     364             : /** @cond INTERNAL_HIDDEN */
     365             : /** @brief Context for capturing HTTP headers */
     366             : struct http_header_capture_ctx {
     367             :         /** Buffer for HTTP headers captured for application use */
     368             :         unsigned char buffer[HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE];
     369             : 
     370             :         /** Descriptor of each captured HTTP header */
     371             :         struct http_header headers[HTTP_SERVER_CAPTURE_HEADER_COUNT];
     372             : 
     373             :         /** Status of captured headers */
     374             :         enum http_header_status status;
     375             : 
     376             :         /** Number of headers captured */
     377             :         size_t count;
     378             : 
     379             :         /** Current position in buffer */
     380             :         size_t cursor;
     381             : 
     382             :         /** The HTTP2 stream associated with the current headers */
     383             :         struct http2_stream_ctx *current_stream;
     384             : 
     385             :         /** The next HTTP header value should be stored */
     386             :         bool store_next_value;
     387             : };
     388             : /** @endcond */
     389             : 
     390             : /** @brief HTTP header name representation */
     391           1 : struct http_header_name {
     392           1 :         const char *name; /**< Pointer to header name NULL-terminated string. */
     393             : };
     394             : 
     395             : /**
     396             :  * @brief Representation of an HTTP client connected to the server.
     397             :  */
     398           1 : struct http_client_ctx {
     399             :         /** Socket descriptor associated with the server. */
     400           1 :         int fd;
     401             : 
     402             :         /** Client data buffer.  */
     403           1 :         unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE];
     404             : 
     405             :         /** Cursor indicating currently processed byte. */
     406           1 :         unsigned char *cursor;
     407             : 
     408             :         /** Data left to process in the buffer. */
     409           1 :         size_t data_len;
     410             : 
     411             :         /** Connection-level window size. */
     412           1 :         int window_size;
     413             : 
     414             :         /** Server state for the associated client. */
     415           1 :         enum http_server_state server_state;
     416             : 
     417             :         /** Currently processed HTTP/2 frame. */
     418           1 :         struct http2_frame current_frame;
     419             : 
     420             :         /** Currently processed resource detail. */
     421           1 :         struct http_resource_detail *current_detail;
     422             : 
     423             :         /** Currently processed stream. */
     424           1 :         struct http2_stream_ctx *current_stream;
     425             : 
     426             :         /** HTTP/2 header parser context. */
     427           1 :         struct http_hpack_header_buf header_field;
     428             : 
     429             :         /** HTTP/2 streams context. */
     430           1 :         struct http2_stream_ctx streams[HTTP_SERVER_MAX_STREAMS];
     431             : 
     432             :         /** HTTP/1 parser configuration. */
     433           1 :         struct http_parser_settings parser_settings;
     434             : 
     435             :         /** HTTP/1 parser context. */
     436           1 :         struct http_parser parser;
     437             : 
     438             :         /** Header capture context */
     439           1 :         struct http_header_capture_ctx header_capture_ctx;
     440             : 
     441             :         /** Request URL. */
     442           1 :         unsigned char url_buffer[HTTP_SERVER_MAX_URL_LENGTH];
     443             : 
     444             :         /** Request content type. */
     445           1 :         unsigned char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN];
     446             : 
     447             :         /** Temp buffer for currently processed header (HTTP/1 only). */
     448           1 :         unsigned char header_buffer[HTTP_SERVER_MAX_HEADER_LEN];
     449             : 
     450             :         /** Request content length. */
     451           1 :         size_t content_len;
     452             : 
     453             :         /** Request method. */
     454           1 :         enum http_method method;
     455             : 
     456             :         /** HTTP/1 parser state. */
     457           1 :         enum http1_parser_state parser_state;
     458             : 
     459             :         /** Length of the payload length in the currently processed request
     460             :          * fragment (HTTP/1 only).
     461             :          */
     462           1 :         int http1_frag_data_len;
     463             : 
     464             :         /** Client inactivity timer. The client connection is closed by the
     465             :          *  server when it expires.
     466             :          */
     467           1 :         struct k_work_delayable inactivity_timer;
     468             : 
     469             : /** @cond INTERNAL_HIDDEN */
     470             :         /** Websocket security key. */
     471             :         IF_ENABLED(CONFIG_WEBSOCKET, (uint8_t ws_sec_key[HTTP_SERVER_WS_MAX_SEC_KEY_LEN]));
     472             : /** @endcond */
     473             : 
     474             :         /** Flag indicating that HTTP2 preface was sent. */
     475           1 :         bool preface_sent : 1;
     476             : 
     477             :         /** Flag indicating that HTTP1 headers were sent. */
     478           1 :         bool http1_headers_sent : 1;
     479             : 
     480             :         /** Flag indicating that upgrade header was present in the request. */
     481           1 :         bool has_upgrade_header : 1;
     482             : 
     483             :         /** Flag indicating HTTP/2 upgrade takes place. */
     484           1 :         bool http2_upgrade : 1;
     485             : 
     486             :         /** Flag indicating Websocket upgrade takes place. */
     487           1 :         bool websocket_upgrade : 1;
     488             : 
     489             :         /** Flag indicating Websocket key is being processed. */
     490           1 :         bool websocket_sec_key_next : 1;
     491             : 
     492             :         /** The next frame on the stream is expectd to be a continuation frame. */
     493           1 :         bool expect_continuation : 1;
     494             : };
     495             : 
     496             : /**
     497             :  * @brief Register an HTTP request header to be captured by the server
     498             :  *
     499             :  * @param _id variable name for the header capture instance
     500             :  * @param _header header to be captured, as literal string
     501             :  */
     502           1 : #define HTTP_SERVER_REGISTER_HEADER_CAPTURE(_id, _header)                                          \
     503             :         BUILD_ASSERT(sizeof(_header) <= CONFIG_HTTP_SERVER_MAX_HEADER_LEN,                         \
     504             :                      "Header is too long to be captured, try increasing "                          \
     505             :                      "CONFIG_HTTP_SERVER_MAX_HEADER_LEN");                                         \
     506             :         static const char *const _id##_str = _header;                                              \
     507             :         static const STRUCT_SECTION_ITERABLE(http_header_name, _id) = {                            \
     508             :                 .name = _id##_str,                                                                 \
     509             :         }
     510             : 
     511             : /** @brief Start the HTTP2 server.
     512             :  *
     513             :  * The server runs in a background thread. Once started, the server will create
     514             :  * a server socket for all HTTP services registered in the system and accept
     515             :  * connections from clients (see @ref HTTP_SERVICE_DEFINE).
     516             :  */
     517           1 : int http_server_start(void);
     518             : 
     519             : /** @brief Stop the HTTP2 server.
     520             :  *
     521             :  * All server sockets are closed and the server thread is suspended.
     522             :  */
     523           1 : int http_server_stop(void);
     524             : 
     525             : #ifdef __cplusplus
     526             : }
     527             : #endif
     528             : 
     529             : /**
     530             :  * @}
     531             :  */
     532             : 
     533             : #endif

Generated by: LCOV version 1.14