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