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¶m2=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