esp_httpd_priv.h 20 KB

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