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/socket.h> 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 /** @cond INTERNAL_HIDDEN */ 35 36 #if defined(CONFIG_HTTP_SERVER) 37 #define HTTP_SERVER_CLIENT_BUFFER_SIZE CONFIG_HTTP_SERVER_CLIENT_BUFFER_SIZE 38 #define HTTP_SERVER_MAX_STREAMS CONFIG_HTTP_SERVER_MAX_STREAMS 39 #define HTTP_SERVER_MAX_CONTENT_TYPE_LEN CONFIG_HTTP_SERVER_MAX_CONTENT_TYPE_LENGTH 40 #define HTTP_SERVER_MAX_URL_LENGTH CONFIG_HTTP_SERVER_MAX_URL_LENGTH 41 #else 42 #define HTTP_SERVER_CLIENT_BUFFER_SIZE 0 43 #define HTTP_SERVER_MAX_STREAMS 0 44 #define HTTP_SERVER_MAX_CONTENT_TYPE_LEN 0 45 #define HTTP_SERVER_MAX_URL_LENGTH 0 46 #endif 47 48 /* Maximum header field name / value length. This is only used to detect Upgrade and 49 * websocket header fields and values in the http1 server so the value is quite short. 50 */ 51 #define HTTP_SERVER_MAX_HEADER_LEN 32 52 53 #define HTTP2_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" 54 55 /** @endcond */ 56 57 /** 58 * @brief HTTP server resource type. 59 */ 60 enum http_resource_type { 61 /** Static resource, cannot be modified on runtime. */ 62 HTTP_RESOURCE_TYPE_STATIC, 63 64 /** serves static gzipped files from a filesystem */ 65 HTTP_RESOURCE_TYPE_STATIC_FS, 66 67 /** Dynamic resource, server interacts with the application via registered 68 * @ref http_resource_dynamic_cb_t. 69 */ 70 HTTP_RESOURCE_TYPE_DYNAMIC, 71 72 /** Websocket resource, application takes control over Websocket connection 73 * after and upgrade. 74 */ 75 HTTP_RESOURCE_TYPE_WEBSOCKET, 76 }; 77 78 /** 79 * @brief Representation of a server resource, common for all resource types. 80 */ 81 struct http_resource_detail { 82 /** Bitmask of supported HTTP methods (@ref http_method). */ 83 uint32_t bitmask_of_supported_http_methods; 84 85 /** Resource type. */ 86 enum http_resource_type type; 87 88 /** Length of the URL path. */ 89 int path_len; 90 91 /** Content encoding of the resource. */ 92 const char *content_encoding; 93 94 /** Content type of the resource. */ 95 const char *content_type; 96 }; 97 98 /** @cond INTERNAL_HIDDEN */ 99 BUILD_ASSERT(NUM_BITS( 100 sizeof(((struct http_resource_detail *)0)->bitmask_of_supported_http_methods)) 101 >= (HTTP_METHOD_END_VALUE - 1)); 102 /** @endcond */ 103 104 /** 105 * @brief Representation of a static server resource. 106 */ 107 struct http_resource_detail_static { 108 /** Common resource details. */ 109 struct http_resource_detail common; 110 111 /** Content of the static resource. */ 112 const void *static_data; 113 114 /** Size of the static resource. */ 115 size_t static_data_len; 116 }; 117 118 /** @cond INTERNAL_HIDDEN */ 119 /* Make sure that the common is the first in the struct. */ 120 BUILD_ASSERT(offsetof(struct http_resource_detail_static, common) == 0); 121 /** @endcond */ 122 123 /** 124 * @brief Representation of a static filesystem server resource. 125 */ 126 struct http_resource_detail_static_fs { 127 /** Common resource details. */ 128 struct http_resource_detail common; 129 130 /** Path in the local filesystem */ 131 const char *fs_path; 132 }; 133 134 /** @cond INTERNAL_HIDDEN */ 135 /* Make sure that the common is the first in the struct. */ 136 BUILD_ASSERT(offsetof(struct http_resource_detail_static_fs, common) == 0); 137 /** @endcond */ 138 139 struct http_content_type { 140 const char *extension; 141 size_t extension_len; 142 const char *content_type; 143 }; 144 145 #define HTTP_SERVER_CONTENT_TYPE(_extension, _content_type) \ 146 const STRUCT_SECTION_ITERABLE(http_content_type, _extension) = { \ 147 .extension = STRINGIFY(_extension), \ 148 .extension_len = sizeof(STRINGIFY(_extension)) - 1, \ 149 .content_type = _content_type, \ 150 }; 151 152 #define HTTP_SERVER_CONTENT_TYPE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_content_type, _it) 153 154 struct http_client_ctx; 155 156 /** Indicates the status of the currently processed piece of data. */ 157 enum http_data_status { 158 /** Transaction aborted, data incomplete. */ 159 HTTP_SERVER_DATA_ABORTED = -1, 160 /** Transaction incomplete, more data expected. */ 161 HTTP_SERVER_DATA_MORE = 0, 162 /** Final data fragment in current transaction. */ 163 HTTP_SERVER_DATA_FINAL = 1, 164 }; 165 166 /** 167 * @typedef http_resource_dynamic_cb_t 168 * @brief Callback used when data is received. Data to be sent to client 169 * can be specified. 170 * 171 * @param client HTTP context information for this client connection. 172 * @param status HTTP data status, indicate whether more data is expected or not. 173 * @param data_buffer Data received. 174 * @param data_len Amount of data received. 175 * @param user_data User specified data. 176 * 177 * @return >0 amount of data to be sent to client, let server to call this 178 * function again when new data is received. 179 * 0 nothing to sent to client, close the connection 180 * <0 error, close the connection. 181 */ 182 typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client, 183 enum http_data_status status, 184 uint8_t *data_buffer, 185 size_t data_len, 186 void *user_data); 187 188 /** 189 * @brief Representation of a dynamic server resource. 190 */ 191 struct http_resource_detail_dynamic { 192 /** Common resource details. */ 193 struct http_resource_detail common; 194 195 /** Resource callback used by the server to interact with the 196 * application. 197 */ 198 http_resource_dynamic_cb_t cb; 199 200 /** Data buffer used to exchanged data between server and the, 201 * application. 202 */ 203 uint8_t *data_buffer; 204 205 /** Length of the data in the data buffer. */ 206 size_t data_buffer_len; 207 208 /** A pointer to the client currently processing resource, used to 209 * prevent concurrent access to the resource from multiple clients. 210 */ 211 struct http_client_ctx *holder; 212 213 /** A pointer to the user data registered by the application. */ 214 void *user_data; 215 }; 216 217 /** @cond INTERNAL_HIDDEN */ 218 BUILD_ASSERT(offsetof(struct http_resource_detail_dynamic, common) == 0); 219 /** @endcond */ 220 221 /** 222 * @typedef http_resource_websocket_cb_t 223 * @brief Callback used when a Websocket connection is setup. The application 224 * will need to handle all functionality related to the connection like 225 * reading and writing websocket data, and closing the connection. 226 * 227 * @param ws_socket A socket for the Websocket data. 228 * @param user_data User specified data. 229 * 230 * @return 0 Accepting the connection, HTTP server library will no longer 231 * handle data to/from the socket and it is application responsibility 232 * to send and receive data to/from the supplied socket. 233 * <0 error, close the connection. 234 */ 235 typedef int (*http_resource_websocket_cb_t)(int ws_socket, 236 void *user_data); 237 238 /** @brief Representation of a websocket server resource */ 239 struct http_resource_detail_websocket { 240 /** Common resource details. */ 241 struct http_resource_detail common; 242 243 /** Websocket socket value */ 244 int ws_sock; 245 246 /** Resource callback used by the server to interact with the 247 * application. 248 */ 249 http_resource_websocket_cb_t cb; 250 251 /** Data buffer used to exchanged data between server and the, 252 * application. 253 */ 254 uint8_t *data_buffer; 255 256 /** Length of the data in the data buffer. */ 257 size_t data_buffer_len; 258 259 /** A pointer to the user data registered by the application. */ 260 void *user_data; 261 }; 262 263 /** @cond INTERNAL_HIDDEN */ 264 BUILD_ASSERT(offsetof(struct http_resource_detail_websocket, common) == 0); 265 /** @endcond */ 266 267 /** @cond INTERNAL_HIDDEN */ 268 269 enum http2_stream_state { 270 HTTP2_STREAM_IDLE, 271 HTTP2_STREAM_RESERVED_LOCAL, 272 HTTP2_STREAM_RESERVED_REMOTE, 273 HTTP2_STREAM_OPEN, 274 HTTP2_STREAM_HALF_CLOSED_LOCAL, 275 HTTP2_STREAM_HALF_CLOSED_REMOTE, 276 HTTP2_STREAM_CLOSED 277 }; 278 279 enum http_server_state { 280 HTTP_SERVER_FRAME_HEADER_STATE, 281 HTTP_SERVER_PREFACE_STATE, 282 HTTP_SERVER_REQUEST_STATE, 283 HTTP_SERVER_FRAME_DATA_STATE, 284 HTTP_SERVER_FRAME_HEADERS_STATE, 285 HTTP_SERVER_FRAME_SETTINGS_STATE, 286 HTTP_SERVER_FRAME_PRIORITY_STATE, 287 HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE, 288 HTTP_SERVER_FRAME_CONTINUATION_STATE, 289 HTTP_SERVER_FRAME_PING_STATE, 290 HTTP_SERVER_FRAME_RST_STREAM_STATE, 291 HTTP_SERVER_FRAME_GOAWAY_STATE, 292 HTTP_SERVER_FRAME_PADDING_STATE, 293 HTTP_SERVER_DONE_STATE, 294 }; 295 296 enum http1_parser_state { 297 HTTP1_INIT_HEADER_STATE, 298 HTTP1_WAITING_HEADER_STATE, 299 HTTP1_RECEIVING_HEADER_STATE, 300 HTTP1_RECEIVED_HEADER_STATE, 301 HTTP1_RECEIVING_DATA_STATE, 302 HTTP1_MESSAGE_COMPLETE_STATE, 303 }; 304 305 #define HTTP_SERVER_INITIAL_WINDOW_SIZE 65536 306 #define HTTP_SERVER_WS_MAX_SEC_KEY_LEN 32 307 308 /** @endcond */ 309 310 /** @brief HTTP/2 stream representation. */ 311 struct http2_stream_ctx { 312 int stream_id; /**< Stream identifier. */ 313 enum http2_stream_state stream_state; /**< Stream state. */ 314 int window_size; /**< Stream-level window size. */ 315 316 /** Flag indicating that headers were sent in the reply. */ 317 bool headers_sent : 1; 318 319 /** Flag indicating that END_STREAM flag was sent. */ 320 bool end_stream_sent : 1; 321 }; 322 323 /** @brief HTTP/2 frame representation. */ 324 struct http2_frame { 325 uint32_t length; /**< Frame payload length. */ 326 uint32_t stream_identifier; /**< Stream ID the frame belongs to. */ 327 uint8_t type; /**< Frame type. */ 328 uint8_t flags; /**< Frame flags. */ 329 uint8_t padding_len; /**< Frame padding length. */ 330 }; 331 332 /** 333 * @brief Representation of an HTTP client connected to the server. 334 */ 335 struct http_client_ctx { 336 /** Socket descriptor associated with the server. */ 337 int fd; 338 339 /** Client data buffer. */ 340 unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE]; 341 342 /** Cursor indicating currently processed byte. */ 343 unsigned char *cursor; 344 345 /** Data left to process in the buffer. */ 346 size_t data_len; 347 348 /** Connection-level window size. */ 349 int window_size; 350 351 /** Server state for the associated client. */ 352 enum http_server_state server_state; 353 354 /** Currently processed HTTP/2 frame. */ 355 struct http2_frame current_frame; 356 357 /** Currently processed resource detail. */ 358 struct http_resource_detail *current_detail; 359 360 /** Currently processed stream. */ 361 struct http2_stream_ctx *current_stream; 362 363 /** HTTP/2 header parser context. */ 364 struct http_hpack_header_buf header_field; 365 366 /** HTTP/2 streams context. */ 367 struct http2_stream_ctx streams[HTTP_SERVER_MAX_STREAMS]; 368 369 /** HTTP/1 parser configuration. */ 370 struct http_parser_settings parser_settings; 371 372 /** HTTP/1 parser context. */ 373 struct http_parser parser; 374 375 /** Request URL. */ 376 unsigned char url_buffer[HTTP_SERVER_MAX_URL_LENGTH]; 377 378 /** Request content type. */ 379 unsigned char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN]; 380 381 /** Temp buffer for currently processed header (HTTP/1 only). */ 382 unsigned char header_buffer[HTTP_SERVER_MAX_HEADER_LEN]; 383 384 /** Request content length. */ 385 size_t content_len; 386 387 /** Request method. */ 388 enum http_method method; 389 390 /** HTTP/1 parser state. */ 391 enum http1_parser_state parser_state; 392 393 /** Length of the payload length in the currently processed request 394 * fragment (HTTP/1 only). 395 */ 396 int http1_frag_data_len; 397 398 /** Client inactivity timer. The client connection is closed by the 399 * server when it expires. 400 */ 401 struct k_work_delayable inactivity_timer; 402 403 /** @cond INTERNAL_HIDDEN */ 404 /** Websocket security key. */ 405 IF_ENABLED(CONFIG_WEBSOCKET, (uint8_t ws_sec_key[HTTP_SERVER_WS_MAX_SEC_KEY_LEN])); 406 /** @endcond */ 407 408 /** Flag indicating that HTTP2 preface was sent. */ 409 bool preface_sent : 1; 410 411 /** Flag indicating that HTTP1 headers were sent. */ 412 bool http1_headers_sent : 1; 413 414 /** Flag indicating that upgrade header was present in the request. */ 415 bool has_upgrade_header : 1; 416 417 /** Flag indicating HTTP/2 upgrade takes place. */ 418 bool http2_upgrade : 1; 419 420 /** Flag indicating Websocket upgrade takes place. */ 421 bool websocket_upgrade : 1; 422 423 /** Flag indicating Websocket key is being processed. */ 424 bool websocket_sec_key_next : 1; 425 426 /** The next frame on the stream is expectd to be a continuation frame. */ 427 bool expect_continuation : 1; 428 }; 429 430 /** @brief Start the HTTP2 server. 431 * 432 * The server runs in a background thread. Once started, the server will create 433 * a server socket for all HTTP services registered in the system and accept 434 * connections from clients (see @ref HTTP_SERVICE_DEFINE). 435 */ 436 int http_server_start(void); 437 438 /** @brief Stop the HTTP2 server. 439 * 440 * All server sockets are closed and the server thread is suspended. 441 */ 442 int http_server_stop(void); 443 444 #ifdef __cplusplus 445 } 446 #endif 447 448 /** 449 * @} 450 */ 451 452 #endif 453