1 // Copyright 2018 Espressif Systems (Shanghai) PTE LTD 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 16 #ifndef _HTTPD_PRIV_H_ 17 #define _HTTPD_PRIV_H_ 18 19 #include <stdbool.h> 20 #include <sys/socket.h> 21 #include <sys/param.h> 22 #include <netinet/in.h> 23 #include <esp_log.h> 24 #include <esp_err.h> 25 26 #include <esp_http_server.h> 27 #include "osal.h" 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 33 /* Size of request data block/chunk (not to be confused with chunked encoded data) 34 * that is received and parsed in one turn of the parsing process. This should not 35 * exceed the scratch buffer size and should at least be 8 bytes */ 36 #define PARSER_BLOCK_SIZE 128 37 38 /* Calculate the maximum size needed for the scratch buffer */ 39 #define HTTPD_SCRATCH_BUF MAX(HTTPD_MAX_REQ_HDR_LEN, HTTPD_MAX_URI_LEN) 40 41 /* Formats a log string to prepend context function name */ 42 #define LOG_FMT(x) "%s: " x, __func__ 43 44 /** 45 * @brief Thread related data for internal use 46 */ 47 struct thread_data { 48 othread_t handle; /*!< Handle to thread/task */ 49 enum { 50 THREAD_IDLE = 0, 51 THREAD_RUNNING, 52 THREAD_STOPPING, 53 THREAD_STOPPED, 54 } status; /*!< State of the thread */ 55 }; 56 57 /** 58 * @brief A database of all the open sockets in the system. 59 */ 60 struct sock_db { 61 int fd; /*!< The file descriptor for this socket */ 62 void *ctx; /*!< A custom context for this socket */ 63 bool ignore_sess_ctx_changes; /*!< Flag indicating if session context changes should be ignored */ 64 void *transport_ctx; /*!< A custom 'transport' context for this socket, to be used by send/recv/pending */ 65 httpd_handle_t handle; /*!< Server handle */ 66 httpd_free_ctx_fn_t free_ctx; /*!< Function for freeing the context */ 67 httpd_free_ctx_fn_t free_transport_ctx; /*!< Function for freeing the 'transport' context */ 68 httpd_send_func_t send_fn; /*!< Send function for this socket */ 69 httpd_recv_func_t recv_fn; /*!< Receive function for this socket */ 70 httpd_pending_func_t pending_fn; /*!< Pending function for this socket */ 71 uint64_t lru_counter; /*!< LRU Counter indicating when the socket was last used */ 72 bool lru_socket; /*!< Flag indicating LRU socket */ 73 char pending_data[PARSER_BLOCK_SIZE]; /*!< Buffer for pending data to be received */ 74 size_t pending_len; /*!< Length of pending data to be received */ 75 #ifdef CONFIG_HTTPD_WS_SUPPORT 76 bool ws_handshake_done; /*!< True if it has done WebSocket handshake (if this socket is a valid WS) */ 77 bool ws_close; /*!< Set to true to close the socket later (when WS Close frame received) */ 78 esp_err_t (*ws_handler)(httpd_req_t *r); /*!< WebSocket handler, leave to null if it's not WebSocket */ 79 bool ws_control_frames; /*!< WebSocket flag indicating that control frames should be passed to user handlers */ 80 #endif 81 }; 82 83 /** 84 * @brief Auxiliary data structure for use during reception and processing 85 * of requests and temporarily keeping responses 86 */ 87 struct httpd_req_aux { 88 struct sock_db *sd; /*!< Pointer to socket database */ 89 char scratch[HTTPD_SCRATCH_BUF + 1]; /*!< Temporary buffer for our operations (1 byte extra for null termination) */ 90 size_t remaining_len; /*!< Amount of data remaining to be fetched */ 91 char *status; /*!< HTTP response's status code */ 92 char *content_type; /*!< HTTP response's content type */ 93 bool first_chunk_sent; /*!< Used to indicate if first chunk sent */ 94 unsigned req_hdrs_count; /*!< Count of total headers in request packet */ 95 unsigned resp_hdrs_count; /*!< Count of additional headers in response packet */ 96 struct resp_hdr { 97 const char *field; 98 const char *value; 99 } *resp_hdrs; /*!< Additional headers in response packet */ 100 struct http_parser_url url_parse_res; /*!< URL parsing result, used for retrieving URL elements */ 101 #ifdef CONFIG_HTTPD_WS_SUPPORT 102 bool ws_handshake_detect; /*!< WebSocket handshake detection flag */ 103 httpd_ws_type_t ws_type; /*!< WebSocket frame type */ 104 bool ws_final; /*!< WebSocket FIN bit (final frame or not) */ 105 #endif 106 }; 107 108 /** 109 * @brief Server data for each instance. This is exposed publicly as 110 * httpd_handle_t but internal structure/members are kept private. 111 */ 112 struct httpd_data { 113 httpd_config_t config; /*!< HTTPD server configuration */ 114 int listen_fd; /*!< Server listener FD */ 115 int ctrl_fd; /*!< Ctrl message receiver FD */ 116 int msg_fd; /*!< Ctrl message sender FD */ 117 struct thread_data hd_td; /*!< Information for the HTTPD thread */ 118 struct sock_db *hd_sd; /*!< The socket database */ 119 httpd_uri_t **hd_calls; /*!< Registered URI handlers */ 120 struct httpd_req hd_req; /*!< The current HTTPD request */ 121 struct httpd_req_aux hd_req_aux; /*!< Additional data about the HTTPD request kept unexposed */ 122 123 /* Array of registered error handler functions */ 124 httpd_err_handler_func_t *err_handler_fns; 125 }; 126 127 /******************* Group : Session Management ********************/ 128 /** @name Session Management 129 * Functions related to HTTP session management 130 * @{ 131 */ 132 133 /** 134 * @brief Retrieve a session by its descriptor 135 * 136 * @param[in] hd Server instance data 137 * @param[in] sockfd Socket FD 138 * @return pointer into the socket DB, or NULL if not found 139 */ 140 struct sock_db *httpd_sess_get(struct httpd_data *hd, int sockfd); 141 142 /** 143 * @brief Delete sessions whose FDs have became invalid. 144 * This is a recovery strategy e.g. after select() fails. 145 * 146 * @param[in] hd Server instance data 147 */ 148 void httpd_sess_delete_invalid(struct httpd_data *hd); 149 150 /** 151 * @brief Initializes an http session by resetting the sockets database. 152 * 153 * @param[in] hd Server instance data 154 */ 155 void httpd_sess_init(struct httpd_data *hd); 156 157 /** 158 * @brief Starts a new session for client requesting connection and adds 159 * it's descriptor to the socket database. 160 * 161 * @param[in] hd Server instance data 162 * @param[in] newfd Descriptor of the new client to be added to the session. 163 * 164 * @return 165 * - ESP_OK : on successfully queuing the work 166 * - ESP_FAIL : in case of control socket error while sending 167 */ 168 esp_err_t httpd_sess_new(struct httpd_data *hd, int newfd); 169 170 /** 171 * @brief Processes incoming HTTP requests 172 * 173 * @param[in] hd Server instance data 174 * @param[in] clifd Descriptor of the client from which data is to be received 175 * 176 * @return 177 * - ESP_OK : on successfully receiving, parsing and responding to a request 178 * - ESP_FAIL : in case of failure in any of the stages of processing 179 */ 180 esp_err_t httpd_sess_process(struct httpd_data *hd, int clifd); 181 182 /** 183 * @brief Remove client descriptor from the session / socket database 184 * and close the connection for this client. 185 * 186 * @note The returned descriptor should be used by httpd_sess_iterate() 187 * to continue the iteration correctly. This ensures that the 188 * iteration is not restarted abruptly which may cause reading from 189 * a socket which has been already processed and thus blocking 190 * the server loop until data appears on that socket. 191 * 192 * @param[in] hd Server instance data 193 * @param[in] clifd Descriptor of the client to be removed from the session. 194 * 195 * @return 196 * - +VE : Client descriptor preceding the one being deleted 197 * - -1 : No descriptor preceding the one being deleted 198 */ 199 int httpd_sess_delete(struct httpd_data *hd, int clifd); 200 201 /** 202 * @brief Free session context 203 * 204 * @param[in] ctx Pointer to session context 205 * @param[in] free_fn Free function to call on session context 206 */ 207 void httpd_sess_free_ctx(void *ctx, httpd_free_ctx_fn_t free_fn); 208 209 /** 210 * @brief Add descriptors present in the socket database to an fdset and 211 * update the value of maxfd which are needed by the select function 212 * for looking through all available sockets for incoming data. 213 * 214 * @param[in] hd Server instance data 215 * @param[out] fdset File descriptor set to be updated. 216 * @param[out] maxfd Maximum value among all file descriptors. 217 */ 218 void httpd_sess_set_descriptors(struct httpd_data *hd, fd_set *fdset, int *maxfd); 219 220 /** 221 * @brief Iterates through the list of client fds in the session /socket database. 222 * Passing the value of a client fd returns the fd for the next client 223 * in the database. In order to iterate from the beginning pass -1 as fd. 224 * 225 * @param[in] hd Server instance data 226 * @param[in] fd Last accessed client descriptor. 227 * -1 to reset iterator to start of database. 228 * 229 * @return 230 * - +VE : Client descriptor next in the database 231 * - -1 : End of iteration 232 */ 233 int httpd_sess_iterate(struct httpd_data *hd, int fd); 234 235 /** 236 * @brief Checks if session can accept another connection from new client. 237 * If sockets database is full then this returns false. 238 * 239 * @param[in] hd Server instance data 240 * 241 * @return True if session can accept new clients 242 */ 243 bool httpd_is_sess_available(struct httpd_data *hd); 244 245 /** 246 * @brief Checks if session has any pending data/packets 247 * for processing 248 * 249 * This is needed as httpd_unrecv may un-receive next 250 * packet in the stream. If only partial packet was 251 * received then select() would mark the fd for processing 252 * as remaining part of the packet would still be in socket 253 * recv queue. But if a complete packet got unreceived 254 * then it would not be processed until further data is 255 * received on the socket. This is when this function 256 * comes in use, as it checks the socket's pending data 257 * buffer. 258 * 259 * @param[in] hd Server instance data 260 * @param[in] fd Client descriptor 261 * 262 * @return True if there is any pending data 263 */ 264 bool httpd_sess_pending(struct httpd_data *hd, int fd); 265 266 /** 267 * @brief Removes the least recently used client from the session 268 * 269 * This may be useful if new clients are requesting for connection but 270 * max number of connections is reached, in which case the client which 271 * is inactive for the longest will be removed from the session. 272 * 273 * @param[in] hd Server instance data 274 * 275 * @return 276 * - ESP_OK : if session closure initiated successfully 277 * - ESP_FAIL : if failed 278 */ 279 esp_err_t httpd_sess_close_lru(struct httpd_data *hd); 280 281 /** End of Group : Session Management 282 * @} 283 */ 284 285 /****************** Group : URI Handling ********************/ 286 /** @name URI Handling 287 * Methods for accessing URI handlers 288 * @{ 289 */ 290 291 /** 292 * @brief For an HTTP request, searches through all the registered URI handlers 293 * and invokes the appropriate one if found 294 * 295 * @param[in] hd Server instance data for which handler needs to be invoked 296 * 297 * @return 298 * - ESP_OK : if handler found and executed successfully 299 * - ESP_FAIL : otherwise 300 */ 301 esp_err_t httpd_uri(struct httpd_data *hd); 302 303 /** 304 * @brief Unregister all URI handlers 305 * 306 * @param[in] hd Server instance data 307 */ 308 void httpd_unregister_all_uri_handlers(struct httpd_data *hd); 309 310 /** 311 * @brief Validates the request to prevent users from calling APIs, that are to 312 * be called only inside a URI handler, outside the handler context 313 * 314 * @param[in] req Pointer to HTTP request that needs to be validated 315 * 316 * @return 317 * - true : if valid request 318 * - false : otherwise 319 */ 320 bool httpd_validate_req_ptr(httpd_req_t *r); 321 322 /* httpd_validate_req_ptr() adds some overhead to frequently used APIs, 323 * and is useful mostly for debugging, so it's preferable to disable 324 * the check by default and enable it only if necessary */ 325 #ifdef CONFIG_HTTPD_VALIDATE_REQ 326 #define httpd_valid_req(r) httpd_validate_req_ptr(r) 327 #else 328 #define httpd_valid_req(r) true 329 #endif 330 331 /** End of Group : URI Handling 332 * @} 333 */ 334 335 /****************** Group : Processing ********************/ 336 /** @name Processing 337 * Methods for processing HTTP requests 338 * @{ 339 */ 340 341 /** 342 * @brief Initiates the processing of HTTP request 343 * 344 * Receives incoming TCP packet on a socket, then parses the packet as 345 * HTTP request and fills httpd_req_t data structure with the extracted 346 * URI, headers are ready to be fetched from scratch buffer and calling 347 * http_recv() after this reads the body of the request. 348 * 349 * @param[in] hd Server instance data 350 * @param[in] sd Pointer to socket which is needed for receiving TCP packets. 351 * 352 * @return 353 * - ESP_OK : if request packet is valid 354 * - ESP_FAIL : otherwise 355 */ 356 esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd); 357 358 /** 359 * @brief For an HTTP request, resets the resources allocated for it and 360 * purges any data left to be received 361 * 362 * @param[in] hd Server instance data 363 * 364 * @return 365 * - ESP_OK : if request packet deleted and resources cleaned. 366 * - ESP_FAIL : otherwise. 367 */ 368 esp_err_t httpd_req_delete(struct httpd_data *hd); 369 370 /** 371 * @brief For handling HTTP errors by invoking registered 372 * error handler function 373 * 374 * @param[in] req Pointer to the HTTP request for which error occurred 375 * @param[in] error Error type 376 * 377 * @return 378 * - ESP_OK : error handled successful 379 * - ESP_FAIL : failure indicates that the underlying socket needs to be closed 380 */ 381 esp_err_t httpd_req_handle_err(httpd_req_t *req, httpd_err_code_t error); 382 383 /** End of Group : Parsing 384 * @} 385 */ 386 387 /****************** Group : Send/Receive ********************/ 388 /** @name Send and Receive 389 * Methods for transmitting and receiving HTTP requests and responses 390 * @{ 391 */ 392 393 /** 394 * @brief For sending out data in response to an HTTP request. 395 * 396 * @param[in] req Pointer to the HTTP request for which the response needs to be sent 397 * @param[in] buf Pointer to the buffer from where the body of the response is taken 398 * @param[in] buf_len Length of the buffer 399 * 400 * @return 401 * - Length of data : if successful 402 * - ESP_FAIL : if failed 403 */ 404 int httpd_send(httpd_req_t *req, const char *buf, size_t buf_len); 405 406 /** 407 * @brief For receiving HTTP request data 408 * 409 * @note The exposed API httpd_recv() is simply this function with last parameter 410 * set as false. This function is used internally during reception and 411 * processing of a new request. The option to halt after receiving pending 412 * data prevents the server from requesting more data than is needed for 413 * completing a packet in case when all the remaining part of the packet is 414 * in the pending buffer. 415 * 416 * @param[in] req Pointer to new HTTP request which only has the socket descriptor 417 * @param[out] buf Pointer to the buffer which will be filled with the received data 418 * @param[in] buf_len Length of the buffer 419 * @param[in] halt_after_pending When set true, halts immediately after receiving from 420 * pending buffer 421 * 422 * @return 423 * - Length of data : if successful 424 * - ESP_FAIL : if failed 425 */ 426 int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, bool halt_after_pending); 427 428 /** 429 * @brief For un-receiving HTTP request data 430 * 431 * This function copies data into internal buffer pending_data so that 432 * when httpd_recv is called, it first fetches this pending data and 433 * then only starts receiving from the socket 434 * 435 * @note If data is too large for the internal buffer then only 436 * part of the data is unreceived, reflected in the returned 437 * length. Make sure that such truncation is checked for and 438 * handled properly. 439 * 440 * @param[in] req Pointer to new HTTP request which only has the socket descriptor 441 * @param[in] buf Pointer to the buffer from where data needs to be un-received 442 * @param[in] buf_len Length of the buffer 443 * 444 * @return Length of data copied into pending buffer 445 */ 446 size_t httpd_unrecv(struct httpd_req *r, const char *buf, size_t buf_len); 447 448 /** 449 * @brief This is the low level default send function of the HTTPD. This should 450 * NEVER be called directly. The semantics of this is exactly similar to 451 * send() of the BSD socket API. 452 * 453 * @param[in] hd Server instance data 454 * @param[in] sockfd Socket descriptor for sending data 455 * @param[in] buf Pointer to the buffer from where the body of the response is taken 456 * @param[in] buf_len Length of the buffer 457 * @param[in] flags Flags for mode selection 458 * 459 * @return 460 * - Length of data : if successful 461 * - -1 : if failed (appropriate errno is set) 462 */ 463 int httpd_default_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags); 464 465 /** 466 * @brief This is the low level default recv function of the HTTPD. This should 467 * NEVER be called directly. The semantics of this is exactly similar to 468 * recv() of the BSD socket API. 469 * 470 * @param[in] hd Server instance data 471 * @param[in] sockfd Socket descriptor for sending data 472 * @param[out] buf Pointer to the buffer which will be filled with the received data 473 * @param[in] buf_len Length of the buffer 474 * @param[in] flags Flags for mode selection 475 * 476 * @return 477 * - Length of data : if successful 478 * - -1 : if failed (appropriate errno is set) 479 */ 480 int httpd_default_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags); 481 482 /** End of Group : Send and Receive 483 * @} 484 */ 485 486 /* ************** Group: WebSocket ************** */ 487 /** @name WebSocket 488 * Functions for WebSocket header parsing 489 * @{ 490 */ 491 492 493 /** 494 * @brief This function is for responding a WebSocket handshake 495 * 496 * @param[in] req Pointer to handshake request that will be handled 497 * @param[in] supported_subprotocol Pointer to the subprotocol supported by this URI 498 * @return 499 * - ESP_OK : When handshake is sucessful 500 * - ESP_ERR_NOT_FOUND : When some headers (Sec-WebSocket-*) are not found 501 * - ESP_ERR_INVALID_VERSION : The WebSocket version is not "13" 502 * - ESP_ERR_INVALID_STATE : Handshake was done beforehand 503 * - ESP_ERR_INVALID_ARG : Argument is invalid (null or non-WebSocket) 504 * - ESP_FAIL : Socket failures 505 */ 506 esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *supported_subprotocol); 507 508 /** 509 * @brief This function is for getting a frame type 510 * and responding a WebSocket control frame automatically 511 * 512 * @param[in] req Pointer to handshake request that will be handled 513 * @return 514 * - ESP_OK : When handshake is sucessful 515 * - ESP_ERR_INVALID_ARG : Argument is invalid (null or non-WebSocket) 516 * - ESP_ERR_INVALID_STATE : Received only some parts of a control frame 517 * - ESP_FAIL : Socket failures 518 */ 519 esp_err_t httpd_ws_get_frame_type(httpd_req_t *req); 520 521 /** End of WebSocket related functions 522 * @} 523 */ 524 525 #ifdef __cplusplus 526 } 527 #endif 528 529 #endif /* ! _HTTPD_PRIV_H_ */ 530