1 /*
2  * SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef _ESP_HTTP_SERVER_H_
8 #define _ESP_HTTP_SERVER_H_
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include <freertos/FreeRTOS.h>
13 #include <freertos/task.h>
14 #include <http_parser.h>
15 #include <sdkconfig.h>
16 #include <esp_err.h>
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 /*
23 note: esp_https_server.h includes a customized copy of this
24 initializer that should be kept in sync
25 */
26 #define HTTPD_DEFAULT_CONFIG() {                        \
27         .task_priority      = tskIDLE_PRIORITY+5,       \
28         .stack_size         = 4096,                     \
29         .core_id            = tskNO_AFFINITY,           \
30         .server_port        = 80,                       \
31         .ctrl_port          = 32768,                    \
32         .max_open_sockets   = 7,                        \
33         .max_uri_handlers   = 8,                        \
34         .max_resp_headers   = 8,                        \
35         .backlog_conn       = 5,                        \
36         .lru_purge_enable   = false,                    \
37         .recv_wait_timeout  = 5,                        \
38         .send_wait_timeout  = 5,                        \
39         .global_user_ctx = NULL,                        \
40         .global_user_ctx_free_fn = NULL,                \
41         .global_transport_ctx = NULL,                   \
42         .global_transport_ctx_free_fn = NULL,           \
43         .open_fn = NULL,                                \
44         .close_fn = NULL,                               \
45         .uri_match_fn = NULL                            \
46 }
47 
48 #define ESP_ERR_HTTPD_BASE              (0xb000)                    /*!< Starting number of HTTPD error codes */
49 #define ESP_ERR_HTTPD_HANDLERS_FULL     (ESP_ERR_HTTPD_BASE +  1)   /*!< All slots for registering URI handlers have been consumed */
50 #define ESP_ERR_HTTPD_HANDLER_EXISTS    (ESP_ERR_HTTPD_BASE +  2)   /*!< URI handler with same method and target URI already registered */
51 #define ESP_ERR_HTTPD_INVALID_REQ       (ESP_ERR_HTTPD_BASE +  3)   /*!< Invalid request pointer */
52 #define ESP_ERR_HTTPD_RESULT_TRUNC      (ESP_ERR_HTTPD_BASE +  4)   /*!< Result string truncated */
53 #define ESP_ERR_HTTPD_RESP_HDR          (ESP_ERR_HTTPD_BASE +  5)   /*!< Response header field larger than supported */
54 #define ESP_ERR_HTTPD_RESP_SEND         (ESP_ERR_HTTPD_BASE +  6)   /*!< Error occured while sending response packet */
55 #define ESP_ERR_HTTPD_ALLOC_MEM         (ESP_ERR_HTTPD_BASE +  7)   /*!< Failed to dynamically allocate memory for resource */
56 #define ESP_ERR_HTTPD_TASK              (ESP_ERR_HTTPD_BASE +  8)   /*!< Failed to launch server task/thread */
57 
58 /* Symbol to be used as length parameter in httpd_resp_send APIs
59  * for setting buffer length to string length */
60 #define HTTPD_RESP_USE_STRLEN -1
61 
62 /* ************** Group: Initialization ************** */
63 /** @name Initialization
64  * APIs related to the Initialization of the web server
65  * @{
66  */
67 
68 /**
69  * @brief   HTTP Server Instance Handle
70  *
71  * Every instance of the server will have a unique handle.
72  */
73 typedef void* httpd_handle_t;
74 
75 /**
76  * @brief   HTTP Method Type wrapper over "enum http_method"
77  *          available in "http_parser" library
78  */
79 typedef enum http_method httpd_method_t;
80 
81 /**
82  * @brief  Prototype for freeing context data (if any)
83  * @param[in] ctx   object to free
84  */
85 typedef void (*httpd_free_ctx_fn_t)(void *ctx);
86 
87 /**
88  * @brief  Function prototype for opening a session.
89  *
90  * Called immediately after the socket was opened to set up the send/recv functions and
91  * other parameters of the socket.
92  *
93  * @param[in] hd       server instance
94  * @param[in] sockfd   session socket file descriptor
95  * @return
96  *  - ESP_OK   : On success
97  *  - Any value other than ESP_OK will signal the server to close the socket immediately
98  */
99 typedef esp_err_t (*httpd_open_func_t)(httpd_handle_t hd, int sockfd);
100 
101 /**
102  * @brief  Function prototype for closing a session.
103  *
104  * @note   It's possible that the socket descriptor is invalid at this point, the function
105  *         is called for all terminated sessions. Ensure proper handling of return codes.
106  *
107  * @param[in] hd   server instance
108  * @param[in] sockfd   session socket file descriptor
109  */
110 typedef void (*httpd_close_func_t)(httpd_handle_t hd, int sockfd);
111 
112 /**
113  * @brief  Function prototype for URI matching.
114  *
115  * @param[in] reference_uri   URI/template with respect to which the other URI is matched
116  * @param[in] uri_to_match    URI/template being matched to the reference URI/template
117  * @param[in] match_upto      For specifying the actual length of `uri_to_match` up to
118  *                            which the matching algorithm is to be applied (The maximum
119  *                            value is `strlen(uri_to_match)`, independent of the length
120  *                            of `reference_uri`)
121  * @return true on match
122  */
123 typedef bool (*httpd_uri_match_func_t)(const char *reference_uri,
124                                        const char *uri_to_match,
125                                        size_t match_upto);
126 
127 /**
128  * @brief   HTTP Server Configuration Structure
129  *
130  * @note    Use HTTPD_DEFAULT_CONFIG() to initialize the configuration
131  *          to a default value and then modify only those fields that are
132  *          specifically determined by the use case.
133  */
134 typedef struct httpd_config {
135     unsigned    task_priority;      /*!< Priority of FreeRTOS task which runs the server */
136     size_t      stack_size;         /*!< The maximum stack size allowed for the server task */
137     BaseType_t  core_id;            /*!< The core the HTTP server task will run on */
138 
139     /**
140      * TCP Port number for receiving and transmitting HTTP traffic
141      */
142     uint16_t    server_port;
143 
144     /**
145      * UDP Port number for asynchronously exchanging control signals
146      * between various components of the server
147      */
148     uint16_t    ctrl_port;
149 
150     uint16_t    max_open_sockets;   /*!< Max number of sockets/clients connected at any time*/
151     uint16_t    max_uri_handlers;   /*!< Maximum allowed uri handlers */
152     uint16_t    max_resp_headers;   /*!< Maximum allowed additional headers in HTTP response */
153     uint16_t    backlog_conn;       /*!< Number of backlog connections */
154     bool        lru_purge_enable;   /*!< Purge "Least Recently Used" connection */
155     uint16_t    recv_wait_timeout;  /*!< Timeout for recv function (in seconds)*/
156     uint16_t    send_wait_timeout;  /*!< Timeout for send function (in seconds)*/
157 
158     /**
159      * Global user context.
160      *
161      * This field can be used to store arbitrary user data within the server context.
162      * The value can be retrieved using the server handle, available e.g. in the httpd_req_t struct.
163      *
164      * When shutting down, the server frees up the user context by
165      * calling free() on the global_user_ctx field. If you wish to use a custom
166      * function for freeing the global user context, please specify that here.
167      */
168     void * global_user_ctx;
169 
170     /**
171      * Free function for global user context
172      */
173     httpd_free_ctx_fn_t global_user_ctx_free_fn;
174 
175     /**
176      * Global transport context.
177      *
178      * Similar to global_user_ctx, but used for session encoding or encryption (e.g. to hold the SSL context).
179      * It will be freed using free(), unless global_transport_ctx_free_fn is specified.
180      */
181     void * global_transport_ctx;
182 
183     /**
184      * Free function for global transport context
185      */
186     httpd_free_ctx_fn_t global_transport_ctx_free_fn;
187 
188     /**
189      * Custom session opening callback.
190      *
191      * Called on a new session socket just after accept(), but before reading any data.
192      *
193      * This is an opportunity to set up e.g. SSL encryption using global_transport_ctx
194      * and the send/recv/pending session overrides.
195      *
196      * If a context needs to be maintained between these functions, store it in the session using
197      * httpd_sess_set_transport_ctx() and retrieve it later with httpd_sess_get_transport_ctx()
198      *
199      * Returning a value other than ESP_OK will immediately close the new socket.
200      */
201     httpd_open_func_t open_fn;
202 
203     /**
204      * Custom session closing callback.
205      *
206      * Called when a session is deleted, before freeing user and transport contexts and before
207      * closing the socket. This is a place for custom de-init code common to all sockets.
208      *
209      * Set the user or transport context to NULL if it was freed here, so the server does not
210      * try to free it again.
211      *
212      * This function is run for all terminated sessions, including sessions where the socket
213      * was closed by the network stack - that is, the file descriptor may not be valid anymore.
214      */
215     httpd_close_func_t close_fn;
216 
217     /**
218      * URI matcher function.
219      *
220      * Called when searching for a matching URI:
221      *     1) whose request handler is to be executed right
222      *        after an HTTP request is successfully parsed
223      *     2) in order to prevent duplication while registering
224      *        a new URI handler using `httpd_register_uri_handler()`
225      *
226      * Available options are:
227      *     1) NULL : Internally do basic matching using `strncmp()`
228      *     2) `httpd_uri_match_wildcard()` : URI wildcard matcher
229      *
230      * Users can implement their own matching functions (See description
231      * of the `httpd_uri_match_func_t` function prototype)
232      */
233     httpd_uri_match_func_t uri_match_fn;
234 } httpd_config_t;
235 
236 /**
237  * @brief Starts the web server
238  *
239  * Create an instance of HTTP server and allocate memory/resources for it
240  * depending upon the specified configuration.
241  *
242  * Example usage:
243  * @code{c}
244  *
245  * //Function for starting the webserver
246  * httpd_handle_t start_webserver(void)
247  * {
248  *      // Generate default configuration
249  *      httpd_config_t config = HTTPD_DEFAULT_CONFIG();
250  *
251  *      // Empty handle to http_server
252  *      httpd_handle_t server = NULL;
253  *
254  *      // Start the httpd server
255  *      if (httpd_start(&server, &config) == ESP_OK) {
256  *          // Register URI handlers
257  *          httpd_register_uri_handler(server, &uri_get);
258  *          httpd_register_uri_handler(server, &uri_post);
259  *      }
260  *      // If server failed to start, handle will be NULL
261  *      return server;
262  * }
263  *
264  * @endcode
265  *
266  * @param[in]  config   Configuration for new instance of the server
267  * @param[out] handle   Handle to newly created instance of the server. NULL on error
268  * @return
269  *  - ESP_OK    : Instance created successfully
270  *  - ESP_ERR_INVALID_ARG      : Null argument(s)
271  *  - ESP_ERR_HTTPD_ALLOC_MEM  : Failed to allocate memory for instance
272  *  - ESP_ERR_HTTPD_TASK       : Failed to launch server task
273  */
274 esp_err_t  httpd_start(httpd_handle_t *handle, const httpd_config_t *config);
275 
276 /**
277  * @brief Stops the web server
278  *
279  * Deallocates memory/resources used by an HTTP server instance and
280  * deletes it. Once deleted the handle can no longer be used for accessing
281  * the instance.
282  *
283  * Example usage:
284  * @code{c}
285  *
286  * // Function for stopping the webserver
287  * void stop_webserver(httpd_handle_t server)
288  * {
289  *      // Ensure handle is non NULL
290  *      if (server != NULL) {
291  *          // Stop the httpd server
292  *          httpd_stop(server);
293  *      }
294  * }
295  *
296  * @endcode
297  *
298  * @param[in] handle Handle to server returned by httpd_start
299  * @return
300  *  - ESP_OK : Server stopped successfully
301  *  - ESP_ERR_INVALID_ARG : Handle argument is Null
302  */
303 esp_err_t httpd_stop(httpd_handle_t handle);
304 
305 /** End of Group Initialization
306  * @}
307  */
308 
309 /* ************** Group: URI Handlers ************** */
310 /** @name URI Handlers
311  * APIs related to the URI handlers
312  * @{
313  */
314 
315 /* Max supported HTTP request header length */
316 #define HTTPD_MAX_REQ_HDR_LEN CONFIG_HTTPD_MAX_REQ_HDR_LEN
317 
318 /* Max supported HTTP request URI length */
319 #define HTTPD_MAX_URI_LEN CONFIG_HTTPD_MAX_URI_LEN
320 
321 /**
322  * @brief HTTP Request Data Structure
323  */
324 typedef struct httpd_req {
325     httpd_handle_t  handle;                     /*!< Handle to server instance */
326     int             method;                     /*!< The type of HTTP request, -1 if unsupported method */
327     const char      uri[HTTPD_MAX_URI_LEN + 1]; /*!< The URI of this request (1 byte extra for null termination) */
328     size_t          content_len;                /*!< Length of the request body */
329     void           *aux;                        /*!< Internally used members */
330 
331     /**
332      * User context pointer passed during URI registration.
333      */
334     void *user_ctx;
335 
336     /**
337      * Session Context Pointer
338      *
339      * A session context. Contexts are maintained across 'sessions' for a
340      * given open TCP connection. One session could have multiple request
341      * responses. The web server will ensure that the context persists
342      * across all these request and responses.
343      *
344      * By default, this is NULL. URI Handlers can set this to any meaningful
345      * value.
346      *
347      * If the underlying socket gets closed, and this pointer is non-NULL,
348      * the web server will free up the context by calling free(), unless
349      * free_ctx function is set.
350      */
351     void *sess_ctx;
352 
353     /**
354      * Pointer to free context hook
355      *
356      * Function to free session context
357      *
358      * If the web server's socket closes, it frees up the session context by
359      * calling free() on the sess_ctx member. If you wish to use a custom
360      * function for freeing the session context, please specify that here.
361      */
362     httpd_free_ctx_fn_t free_ctx;
363 
364     /**
365      * Flag indicating if Session Context changes should be ignored
366      *
367      * By default, if you change the sess_ctx in some URI handler, the http server
368      * will internally free the earlier context (if non NULL), after the URI handler
369      * returns. If you want to manage the allocation/reallocation/freeing of
370      * sess_ctx yourself, set this flag to true, so that the server will not
371      * perform any checks on it. The context will be cleared by the server
372      * (by calling free_ctx or free()) only if the socket gets closed.
373      */
374     bool ignore_sess_ctx_changes;
375 } httpd_req_t;
376 
377 /**
378  * @brief Structure for URI handler
379  */
380 typedef struct httpd_uri {
381     const char       *uri;    /*!< The URI to handle */
382     httpd_method_t    method; /*!< Method supported by the URI */
383 
384     /**
385      * Handler to call for supported request method. This must
386      * return ESP_OK, or else the underlying socket will be closed.
387      */
388     esp_err_t (*handler)(httpd_req_t *r);
389 
390     /**
391      * Pointer to user context data which will be available to handler
392      */
393     void *user_ctx;
394 
395 #ifdef CONFIG_HTTPD_WS_SUPPORT
396     /**
397      * Flag for indicating a WebSocket endpoint.
398      * If this flag is true, then method must be HTTP_GET. Otherwise the handshake will not be handled.
399      */
400     bool is_websocket;
401 
402     /**
403      * Flag indicating that control frames (PING, PONG, CLOSE) are also passed to the handler
404      * This is used if a custom processing of the control frames is needed
405      */
406     bool handle_ws_control_frames;
407 
408     /**
409      * Pointer to subprotocol supported by URI
410      */
411     const char *supported_subprotocol;
412 #endif
413 } httpd_uri_t;
414 
415 /**
416  * @brief   Registers a URI handler
417  *
418  * @note    URI handlers can be registered in real time as long as the
419  *          server handle is valid.
420  *
421  * Example usage:
422  * @code{c}
423  *
424  * esp_err_t my_uri_handler(httpd_req_t* req)
425  * {
426  *     // Recv , Process and Send
427  *     ....
428  *     ....
429  *     ....
430  *
431  *     // Fail condition
432  *     if (....) {
433  *         // Return fail to close session //
434  *         return ESP_FAIL;
435  *     }
436  *
437  *     // On success
438  *     return ESP_OK;
439  * }
440  *
441  * // URI handler structure
442  * httpd_uri_t my_uri {
443  *     .uri      = "/my_uri/path/xyz",
444  *     .method   = HTTPD_GET,
445  *     .handler  = my_uri_handler,
446  *     .user_ctx = NULL
447  * };
448  *
449  * // Register handler
450  * if (httpd_register_uri_handler(server_handle, &my_uri) != ESP_OK) {
451  *    // If failed to register handler
452  *    ....
453  * }
454  *
455  * @endcode
456  *
457  * @param[in] handle      handle to HTTPD server instance
458  * @param[in] uri_handler pointer to handler that needs to be registered
459  *
460  * @return
461  *  - ESP_OK : On successfully registering the handler
462  *  - ESP_ERR_INVALID_ARG : Null arguments
463  *  - ESP_ERR_HTTPD_HANDLERS_FULL  : If no slots left for new handler
464  *  - ESP_ERR_HTTPD_HANDLER_EXISTS : If handler with same URI and
465  *                                   method is already registered
466  */
467 esp_err_t httpd_register_uri_handler(httpd_handle_t handle,
468                                      const httpd_uri_t *uri_handler);
469 
470 /**
471  * @brief   Unregister a URI handler
472  *
473  * @param[in] handle    handle to HTTPD server instance
474  * @param[in] uri       URI string
475  * @param[in] method    HTTP method
476  *
477  * @return
478  *  - ESP_OK : On successfully deregistering the handler
479  *  - ESP_ERR_INVALID_ARG : Null arguments
480  *  - ESP_ERR_NOT_FOUND   : Handler with specified URI and method not found
481  */
482 esp_err_t httpd_unregister_uri_handler(httpd_handle_t handle,
483                                        const char *uri, httpd_method_t method);
484 
485 /**
486  * @brief   Unregister all URI handlers with the specified uri string
487  *
488  * @param[in] handle   handle to HTTPD server instance
489  * @param[in] uri      uri string specifying all handlers that need
490  *                     to be deregisterd
491  *
492  * @return
493  *  - ESP_OK : On successfully deregistering all such handlers
494  *  - ESP_ERR_INVALID_ARG : Null arguments
495  *  - ESP_ERR_NOT_FOUND   : No handler registered with specified uri string
496  */
497 esp_err_t httpd_unregister_uri(httpd_handle_t handle, const char* uri);
498 
499 /** End of URI Handlers
500  * @}
501  */
502 
503 /* ************** Group: HTTP Error ************** */
504 /** @name HTTP Error
505  * Prototype for HTTP errors and error handling functions
506  * @{
507  */
508 
509 /**
510  * @brief Error codes sent as HTTP response in case of errors
511  *        encountered during processing of an HTTP request
512  */
513 typedef enum {
514     /* For any unexpected errors during parsing, like unexpected
515      * state transitions, or unhandled errors.
516      */
517     HTTPD_500_INTERNAL_SERVER_ERROR = 0,
518 
519     /* For methods not supported by http_parser. Presently
520      * http_parser halts parsing when such methods are
521      * encountered and so the server responds with 400 Bad
522      * Request error instead.
523      */
524     HTTPD_501_METHOD_NOT_IMPLEMENTED,
525 
526     /* When HTTP version is not 1.1 */
527     HTTPD_505_VERSION_NOT_SUPPORTED,
528 
529     /* Returned when http_parser halts parsing due to incorrect
530      * syntax of request, unsupported method in request URI or
531      * due to chunked encoding / upgrade field present in headers
532      */
533     HTTPD_400_BAD_REQUEST,
534 
535     /* This response means the client must authenticate itself
536      * to get the requested response.
537      */
538     HTTPD_401_UNAUTHORIZED,
539 
540     /* The client does not have access rights to the content,
541      * so the server is refusing to give the requested resource.
542      * Unlike 401, the client's identity is known to the server.
543      */
544     HTTPD_403_FORBIDDEN,
545 
546     /* When requested URI is not found */
547     HTTPD_404_NOT_FOUND,
548 
549     /* When URI found, but method has no handler registered */
550     HTTPD_405_METHOD_NOT_ALLOWED,
551 
552     /* Intended for recv timeout. Presently it's being sent
553      * for other recv errors as well. Client should expect the
554      * server to immediately close the connection after
555      * responding with this.
556      */
557     HTTPD_408_REQ_TIMEOUT,
558 
559     /* Intended for responding to chunked encoding, which is
560      * not supported currently. Though unhandled http_parser
561      * callback for chunked request returns "400 Bad Request"
562      */
563     HTTPD_411_LENGTH_REQUIRED,
564 
565     /* URI length greater than CONFIG_HTTPD_MAX_URI_LEN */
566     HTTPD_414_URI_TOO_LONG,
567 
568     /* Headers section larger than CONFIG_HTTPD_MAX_REQ_HDR_LEN */
569     HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE,
570 
571     /* Used internally for retrieving the total count of errors */
572     HTTPD_ERR_CODE_MAX
573 } httpd_err_code_t;
574 
575 /**
576  * @brief  Function prototype for HTTP error handling.
577  *
578  * This function is executed upon HTTP errors generated during
579  * internal processing of an HTTP request. This is used to override
580  * the default behavior on error, which is to send HTTP error response
581  * and close the underlying socket.
582  *
583  * @note
584  *  - If implemented, the server will not automatically send out HTTP
585  *    error response codes, therefore, httpd_resp_send_err() must be
586  *    invoked inside this function if user wishes to generate HTTP
587  *    error responses.
588  *  - When invoked, the validity of `uri`, `method`, `content_len`
589  *    and `user_ctx` fields of the httpd_req_t parameter is not
590  *    guaranteed as the HTTP request may be partially received/parsed.
591  *  - The function must return ESP_OK if underlying socket needs to
592  *    be kept open. Any other value will ensure that the socket is
593  *    closed. The return value is ignored when error is of type
594  *    `HTTPD_500_INTERNAL_SERVER_ERROR` and the socket closed anyway.
595  *
596  * @param[in] req    HTTP request for which the error needs to be handled
597  * @param[in] error  Error type
598  *
599  * @return
600  *  - ESP_OK   : error handled successful
601  *  - ESP_FAIL : failure indicates that the underlying socket needs to be closed
602  */
603 typedef esp_err_t (*httpd_err_handler_func_t)(httpd_req_t *req,
604                                               httpd_err_code_t error);
605 
606 /**
607  * @brief  Function for registering HTTP error handlers
608  *
609  * This function maps a handler function to any supported error code
610  * given by `httpd_err_code_t`. See prototype `httpd_err_handler_func_t`
611  * above for details.
612  *
613  * @param[in] handle     HTTP server handle
614  * @param[in] error      Error type
615  * @param[in] handler_fn User implemented handler function
616  *                       (Pass NULL to unset any previously set handler)
617  *
618  * @return
619  *  - ESP_OK : handler registered successfully
620  *  - ESP_ERR_INVALID_ARG : invalid error code or server handle
621  */
622 esp_err_t httpd_register_err_handler(httpd_handle_t handle,
623                                      httpd_err_code_t error,
624                                      httpd_err_handler_func_t handler_fn);
625 
626 /** End of HTTP Error
627  * @}
628  */
629 
630 /* ************** Group: TX/RX ************** */
631 /** @name TX / RX
632  * Prototype for HTTPDs low-level send/recv functions
633  * @{
634  */
635 
636 #define HTTPD_SOCK_ERR_FAIL      -1
637 #define HTTPD_SOCK_ERR_INVALID   -2
638 #define HTTPD_SOCK_ERR_TIMEOUT   -3
639 
640 /**
641  * @brief  Prototype for HTTPDs low-level send function
642  *
643  * @note   User specified send function must handle errors internally,
644  *         depending upon the set value of errno, and return specific
645  *         HTTPD_SOCK_ERR_ codes, which will eventually be conveyed as
646  *         return value of httpd_send() function
647  *
648  * @param[in] hd        server instance
649  * @param[in] sockfd    session socket file descriptor
650  * @param[in] buf       buffer with bytes to send
651  * @param[in] buf_len   data size
652  * @param[in] flags     flags for the send() function
653  * @return
654  *  - Bytes : The number of bytes sent successfully
655  *  - HTTPD_SOCK_ERR_INVALID  : Invalid arguments
656  *  - HTTPD_SOCK_ERR_TIMEOUT  : Timeout/interrupted while calling socket send()
657  *  - HTTPD_SOCK_ERR_FAIL     : Unrecoverable error while calling socket send()
658  */
659 typedef int (*httpd_send_func_t)(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags);
660 
661 /**
662  * @brief  Prototype for HTTPDs low-level recv function
663  *
664  * @note   User specified recv function must handle errors internally,
665  *         depending upon the set value of errno, and return specific
666  *         HTTPD_SOCK_ERR_ codes, which will eventually be conveyed as
667  *         return value of httpd_req_recv() function
668  *
669  * @param[in] hd        server instance
670  * @param[in] sockfd    session socket file descriptor
671  * @param[in] buf       buffer with bytes to send
672  * @param[in] buf_len   data size
673  * @param[in] flags     flags for the send() function
674  * @return
675  *  - Bytes : The number of bytes received successfully
676  *  - 0     : Buffer length parameter is zero / connection closed by peer
677  *  - HTTPD_SOCK_ERR_INVALID  : Invalid arguments
678  *  - HTTPD_SOCK_ERR_TIMEOUT  : Timeout/interrupted while calling socket recv()
679  *  - HTTPD_SOCK_ERR_FAIL     : Unrecoverable error while calling socket recv()
680  */
681 typedef int (*httpd_recv_func_t)(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags);
682 
683 /**
684  * @brief  Prototype for HTTPDs low-level "get pending bytes" function
685  *
686  * @note   User specified pending function must handle errors internally,
687  *         depending upon the set value of errno, and return specific
688  *         HTTPD_SOCK_ERR_ codes, which will be handled accordingly in
689  *         the server task.
690  *
691  * @param[in] hd       server instance
692  * @param[in] sockfd   session socket file descriptor
693  * @return
694  *  - Bytes : The number of bytes waiting to be received
695  *  - HTTPD_SOCK_ERR_INVALID  : Invalid arguments
696  *  - HTTPD_SOCK_ERR_TIMEOUT  : Timeout/interrupted while calling socket pending()
697  *  - HTTPD_SOCK_ERR_FAIL     : Unrecoverable error while calling socket pending()
698  */
699 typedef int (*httpd_pending_func_t)(httpd_handle_t hd, int sockfd);
700 
701 /** End of TX / RX
702  * @}
703  */
704 
705 /* ************** Group: Request/Response ************** */
706 /** @name Request / Response
707  * APIs related to the data send/receive by URI handlers.
708  * These APIs are supposed to be called only from the context of
709  * a URI handler where httpd_req_t* request pointer is valid.
710  * @{
711  */
712 
713 /**
714  * @brief   Override web server's receive function (by session FD)
715  *
716  * This function overrides the web server's receive function. This same function is
717  * used to read HTTP request packets.
718  *
719  * @note    This API is supposed to be called either from the context of
720  *          - an http session APIs where sockfd is a valid parameter
721  *          - a URI handler where sockfd is obtained using httpd_req_to_sockfd()
722  *
723  * @param[in] hd        HTTPD instance handle
724  * @param[in] sockfd    Session socket FD
725  * @param[in] recv_func The receive function to be set for this session
726  *
727  * @return
728  *  - ESP_OK : On successfully registering override
729  *  - ESP_ERR_INVALID_ARG : Null arguments
730  */
731 esp_err_t httpd_sess_set_recv_override(httpd_handle_t hd, int sockfd, httpd_recv_func_t recv_func);
732 
733 /**
734  * @brief   Override web server's send function (by session FD)
735  *
736  * This function overrides the web server's send function. This same function is
737  * used to send out any response to any HTTP request.
738  *
739  * @note    This API is supposed to be called either from the context of
740  *          - an http session APIs where sockfd is a valid parameter
741  *          - a URI handler where sockfd is obtained using httpd_req_to_sockfd()
742  *
743  * @param[in] hd        HTTPD instance handle
744  * @param[in] sockfd    Session socket FD
745  * @param[in] send_func The send function to be set for this session
746  *
747  * @return
748  *  - ESP_OK : On successfully registering override
749  *  - ESP_ERR_INVALID_ARG : Null arguments
750  */
751 esp_err_t httpd_sess_set_send_override(httpd_handle_t hd, int sockfd, httpd_send_func_t send_func);
752 
753 /**
754  * @brief   Override web server's pending function (by session FD)
755  *
756  * This function overrides the web server's pending function. This function is
757  * used to test for pending bytes in a socket.
758  *
759  * @note    This API is supposed to be called either from the context of
760  *          - an http session APIs where sockfd is a valid parameter
761  *          - a URI handler where sockfd is obtained using httpd_req_to_sockfd()
762  *
763  * @param[in] hd           HTTPD instance handle
764  * @param[in] sockfd       Session socket FD
765  * @param[in] pending_func The receive function to be set for this session
766  *
767  * @return
768  *  - ESP_OK : On successfully registering override
769  *  - ESP_ERR_INVALID_ARG : Null arguments
770  */
771 esp_err_t httpd_sess_set_pending_override(httpd_handle_t hd, int sockfd, httpd_pending_func_t pending_func);
772 
773 /**
774  * @brief   Get the Socket Descriptor from the HTTP request
775  *
776  * This API will return the socket descriptor of the session for
777  * which URI handler was executed on reception of HTTP request.
778  * This is useful when user wants to call functions that require
779  * session socket fd, from within a URI handler, ie. :
780  *      httpd_sess_get_ctx(),
781  *      httpd_sess_trigger_close(),
782  *      httpd_sess_update_lru_counter().
783  *
784  * @note    This API is supposed to be called only from the context of
785  *          a URI handler where httpd_req_t* request pointer is valid.
786  *
787  * @param[in] r The request whose socket descriptor should be found
788  *
789  * @return
790  *  - Socket descriptor : The socket descriptor for this request
791  *  - -1 : Invalid/NULL request pointer
792  */
793 int httpd_req_to_sockfd(httpd_req_t *r);
794 
795 /**
796  * @brief   API to read content data from the HTTP request
797  *
798  * This API will read HTTP content data from the HTTP request into
799  * provided buffer. Use content_len provided in httpd_req_t structure
800  * to know the length of data to be fetched. If content_len is too
801  * large for the buffer then user may have to make multiple calls to
802  * this function, each time fetching 'buf_len' number of bytes,
803  * while the pointer to content data is incremented internally by
804  * the same number.
805  *
806  * @note
807  *  - This API is supposed to be called only from the context of
808  *    a URI handler where httpd_req_t* request pointer is valid.
809  *  - If an error is returned, the URI handler must further return an error.
810  *    This will ensure that the erroneous socket is closed and cleaned up by
811  *    the web server.
812  *  - Presently Chunked Encoding is not supported
813  *
814  * @param[in] r         The request being responded to
815  * @param[in] buf       Pointer to a buffer that the data will be read into
816  * @param[in] buf_len   Length of the buffer
817  *
818  * @return
819  *  - Bytes : Number of bytes read into the buffer successfully
820  *  - 0     : Buffer length parameter is zero / connection closed by peer
821  *  - HTTPD_SOCK_ERR_INVALID  : Invalid arguments
822  *  - HTTPD_SOCK_ERR_TIMEOUT  : Timeout/interrupted while calling socket recv()
823  *  - HTTPD_SOCK_ERR_FAIL     : Unrecoverable error while calling socket recv()
824  */
825 int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len);
826 
827 /**
828  * @brief   Search for a field in request headers and
829  *          return the string length of it's value
830  *
831  * @note
832  *  - This API is supposed to be called only from the context of
833  *    a URI handler where httpd_req_t* request pointer is valid.
834  *  - Once httpd_resp_send() API is called all request headers
835  *    are purged, so request headers need be copied into separate
836  *    buffers if they are required later.
837  *
838  * @param[in]  r        The request being responded to
839  * @param[in]  field    The header field to be searched in the request
840  *
841  * @return
842  *  - Length    : If field is found in the request URL
843  *  - Zero      : Field not found / Invalid request / Null arguments
844  */
845 size_t httpd_req_get_hdr_value_len(httpd_req_t *r, const char *field);
846 
847 /**
848  * @brief   Get the value string of a field from the request headers
849  *
850  * @note
851  *  - This API is supposed to be called only from the context of
852  *    a URI handler where httpd_req_t* request pointer is valid.
853  *  - Once httpd_resp_send() API is called all request headers
854  *    are purged, so request headers need be copied into separate
855  *    buffers if they are required later.
856  *  - If output size is greater than input, then the value is truncated,
857  *    accompanied by truncation error as return value.
858  *  - Use httpd_req_get_hdr_value_len() to know the right buffer length
859  *
860  * @param[in]  r        The request being responded to
861  * @param[in]  field    The field to be searched in the header
862  * @param[out] val      Pointer to the buffer into which the value will be copied if the field is found
863  * @param[in]  val_size Size of the user buffer "val"
864  *
865  * @return
866  *  - ESP_OK : Field found in the request header and value string copied
867  *  - ESP_ERR_NOT_FOUND          : Key not found
868  *  - ESP_ERR_INVALID_ARG        : Null arguments
869  *  - ESP_ERR_HTTPD_INVALID_REQ  : Invalid HTTP request pointer
870  *  - ESP_ERR_HTTPD_RESULT_TRUNC : Value string truncated
871  */
872 esp_err_t httpd_req_get_hdr_value_str(httpd_req_t *r, const char *field, char *val, size_t val_size);
873 
874 /**
875  * @brief   Get Query string length from the request URL
876  *
877  * @note    This API is supposed to be called only from the context of
878  *          a URI handler where httpd_req_t* request pointer is valid
879  *
880  * @param[in]  r    The request being responded to
881  *
882  * @return
883  *  - Length    : Query is found in the request URL
884  *  - Zero      : Query not found / Null arguments / Invalid request
885  */
886 size_t httpd_req_get_url_query_len(httpd_req_t *r);
887 
888 /**
889  * @brief   Get Query string from the request URL
890  *
891  * @note
892  *  - Presently, the user can fetch the full URL query string, but decoding
893  *    will have to be performed by the user. Request headers can be read using
894  *    httpd_req_get_hdr_value_str() to know the 'Content-Type' (eg. Content-Type:
895  *    application/x-www-form-urlencoded) and then the appropriate decoding
896  *    algorithm needs to be applied.
897  *  - This API is supposed to be called only from the context of
898  *    a URI handler where httpd_req_t* request pointer is valid
899  *  - If output size is greater than input, then the value is truncated,
900  *    accompanied by truncation error as return value
901  *  - Prior to calling this function, one can use httpd_req_get_url_query_len()
902  *    to know the query string length beforehand and hence allocate the buffer
903  *    of right size (usually query string length + 1 for null termination)
904  *    for storing the query string
905  *
906  * @param[in]  r         The request being responded to
907  * @param[out] buf       Pointer to the buffer into which the query string will be copied (if found)
908  * @param[in]  buf_len   Length of output buffer
909  *
910  * @return
911  *  - ESP_OK : Query is found in the request URL and copied to buffer
912  *  - ESP_ERR_NOT_FOUND          : Query not found
913  *  - ESP_ERR_INVALID_ARG        : Null arguments
914  *  - ESP_ERR_HTTPD_INVALID_REQ  : Invalid HTTP request pointer
915  *  - ESP_ERR_HTTPD_RESULT_TRUNC : Query string truncated
916  */
917 esp_err_t httpd_req_get_url_query_str(httpd_req_t *r, char *buf, size_t buf_len);
918 
919 /**
920  * @brief   Helper function to get a URL query tag from a query
921  *          string of the type param1=val1&param2=val2
922  *
923  * @note
924  *  - The components of URL query string (keys and values) are not URLdecoded.
925  *    The user must check for 'Content-Type' field in the request headers and
926  *    then depending upon the specified encoding (URLencoded or otherwise) apply
927  *    the appropriate decoding algorithm.
928  *  - If actual value size is greater than val_size, then the value is truncated,
929  *    accompanied by truncation error as return value.
930  *
931  * @param[in]  qry       Pointer to query string
932  * @param[in]  key       The key to be searched in the query string
933  * @param[out] val       Pointer to the buffer into which the value will be copied if the key is found
934  * @param[in]  val_size  Size of the user buffer "val"
935  *
936  * @return
937  *  - ESP_OK : Key is found in the URL query string and copied to buffer
938  *  - ESP_ERR_NOT_FOUND          : Key not found
939  *  - ESP_ERR_INVALID_ARG        : Null arguments
940  *  - ESP_ERR_HTTPD_RESULT_TRUNC : Value string truncated
941  */
942 esp_err_t httpd_query_key_value(const char *qry, const char *key, char *val, size_t val_size);
943 
944 /**
945  * @brief   Get the value string of a cookie value from the "Cookie" request headers by cookie name.
946  *
947  * @param[in]       req             Pointer to the HTTP request
948  * @param[in]       cookie_name     The cookie name to be searched in the request
949  * @param[out]      val             Pointer to the buffer into which the value of cookie will be copied if the cookie is found
950  * @param[inout]    val_size        Pointer to size of the user buffer "val". This variable will contain cookie length if
951  *                                  ESP_OK is returned and required buffer length incase ESP_ERR_HTTPD_RESULT_TRUNC is returned.
952  *
953  * @return
954  *  - ESP_OK : Key is found in the cookie string and copied to buffer
955  *  - ESP_ERR_NOT_FOUND          : Key not found
956  *  - ESP_ERR_INVALID_ARG        : Null arguments
957  *  - ESP_ERR_HTTPD_RESULT_TRUNC : Value string truncated
958  *  - ESP_ERR_NO_MEM             : Memory allocation failure
959  */
960 esp_err_t httpd_req_get_cookie_val(httpd_req_t *req, const char *cookie_name, char *val, size_t *val_size);
961 
962 /**
963  * @brief Test if a URI matches the given wildcard template.
964  *
965  * Template may end with "?" to make the previous character optional (typically a slash),
966  * "*" for a wildcard match, and "?*" to make the previous character optional, and if present,
967  * allow anything to follow.
968  *
969  * Example:
970  *   - * matches everything
971  *   - /foo/? matches /foo and /foo/
972  *   - /foo/\* (sans the backslash) matches /foo/ and /foo/bar, but not /foo or /fo
973  *   - /foo/?* or /foo/\*?  (sans the backslash) matches /foo/, /foo/bar, and also /foo, but not /foox or /fo
974  *
975  * The special characters "?" and "*" anywhere else in the template will be taken literally.
976  *
977  * @param[in] uri_template   URI template (pattern)
978  * @param[in] uri_to_match   URI to be matched
979  * @param[in] match_upto     how many characters of the URI buffer to test
980  *                          (there may be trailing query string etc.)
981  *
982  * @return true if a match was found
983  */
984 bool httpd_uri_match_wildcard(const char *uri_template, const char *uri_to_match, size_t match_upto);
985 
986 /**
987  * @brief   API to send a complete HTTP response.
988  *
989  * This API will send the data as an HTTP response to the request.
990  * This assumes that you have the entire response ready in a single
991  * buffer. If you wish to send response in incremental chunks use
992  * httpd_resp_send_chunk() instead.
993  *
994  * If no status code and content-type were set, by default this
995  * will send 200 OK status code and content type as text/html.
996  * You may call the following functions before this API to configure
997  * the response headers :
998  *      httpd_resp_set_status() - for setting the HTTP status string,
999  *      httpd_resp_set_type()   - for setting the Content Type,
1000  *      httpd_resp_set_hdr()    - for appending any additional field
1001  *                                value entries in the response header
1002  *
1003  * @note
1004  *  - This API is supposed to be called only from the context of
1005  *    a URI handler where httpd_req_t* request pointer is valid.
1006  *  - Once this API is called, the request has been responded to.
1007  *  - No additional data can then be sent for the request.
1008  *  - Once this API is called, all request headers are purged, so
1009  *    request headers need be copied into separate buffers if
1010  *    they are required later.
1011  *
1012  * @param[in] r         The request being responded to
1013  * @param[in] buf       Buffer from where the content is to be fetched
1014  * @param[in] buf_len   Length of the buffer, HTTPD_RESP_USE_STRLEN to use strlen()
1015  *
1016  * @return
1017  *  - ESP_OK : On successfully sending the response packet
1018  *  - ESP_ERR_INVALID_ARG : Null request pointer
1019  *  - ESP_ERR_HTTPD_RESP_HDR    : Essential headers are too large for internal buffer
1020  *  - ESP_ERR_HTTPD_RESP_SEND   : Error in raw send
1021  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
1022  */
1023 esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len);
1024 
1025 /**
1026  * @brief   API to send one HTTP chunk
1027  *
1028  * This API will send the data as an HTTP response to the
1029  * request. This API will use chunked-encoding and send the response
1030  * in the form of chunks. If you have the entire response contained in
1031  * a single buffer, please use httpd_resp_send() instead.
1032  *
1033  * If no status code and content-type were set, by default this will
1034  * send 200 OK status code and content type as text/html. You may
1035  * call the following functions before this API to configure the
1036  * response headers
1037  *      httpd_resp_set_status() - for setting the HTTP status string,
1038  *      httpd_resp_set_type()   - for setting the Content Type,
1039  *      httpd_resp_set_hdr()    - for appending any additional field
1040  *                                value entries in the response header
1041  *
1042  * @note
1043  * - This API is supposed to be called only from the context of
1044  *   a URI handler where httpd_req_t* request pointer is valid.
1045  * - When you are finished sending all your chunks, you must call
1046  *   this function with buf_len as 0.
1047  * - Once this API is called, all request headers are purged, so
1048  *   request headers need be copied into separate buffers if they
1049  *   are required later.
1050  *
1051  * @param[in] r         The request being responded to
1052  * @param[in] buf       Pointer to a buffer that stores the data
1053  * @param[in] buf_len   Length of the buffer, HTTPD_RESP_USE_STRLEN to use strlen()
1054  *
1055  * @return
1056  *  - ESP_OK : On successfully sending the response packet chunk
1057  *  - ESP_ERR_INVALID_ARG : Null request pointer
1058  *  - ESP_ERR_HTTPD_RESP_HDR    : Essential headers are too large for internal buffer
1059  *  - ESP_ERR_HTTPD_RESP_SEND   : Error in raw send
1060  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
1061  */
1062 esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len);
1063 
1064 /**
1065  * @brief   API to send a complete string as HTTP response.
1066  *
1067  * This API simply calls http_resp_send with buffer length
1068  * set to string length assuming the buffer contains a null
1069  * terminated string
1070  *
1071  * @param[in] r         The request being responded to
1072  * @param[in] str       String to be sent as response body
1073  *
1074  * @return
1075  *  - ESP_OK : On successfully sending the response packet
1076  *  - ESP_ERR_INVALID_ARG : Null request pointer
1077  *  - ESP_ERR_HTTPD_RESP_HDR    : Essential headers are too large for internal buffer
1078  *  - ESP_ERR_HTTPD_RESP_SEND   : Error in raw send
1079  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
1080  */
httpd_resp_sendstr(httpd_req_t * r,const char * str)1081 static inline esp_err_t httpd_resp_sendstr(httpd_req_t *r, const char *str) {
1082     return httpd_resp_send(r, str, (str == NULL) ? 0 : HTTPD_RESP_USE_STRLEN);
1083 }
1084 
1085 /**
1086  * @brief   API to send a string as an HTTP response chunk.
1087  *
1088  * This API simply calls http_resp_send_chunk with buffer length
1089  * set to string length assuming the buffer contains a null
1090  * terminated string
1091  *
1092  * @param[in] r    The request being responded to
1093  * @param[in] str  String to be sent as response body (NULL to finish response packet)
1094  *
1095  * @return
1096  *  - ESP_OK : On successfully sending the response packet
1097  *  - ESP_ERR_INVALID_ARG : Null request pointer
1098  *  - ESP_ERR_HTTPD_RESP_HDR    : Essential headers are too large for internal buffer
1099  *  - ESP_ERR_HTTPD_RESP_SEND   : Error in raw send
1100  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
1101  */
httpd_resp_sendstr_chunk(httpd_req_t * r,const char * str)1102 static inline esp_err_t httpd_resp_sendstr_chunk(httpd_req_t *r, const char *str) {
1103     return httpd_resp_send_chunk(r, str, (str == NULL) ? 0 : HTTPD_RESP_USE_STRLEN);
1104 }
1105 
1106 /* Some commonly used status codes */
1107 #define HTTPD_200      "200 OK"                     /*!< HTTP Response 200 */
1108 #define HTTPD_204      "204 No Content"             /*!< HTTP Response 204 */
1109 #define HTTPD_207      "207 Multi-Status"           /*!< HTTP Response 207 */
1110 #define HTTPD_400      "400 Bad Request"            /*!< HTTP Response 400 */
1111 #define HTTPD_404      "404 Not Found"              /*!< HTTP Response 404 */
1112 #define HTTPD_408      "408 Request Timeout"        /*!< HTTP Response 408 */
1113 #define HTTPD_500      "500 Internal Server Error"  /*!< HTTP Response 500 */
1114 
1115 /**
1116  * @brief   API to set the HTTP status code
1117  *
1118  * This API sets the status of the HTTP response to the value specified.
1119  * By default, the '200 OK' response is sent as the response.
1120  *
1121  * @note
1122  *  - This API is supposed to be called only from the context of
1123  *    a URI handler where httpd_req_t* request pointer is valid.
1124  *  - This API only sets the status to this value. The status isn't
1125  *    sent out until any of the send APIs is executed.
1126  *  - Make sure that the lifetime of the status string is valid till
1127  *    send function is called.
1128  *
1129  * @param[in] r         The request being responded to
1130  * @param[in] status    The HTTP status code of this response
1131  *
1132  * @return
1133  *  - ESP_OK : On success
1134  *  - ESP_ERR_INVALID_ARG : Null arguments
1135  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
1136  */
1137 esp_err_t httpd_resp_set_status(httpd_req_t *r, const char *status);
1138 
1139 /* Some commonly used content types */
1140 #define HTTPD_TYPE_JSON   "application/json"            /*!< HTTP Content type JSON */
1141 #define HTTPD_TYPE_TEXT   "text/html"                   /*!< HTTP Content type text/HTML */
1142 #define HTTPD_TYPE_OCTET  "application/octet-stream"    /*!< HTTP Content type octext-stream */
1143 
1144 /**
1145  * @brief   API to set the HTTP content type
1146  *
1147  * This API sets the 'Content Type' field of the response.
1148  * The default content type is 'text/html'.
1149  *
1150  * @note
1151  *  - This API is supposed to be called only from the context of
1152  *    a URI handler where httpd_req_t* request pointer is valid.
1153  *  - This API only sets the content type to this value. The type
1154  *    isn't sent out until any of the send APIs is executed.
1155  *  - Make sure that the lifetime of the type string is valid till
1156  *    send function is called.
1157  *
1158  * @param[in] r     The request being responded to
1159  * @param[in] type  The Content Type of the response
1160  *
1161  * @return
1162  *  - ESP_OK   : On success
1163  *  - ESP_ERR_INVALID_ARG : Null arguments
1164  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
1165  */
1166 esp_err_t httpd_resp_set_type(httpd_req_t *r, const char *type);
1167 
1168 /**
1169  * @brief   API to append any additional headers
1170  *
1171  * This API sets any additional header fields that need to be sent in the response.
1172  *
1173  * @note
1174  *  - This API is supposed to be called only from the context of
1175  *    a URI handler where httpd_req_t* request pointer is valid.
1176  *  - The header isn't sent out until any of the send APIs is executed.
1177  *  - The maximum allowed number of additional headers is limited to
1178  *    value of max_resp_headers in config structure.
1179  *  - Make sure that the lifetime of the field value strings are valid till
1180  *    send function is called.
1181  *
1182  * @param[in] r     The request being responded to
1183  * @param[in] field The field name of the HTTP header
1184  * @param[in] value The value of this HTTP header
1185  *
1186  * @return
1187  *  - ESP_OK : On successfully appending new header
1188  *  - ESP_ERR_INVALID_ARG : Null arguments
1189  *  - ESP_ERR_HTTPD_RESP_HDR    : Total additional headers exceed max allowed
1190  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
1191  */
1192 esp_err_t httpd_resp_set_hdr(httpd_req_t *r, const char *field, const char *value);
1193 
1194 /**
1195  * @brief   For sending out error code in response to HTTP request.
1196  *
1197  * @note
1198  *  - This API is supposed to be called only from the context of
1199  *    a URI handler where httpd_req_t* request pointer is valid.
1200  *  - Once this API is called, all request headers are purged, so
1201  *    request headers need be copied into separate buffers if
1202  *    they are required later.
1203  *  - If you wish to send additional data in the body of the
1204  *    response, please use the lower-level functions directly.
1205  *
1206  * @param[in] req     Pointer to the HTTP request for which the response needs to be sent
1207  * @param[in] error   Error type to send
1208  * @param[in] msg     Error message string (pass NULL for default message)
1209  *
1210  * @return
1211  *  - ESP_OK : On successfully sending the response packet
1212  *  - ESP_ERR_INVALID_ARG : Null arguments
1213  *  - ESP_ERR_HTTPD_RESP_SEND   : Error in raw send
1214  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
1215  */
1216 esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_code_t error, const char *msg);
1217 
1218 /**
1219  * @brief   Helper function for HTTP 404
1220  *
1221  * Send HTTP 404 message. If you wish to send additional data in the body of the
1222  * response, please use the lower-level functions directly.
1223  *
1224  * @note
1225  *  - This API is supposed to be called only from the context of
1226  *    a URI handler where httpd_req_t* request pointer is valid.
1227  *  - Once this API is called, all request headers are purged, so
1228  *    request headers need be copied into separate buffers if
1229  *    they are required later.
1230  *
1231  * @param[in] r The request being responded to
1232  *
1233  * @return
1234  *  - ESP_OK : On successfully sending the response packet
1235  *  - ESP_ERR_INVALID_ARG : Null arguments
1236  *  - ESP_ERR_HTTPD_RESP_SEND   : Error in raw send
1237  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
1238  */
httpd_resp_send_404(httpd_req_t * r)1239 static inline esp_err_t httpd_resp_send_404(httpd_req_t *r) {
1240     return httpd_resp_send_err(r, HTTPD_404_NOT_FOUND, NULL);
1241 }
1242 
1243 /**
1244  * @brief   Helper function for HTTP 408
1245  *
1246  * Send HTTP 408 message. If you wish to send additional data in the body of the
1247  * response, please use the lower-level functions directly.
1248  *
1249  * @note
1250  *  - This API is supposed to be called only from the context of
1251  *    a URI handler where httpd_req_t* request pointer is valid.
1252  *  - Once this API is called, all request headers are purged, so
1253  *    request headers need be copied into separate buffers if
1254  *    they are required later.
1255  *
1256  * @param[in] r The request being responded to
1257  *
1258  * @return
1259  *  - ESP_OK : On successfully sending the response packet
1260  *  - ESP_ERR_INVALID_ARG : Null arguments
1261  *  - ESP_ERR_HTTPD_RESP_SEND   : Error in raw send
1262  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
1263  */
httpd_resp_send_408(httpd_req_t * r)1264 static inline esp_err_t httpd_resp_send_408(httpd_req_t *r) {
1265     return httpd_resp_send_err(r, HTTPD_408_REQ_TIMEOUT, NULL);
1266 }
1267 
1268 /**
1269  * @brief   Helper function for HTTP 500
1270  *
1271  * Send HTTP 500 message. If you wish to send additional data in the body of the
1272  * response, please use the lower-level functions directly.
1273  *
1274  * @note
1275  *  - This API is supposed to be called only from the context of
1276  *    a URI handler where httpd_req_t* request pointer is valid.
1277  *  - Once this API is called, all request headers are purged, so
1278  *    request headers need be copied into separate buffers if
1279  *    they are required later.
1280  *
1281  * @param[in] r The request being responded to
1282  *
1283  * @return
1284  *  - ESP_OK : On successfully sending the response packet
1285  *  - ESP_ERR_INVALID_ARG : Null arguments
1286  *  - ESP_ERR_HTTPD_RESP_SEND   : Error in raw send
1287  *  - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
1288  */
httpd_resp_send_500(httpd_req_t * r)1289 static inline esp_err_t httpd_resp_send_500(httpd_req_t *r) {
1290     return httpd_resp_send_err(r, HTTPD_500_INTERNAL_SERVER_ERROR, NULL);
1291 }
1292 
1293 /**
1294  * @brief   Raw HTTP send
1295  *
1296  * Call this API if you wish to construct your custom response packet.
1297  * When using this, all essential header, eg. HTTP version, Status Code,
1298  * Content Type and Length, Encoding, etc. will have to be constructed
1299  * manually, and HTTP delimeters (CRLF) will need to be placed correctly
1300  * for separating sub-sections of the HTTP response packet.
1301  *
1302  * If the send override function is set, this API will end up
1303  * calling that function eventually to send data out.
1304  *
1305  * @note
1306  *  - This API is supposed to be called only from the context of
1307  *    a URI handler where httpd_req_t* request pointer is valid.
1308  *  - Unless the response has the correct HTTP structure (which the
1309  *    user must now ensure) it is not guaranteed that it will be
1310  *    recognized by the client. For most cases, you wouldn't have
1311  *    to call this API, but you would rather use either of :
1312  *          httpd_resp_send(),
1313  *          httpd_resp_send_chunk()
1314  *
1315  * @param[in] r         The request being responded to
1316  * @param[in] buf       Buffer from where the fully constructed packet is to be read
1317  * @param[in] buf_len   Length of the buffer
1318  *
1319  * @return
1320  *  - Bytes : Number of bytes that were sent successfully
1321  *  - HTTPD_SOCK_ERR_INVALID  : Invalid arguments
1322  *  - HTTPD_SOCK_ERR_TIMEOUT  : Timeout/interrupted while calling socket send()
1323  *  - HTTPD_SOCK_ERR_FAIL     : Unrecoverable error while calling socket send()
1324  */
1325 int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len);
1326 
1327 /**
1328  * A low level API to send data on a given socket
1329  *
1330  * @note This API is not recommended to be used in any request handler.
1331  * Use this only for advanced use cases, wherein some asynchronous
1332  * data is to be sent over a socket.
1333  *
1334  * This internally calls the default send function, or the function registered by
1335  * httpd_sess_set_send_override().
1336  *
1337  * @param[in] hd        server instance
1338  * @param[in] sockfd    session socket file descriptor
1339  * @param[in] buf       buffer with bytes to send
1340  * @param[in] buf_len   data size
1341  * @param[in] flags     flags for the send() function
1342  * @return
1343  *  - Bytes : The number of bytes sent successfully
1344  *  - HTTPD_SOCK_ERR_INVALID  : Invalid arguments
1345  *  - HTTPD_SOCK_ERR_TIMEOUT  : Timeout/interrupted while calling socket send()
1346  *  - HTTPD_SOCK_ERR_FAIL     : Unrecoverable error while calling socket send()
1347  */
1348 int httpd_socket_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags);
1349 
1350 /**
1351  * A low level API to receive data from a given socket
1352  *
1353  * @note This API is not recommended to be used in any request handler.
1354  * Use this only for advanced use cases, wherein some asynchronous
1355  * communication is required.
1356  *
1357  * This internally calls the default recv function, or the function registered by
1358  * httpd_sess_set_recv_override().
1359  *
1360  * @param[in] hd        server instance
1361  * @param[in] sockfd    session socket file descriptor
1362  * @param[in] buf       buffer with bytes to send
1363  * @param[in] buf_len   data size
1364  * @param[in] flags     flags for the send() function
1365  * @return
1366  *  - Bytes : The number of bytes received successfully
1367  *  - 0     : Buffer length parameter is zero / connection closed by peer
1368  *  - HTTPD_SOCK_ERR_INVALID  : Invalid arguments
1369  *  - HTTPD_SOCK_ERR_TIMEOUT  : Timeout/interrupted while calling socket recv()
1370  *  - HTTPD_SOCK_ERR_FAIL     : Unrecoverable error while calling socket recv()
1371  */
1372 int httpd_socket_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags);
1373 
1374 /** End of Request / Response
1375  * @}
1376  */
1377 
1378 /* ************** Group: Session ************** */
1379 /** @name Session
1380  * Functions for controlling sessions and accessing context data
1381  * @{
1382  */
1383 
1384 /**
1385  * @brief   Get session context from socket descriptor
1386  *
1387  * Typically if a session context is created, it is available to URI handlers
1388  * through the httpd_req_t structure. But, there are cases where the web
1389  * server's send/receive functions may require the context (for example, for
1390  * accessing keying information etc). Since the send/receive function only have
1391  * the socket descriptor at their disposal, this API provides them with a way to
1392  * retrieve the session context.
1393  *
1394  * @param[in] handle    Handle to server returned by httpd_start
1395  * @param[in] sockfd    The socket descriptor for which the context should be extracted.
1396  *
1397  * @return
1398  *  - void* : Pointer to the context associated with this session
1399  *  - NULL  : Empty context / Invalid handle / Invalid socket fd
1400  */
1401 void *httpd_sess_get_ctx(httpd_handle_t handle, int sockfd);
1402 
1403 /**
1404  * @brief   Set session context by socket descriptor
1405  *
1406  * @param[in] handle    Handle to server returned by httpd_start
1407  * @param[in] sockfd    The socket descriptor for which the context should be extracted.
1408  * @param[in] ctx       Context object to assign to the session
1409  * @param[in] free_fn   Function that should be called to free the context
1410  */
1411 void httpd_sess_set_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn);
1412 
1413 /**
1414  * @brief   Get session 'transport' context by socket descriptor
1415  * @see     httpd_sess_get_ctx()
1416  *
1417  * This context is used by the send/receive functions, for example to manage SSL context.
1418  *
1419  * @param[in] handle    Handle to server returned by httpd_start
1420  * @param[in] sockfd    The socket descriptor for which the context should be extracted.
1421  * @return
1422  *  - void* : Pointer to the transport context associated with this session
1423  *  - NULL  : Empty context / Invalid handle / Invalid socket fd
1424  */
1425 void *httpd_sess_get_transport_ctx(httpd_handle_t handle, int sockfd);
1426 
1427 /**
1428  * @brief   Set session 'transport' context by socket descriptor
1429  * @see     httpd_sess_set_ctx()
1430  *
1431  * @param[in] handle    Handle to server returned by httpd_start
1432  * @param[in] sockfd    The socket descriptor for which the context should be extracted.
1433  * @param[in] ctx       Transport context object to assign to the session
1434  * @param[in] free_fn   Function that should be called to free the transport context
1435  */
1436 void httpd_sess_set_transport_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn);
1437 
1438 /**
1439  * @brief   Get HTTPD global user context (it was set in the server config struct)
1440  *
1441  * @param[in] handle    Handle to server returned by httpd_start
1442  * @return global user context
1443  */
1444 void *httpd_get_global_user_ctx(httpd_handle_t handle);
1445 
1446 /**
1447  * @brief   Get HTTPD global transport context (it was set in the server config struct)
1448  *
1449  * @param[in] handle    Handle to server returned by httpd_start
1450  * @return global transport context
1451  */
1452 void *httpd_get_global_transport_ctx(httpd_handle_t handle);
1453 
1454 /**
1455  * @brief   Trigger an httpd session close externally
1456  *
1457  * @note    Calling this API is only required in special circumstances wherein
1458  *          some application requires to close an httpd client session asynchronously.
1459  *
1460  * @param[in] handle    Handle to server returned by httpd_start
1461  * @param[in] sockfd    The socket descriptor of the session to be closed
1462  *
1463  * @return
1464  *  - ESP_OK    : On successfully initiating closure
1465  *  - ESP_FAIL  : Failure to queue work
1466  *  - ESP_ERR_NOT_FOUND   : Socket fd not found
1467  *  - ESP_ERR_INVALID_ARG : Null arguments
1468  */
1469 esp_err_t httpd_sess_trigger_close(httpd_handle_t handle, int sockfd);
1470 
1471 /**
1472  * @brief   Update LRU counter for a given socket
1473  *
1474  * LRU Counters are internally associated with each session to monitor
1475  * how recently a session exchanged traffic. When LRU purge is enabled,
1476  * if a client is requesting for connection but maximum number of
1477  * sockets/sessions is reached, then the session having the earliest
1478  * LRU counter is closed automatically.
1479  *
1480  * Updating the LRU counter manually prevents the socket from being purged
1481  * due to the Least Recently Used (LRU) logic, even though it might not
1482  * have received traffic for some time. This is useful when all open
1483  * sockets/session are frequently exchanging traffic but the user specifically
1484  * wants one of the sessions to be kept open, irrespective of when it last
1485  * exchanged a packet.
1486  *
1487  * @note    Calling this API is only necessary if the LRU Purge Enable option
1488  *          is enabled.
1489  *
1490  * @param[in] handle    Handle to server returned by httpd_start
1491  * @param[in] sockfd    The socket descriptor of the session for which LRU counter
1492  *                      is to be updated
1493  *
1494  * @return
1495  *  - ESP_OK : Socket found and LRU counter updated
1496  *  - ESP_ERR_NOT_FOUND   : Socket not found
1497  *  - ESP_ERR_INVALID_ARG : Null arguments
1498  */
1499 esp_err_t httpd_sess_update_lru_counter(httpd_handle_t handle, int sockfd);
1500 
1501 /**
1502  * @brief   Returns list of current socket descriptors of active sessions
1503  *
1504  * @param[in] handle    Handle to server returned by httpd_start
1505  * @param[in,out] fds   In: Size of provided client_fds array
1506  *                      Out: Number of valid client fds returned in client_fds,
1507  * @param[out] client_fds  Array of client fds
1508  *
1509  * @note Size of provided array has to be equal or greater then maximum number of opened
1510  *       sockets, configured upon initialization with max_open_sockets field in
1511  *       httpd_config_t structure.
1512  *
1513  * @return
1514  *  - ESP_OK              : Successfully retrieved session list
1515  *  - ESP_ERR_INVALID_ARG : Wrong arguments or list is longer than provided array
1516  */
1517 esp_err_t httpd_get_client_list(httpd_handle_t handle, size_t *fds, int *client_fds);
1518 
1519 /** End of Session
1520  * @}
1521  */
1522 
1523 /* ************** Group: Work Queue ************** */
1524 /** @name Work Queue
1525  * APIs related to the HTTPD Work Queue
1526  * @{
1527  */
1528 
1529 /**
1530  * @brief   Prototype of the HTTPD work function
1531  *          Please refer to httpd_queue_work() for more details.
1532  * @param[in] arg   The arguments for this work function
1533  */
1534 typedef void (*httpd_work_fn_t)(void *arg);
1535 
1536 /**
1537  * @brief   Queue execution of a function in HTTPD's context
1538  *
1539  * This API queues a work function for asynchronous execution
1540  *
1541  * @note    Some protocols require that the web server generate some asynchronous data
1542  *          and send it to the persistently opened connection. This facility is for use
1543  *          by such protocols.
1544  *
1545  * @param[in] handle    Handle to server returned by httpd_start
1546  * @param[in] work      Pointer to the function to be executed in the HTTPD's context
1547  * @param[in] arg       Pointer to the arguments that should be passed to this function
1548  *
1549  * @return
1550  *  - ESP_OK   : On successfully queueing the work
1551  *  - ESP_FAIL : Failure in ctrl socket
1552  *  - ESP_ERR_INVALID_ARG : Null arguments
1553  */
1554 esp_err_t httpd_queue_work(httpd_handle_t handle, httpd_work_fn_t work, void *arg);
1555 
1556 /** End of Group Work Queue
1557  * @}
1558  */
1559 
1560 /* ************** Group: WebSocket ************** */
1561 /** @name WebSocket
1562  * Functions and structs for WebSocket server
1563  * @{
1564  */
1565 #ifdef CONFIG_HTTPD_WS_SUPPORT
1566 /**
1567  * @brief Enum for WebSocket packet types (Opcode in the header)
1568  * @note Please refer to RFC6455 Section 5.4 for more details
1569  */
1570 typedef enum {
1571     HTTPD_WS_TYPE_CONTINUE   = 0x0,
1572     HTTPD_WS_TYPE_TEXT       = 0x1,
1573     HTTPD_WS_TYPE_BINARY     = 0x2,
1574     HTTPD_WS_TYPE_CLOSE      = 0x8,
1575     HTTPD_WS_TYPE_PING       = 0x9,
1576     HTTPD_WS_TYPE_PONG       = 0xA
1577 } httpd_ws_type_t;
1578 
1579 /**
1580  * @brief Enum for client info description
1581  */
1582 typedef enum {
1583     HTTPD_WS_CLIENT_INVALID        = 0x0,
1584     HTTPD_WS_CLIENT_HTTP           = 0x1,
1585     HTTPD_WS_CLIENT_WEBSOCKET      = 0x2,
1586 } httpd_ws_client_info_t;
1587 
1588 /**
1589  * @brief WebSocket frame format
1590  */
1591 typedef struct httpd_ws_frame {
1592     bool final;                 /*!< Final frame:
1593                                      For received frames this field indicates whether the `FIN` flag was set.
1594                                      For frames to be transmitted, this field is only used if the `fragmented`
1595                                          option is set as well. If `fragmented` is false, the `FIN` flag is set
1596                                          by default, marking the ws_frame as a complete/unfragmented message
1597                                          (esp_http_server doesn't automatically fragment messages) */
1598     bool fragmented;            /*!< Indication that the frame allocated for transmission is a message fragment,
1599                                      so the `FIN` flag is set manually according to the `final` option.
1600                                      This flag is never set for received messages */
1601     httpd_ws_type_t type;       /*!< WebSocket frame type */
1602     uint8_t *payload;           /*!< Pre-allocated data buffer */
1603     size_t len;                 /*!< Length of the WebSocket data */
1604 } httpd_ws_frame_t;
1605 
1606 /**
1607  * @brief Transfer complete callback
1608  */
1609 typedef void (*transfer_complete_cb)(esp_err_t err, int socket, void *arg);
1610 
1611 /**
1612  * @brief Receive and parse a WebSocket frame
1613  *
1614  * @note    Calling httpd_ws_recv_frame() with max_len as 0 will give actual frame size in pkt->len.
1615  *          The user can dynamically allocate space for pkt->payload as per this length and call httpd_ws_recv_frame() again to get the actual data.
1616  *          Please refer to the corresponding example for usage.
1617  *
1618  * @param[in]   req         Current request
1619  * @param[out]  pkt         WebSocket packet
1620  * @param[in]   max_len     Maximum length for receive
1621  * @return
1622  *  - ESP_OK                    : On successful
1623  *  - ESP_FAIL                  : Socket errors occurs
1624  *  - ESP_ERR_INVALID_STATE     : Handshake was already done beforehand
1625  *  - ESP_ERR_INVALID_ARG       : Argument is invalid (null or non-WebSocket)
1626  */
1627 esp_err_t httpd_ws_recv_frame(httpd_req_t *req, httpd_ws_frame_t *pkt, size_t max_len);
1628 
1629 /**
1630  * @brief Construct and send a WebSocket frame
1631  * @param[in]   req     Current request
1632  * @param[in]   pkt     WebSocket frame
1633  * @return
1634  *  - ESP_OK                    : On successful
1635  *  - ESP_FAIL                  : When socket errors occurs
1636  *  - ESP_ERR_INVALID_STATE     : Handshake was already done beforehand
1637  *  - ESP_ERR_INVALID_ARG       : Argument is invalid (null or non-WebSocket)
1638  */
1639 esp_err_t httpd_ws_send_frame(httpd_req_t *req, httpd_ws_frame_t *pkt);
1640 
1641 /**
1642  * @brief Low level send of a WebSocket frame out of the scope of current request
1643  * using internally configured httpd send function
1644  *
1645  * This API should rarely be called directly, with an exception of asynchronous send using httpd_queue_work.
1646  *
1647  * @param[in] hd      Server instance data
1648  * @param[in] fd      Socket descriptor for sending data
1649  * @param[in] frame     WebSocket frame
1650  * @return
1651  *  - ESP_OK                    : On successful
1652  *  - ESP_FAIL                  : When socket errors occurs
1653  *  - ESP_ERR_INVALID_STATE     : Handshake was already done beforehand
1654  *  - ESP_ERR_INVALID_ARG       : Argument is invalid (null or non-WebSocket)
1655  */
1656 esp_err_t httpd_ws_send_frame_async(httpd_handle_t hd, int fd, httpd_ws_frame_t *frame);
1657 
1658 /**
1659  * @brief Checks the supplied socket descriptor if it belongs to any active client
1660  * of this server instance and if the websoket protocol is active
1661  *
1662  * @param[in] hd      Server instance data
1663  * @param[in] fd      Socket descriptor
1664  * @return
1665  *  - HTTPD_WS_CLIENT_INVALID   : This fd is not a client of this httpd
1666  *  - HTTPD_WS_CLIENT_HTTP      : This fd is an active client, protocol is not WS
1667  *  - HTTPD_WS_CLIENT_WEBSOCKET : This fd is an active client, protocol is WS
1668  */
1669 httpd_ws_client_info_t httpd_ws_get_fd_info(httpd_handle_t hd, int fd);
1670 
1671 /**
1672  * @brief Sends data to to specified websocket synchronously
1673  *
1674  * @param[in] handle  Server instance data
1675  * @param[in] socket  Socket descriptor
1676  * @param[in] frame   Websocket frame
1677  * @return
1678  *  - ESP_OK                    : On successful
1679  *  - ESP_FAIL                  : When socket errors occurs
1680  *  - ESP_ERR_NO_MEM            : Unable to allocate memory
1681  */
1682 esp_err_t httpd_ws_send_data(httpd_handle_t handle, int socket, httpd_ws_frame_t *frame);
1683 
1684 /**
1685  * @brief Sends data to to specified websocket asynchronously
1686  *
1687  * @param[in] handle    Server instance data
1688  * @param[in] socket    Socket descriptor
1689  * @param[in] frame     Websocket frame
1690  * @param[in] callback  Callback invoked after sending data
1691  * @param[in] arg       User data passed to provided callback
1692  * @return
1693  *  - ESP_OK                    : On successful
1694  *  - ESP_FAIL                  : When socket errors occurs
1695  *  - ESP_ERR_NO_MEM            : Unable to allocate memory
1696  */
1697 esp_err_t httpd_ws_send_data_async(httpd_handle_t handle, int socket, httpd_ws_frame_t *frame,
1698                                    transfer_complete_cb callback, void *arg);
1699 
1700 #endif /* CONFIG_HTTPD_WS_SUPPORT */
1701 /** End of WebSocket related stuff
1702  * @}
1703  */
1704 
1705 #ifdef __cplusplus
1706 }
1707 #endif
1708 
1709 #endif /* ! _ESP_HTTP_SERVER_H_ */
1710