From 0885d8542d269ea524cf421f0800ee8444ac7e83 Mon Sep 17 00:00:00 2001 From: Harshit Malpani Date: Thu, 17 Nov 2022 14:14:15 +0530 Subject: [PATCH] esp_http_server: Added support for esp_events --- components/esp_http_server/CMakeLists.txt | 2 +- .../esp_http_server/include/esp_http_server.h | 24 +++++++++++++++++++ .../esp_http_server/src/esp_httpd_priv.h | 6 +++++ components/esp_http_server/src/httpd_main.c | 14 +++++++++++ components/esp_http_server/src/httpd_parse.c | 1 + components/esp_http_server/src/httpd_sess.c | 1 + components/esp_http_server/src/httpd_txrx.c | 18 ++++++++++++++ .../protocols/esp_http_server.rst | 17 +++++++++++++ 8 files changed, 82 insertions(+), 1 deletion(-) diff --git a/components/esp_http_server/CMakeLists.txt b/components/esp_http_server/CMakeLists.txt index 6ec66da6455..d098ec067da 100644 --- a/components/esp_http_server/CMakeLists.txt +++ b/components/esp_http_server/CMakeLists.txt @@ -7,7 +7,7 @@ idf_component_register(SRCS "src/httpd_main.c" "src/util/ctrl_sock.c" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "src/port/esp32" "src/util" - REQUIRES http_parser # for http_parser.h + REQUIRES esp_event http_parser # for http_parser.h PRIV_REQUIRES lwip mbedtls esp_timer) target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/esp_http_server/include/esp_http_server.h b/components/esp_http_server/include/esp_http_server.h index 8103dcf1b7a..3826a40c9a3 100644 --- a/components/esp_http_server/include/esp_http_server.h +++ b/components/esp_http_server/include/esp_http_server.h @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -21,6 +22,29 @@ extern "C" { #define ESP_HTTPD_DEF_CTRL_PORT (32768) /*!< HTTP Server control socket port*/ +ESP_EVENT_DECLARE_BASE(ESP_HTTP_SERVER_EVENT); + +/** + * @brief HTTP Server events id + */ +typedef enum { + HTTP_SERVER_EVENT_ERROR = 0, /*!< This event occurs when there are any errors during execution */ + HTTP_SERVER_EVENT_START, /*!< This event occurs when HTTP Server is started */ + HTTP_SERVER_EVENT_ON_CONNECTED, /*!< Once the HTTP Server has been connected to the client, no data exchange has been performed */ + HTTP_SERVER_EVENT_ON_HEADER, /*!< Occurs when receiving each header sent from the client */ + HTTP_SERVER_EVENT_HEADERS_SENT, /*!< After sending all the headers to the client */ + HTTP_SERVER_EVENT_ON_DATA, /*!< Occurs when receiving data from the client */ + HTTP_SERVER_EVENT_SENT_DATA, /*!< Occurs when an ESP HTTP server session is finished */ + HTTP_SERVER_EVENT_DISCONNECTED, /*!< The connection has been disconnected */ + HTTP_SERVER_EVENT_STOP, /*!< This event occurs when HTTP Server is stopped */ +} esp_http_server_event_id_t; + +/** Argument structure for HTTP_SERVER_EVENT_ON_DATA and HTTP_SERVER_EVENT_SENT_DATA event */ +typedef struct { + int fd; /*!< Session socket file descriptor */ + int data_len; /*!< Data length */ +} esp_http_server_event_data; + /* note: esp_https_server.h includes a customized copy of this initializer that should be kept in sync diff --git a/components/esp_http_server/src/esp_httpd_priv.h b/components/esp_http_server/src/esp_httpd_priv.h index fc22c9118d0..7aa47241bb1 100644 --- a/components/esp_http_server/src/esp_httpd_priv.h +++ b/components/esp_http_server/src/esp_httpd_priv.h @@ -544,6 +544,12 @@ esp_err_t httpd_sess_trigger_close_(httpd_handle_t handle, struct sock_db *sessi * @} */ +/** + * @brief Function to dispatch events in default event loop + * + */ +void esp_http_server_dispatch_event(int32_t event_id, const void* event_data, size_t event_data_size); + #ifdef __cplusplus } #endif diff --git a/components/esp_http_server/src/httpd_main.c b/components/esp_http_server/src/httpd_main.c index 097a9b48974..3d1923542d4 100644 --- a/components/esp_http_server/src/httpd_main.c +++ b/components/esp_http_server/src/httpd_main.c @@ -30,6 +30,16 @@ typedef struct { static const char *TAG = "httpd"; +ESP_EVENT_DEFINE_BASE(ESP_HTTP_SERVER_EVENT); + +void esp_http_server_dispatch_event(int32_t event_id, const void* event_data, size_t event_data_size) +{ + esp_err_t err = esp_event_post(ESP_HTTP_SERVER_EVENT, event_id, event_data, event_data_size, portMAX_DELAY); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to post esp_http_server event: %s", esp_err_to_name(err)); + } +} + static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd) { /* If no space is available for new session, close the least recently used one */ @@ -101,6 +111,7 @@ static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd) goto exit; } ESP_LOGD(TAG, LOG_FMT("complete")); + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_ON_CONNECTED, &new_fd, sizeof(int)); return ESP_OK; exit: close(new_fd); @@ -507,6 +518,8 @@ esp_err_t httpd_start(httpd_handle_t *handle, const httpd_config_t *config) } *handle = (httpd_handle_t)hd; + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_START, NULL, 0); + return ESP_OK; } @@ -556,5 +569,6 @@ esp_err_t httpd_stop(httpd_handle_t handle) vSemaphoreDelete(hd->ctrl_sock_semaphore); #endif httpd_delete(hd); + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_STOP, NULL, 0); return ESP_OK; } diff --git a/components/esp_http_server/src/httpd_parse.c b/components/esp_http_server/src/httpd_parse.c index 453ef78c29e..5ff8aafa0ed 100644 --- a/components/esp_http_server/src/httpd_parse.c +++ b/components/esp_http_server/src/httpd_parse.c @@ -401,6 +401,7 @@ static esp_err_t cb_headers_complete(http_parser *parser) parser_data->status = PARSING_BODY; ra->remaining_len = r->content_len; + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_ON_HEADER, &(ra->sd->fd), sizeof(int)); return ESP_OK; } diff --git a/components/esp_http_server/src/httpd_sess.c b/components/esp_http_server/src/httpd_sess.c index 329af34183d..e7ee862e7bb 100644 --- a/components/esp_http_server/src/httpd_sess.c +++ b/components/esp_http_server/src/httpd_sess.c @@ -370,6 +370,7 @@ void httpd_sess_delete(struct httpd_data *hd, struct sock_db *session) } else { close(session->fd); } + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_DISCONNECTED, &session->fd, sizeof(int)); // clear all contexts httpd_sess_clear_ctx(session); diff --git a/components/esp_http_server/src/httpd_txrx.c b/components/esp_http_server/src/httpd_txrx.c index 88e291edcd5..0563c87cb03 100644 --- a/components/esp_http_server/src/httpd_txrx.c +++ b/components/esp_http_server/src/httpd_txrx.c @@ -281,6 +281,7 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len) if (httpd_send_all(r, cr_lf_seperator, strlen(cr_lf_seperator)) != ESP_OK) { return ESP_ERR_HTTPD_RESP_SEND; } + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_HEADERS_SENT, &(ra->sd->fd), sizeof(int)); /* Sending content */ if (buf && buf_len) { @@ -288,6 +289,11 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len) return ESP_ERR_HTTPD_RESP_SEND; } } + esp_http_server_event_data evt_data = { + .fd = ra->sd->fd, + .data_len = buf_len, + }; + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_SENT_DATA, &evt_data, sizeof(esp_http_server_event_data)); return ESP_OK; } @@ -369,6 +375,12 @@ esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len if (httpd_send_all(r, "\r\n", strlen("\r\n")) != ESP_OK) { return ESP_ERR_HTTPD_RESP_SEND; } + esp_http_server_event_data evt_data = { + .fd = ra->sd->fd, + .data_len = buf_len, + }; + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_SENT_DATA, &evt_data, sizeof(esp_http_server_event_data)); + return ESP_OK; } @@ -465,6 +477,7 @@ esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_code_t error, const ch } } #endif + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_ERROR, &error, sizeof(httpd_err_code_t)); return ret; } @@ -532,6 +545,11 @@ int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len) } ra->remaining_len -= ret; ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret); + esp_http_server_event_data evt_data = { + .fd = ra->sd->fd, + .data_len = ret, + }; + esp_http_server_dispatch_event(HTTP_SERVER_EVENT_ON_DATA, &evt_data, sizeof(esp_http_server_event_data)); return ret; } diff --git a/docs/en/api-reference/protocols/esp_http_server.rst b/docs/en/api-reference/protocols/esp_http_server.rst index 3907d8d8a92..6039e47825a 100644 --- a/docs/en/api-reference/protocols/esp_http_server.rst +++ b/docs/en/api-reference/protocols/esp_http_server.rst @@ -158,6 +158,23 @@ Websocket Server The HTTP server component provides websocket support. The websocket feature can be enabled in menuconfig using the :ref:`CONFIG_HTTPD_WS_SUPPORT` option. Please refer to the :example:`protocols/http_server/ws_echo_server` example which demonstrates usage of the websocket feature. +Event Handling +-------------- + +ESP HTTP Server has various events for which a handler can be triggered by :doc:`the Event Loop library <../system/esp_event>` when the particular event occurs. The handler has to be registered using :cpp:func:`esp_event_handler_register`. This helps in event handling for ESP HTTP Server. +:cpp:enum:`esp_http_server_event_id_t` has all the events which can happen for ESP HTTP Server. + +Expected data type for different ESP HTTP Server events in event loop: + - HTTP_SERVER_EVENT_ERROR : ``httpd_err_code_t`` + - HTTP_SERVER_EVENT_START : ``NULL`` + - HTTP_SERVER_EVENT_ON_CONNECTED : ``int`` + - HTTP_SERVER_EVENT_ON_HEADER : ``int`` + - HTTP_SERVER_EVENT_HEADERS_SENT : ``int`` + - HTTP_SERVER_EVENT_ON_DATA : ``esp_http_server_event_data`` + - HTTP_SERVER_EVENT_SENT_DATA : ``esp_http_server_event_data`` + - HTTP_SERVER_EVENT_DISCONNECTED : ``int`` + - HTTP_SERVER_EVENT_STOP : ``NULL`` + API Reference -------------