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 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 struct http_resource_detail { 89 /** Bitmask of supported HTTP methods (@ref http_method). */ 90 uint32_t bitmask_of_supported_http_methods; 91 92 /** Resource type. */ 93 enum http_resource_type type; 94 95 /** Length of the URL path. */ 96 int path_len; 97 98 /** Content encoding of the resource. */ 99 const char *content_encoding; 100 101 /** Content type of the resource. */ 102 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 struct http_resource_detail_static { 115 /** Common resource details. */ 116 struct http_resource_detail common; 117 118 /** Content of the static resource. */ 119 const void *static_data; 120 121 /** Size of the static resource. */ 122 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 struct http_resource_detail_static_fs { 134 /** Common resource details. */ 135 struct http_resource_detail common; 136 137 /** Path in the local filesystem */ 138 const char *fs_path; 139 }; 140 141 /** @brief HTTP compressions */ 142 enum http_compression { 143 HTTP_NONE = 0, /**< NONE */ 144 HTTP_GZIP = 1, /**< GZIP */ 145 HTTP_COMPRESS = 2, /**< COMPRESS */ 146 HTTP_DEFLATE = 3, /**< DEFLATE */ 147 HTTP_BR = 4, /**< BR */ 148 HTTP_ZSTD = 5 /**< ZSTD */ 149 }; 150 151 /** @cond INTERNAL_HIDDEN */ 152 /* Make sure that the common is the first in the struct. */ 153 BUILD_ASSERT(offsetof(struct http_resource_detail_static_fs, common) == 0); 154 /** @endcond */ 155 156 struct http_content_type { 157 const char *extension; 158 size_t extension_len; 159 const char *content_type; 160 }; 161 162 #define HTTP_SERVER_CONTENT_TYPE(_extension, _content_type) \ 163 const STRUCT_SECTION_ITERABLE(http_content_type, _extension) = { \ 164 .extension = STRINGIFY(_extension), \ 165 .extension_len = sizeof(STRINGIFY(_extension)) - 1, \ 166 .content_type = _content_type, \ 167 }; 168 169 #define HTTP_SERVER_CONTENT_TYPE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_content_type, _it) 170 171 struct http_client_ctx; 172 173 /** Indicates the status of the currently processed piece of data. */ 174 enum http_data_status { 175 /** Transaction aborted, data incomplete. */ 176 HTTP_SERVER_DATA_ABORTED = -1, 177 /** Transaction incomplete, more data expected. */ 178 HTTP_SERVER_DATA_MORE = 0, 179 /** Final data fragment in current transaction. */ 180 HTTP_SERVER_DATA_FINAL = 1, 181 }; 182 183 /** @brief Status of captured request headers */ 184 enum http_header_status { 185 HTTP_HEADER_STATUS_OK, /**< All available headers were successfully captured. */ 186 HTTP_HEADER_STATUS_DROPPED, /**< One or more headers were dropped due to lack of space. */ 187 HTTP_HEADER_STATUS_NONE, /**< No header status is available. */ 188 }; 189 190 /** @brief HTTP header representation */ 191 struct http_header { 192 const char *name; /**< Pointer to header name NULL-terminated string. */ 193 const char *value; /**< Pointer to header value NULL-terminated string. */ 194 }; 195 196 /** @brief HTTP request context */ 197 struct http_request_ctx { 198 uint8_t *data; /**< HTTP request data */ 199 size_t data_len; /**< Length of HTTP request data */ 200 struct http_header *headers; /**< Array of HTTP request headers */ 201 size_t header_count; /**< Array length of HTTP request headers */ 202 enum http_header_status headers_status; /**< Status of HTTP request headers */ 203 }; 204 205 /** @brief HTTP response context */ 206 struct http_response_ctx { 207 enum http_status status; /**< HTTP status code to include in response */ 208 const struct http_header *headers; /**< Array of HTTP headers */ 209 size_t header_count; /**< Length of headers array */ 210 const uint8_t *body; /**< Pointer to body data */ 211 size_t body_len; /**< Length of body data */ 212 bool final_chunk; /**< Flag set to true when the application has no more data to send */ 213 }; 214 215 /** 216 * @typedef http_resource_dynamic_cb_t 217 * @brief Callback used when data is received. Data to be sent to client 218 * can be specified. 219 * 220 * @param client HTTP context information for this client connection. 221 * @param status HTTP data status, indicate whether more data is expected or not. 222 * @param request_ctx Request context structure containing HTTP request data that was received. 223 * @param response_ctx Response context structure for application to populate with response data. 224 * @param user_data User specified data. 225 * 226 * @return 0 success, server can send any response data provided in the response_ctx. 227 * <0 error, close the connection. 228 */ 229 typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client, 230 enum http_data_status status, 231 const struct http_request_ctx *request_ctx, 232 struct http_response_ctx *response_ctx, 233 void *user_data); 234 235 /** 236 * @brief Representation of a dynamic server resource. 237 */ 238 struct http_resource_detail_dynamic { 239 /** Common resource details. */ 240 struct http_resource_detail common; 241 242 /** Resource callback used by the server to interact with the 243 * application. 244 */ 245 http_resource_dynamic_cb_t cb; 246 247 /** A pointer to the client currently processing resource, used to 248 * prevent concurrent access to the resource from multiple clients. 249 */ 250 struct http_client_ctx *holder; 251 252 /** A pointer to the user data registered by the application. */ 253 void *user_data; 254 }; 255 256 /** @cond INTERNAL_HIDDEN */ 257 BUILD_ASSERT(offsetof(struct http_resource_detail_dynamic, common) == 0); 258 /** @endcond */ 259 260 /** 261 * @typedef http_resource_websocket_cb_t 262 * @brief Callback used when a Websocket connection is setup. The application 263 * will need to handle all functionality related to the connection like 264 * reading and writing websocket data, and closing the connection. 265 * 266 * @param ws_socket A socket for the Websocket data. 267 * @param request_ctx Request context structure associated with HTTP upgrade request 268 * @param user_data User specified data. 269 * 270 * @return 0 Accepting the connection, HTTP server library will no longer 271 * handle data to/from the socket and it is application responsibility 272 * to send and receive data to/from the supplied socket. 273 * <0 error, close the connection. 274 */ 275 typedef int (*http_resource_websocket_cb_t)(int ws_socket, struct http_request_ctx *request_ctx, 276 void *user_data); 277 278 /** @brief Representation of a websocket server resource */ 279 struct http_resource_detail_websocket { 280 /** Common resource details. */ 281 struct http_resource_detail common; 282 283 /** Websocket socket value */ 284 int ws_sock; 285 286 /** Resource callback used by the server to interact with the 287 * application. 288 */ 289 http_resource_websocket_cb_t cb; 290 291 /** Data buffer used to exchanged data between server and the, 292 * application. 293 */ 294 uint8_t *data_buffer; 295 296 /** Length of the data in the data buffer. */ 297 size_t data_buffer_len; 298 299 /** A pointer to the user data registered by the application. */ 300 void *user_data; 301 }; 302 303 /** @cond INTERNAL_HIDDEN */ 304 BUILD_ASSERT(offsetof(struct http_resource_detail_websocket, common) == 0); 305 /** @endcond */ 306 307 /** @cond INTERNAL_HIDDEN */ 308 309 enum http2_stream_state { 310 HTTP2_STREAM_IDLE, 311 HTTP2_STREAM_RESERVED_LOCAL, 312 HTTP2_STREAM_RESERVED_REMOTE, 313 HTTP2_STREAM_OPEN, 314 HTTP2_STREAM_HALF_CLOSED_LOCAL, 315 HTTP2_STREAM_HALF_CLOSED_REMOTE, 316 HTTP2_STREAM_CLOSED 317 }; 318 319 enum http_server_state { 320 HTTP_SERVER_FRAME_HEADER_STATE, 321 HTTP_SERVER_PREFACE_STATE, 322 HTTP_SERVER_REQUEST_STATE, 323 HTTP_SERVER_FRAME_DATA_STATE, 324 HTTP_SERVER_FRAME_HEADERS_STATE, 325 HTTP_SERVER_FRAME_SETTINGS_STATE, 326 HTTP_SERVER_FRAME_PRIORITY_STATE, 327 HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE, 328 HTTP_SERVER_FRAME_CONTINUATION_STATE, 329 HTTP_SERVER_FRAME_PING_STATE, 330 HTTP_SERVER_FRAME_RST_STREAM_STATE, 331 HTTP_SERVER_FRAME_GOAWAY_STATE, 332 HTTP_SERVER_FRAME_PADDING_STATE, 333 HTTP_SERVER_DONE_STATE, 334 }; 335 336 enum http1_parser_state { 337 HTTP1_INIT_HEADER_STATE, 338 HTTP1_WAITING_HEADER_STATE, 339 HTTP1_RECEIVING_HEADER_STATE, 340 HTTP1_RECEIVED_HEADER_STATE, 341 HTTP1_RECEIVING_DATA_STATE, 342 HTTP1_MESSAGE_COMPLETE_STATE, 343 }; 344 345 #define HTTP_SERVER_INITIAL_WINDOW_SIZE 65536 346 #define HTTP_SERVER_WS_MAX_SEC_KEY_LEN 32 347 348 /** @endcond */ 349 350 /** @brief HTTP/2 stream representation. */ 351 struct http2_stream_ctx { 352 int stream_id; /**< Stream identifier. */ 353 enum http2_stream_state stream_state; /**< Stream state. */ 354 int window_size; /**< Stream-level window size. */ 355 356 /** Currently processed resource detail. */ 357 struct http_resource_detail *current_detail; 358 359 /** Flag indicating that headers were sent in the reply. */ 360 bool headers_sent : 1; 361 362 /** Flag indicating that END_STREAM flag was sent. */ 363 bool end_stream_sent : 1; 364 }; 365 366 /** @brief HTTP/2 frame representation. */ 367 struct http2_frame { 368 uint32_t length; /**< Frame payload length. */ 369 uint32_t stream_identifier; /**< Stream ID the frame belongs to. */ 370 uint8_t type; /**< Frame type. */ 371 uint8_t flags; /**< Frame flags. */ 372 uint8_t padding_len; /**< Frame padding length. */ 373 }; 374 375 /** @cond INTERNAL_HIDDEN */ 376 /** @brief Context for capturing HTTP headers */ 377 struct http_header_capture_ctx { 378 /** Buffer for HTTP headers captured for application use */ 379 unsigned char buffer[HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE]; 380 381 /** Descriptor of each captured HTTP header */ 382 struct http_header headers[HTTP_SERVER_CAPTURE_HEADER_COUNT]; 383 384 /** Status of captured headers */ 385 enum http_header_status status; 386 387 /** Number of headers captured */ 388 size_t count; 389 390 /** Current position in buffer */ 391 size_t cursor; 392 393 /** The HTTP2 stream associated with the current headers */ 394 struct http2_stream_ctx *current_stream; 395 396 /** The next HTTP header value should be stored */ 397 bool store_next_value; 398 }; 399 /** @endcond */ 400 401 /** @brief HTTP header name representation */ 402 struct http_header_name { 403 const char *name; /**< Pointer to header name NULL-terminated string. */ 404 }; 405 406 /** 407 * @brief Representation of an HTTP client connected to the server. 408 */ 409 struct http_client_ctx { 410 /** Socket descriptor associated with the server. */ 411 int fd; 412 413 /** HTTP service on which the client is connected */ 414 const struct http_service_desc *service; 415 416 /** Client data buffer. */ 417 unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE]; 418 419 /** Cursor indicating currently processed byte. */ 420 unsigned char *cursor; 421 422 /** Data left to process in the buffer. */ 423 size_t data_len; 424 425 /** Connection-level window size. */ 426 int window_size; 427 428 /** Server state for the associated client. */ 429 enum http_server_state server_state; 430 431 /** Currently processed HTTP/2 frame. */ 432 struct http2_frame current_frame; 433 434 /** Currently processed resource detail. */ 435 struct http_resource_detail *current_detail; 436 437 /** Currently processed stream. */ 438 struct http2_stream_ctx *current_stream; 439 440 /** HTTP/2 header parser context. */ 441 struct http_hpack_header_buf header_field; 442 443 /** HTTP/2 streams context. */ 444 struct http2_stream_ctx streams[HTTP_SERVER_MAX_STREAMS]; 445 446 /** HTTP/1 parser configuration. */ 447 struct http_parser_settings parser_settings; 448 449 /** HTTP/1 parser context. */ 450 struct http_parser parser; 451 452 /** Header capture context */ 453 struct http_header_capture_ctx header_capture_ctx; 454 455 /** Request URL. */ 456 unsigned char url_buffer[HTTP_SERVER_MAX_URL_LENGTH]; 457 458 /** Request content type. */ 459 unsigned char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN]; 460 461 /** Temp buffer for currently processed header (HTTP/1 only). */ 462 unsigned char header_buffer[HTTP_SERVER_MAX_HEADER_LEN]; 463 464 /** Request content length. */ 465 size_t content_len; 466 467 /** Request method. */ 468 enum http_method method; 469 470 /** HTTP/1 parser state. */ 471 enum http1_parser_state parser_state; 472 473 /** Length of the payload length in the currently processed request 474 * fragment (HTTP/1 only). 475 */ 476 int http1_frag_data_len; 477 478 /** Client inactivity timer. The client connection is closed by the 479 * server when it expires. 480 */ 481 struct k_work_delayable inactivity_timer; 482 483 /** @cond INTERNAL_HIDDEN */ 484 /** Websocket security key. */ 485 IF_ENABLED(CONFIG_WEBSOCKET, (uint8_t ws_sec_key[HTTP_SERVER_WS_MAX_SEC_KEY_LEN])); 486 /** @endcond */ 487 488 /** @cond INTERNAL_HIDDEN */ 489 /** Client supported compression. */ 490 IF_ENABLED(CONFIG_HTTP_SERVER_COMPRESSION, (uint8_t supported_compression)); 491 /** @endcond */ 492 493 /** Flag indicating that HTTP2 preface was sent. */ 494 bool preface_sent : 1; 495 496 /** Flag indicating that HTTP1 headers were sent. */ 497 bool http1_headers_sent : 1; 498 499 /** Flag indicating that upgrade header was present in the request. */ 500 bool has_upgrade_header : 1; 501 502 /** Flag indicating HTTP/2 upgrade takes place. */ 503 bool http2_upgrade : 1; 504 505 /** Flag indicating Websocket upgrade takes place. */ 506 bool websocket_upgrade : 1; 507 508 /** Flag indicating Websocket key is being processed. */ 509 bool websocket_sec_key_next : 1; 510 511 /** Flag indicating accept encoding is being processed. */ 512 IF_ENABLED(CONFIG_HTTP_SERVER_COMPRESSION, (bool accept_encoding_next: 1)); 513 514 /** The next frame on the stream is expectd to be a continuation frame. */ 515 bool expect_continuation : 1; 516 }; 517 518 /** 519 * @brief Register an HTTP request header to be captured by the server 520 * 521 * @param _id variable name for the header capture instance 522 * @param _header header to be captured, as literal string 523 */ 524 #define HTTP_SERVER_REGISTER_HEADER_CAPTURE(_id, _header) \ 525 BUILD_ASSERT(sizeof(_header) <= CONFIG_HTTP_SERVER_MAX_HEADER_LEN, \ 526 "Header is too long to be captured, try increasing " \ 527 "CONFIG_HTTP_SERVER_MAX_HEADER_LEN"); \ 528 static const char *const _id##_str = _header; \ 529 static const STRUCT_SECTION_ITERABLE(http_header_name, _id) = { \ 530 .name = _id##_str, \ 531 } 532 533 /** @brief Start the HTTP2 server. 534 * 535 * The server runs in a background thread. Once started, the server will create 536 * a server socket for all HTTP services registered in the system and accept 537 * connections from clients (see @ref HTTP_SERVICE_DEFINE). 538 */ 539 int http_server_start(void); 540 541 /** @brief Stop the HTTP2 server. 542 * 543 * All server sockets are closed and the server thread is suspended. 544 */ 545 int http_server_stop(void); 546 547 #ifdef __cplusplus 548 } 549 #endif 550 551 /** 552 * @} 553 */ 554 555 #endif 556