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