mirror of
https://github.com/espressif/esp-idf
synced 2025-03-12 18:49:08 -04:00
Merge branch 'feature/http_server_backport_api_changes' into 'release/v3.2'
(backport v3.2) HTTP Server API changes See merge request idf/esp-idf!4232
This commit is contained in:
commit
37b7153c0e
@ -27,6 +27,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
note: esp_https_server.h includes a customized copy of this
|
||||||
|
initializer that should be kept in sync
|
||||||
|
*/
|
||||||
#define HTTPD_DEFAULT_CONFIG() { \
|
#define HTTPD_DEFAULT_CONFIG() { \
|
||||||
.task_priority = tskIDLE_PRIORITY+5, \
|
.task_priority = tskIDLE_PRIORITY+5, \
|
||||||
.stack_size = 4096, \
|
.stack_size = 4096, \
|
||||||
@ -39,7 +43,13 @@ extern "C" {
|
|||||||
.lru_purge_enable = false, \
|
.lru_purge_enable = false, \
|
||||||
.recv_wait_timeout = 5, \
|
.recv_wait_timeout = 5, \
|
||||||
.send_wait_timeout = 5, \
|
.send_wait_timeout = 5, \
|
||||||
};
|
.global_user_ctx = NULL, \
|
||||||
|
.global_user_ctx_free_fn = NULL, \
|
||||||
|
.global_transport_ctx = NULL, \
|
||||||
|
.global_transport_ctx_free_fn = NULL, \
|
||||||
|
.open_fn = NULL, \
|
||||||
|
.close_fn = NULL, \
|
||||||
|
}
|
||||||
|
|
||||||
#define ESP_ERR_HTTPD_BASE (0x8000) /*!< Starting number of HTTPD error codes */
|
#define ESP_ERR_HTTPD_BASE (0x8000) /*!< Starting number of HTTPD error codes */
|
||||||
#define ESP_ERR_HTTPD_HANDLERS_FULL (ESP_ERR_HTTPD_BASE + 1) /*!< All slots for registering URI handlers have been consumed */
|
#define ESP_ERR_HTTPD_HANDLERS_FULL (ESP_ERR_HTTPD_BASE + 1) /*!< All slots for registering URI handlers have been consumed */
|
||||||
@ -70,6 +80,35 @@ typedef void* httpd_handle_t;
|
|||||||
*/
|
*/
|
||||||
typedef enum http_method httpd_method_t;
|
typedef enum http_method httpd_method_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prototype for freeing context data (if any)
|
||||||
|
* @param[in] ctx : object to free
|
||||||
|
*/
|
||||||
|
typedef void (*httpd_free_ctx_fn_t)(void *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function prototype for opening a session.
|
||||||
|
*
|
||||||
|
* Called immediately after the socket was opened to set up the send/recv functions and
|
||||||
|
* other parameters of the socket.
|
||||||
|
*
|
||||||
|
* @param[in] hd : server instance
|
||||||
|
* @param[in] sockfd : session socket file descriptor
|
||||||
|
* @return status
|
||||||
|
*/
|
||||||
|
typedef esp_err_t (*httpd_open_func_t)(httpd_handle_t hd, int sockfd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function prototype for closing a session.
|
||||||
|
*
|
||||||
|
* @note It's possible that the socket descriptor is invalid at this point, the function
|
||||||
|
* is called for all terminated sessions. Ensure proper handling of return codes.
|
||||||
|
*
|
||||||
|
* @param[in] hd : server instance
|
||||||
|
* @param[in] sockfd : session socket file descriptor
|
||||||
|
*/
|
||||||
|
typedef void (*httpd_close_func_t)(httpd_handle_t hd, int sockfd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief HTTP Server Configuration Structure
|
* @brief HTTP Server Configuration Structure
|
||||||
*
|
*
|
||||||
@ -99,6 +138,63 @@ typedef struct httpd_config {
|
|||||||
bool lru_purge_enable; /*!< Purge "Least Recently Used" connection */
|
bool lru_purge_enable; /*!< Purge "Least Recently Used" connection */
|
||||||
uint16_t recv_wait_timeout; /*!< Timeout for recv function (in seconds)*/
|
uint16_t recv_wait_timeout; /*!< Timeout for recv function (in seconds)*/
|
||||||
uint16_t send_wait_timeout; /*!< Timeout for send function (in seconds)*/
|
uint16_t send_wait_timeout; /*!< Timeout for send function (in seconds)*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global user context.
|
||||||
|
*
|
||||||
|
* This field can be used to store arbitrary user data within the server context.
|
||||||
|
* The value can be retrieved using the server handle, available e.g. in the httpd_req_t struct.
|
||||||
|
*
|
||||||
|
* When shutting down, the server frees up the user context by
|
||||||
|
* calling free() on the global_user_ctx field. If you wish to use a custom
|
||||||
|
* function for freeing the global user context, please specify that here.
|
||||||
|
*/
|
||||||
|
void * global_user_ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free function for global user context
|
||||||
|
*/
|
||||||
|
httpd_free_ctx_fn_t global_user_ctx_free_fn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global transport context.
|
||||||
|
*
|
||||||
|
* Similar to global_user_ctx, but used for session encoding or encryption (e.g. to hold the SSL context).
|
||||||
|
* It will be freed using free(), unless global_transport_ctx_free_fn is specified.
|
||||||
|
*/
|
||||||
|
void * global_transport_ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free function for global transport context
|
||||||
|
*/
|
||||||
|
httpd_free_ctx_fn_t global_transport_ctx_free_fn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom session opening callback.
|
||||||
|
*
|
||||||
|
* Called on a new session socket just after accept(), but before reading any data.
|
||||||
|
*
|
||||||
|
* This is an opportunity to set up e.g. SSL encryption using global_transport_ctx
|
||||||
|
* and the send/recv/pending session overrides.
|
||||||
|
*
|
||||||
|
* If a context needs to be maintained between these functions, store it in the session using
|
||||||
|
* httpd_sess_set_transport_ctx() and retrieve it later with httpd_sess_get_transport_ctx()
|
||||||
|
*/
|
||||||
|
httpd_open_func_t open_fn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom session closing callback.
|
||||||
|
*
|
||||||
|
* Called when a session is deleted, before freeing user and transport contexts and before
|
||||||
|
* closing the socket. This is a place for custom de-init code common to all sockets.
|
||||||
|
*
|
||||||
|
* Set the user or transport context to NULL if it was freed here, so the server does not
|
||||||
|
* try to free it again.
|
||||||
|
*
|
||||||
|
* This function is run for all terminated sessions, including sessions where the socket
|
||||||
|
* was closed by the network stack - that is, the file descriptor may not be valid anymore.
|
||||||
|
*/
|
||||||
|
httpd_close_func_t close_fn;
|
||||||
} httpd_config_t;
|
} httpd_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,11 +276,6 @@ esp_err_t httpd_stop(httpd_handle_t handle);
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function type for freeing context data (if any)
|
|
||||||
*/
|
|
||||||
typedef void (*httpd_free_sess_ctx_fn_t)(void *sess_ctx);
|
|
||||||
|
|
||||||
/* Max supported HTTP request header length */
|
/* Max supported HTTP request header length */
|
||||||
#define HTTPD_MAX_REQ_HDR_LEN CONFIG_HTTPD_MAX_REQ_HDR_LEN
|
#define HTTPD_MAX_REQ_HDR_LEN CONFIG_HTTPD_MAX_REQ_HDR_LEN
|
||||||
|
|
||||||
@ -232,7 +323,7 @@ typedef struct httpd_req {
|
|||||||
* calling free() on the sess_ctx member. If you wish to use a custom
|
* calling free() on the sess_ctx member. If you wish to use a custom
|
||||||
* function for freeing the session context, please specify that here.
|
* function for freeing the session context, please specify that here.
|
||||||
*/
|
*/
|
||||||
httpd_free_sess_ctx_fn_t free_ctx;
|
httpd_free_ctx_fn_t free_ctx;
|
||||||
} httpd_req_t;
|
} httpd_req_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -360,13 +451,18 @@ esp_err_t httpd_unregister_uri(httpd_handle_t handle, const char* uri);
|
|||||||
* HTTPD_SOCK_ERR_ codes, which will eventually be conveyed as
|
* HTTPD_SOCK_ERR_ codes, which will eventually be conveyed as
|
||||||
* return value of httpd_send() function
|
* return value of httpd_send() function
|
||||||
*
|
*
|
||||||
|
* @param[in] hd : server instance
|
||||||
|
* @param[in] sockfd : session socket file descriptor
|
||||||
|
* @param[in] buf : buffer with bytes to send
|
||||||
|
* @param[in] buf_len : data size
|
||||||
|
* @param[in] flags : flags for the send() function
|
||||||
* @return
|
* @return
|
||||||
* - Bytes : The number of bytes sent successfully
|
* - Bytes : The number of bytes sent successfully
|
||||||
* - HTTPD_SOCK_ERR_INVALID : Invalid arguments
|
* - HTTPD_SOCK_ERR_INVALID : Invalid arguments
|
||||||
* - HTTPD_SOCK_ERR_TIMEOUT : Timeout/interrupted while calling socket send()
|
* - HTTPD_SOCK_ERR_TIMEOUT : Timeout/interrupted while calling socket send()
|
||||||
* - HTTPD_SOCK_ERR_FAIL : Unrecoverable error while calling socket send()
|
* - HTTPD_SOCK_ERR_FAIL : Unrecoverable error while calling socket send()
|
||||||
*/
|
*/
|
||||||
typedef int (*httpd_send_func_t)(int sockfd, const char *buf, size_t buf_len, int flags);
|
typedef int (*httpd_send_func_t)(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Prototype for HTTPDs low-level recv function
|
* @brief Prototype for HTTPDs low-level recv function
|
||||||
@ -376,6 +472,11 @@ typedef int (*httpd_send_func_t)(int sockfd, const char *buf, size_t buf_len, in
|
|||||||
* HTTPD_SOCK_ERR_ codes, which will eventually be conveyed as
|
* HTTPD_SOCK_ERR_ codes, which will eventually be conveyed as
|
||||||
* return value of httpd_req_recv() function
|
* return value of httpd_req_recv() function
|
||||||
*
|
*
|
||||||
|
* @param[in] hd : server instance
|
||||||
|
* @param[in] sockfd : session socket file descriptor
|
||||||
|
* @param[in] buf : buffer with bytes to send
|
||||||
|
* @param[in] buf_len : data size
|
||||||
|
* @param[in] flags : flags for the send() function
|
||||||
* @return
|
* @return
|
||||||
* - Bytes : The number of bytes received successfully
|
* - Bytes : The number of bytes received successfully
|
||||||
* - 0 : Buffer length parameter is zero / connection closed by peer
|
* - 0 : Buffer length parameter is zero / connection closed by peer
|
||||||
@ -383,7 +484,25 @@ typedef int (*httpd_send_func_t)(int sockfd, const char *buf, size_t buf_len, in
|
|||||||
* - HTTPD_SOCK_ERR_TIMEOUT : Timeout/interrupted while calling socket recv()
|
* - HTTPD_SOCK_ERR_TIMEOUT : Timeout/interrupted while calling socket recv()
|
||||||
* - HTTPD_SOCK_ERR_FAIL : Unrecoverable error while calling socket recv()
|
* - HTTPD_SOCK_ERR_FAIL : Unrecoverable error while calling socket recv()
|
||||||
*/
|
*/
|
||||||
typedef int (*httpd_recv_func_t)(int sockfd, char *buf, size_t buf_len, int flags);
|
typedef int (*httpd_recv_func_t)(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prototype for HTTPDs low-level "get pending bytes" function
|
||||||
|
*
|
||||||
|
* @note User specified pending function must handle errors internally,
|
||||||
|
* depending upon the set value of errno, and return specific
|
||||||
|
* HTTPD_SOCK_ERR_ codes, which will be handled accordingly in
|
||||||
|
* the server task.
|
||||||
|
*
|
||||||
|
* @param[in] hd : server instance
|
||||||
|
* @param[in] sockfd : session socket file descriptor
|
||||||
|
* @return
|
||||||
|
* - Bytes : The number of bytes waiting to be received
|
||||||
|
* - HTTPD_SOCK_ERR_INVALID : Invalid arguments
|
||||||
|
* - HTTPD_SOCK_ERR_TIMEOUT : Timeout/interrupted while calling socket pending()
|
||||||
|
* - HTTPD_SOCK_ERR_FAIL : Unrecoverable error while calling socket pending()
|
||||||
|
*/
|
||||||
|
typedef int (*httpd_pending_func_t)(httpd_handle_t hd, int sockfd);
|
||||||
|
|
||||||
/** End of TX / RX
|
/** End of TX / RX
|
||||||
* @}
|
* @}
|
||||||
@ -398,42 +517,64 @@ typedef int (*httpd_recv_func_t)(int sockfd, char *buf, size_t buf_len, int flag
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Override web server's receive function
|
* @brief Override web server's receive function (by session FD)
|
||||||
*
|
*
|
||||||
* This function overrides the web server's receive function. This same function is
|
* This function overrides the web server's receive function. This same function is
|
||||||
* used to read and parse HTTP headers as well as body.
|
* used to read HTTP request packets.
|
||||||
*
|
*
|
||||||
* @note This API is supposed to be called only from the context of
|
* @note This API is supposed to be called either from the context of
|
||||||
* a URI handler where httpd_req_t* request pointer is valid.
|
* - an http session APIs where sockfd is a valid parameter
|
||||||
|
* - a URI handler where sockfd is obtained using httpd_req_to_sockfd()
|
||||||
*
|
*
|
||||||
* @param[in] r The request being responded to
|
* @param[in] hd HTTPD instance handle
|
||||||
* @param[in] recv_func The receive function to be set for this request
|
* @param[in] sockfd Session socket FD
|
||||||
|
* @param[in] recv_func The receive function to be set for this session
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK : On successfully registering override
|
* - ESP_OK : On successfully registering override
|
||||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
|
||||||
*/
|
*/
|
||||||
esp_err_t httpd_set_recv_override(httpd_req_t *r, httpd_recv_func_t recv_func);
|
esp_err_t httpd_sess_set_recv_override(httpd_handle_t hd, int sockfd, httpd_recv_func_t recv_func);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Override web server's send function
|
* @brief Override web server's send function (by session FD)
|
||||||
*
|
*
|
||||||
* This function overrides the web server's send function. This same function is
|
* This function overrides the web server's send function. This same function is
|
||||||
* used to send out any response to any HTTP request.
|
* used to send out any response to any HTTP request.
|
||||||
*
|
*
|
||||||
* @note This API is supposed to be called only from the context of
|
* @note This API is supposed to be called either from the context of
|
||||||
* a URI handler where httpd_req_t* request pointer is valid.
|
* - an http session APIs where sockfd is a valid parameter
|
||||||
|
* - a URI handler where sockfd is obtained using httpd_req_to_sockfd()
|
||||||
*
|
*
|
||||||
* @param[in] r The request being responded to
|
* @param[in] hd HTTPD instance handle
|
||||||
* @param[in] send_func The send function to be set for this request
|
* @param[in] sockfd Session socket FD
|
||||||
|
* @param[in] send_func The send function to be set for this session
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK : On successfully registering override
|
* - ESP_OK : On successfully registering override
|
||||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
|
||||||
*/
|
*/
|
||||||
esp_err_t httpd_set_send_override(httpd_req_t *r, httpd_send_func_t send_func);
|
esp_err_t httpd_sess_set_send_override(httpd_handle_t hd, int sockfd, httpd_send_func_t send_func);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Override web server's pending function (by session FD)
|
||||||
|
*
|
||||||
|
* This function overrides the web server's pending function. This function is
|
||||||
|
* used to test for pending bytes in a socket.
|
||||||
|
*
|
||||||
|
* @note This API is supposed to be called either from the context of
|
||||||
|
* - an http session APIs where sockfd is a valid parameter
|
||||||
|
* - a URI handler where sockfd is obtained using httpd_req_to_sockfd()
|
||||||
|
*
|
||||||
|
* @param[in] hd HTTPD instance handle
|
||||||
|
* @param[in] sockfd Session socket FD
|
||||||
|
* @param[in] pending_func The receive function to be set for this session
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : On successfully registering override
|
||||||
|
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||||
|
*/
|
||||||
|
esp_err_t httpd_sess_set_pending_override(httpd_handle_t hd, int sockfd, httpd_pending_func_t pending_func);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the Socket Descriptor from the HTTP request
|
* @brief Get the Socket Descriptor from the HTTP request
|
||||||
@ -443,7 +584,7 @@ esp_err_t httpd_set_send_override(httpd_req_t *r, httpd_send_func_t send_func);
|
|||||||
* This is useful when user wants to call functions that require
|
* This is useful when user wants to call functions that require
|
||||||
* session socket fd, from within a URI handler, ie. :
|
* session socket fd, from within a URI handler, ie. :
|
||||||
* httpd_sess_get_ctx(),
|
* httpd_sess_get_ctx(),
|
||||||
* httpd_trigger_sess_close(),
|
* httpd_sess_trigger_close(),
|
||||||
* httpd_sess_update_timestamp().
|
* httpd_sess_update_timestamp().
|
||||||
*
|
*
|
||||||
* @note This API is supposed to be called only from the context of
|
* @note This API is supposed to be called only from the context of
|
||||||
@ -631,7 +772,7 @@ esp_err_t httpd_query_key_value(const char *qry, const char *key, char *val, siz
|
|||||||
*
|
*
|
||||||
* @param[in] r The request being responded to
|
* @param[in] r The request being responded to
|
||||||
* @param[in] buf Buffer from where the content is to be fetched
|
* @param[in] buf Buffer from where the content is to be fetched
|
||||||
* @param[in] buf_len Length of the buffer
|
* @param[in] buf_len Length of the buffer, -1 to use strlen()
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK : On successfully sending the response packet
|
* - ESP_OK : On successfully sending the response packet
|
||||||
@ -640,7 +781,7 @@ esp_err_t httpd_query_key_value(const char *qry, const char *key, char *val, siz
|
|||||||
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
||||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
|
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
|
||||||
*/
|
*/
|
||||||
esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len);
|
esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief API to send one HTTP chunk
|
* @brief API to send one HTTP chunk
|
||||||
@ -670,7 +811,7 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len);
|
|||||||
*
|
*
|
||||||
* @param[in] r The request being responded to
|
* @param[in] r The request being responded to
|
||||||
* @param[in] buf Pointer to a buffer that stores the data
|
* @param[in] buf Pointer to a buffer that stores the data
|
||||||
* @param[in] buf_len Length of the data from the buffer that should be sent out
|
* @param[in] buf_len Length of the data from the buffer that should be sent out, -1 to use strlen()
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK : On successfully sending the response packet chunk
|
* - ESP_OK : On successfully sending the response packet chunk
|
||||||
@ -679,7 +820,7 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len);
|
|||||||
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
||||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
||||||
*/
|
*/
|
||||||
esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, size_t buf_len);
|
esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len);
|
||||||
|
|
||||||
/* Some commonly used status codes */
|
/* Some commonly used status codes */
|
||||||
#define HTTPD_200 "200 OK" /*!< HTTP Response 200 */
|
#define HTTPD_200 "200 OK" /*!< HTTP Response 200 */
|
||||||
@ -901,6 +1042,57 @@ int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len);
|
|||||||
*/
|
*/
|
||||||
void *httpd_sess_get_ctx(httpd_handle_t handle, int sockfd);
|
void *httpd_sess_get_ctx(httpd_handle_t handle, int sockfd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set session context by socket descriptor
|
||||||
|
*
|
||||||
|
* @param[in] handle Handle to server returned by httpd_start
|
||||||
|
* @param[in] sockfd The socket descriptor for which the context should be extracted.
|
||||||
|
* @param[in] ctx Context object to assign to the session
|
||||||
|
* @param[in] free_fn Function that should be called to free the context
|
||||||
|
*/
|
||||||
|
void httpd_sess_set_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get session 'transport' context by socket descriptor
|
||||||
|
* @see httpd_sess_get_ctx()
|
||||||
|
*
|
||||||
|
* This context is used by the send/receive functions, for example to manage SSL context.
|
||||||
|
*
|
||||||
|
* @param[in] handle Handle to server returned by httpd_start
|
||||||
|
* @param[in] sockfd The socket descriptor for which the context should be extracted.
|
||||||
|
* @return
|
||||||
|
* - void* : Pointer to the transport context associated with this session
|
||||||
|
* - NULL : Empty context / Invalid handle / Invalid socket fd
|
||||||
|
*/
|
||||||
|
void *httpd_sess_get_transport_ctx(httpd_handle_t handle, int sockfd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set session 'transport' context by socket descriptor
|
||||||
|
* @see httpd_sess_set_ctx()
|
||||||
|
*
|
||||||
|
* @param[in] handle Handle to server returned by httpd_start
|
||||||
|
* @param[in] sockfd The socket descriptor for which the context should be extracted.
|
||||||
|
* @param[in] ctx Transport context object to assign to the session
|
||||||
|
* @param[in] free_fn Function that should be called to free the transport context
|
||||||
|
*/
|
||||||
|
void httpd_sess_set_transport_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get HTTPD global user context (it was set in the server config struct)
|
||||||
|
*
|
||||||
|
* @param[in] handle Handle to server returned by httpd_start
|
||||||
|
* @return global user context
|
||||||
|
*/
|
||||||
|
void *httpd_get_global_user_ctx(httpd_handle_t handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get HTTPD global transport context (it was set in the server config struct)
|
||||||
|
*
|
||||||
|
* @param[in] handle Handle to server returned by httpd_start
|
||||||
|
* @return global transport context
|
||||||
|
*/
|
||||||
|
void *httpd_get_global_transport_ctx(httpd_handle_t handle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Trigger an httpd session close externally
|
* @brief Trigger an httpd session close externally
|
||||||
*
|
*
|
||||||
@ -916,7 +1108,7 @@ void *httpd_sess_get_ctx(httpd_handle_t handle, int sockfd);
|
|||||||
* - ESP_ERR_NOT_FOUND : Socket fd not found
|
* - ESP_ERR_NOT_FOUND : Socket fd not found
|
||||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||||
*/
|
*/
|
||||||
esp_err_t httpd_trigger_sess_close(httpd_handle_t handle, int sockfd);
|
esp_err_t httpd_sess_trigger_close(httpd_handle_t handle, int sockfd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update timestamp for a given socket
|
* @brief Update timestamp for a given socket
|
||||||
|
@ -118,10 +118,13 @@ typedef enum {
|
|||||||
struct sock_db {
|
struct sock_db {
|
||||||
int fd; /*!< The file descriptor for this socket */
|
int fd; /*!< The file descriptor for this socket */
|
||||||
void *ctx; /*!< A custom context for this socket */
|
void *ctx; /*!< A custom context for this socket */
|
||||||
|
void *transport_ctx; /*!< A custom 'transport' context for this socket, to be used by send/recv/pending */
|
||||||
httpd_handle_t handle; /*!< Server handle */
|
httpd_handle_t handle; /*!< Server handle */
|
||||||
httpd_free_sess_ctx_fn_t free_ctx; /*!< Function for freeing the context */
|
httpd_free_ctx_fn_t free_ctx; /*!< Function for freeing the context */
|
||||||
|
httpd_free_ctx_fn_t free_transport_ctx; /*!< Function for freeing the 'transport' context */
|
||||||
httpd_send_func_t send_fn; /*!< Send function for this socket */
|
httpd_send_func_t send_fn; /*!< Send function for this socket */
|
||||||
httpd_recv_func_t recv_fn; /*!< Send function for this socket */
|
httpd_recv_func_t recv_fn; /*!< Receive function for this socket */
|
||||||
|
httpd_pending_func_t pending_fn; /*!< Pending function for this socket */
|
||||||
int64_t timestamp; /*!< Timestamp indicating when the socket was last used */
|
int64_t timestamp; /*!< Timestamp indicating when the socket was last used */
|
||||||
char pending_data[PARSER_BLOCK_SIZE]; /*!< Buffer for pending data to be received */
|
char pending_data[PARSER_BLOCK_SIZE]; /*!< Buffer for pending data to be received */
|
||||||
size_t pending_len; /*!< Length of pending data to be received */
|
size_t pending_len; /*!< Length of pending data to be received */
|
||||||
@ -169,6 +172,23 @@ struct httpd_data {
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieve a session by its descriptor
|
||||||
|
*
|
||||||
|
* @param[in] hd Server instance data
|
||||||
|
* @param[in] sockfd Socket FD
|
||||||
|
* @return pointer into the socket DB, or NULL if not found
|
||||||
|
*/
|
||||||
|
struct sock_db *httpd_sess_get(struct httpd_data *hd, int sockfd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete sessions whose FDs have became invalid.
|
||||||
|
* This is a recovery strategy e.g. after select() fails.
|
||||||
|
*
|
||||||
|
* @param[in] hd Server instance data
|
||||||
|
*/
|
||||||
|
void httpd_sess_delete_invalid(struct httpd_data *hd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes an http session by resetting the sockets database.
|
* @brief Initializes an http session by resetting the sockets database.
|
||||||
*
|
*
|
||||||
@ -220,6 +240,14 @@ esp_err_t httpd_sess_process(struct httpd_data *hd, int clifd);
|
|||||||
*/
|
*/
|
||||||
int httpd_sess_delete(struct httpd_data *hd, int clifd);
|
int httpd_sess_delete(struct httpd_data *hd, int clifd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free session context
|
||||||
|
*
|
||||||
|
* @param[in] ctx Pointer to session context
|
||||||
|
* @param[in] free_fn Free function to call on session context
|
||||||
|
*/
|
||||||
|
void httpd_sess_free_ctx(void *ctx, httpd_free_ctx_fn_t free_fn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add descriptors present in the socket database to an fd_set and
|
* @brief Add descriptors present in the socket database to an fd_set and
|
||||||
* update the value of maxfd which are needed by the select function
|
* update the value of maxfd which are needed by the select function
|
||||||
@ -331,7 +359,16 @@ void httpd_unregister_all_uri_handlers(struct httpd_data *hd);
|
|||||||
* - true : if valid request
|
* - true : if valid request
|
||||||
* - false : otherwise
|
* - false : otherwise
|
||||||
*/
|
*/
|
||||||
bool httpd_valid_req(httpd_req_t *r);
|
bool httpd_validate_req_ptr(httpd_req_t *r);
|
||||||
|
|
||||||
|
/* httpd_validate_req_ptr() adds some overhead to frequently used APIs,
|
||||||
|
* and is useful mostly for debugging, so it's preferable to disable
|
||||||
|
* the check by defaut and enable it only if necessary */
|
||||||
|
#ifdef CONFIG_HTTPD_VALIDATE_REQ
|
||||||
|
#define httpd_valid_req(r) httpd_validate_req_ptr(r)
|
||||||
|
#else
|
||||||
|
#define httpd_valid_req(r) true
|
||||||
|
#endif
|
||||||
|
|
||||||
/** End of Group : URI Handling
|
/** End of Group : URI Handling
|
||||||
* @}
|
* @}
|
||||||
@ -454,6 +491,7 @@ size_t httpd_unrecv(struct httpd_req *r, const char *buf, size_t buf_len);
|
|||||||
* NEVER be called directly. The semantics of this is exactly similar to
|
* NEVER be called directly. The semantics of this is exactly similar to
|
||||||
* send() of the BSD socket API.
|
* send() of the BSD socket API.
|
||||||
*
|
*
|
||||||
|
* @param[in] hd Server instance data
|
||||||
* @param[in] sockfd Socket descriptor for sending data
|
* @param[in] sockfd Socket descriptor for sending data
|
||||||
* @param[in] buf Pointer to the buffer from where the body of the response is taken
|
* @param[in] buf Pointer to the buffer from where the body of the response is taken
|
||||||
* @param[in] buf_len Length of the buffer
|
* @param[in] buf_len Length of the buffer
|
||||||
@ -463,13 +501,14 @@ size_t httpd_unrecv(struct httpd_req *r, const char *buf, size_t buf_len);
|
|||||||
* - Length of data : if successful
|
* - Length of data : if successful
|
||||||
* - -1 : if failed (appropriate errno is set)
|
* - -1 : if failed (appropriate errno is set)
|
||||||
*/
|
*/
|
||||||
int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags);
|
int httpd_default_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the low level default recv function of the HTTPD. This should
|
* @brief This is the low level default recv function of the HTTPD. This should
|
||||||
* NEVER be called directly. The semantics of this is exactly similar to
|
* NEVER be called directly. The semantics of this is exactly similar to
|
||||||
* recv() of the BSD socket API.
|
* recv() of the BSD socket API.
|
||||||
*
|
*
|
||||||
|
* @param[in] hd Server instance data
|
||||||
* @param[in] sockfd Socket descriptor for sending data
|
* @param[in] sockfd Socket descriptor for sending data
|
||||||
* @param[out] buf Pointer to the buffer which will be filled with the received data
|
* @param[out] buf Pointer to the buffer which will be filled with the received data
|
||||||
* @param[in] buf_len Length of the buffer
|
* @param[in] buf_len Length of the buffer
|
||||||
@ -479,7 +518,7 @@ int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags);
|
|||||||
* - Length of data : if successful
|
* - Length of data : if successful
|
||||||
* - -1 : if failed (appropriate errno is set)
|
* - -1 : if failed (appropriate errno is set)
|
||||||
*/
|
*/
|
||||||
int httpd_default_recv(int sockfd, char *buf, size_t buf_len, int flags);
|
int httpd_default_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags);
|
||||||
|
|
||||||
/** End of Group : Send and Receive
|
/** End of Group : Send and Receive
|
||||||
* @}
|
* @}
|
||||||
|
@ -62,8 +62,8 @@ static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd)
|
|||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv));
|
setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv));
|
||||||
|
|
||||||
if (httpd_sess_new(hd, new_fd)) {
|
if (ESP_OK != httpd_sess_new(hd, new_fd)) {
|
||||||
ESP_LOGW(TAG, LOG_FMT("no slots left for launching new session"));
|
ESP_LOGW(TAG, LOG_FMT("session creation failed"));
|
||||||
close(new_fd);
|
close(new_fd);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@ -102,6 +102,16 @@ esp_err_t httpd_queue_work(httpd_handle_t handle, httpd_work_fn_t work, void *ar
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *httpd_get_global_user_ctx(httpd_handle_t handle)
|
||||||
|
{
|
||||||
|
return ((struct httpd_data *)handle)->config.global_user_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *httpd_get_global_transport_ctx(httpd_handle_t handle)
|
||||||
|
{
|
||||||
|
return ((struct httpd_data *)handle)->config.global_transport_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
static void httpd_close_all_sessions(struct httpd_data *hd)
|
static void httpd_close_all_sessions(struct httpd_data *hd)
|
||||||
{
|
{
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
@ -159,11 +169,8 @@ static esp_err_t httpd_server(struct httpd_data *hd)
|
|||||||
int active_cnt = select(maxfd + 1, &read_set, NULL, NULL, NULL);
|
int active_cnt = select(maxfd + 1, &read_set, NULL, NULL, NULL);
|
||||||
if (active_cnt < 0) {
|
if (active_cnt < 0) {
|
||||||
ESP_LOGE(TAG, LOG_FMT("error in select (%d)"), errno);
|
ESP_LOGE(TAG, LOG_FMT("error in select (%d)"), errno);
|
||||||
/* Assert, as it's not possible to recover from this point onwards,
|
httpd_sess_delete_invalid(hd);
|
||||||
* and there is no way to notify the main thread that server handle
|
return ESP_OK;
|
||||||
* has become invalid */
|
|
||||||
assert(false);
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Case0: Do we have a control message? */
|
/* Case0: Do we have a control message? */
|
||||||
@ -367,7 +374,27 @@ esp_err_t httpd_stop(httpd_handle_t handle)
|
|||||||
|
|
||||||
ESP_LOGD(TAG, LOG_FMT("sent control msg to stop server"));
|
ESP_LOGD(TAG, LOG_FMT("sent control msg to stop server"));
|
||||||
while (hd->hd_td.status != THREAD_STOPPED) {
|
while (hd->hd_td.status != THREAD_STOPPED) {
|
||||||
httpd_os_thread_sleep(1000);
|
httpd_os_thread_sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release global user context, if not NULL */
|
||||||
|
if (hd->config.global_user_ctx) {
|
||||||
|
if (hd->config.global_user_ctx_free_fn) {
|
||||||
|
hd->config.global_user_ctx_free_fn(hd->config.global_user_ctx);
|
||||||
|
} else {
|
||||||
|
free(hd->config.global_user_ctx);
|
||||||
|
}
|
||||||
|
hd->config.global_user_ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release global transport context, if not NULL */
|
||||||
|
if (hd->config.global_transport_ctx) {
|
||||||
|
if (hd->config.global_transport_ctx_free_fn) {
|
||||||
|
hd->config.global_transport_ctx_free_fn(hd->config.global_transport_ctx);
|
||||||
|
} else {
|
||||||
|
free(hd->config.global_transport_ctx);
|
||||||
|
}
|
||||||
|
hd->config.global_transport_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, LOG_FMT("server stopped"));
|
ESP_LOGD(TAG, LOG_FMT("server stopped"));
|
||||||
|
@ -552,6 +552,24 @@ static void init_req_aux(struct httpd_req_aux *ra, httpd_config_t *config)
|
|||||||
memset(ra->resp_hdrs, 0, config->max_resp_headers * sizeof(struct resp_hdr));
|
memset(ra->resp_hdrs, 0, config->max_resp_headers * sizeof(struct resp_hdr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void httpd_req_cleanup(httpd_req_t *r)
|
||||||
|
{
|
||||||
|
struct httpd_req_aux *ra = r->aux;
|
||||||
|
|
||||||
|
/* Retrieve session info from the request into the socket database */
|
||||||
|
if (ra->sd->ctx != r->sess_ctx) {
|
||||||
|
/* Free previous context */
|
||||||
|
httpd_sess_free_ctx(ra->sd->ctx, ra->sd->free_ctx);
|
||||||
|
ra->sd->ctx = r->sess_ctx;
|
||||||
|
}
|
||||||
|
ra->sd->free_ctx = r->free_ctx;
|
||||||
|
|
||||||
|
/* Clear out the request and request_aux structures */
|
||||||
|
ra->sd = NULL;
|
||||||
|
r->handle = NULL;
|
||||||
|
r->aux = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Function that processes incoming TCP data and
|
/* Function that processes incoming TCP data and
|
||||||
* updates the http request data httpd_req_t
|
* updates the http request data httpd_req_t
|
||||||
*/
|
*/
|
||||||
@ -563,7 +581,7 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
|
|||||||
r->handle = hd;
|
r->handle = hd;
|
||||||
r->aux = &hd->hd_req_aux;
|
r->aux = &hd->hd_req_aux;
|
||||||
/* Associate the request to the socket */
|
/* Associate the request to the socket */
|
||||||
struct httpd_req_aux *ra = r->aux;
|
struct httpd_req_aux *ra = r->aux;
|
||||||
ra->sd = sd;
|
ra->sd = sd;
|
||||||
/* Set defaults */
|
/* Set defaults */
|
||||||
ra->status = (char *)HTTPD_200;
|
ra->status = (char *)HTTPD_200;
|
||||||
@ -573,7 +591,11 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
|
|||||||
r->sess_ctx = sd->ctx;
|
r->sess_ctx = sd->ctx;
|
||||||
r->free_ctx = sd->free_ctx;
|
r->free_ctx = sd->free_ctx;
|
||||||
/* Parse request */
|
/* Parse request */
|
||||||
return httpd_parse_req(hd);
|
esp_err_t err = httpd_parse_req(hd);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
httpd_req_cleanup(r);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function that resets the http request data
|
/* Function that resets the http request data
|
||||||
@ -592,6 +614,7 @@ esp_err_t httpd_req_delete(struct httpd_data *hd)
|
|||||||
int recv_len = MIN(sizeof(dummy) - 1, ra->remaining_len);
|
int recv_len = MIN(sizeof(dummy) - 1, ra->remaining_len);
|
||||||
int ret = httpd_req_recv(r, dummy, recv_len);
|
int ret = httpd_req_recv(r, dummy, recv_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
httpd_req_cleanup(r);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,20 +622,14 @@ esp_err_t httpd_req_delete(struct httpd_data *hd)
|
|||||||
ESP_LOGD(TAG, LOG_FMT("purging data : %s"), dummy);
|
ESP_LOGD(TAG, LOG_FMT("purging data : %s"), dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve session info from the request into the socket database */
|
httpd_req_cleanup(r);
|
||||||
ra->sd->ctx = r->sess_ctx;
|
|
||||||
ra->sd->free_ctx = r->free_ctx;
|
|
||||||
|
|
||||||
/* Clear out the request and request_aux structures */
|
|
||||||
ra->sd = NULL;
|
|
||||||
r->aux = NULL;
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Validates the request to prevent users from calling APIs, that are to
|
/* Validates the request to prevent users from calling APIs, that are to
|
||||||
* be called only inside URI handler, outside the handler context
|
* be called only inside URI handler, outside the handler context
|
||||||
*/
|
*/
|
||||||
bool httpd_valid_req(httpd_req_t *r)
|
bool httpd_validate_req_ptr(httpd_req_t *r)
|
||||||
{
|
{
|
||||||
if (r) {
|
if (r) {
|
||||||
struct httpd_data *hd = (struct httpd_data *) r->handle;
|
struct httpd_data *hd = (struct httpd_data *) r->handle;
|
||||||
|
@ -33,11 +33,23 @@ bool httpd_is_sess_available(struct httpd_data *hd)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sock_db *httpd_sess_get(struct httpd_data *hd, int newfd)
|
struct sock_db *httpd_sess_get(struct httpd_data *hd, int sockfd)
|
||||||
{
|
{
|
||||||
|
if (hd == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if called inside a request handler, and the
|
||||||
|
* session sockfd in use is same as the parameter */
|
||||||
|
if ((hd->hd_req_aux.sd) && (hd->hd_req_aux.sd->fd == sockfd)) {
|
||||||
|
/* Just return the pointer to the sock_db
|
||||||
|
* corresponding to the request */
|
||||||
|
return hd->hd_req_aux.sd;
|
||||||
|
}
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < hd->config.max_open_sockets; i++) {
|
for (i = 0; i < hd->config.max_open_sockets; i++) {
|
||||||
if (hd->hd_sd[i].fd == newfd) {
|
if (hd->hd_sd[i].fd == sockfd) {
|
||||||
return &hd->hd_sd[i];
|
return &hd->hd_sd[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,6 +73,12 @@ esp_err_t httpd_sess_new(struct httpd_data *hd, int newfd)
|
|||||||
hd->hd_sd[i].handle = (httpd_handle_t) hd;
|
hd->hd_sd[i].handle = (httpd_handle_t) hd;
|
||||||
hd->hd_sd[i].send_fn = httpd_default_send;
|
hd->hd_sd[i].send_fn = httpd_default_send;
|
||||||
hd->hd_sd[i].recv_fn = httpd_default_recv;
|
hd->hd_sd[i].recv_fn = httpd_default_recv;
|
||||||
|
|
||||||
|
/* Call user-defined session opening function */
|
||||||
|
if (hd->config.open_fn) {
|
||||||
|
esp_err_t ret = hd->config.open_fn(hd, hd->hd_sd[i].fd);
|
||||||
|
if (ret != ESP_OK) return ret;
|
||||||
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,21 +86,94 @@ esp_err_t httpd_sess_new(struct httpd_data *hd, int newfd)
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void httpd_sess_free_ctx(void *ctx, httpd_free_ctx_fn_t free_fn)
|
||||||
|
{
|
||||||
|
if (ctx) {
|
||||||
|
if (free_fn) {
|
||||||
|
free_fn(ctx);
|
||||||
|
} else {
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void *httpd_sess_get_ctx(httpd_handle_t handle, int sockfd)
|
void *httpd_sess_get_ctx(httpd_handle_t handle, int sockfd)
|
||||||
{
|
{
|
||||||
if (handle == NULL) {
|
struct sock_db *sd = httpd_sess_get(handle, sockfd);
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct httpd_data *hd = (struct httpd_data *) handle;
|
|
||||||
struct sock_db *sd = httpd_sess_get(hd, sockfd);
|
|
||||||
if (sd == NULL) {
|
if (sd == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if the function has been called from inside a
|
||||||
|
* request handler, in which case fetch the context from
|
||||||
|
* the httpd_req_t structure */
|
||||||
|
struct httpd_data *hd = (struct httpd_data *) handle;
|
||||||
|
if (hd->hd_req_aux.sd == sd) {
|
||||||
|
return hd->hd_req.sess_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
return sd->ctx;
|
return sd->ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void httpd_sess_set_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn)
|
||||||
|
{
|
||||||
|
struct sock_db *sd = httpd_sess_get(handle, sockfd);
|
||||||
|
if (sd == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the function has been called from inside a
|
||||||
|
* request handler, in which case set the context inside
|
||||||
|
* the httpd_req_t structure */
|
||||||
|
struct httpd_data *hd = (struct httpd_data *) handle;
|
||||||
|
if (hd->hd_req_aux.sd == sd) {
|
||||||
|
if (hd->hd_req.sess_ctx != ctx) {
|
||||||
|
/* Don't free previous context if it is in sockdb
|
||||||
|
* as it will be freed inside httpd_req_cleanup() */
|
||||||
|
if (sd->ctx != hd->hd_req.sess_ctx) {
|
||||||
|
/* Free previous context */
|
||||||
|
httpd_sess_free_ctx(hd->hd_req.sess_ctx, hd->hd_req.free_ctx);
|
||||||
|
}
|
||||||
|
hd->hd_req.sess_ctx = ctx;
|
||||||
|
}
|
||||||
|
hd->hd_req.free_ctx = free_fn;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Else set the context inside the sock_db structure */
|
||||||
|
if (sd->ctx != ctx) {
|
||||||
|
/* Free previous context */
|
||||||
|
httpd_sess_free_ctx(sd->ctx, sd->free_ctx);
|
||||||
|
sd->ctx = ctx;
|
||||||
|
}
|
||||||
|
sd->free_ctx = free_fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *httpd_sess_get_transport_ctx(httpd_handle_t handle, int sockfd)
|
||||||
|
{
|
||||||
|
struct sock_db *sd = httpd_sess_get(handle, sockfd);
|
||||||
|
if (sd == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sd->transport_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpd_sess_set_transport_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn)
|
||||||
|
{
|
||||||
|
struct sock_db *sd = httpd_sess_get(handle, sockfd);
|
||||||
|
if (sd == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sd->transport_ctx != ctx) {
|
||||||
|
/* Free previous transport context */
|
||||||
|
httpd_sess_free_ctx(sd->transport_ctx, sd->free_transport_ctx);
|
||||||
|
sd->transport_ctx = ctx;
|
||||||
|
}
|
||||||
|
sd->free_transport_ctx = free_fn;
|
||||||
|
}
|
||||||
|
|
||||||
void httpd_sess_set_descriptors(struct httpd_data *hd,
|
void httpd_sess_set_descriptors(struct httpd_data *hd,
|
||||||
fd_set *fdset, int *maxfd)
|
fd_set *fdset, int *maxfd)
|
||||||
{
|
{
|
||||||
@ -98,6 +189,22 @@ void httpd_sess_set_descriptors(struct httpd_data *hd,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check if a FD is valid */
|
||||||
|
static int fd_is_valid(int fd)
|
||||||
|
{
|
||||||
|
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpd_sess_delete_invalid(struct httpd_data *hd)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < hd->config.max_open_sockets; i++) {
|
||||||
|
if (hd->hd_sd[i].fd != -1 && !fd_is_valid(hd->hd_sd[i].fd)) {
|
||||||
|
ESP_LOGW(TAG, LOG_FMT("Closing invalid socket %d"), hd->hd_sd[i].fd);
|
||||||
|
httpd_sess_delete(hd, hd->hd_sd[i].fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int httpd_sess_delete(struct httpd_data *hd, int fd)
|
int httpd_sess_delete(struct httpd_data *hd, int fd)
|
||||||
{
|
{
|
||||||
ESP_LOGD(TAG, LOG_FMT("fd = %d"), fd);
|
ESP_LOGD(TAG, LOG_FMT("fd = %d"), fd);
|
||||||
@ -105,7 +212,12 @@ int httpd_sess_delete(struct httpd_data *hd, int fd)
|
|||||||
int pre_sess_fd = -1;
|
int pre_sess_fd = -1;
|
||||||
for (i = 0; i < hd->config.max_open_sockets; i++) {
|
for (i = 0; i < hd->config.max_open_sockets; i++) {
|
||||||
if (hd->hd_sd[i].fd == fd) {
|
if (hd->hd_sd[i].fd == fd) {
|
||||||
hd->hd_sd[i].fd = -1;
|
/* global close handler */
|
||||||
|
if (hd->config.close_fn) {
|
||||||
|
hd->config.close_fn(hd, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release 'user' context */
|
||||||
if (hd->hd_sd[i].ctx) {
|
if (hd->hd_sd[i].ctx) {
|
||||||
if (hd->hd_sd[i].free_ctx) {
|
if (hd->hd_sd[i].free_ctx) {
|
||||||
hd->hd_sd[i].free_ctx(hd->hd_sd[i].ctx);
|
hd->hd_sd[i].free_ctx(hd->hd_sd[i].ctx);
|
||||||
@ -115,6 +227,20 @@ int httpd_sess_delete(struct httpd_data *hd, int fd)
|
|||||||
hd->hd_sd[i].ctx = NULL;
|
hd->hd_sd[i].ctx = NULL;
|
||||||
hd->hd_sd[i].free_ctx = NULL;
|
hd->hd_sd[i].free_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* release 'transport' context */
|
||||||
|
if (hd->hd_sd[i].transport_ctx) {
|
||||||
|
if (hd->hd_sd[i].free_transport_ctx) {
|
||||||
|
hd->hd_sd[i].free_transport_ctx(hd->hd_sd[i].transport_ctx);
|
||||||
|
} else {
|
||||||
|
free(hd->hd_sd[i].transport_ctx);
|
||||||
|
}
|
||||||
|
hd->hd_sd[i].transport_ctx = NULL;
|
||||||
|
hd->hd_sd[i].free_transport_ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mark session slot as available */
|
||||||
|
hd->hd_sd[i].fd = -1;
|
||||||
break;
|
break;
|
||||||
} else if (hd->hd_sd[i].fd != -1) {
|
} else if (hd->hd_sd[i].fd != -1) {
|
||||||
/* Return the fd just preceding the one being
|
/* Return the fd just preceding the one being
|
||||||
@ -142,6 +268,12 @@ bool httpd_sess_pending(struct httpd_data *hd, int fd)
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sd->pending_fn) {
|
||||||
|
// test if there's any data to be read (besides read() function, which is handled by select() in the main httpd loop)
|
||||||
|
// this should check e.g. for the SSL data buffer
|
||||||
|
if (sd->pending_fn(hd, fd) > 0) return true;
|
||||||
|
}
|
||||||
|
|
||||||
return (sd->pending_len != 0);
|
return (sd->pending_len != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +338,7 @@ esp_err_t httpd_sess_close_lru(struct httpd_data *hd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOGD(TAG, LOG_FMT("fd = %d"), lru_fd);
|
ESP_LOGD(TAG, LOG_FMT("fd = %d"), lru_fd);
|
||||||
return httpd_trigger_sess_close(hd, lru_fd);
|
return httpd_sess_trigger_close(hd, lru_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int httpd_sess_iterate(struct httpd_data *hd, int start_fd)
|
int httpd_sess_iterate(struct httpd_data *hd, int start_fd)
|
||||||
@ -243,14 +375,9 @@ static void httpd_sess_close(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t httpd_trigger_sess_close(httpd_handle_t handle, int sockfd)
|
esp_err_t httpd_sess_trigger_close(httpd_handle_t handle, int sockfd)
|
||||||
{
|
{
|
||||||
if (handle == NULL) {
|
struct sock_db *sock_db = httpd_sess_get(handle, sockfd);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct httpd_data *hd = (struct httpd_data *) handle;
|
|
||||||
struct sock_db *sock_db = httpd_sess_get(hd, sockfd);
|
|
||||||
if (sock_db) {
|
if (sock_db) {
|
||||||
return httpd_queue_work(handle, httpd_sess_close, sock_db);
|
return httpd_queue_work(handle, httpd_sess_close, sock_db);
|
||||||
}
|
}
|
||||||
|
@ -22,33 +22,33 @@
|
|||||||
|
|
||||||
static const char *TAG = "httpd_txrx";
|
static const char *TAG = "httpd_txrx";
|
||||||
|
|
||||||
esp_err_t httpd_set_send_override(httpd_req_t *r, httpd_send_func_t send_func)
|
esp_err_t httpd_sess_set_send_override(httpd_handle_t hd, int sockfd, httpd_send_func_t send_func)
|
||||||
{
|
{
|
||||||
if (r == NULL || send_func == NULL) {
|
struct sock_db *sess = httpd_sess_get(hd, sockfd);
|
||||||
|
if (!sess) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
sess->send_fn = send_func;
|
||||||
if (!httpd_valid_req(r)) {
|
|
||||||
return ESP_ERR_HTTPD_INVALID_REQ;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct httpd_req_aux *ra = r->aux;
|
|
||||||
ra->sd->send_fn = send_func;
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t httpd_set_recv_override(httpd_req_t *r, httpd_recv_func_t recv_func)
|
esp_err_t httpd_sess_set_recv_override(httpd_handle_t hd, int sockfd, httpd_recv_func_t recv_func)
|
||||||
{
|
{
|
||||||
if (r == NULL || recv_func == NULL) {
|
struct sock_db *sess = httpd_sess_get(hd, sockfd);
|
||||||
|
if (!sess) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
sess->recv_fn = recv_func;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (!httpd_valid_req(r)) {
|
esp_err_t httpd_sess_set_pending_override(httpd_handle_t hd, int sockfd, httpd_pending_func_t pending_func)
|
||||||
return ESP_ERR_HTTPD_INVALID_REQ;
|
{
|
||||||
|
struct sock_db *sess = httpd_sess_get(hd, sockfd);
|
||||||
|
if (!sess) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
sess->pending_fn = pending_func;
|
||||||
struct httpd_req_aux *ra = r->aux;
|
|
||||||
ra->sd->recv_fn = recv_func;
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct httpd_req_aux *ra = r->aux;
|
struct httpd_req_aux *ra = r->aux;
|
||||||
int ret = ra->sd->send_fn(ra->sd->fd, buf, buf_len, 0);
|
int ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
|
ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
|
||||||
return ret;
|
return ret;
|
||||||
@ -77,7 +77,7 @@ static esp_err_t httpd_send_all(httpd_req_t *r, const char *buf, size_t buf_len)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
while (buf_len > 0) {
|
while (buf_len > 0) {
|
||||||
ret = ra->sd->send_fn(ra->sd->fd, buf, buf_len, 0);
|
ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
|
ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
@ -125,7 +125,7 @@ int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, bool halt_aft
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Receive data of remaining length */
|
/* Receive data of remaining length */
|
||||||
int ret = ra->sd->recv_fn(ra->sd->fd, buf, buf_len, 0);
|
int ret = ra->sd->recv_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ESP_LOGD(TAG, LOG_FMT("error in recv_fn"));
|
ESP_LOGD(TAG, LOG_FMT("error in recv_fn"));
|
||||||
if ((ret == HTTPD_SOCK_ERR_TIMEOUT) && (pending_len != 0)) {
|
if ((ret == HTTPD_SOCK_ERR_TIMEOUT) && (pending_len != 0)) {
|
||||||
@ -231,7 +231,7 @@ esp_err_t httpd_resp_set_type(httpd_req_t *r, const char *type)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len)
|
esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len)
|
||||||
{
|
{
|
||||||
if (r == NULL) {
|
if (r == NULL) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
@ -246,6 +246,8 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len)
|
|||||||
const char *colon_separator = ": ";
|
const char *colon_separator = ": ";
|
||||||
const char *cr_lf_seperator = "\r\n";
|
const char *cr_lf_seperator = "\r\n";
|
||||||
|
|
||||||
|
if (buf_len == -1) buf_len = strlen(buf);
|
||||||
|
|
||||||
/* Request headers are no longer available */
|
/* Request headers are no longer available */
|
||||||
ra->req_hdrs_count = 0;
|
ra->req_hdrs_count = 0;
|
||||||
|
|
||||||
@ -294,7 +296,7 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, size_t buf_len)
|
esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len)
|
||||||
{
|
{
|
||||||
if (r == NULL) {
|
if (r == NULL) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
@ -304,6 +306,8 @@ esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, size_t buf_len)
|
|||||||
return ESP_ERR_HTTPD_INVALID_REQ;
|
return ESP_ERR_HTTPD_INVALID_REQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buf_len == -1) buf_len = strlen(buf);
|
||||||
|
|
||||||
struct httpd_req_aux *ra = r->aux;
|
struct httpd_req_aux *ra = r->aux;
|
||||||
const char *httpd_chunked_hdr_str = "HTTP/1.1 %s\r\nContent-Type: %s\r\nTransfer-Encoding: chunked\r\n";
|
const char *httpd_chunked_hdr_str = "HTTP/1.1 %s\r\nContent-Type: %s\r\nTransfer-Encoding: chunked\r\n";
|
||||||
const char *colon_separator = ": ";
|
const char *colon_separator = ": ";
|
||||||
@ -359,7 +363,7 @@ esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, size_t buf_len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buf) {
|
if (buf) {
|
||||||
if (httpd_send_all(r, buf, buf_len) != ESP_OK) {
|
if (httpd_send_all(r, buf, (size_t) buf_len) != ESP_OK) {
|
||||||
return ESP_ERR_HTTPD_RESP_SEND;
|
return ESP_ERR_HTTPD_RESP_SEND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -520,8 +524,9 @@ static int httpd_sock_err(const char *ctx, int sockfd)
|
|||||||
return errval;
|
return errval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags)
|
int httpd_default_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags)
|
||||||
{
|
{
|
||||||
|
(void)hd;
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
return HTTPD_SOCK_ERR_INVALID;
|
return HTTPD_SOCK_ERR_INVALID;
|
||||||
}
|
}
|
||||||
@ -533,8 +538,9 @@ int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int httpd_default_recv(int sockfd, char *buf, size_t buf_len, int flags)
|
int httpd_default_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags)
|
||||||
{
|
{
|
||||||
|
(void)hd;
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
return HTTPD_SOCK_ERR_INVALID;
|
return HTTPD_SOCK_ERR_INVALID;
|
||||||
}
|
}
|
||||||
|
@ -201,8 +201,10 @@ esp_err_t httpd_uri(struct httpd_data *hd)
|
|||||||
if (uri == NULL) {
|
if (uri == NULL) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case HTTPD_404_NOT_FOUND:
|
case HTTPD_404_NOT_FOUND:
|
||||||
|
ESP_LOGW(TAG, LOG_FMT("URI '%s' not found"), req->uri);
|
||||||
return httpd_resp_send_err(req, HTTPD_404_NOT_FOUND);
|
return httpd_resp_send_err(req, HTTPD_404_NOT_FOUND);
|
||||||
case HTTPD_405_METHOD_NOT_ALLOWED:
|
case HTTPD_405_METHOD_NOT_ALLOWED:
|
||||||
|
ESP_LOGW(TAG, LOG_FMT("Method '%d' not allowed for URI '%s'"), req->method, req->uri);
|
||||||
return httpd_resp_send_err(req, HTTPD_405_METHOD_NOT_ALLOWED);
|
return httpd_resp_send_err(req, HTTPD_405_METHOD_NOT_ALLOWED);
|
||||||
default:
|
default:
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
|
@ -12,6 +12,11 @@ static const char *TAG="TESTS";
|
|||||||
int pre_start_mem, post_stop_mem, post_stop_min_mem;
|
int pre_start_mem, post_stop_mem, post_stop_min_mem;
|
||||||
bool basic_sanity = true;
|
bool basic_sanity = true;
|
||||||
|
|
||||||
|
struct async_resp_arg {
|
||||||
|
httpd_handle_t hd;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
/********************* Basic Handlers Start *******************/
|
/********************* Basic Handlers Start *******************/
|
||||||
|
|
||||||
esp_err_t hello_get_handler(httpd_req_t *req)
|
esp_err_t hello_get_handler(httpd_req_t *req)
|
||||||
@ -157,11 +162,13 @@ esp_err_t leftover_data_post_handler(httpd_req_t *req)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int httpd_default_send(int sockfd, const char *buf, unsigned buf_len, int flags);
|
int httpd_default_send(httpd_handle_t hd, int sockfd, const char *buf, unsigned buf_len, int flags);
|
||||||
void generate_async_resp(void *arg)
|
void generate_async_resp(void *arg)
|
||||||
{
|
{
|
||||||
char buf[250];
|
char buf[250];
|
||||||
int fd = (int )arg;
|
struct async_resp_arg *resp_arg = (struct async_resp_arg *)arg;
|
||||||
|
httpd_handle_t hd = resp_arg->hd;
|
||||||
|
int fd = resp_arg->fd;
|
||||||
#define HTTPD_HDR_STR "HTTP/1.1 200 OK\r\n" \
|
#define HTTPD_HDR_STR "HTTP/1.1 200 OK\r\n" \
|
||||||
"Content-Type: text/html\r\n" \
|
"Content-Type: text/html\r\n" \
|
||||||
"Content-Length: %d\r\n"
|
"Content-Length: %d\r\n"
|
||||||
@ -171,11 +178,12 @@ void generate_async_resp(void *arg)
|
|||||||
|
|
||||||
snprintf(buf, sizeof(buf), HTTPD_HDR_STR,
|
snprintf(buf, sizeof(buf), HTTPD_HDR_STR,
|
||||||
strlen(STR));
|
strlen(STR));
|
||||||
httpd_default_send(fd, buf, strlen(buf), 0);
|
httpd_default_send(hd, fd, buf, strlen(buf), 0);
|
||||||
/* Space for sending additional headers based on set_header */
|
/* Space for sending additional headers based on set_header */
|
||||||
httpd_default_send(fd, "\r\n", strlen("\r\n"), 0);
|
httpd_default_send(hd, fd, "\r\n", strlen("\r\n"), 0);
|
||||||
httpd_default_send(fd, STR, strlen(STR), 0);
|
httpd_default_send(hd, fd, STR, strlen(STR), 0);
|
||||||
#undef STR
|
#undef STR
|
||||||
|
free(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t async_get_handler(httpd_req_t *req)
|
esp_err_t async_get_handler(httpd_req_t *req)
|
||||||
@ -185,12 +193,15 @@ esp_err_t async_get_handler(httpd_req_t *req)
|
|||||||
/* Also register a HTTPD Work which sends the same data on the same
|
/* Also register a HTTPD Work which sends the same data on the same
|
||||||
* socket again
|
* socket again
|
||||||
*/
|
*/
|
||||||
int fd = httpd_req_to_sockfd(req);
|
struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg));
|
||||||
if (fd < 0) {
|
resp_arg->hd = req->handle;
|
||||||
|
resp_arg->fd = httpd_req_to_sockfd(req);
|
||||||
|
if (resp_arg->fd < 0) {
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Queuing work fd : %d", fd);
|
|
||||||
httpd_queue_work(req->handle, generate_async_resp, (void *)fd);
|
ESP_LOGI(TAG, "Queuing work fd : %d", resp_arg->fd);
|
||||||
|
httpd_queue_work(req->handle, generate_async_resp, resp_arg);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
#undef STR
|
#undef STR
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user