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 /** @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 struct http_content_type { 147 const char *extension; 148 size_t extension_len; 149 const char *content_type; 150 }; 151 152 #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 #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 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 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 struct http_header { 182 const char *name; /**< Pointer to header name NULL-terminated string. */ 183 const char *value; /**< Pointer to header value NULL-terminated string. */ 184 }; 185 186 /** @brief HTTP request context */ 187 struct http_request_ctx { 188 uint8_t *data; /**< HTTP request data */ 189 size_t data_len; /**< Length of HTTP request data */ 190 struct http_header *headers; /**< Array of HTTP request headers */ 191 size_t header_count; /**< Array length of HTTP request headers */ 192 enum http_header_status headers_status; /**< Status of HTTP request headers */ 193 }; 194 195 /** @brief HTTP response context */ 196 struct http_response_ctx { 197 enum http_status status; /**< HTTP status code to include in response */ 198 const struct http_header *headers; /**< Array of HTTP headers */ 199 size_t header_count; /**< Length of headers array */ 200 const uint8_t *body; /**< Pointer to body data */ 201 size_t body_len; /**< Length of body data */ 202 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 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 struct http_resource_detail_dynamic { 229 /** Common resource details. */ 230 struct http_resource_detail common; 231 232 /** Resource callback used by the server to interact with the 233 * application. 234 */ 235 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 struct http_client_ctx *holder; 241 242 /** A pointer to the user data registered by the application. */ 243 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 typedef int (*http_resource_websocket_cb_t)(int ws_socket, 265 void *user_data); 266 267 /** @brief Representation of a websocket server resource */ 268 struct http_resource_detail_websocket { 269 /** Common resource details. */ 270 struct http_resource_detail common; 271 272 /** Websocket socket value */ 273 int ws_sock; 274 275 /** Resource callback used by the server to interact with the 276 * application. 277 */ 278 http_resource_websocket_cb_t cb; 279 280 /** Data buffer used to exchanged data between server and the, 281 * application. 282 */ 283 uint8_t *data_buffer; 284 285 /** Length of the data in the data buffer. */ 286 size_t data_buffer_len; 287 288 /** A pointer to the user data registered by the application. */ 289 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 struct http2_stream_ctx { 341 int stream_id; /**< Stream identifier. */ 342 enum http2_stream_state stream_state; /**< Stream state. */ 343 int window_size; /**< Stream-level window size. */ 344 345 /** Currently processed resource detail. */ 346 struct http_resource_detail *current_detail; 347 348 /** Flag indicating that headers were sent in the reply. */ 349 bool headers_sent : 1; 350 351 /** Flag indicating that END_STREAM flag was sent. */ 352 bool end_stream_sent : 1; 353 }; 354 355 /** @brief HTTP/2 frame representation. */ 356 struct http2_frame { 357 uint32_t length; /**< Frame payload length. */ 358 uint32_t stream_identifier; /**< Stream ID the frame belongs to. */ 359 uint8_t type; /**< Frame type. */ 360 uint8_t flags; /**< Frame flags. */ 361 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 struct http_header_name { 392 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 struct http_client_ctx { 399 /** Socket descriptor associated with the server. */ 400 int fd; 401 402 /** Client data buffer. */ 403 unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE]; 404 405 /** Cursor indicating currently processed byte. */ 406 unsigned char *cursor; 407 408 /** Data left to process in the buffer. */ 409 size_t data_len; 410 411 /** Connection-level window size. */ 412 int window_size; 413 414 /** Server state for the associated client. */ 415 enum http_server_state server_state; 416 417 /** Currently processed HTTP/2 frame. */ 418 struct http2_frame current_frame; 419 420 /** Currently processed resource detail. */ 421 struct http_resource_detail *current_detail; 422 423 /** Currently processed stream. */ 424 struct http2_stream_ctx *current_stream; 425 426 /** HTTP/2 header parser context. */ 427 struct http_hpack_header_buf header_field; 428 429 /** HTTP/2 streams context. */ 430 struct http2_stream_ctx streams[HTTP_SERVER_MAX_STREAMS]; 431 432 /** HTTP/1 parser configuration. */ 433 struct http_parser_settings parser_settings; 434 435 /** HTTP/1 parser context. */ 436 struct http_parser parser; 437 438 /** Header capture context */ 439 struct http_header_capture_ctx header_capture_ctx; 440 441 /** Request URL. */ 442 unsigned char url_buffer[HTTP_SERVER_MAX_URL_LENGTH]; 443 444 /** Request content type. */ 445 unsigned char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN]; 446 447 /** Temp buffer for currently processed header (HTTP/1 only). */ 448 unsigned char header_buffer[HTTP_SERVER_MAX_HEADER_LEN]; 449 450 /** Request content length. */ 451 size_t content_len; 452 453 /** Request method. */ 454 enum http_method method; 455 456 /** HTTP/1 parser state. */ 457 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 int http1_frag_data_len; 463 464 /** Client inactivity timer. The client connection is closed by the 465 * server when it expires. 466 */ 467 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 bool preface_sent : 1; 476 477 /** Flag indicating that HTTP1 headers were sent. */ 478 bool http1_headers_sent : 1; 479 480 /** Flag indicating that upgrade header was present in the request. */ 481 bool has_upgrade_header : 1; 482 483 /** Flag indicating HTTP/2 upgrade takes place. */ 484 bool http2_upgrade : 1; 485 486 /** Flag indicating Websocket upgrade takes place. */ 487 bool websocket_upgrade : 1; 488 489 /** Flag indicating Websocket key is being processed. */ 490 bool websocket_sec_key_next : 1; 491 492 /** The next frame on the stream is expectd to be a continuation frame. */ 493 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 #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 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 int http_server_stop(void); 524 525 #ifdef __cplusplus 526 } 527 #endif 528 529 /** 530 * @} 531 */ 532 533 #endif 534