From 674fd8feb88297d4e51ce178d99f17bca75f11bc Mon Sep 17 00:00:00 2001 From: Harshit Malpani Date: Wed, 16 Nov 2022 17:31:07 +0530 Subject: [PATCH 1/2] esp_http_client: Add support for esp_events --- components/esp_http_client/CMakeLists.txt | 4 ++- components/esp_http_client/esp_http_client.c | 33 +++++++++++++++++++ .../esp_http_client/include/esp_http_client.h | 18 ++++++++++ .../protocols/esp_http_client.rst | 27 +++++++++++++++ .../linux_stubs/esp_stubs/esp_stubs.c | 7 ++++ .../linux_stubs/esp_stubs/include/esp_event.h | 9 +++++ 6 files changed, 97 insertions(+), 1 deletion(-) diff --git a/components/esp_http_client/CMakeLists.txt b/components/esp_http_client/CMakeLists.txt index 7a7fc52487c..cd2361398ee 100644 --- a/components/esp_http_client/CMakeLists.txt +++ b/components/esp_http_client/CMakeLists.txt @@ -1,5 +1,7 @@ if(NOT ${IDF_TARGET} STREQUAL "linux") - set(req lwip) + set(req lwip esp_event) +else() + set(req esp_stubs) endif() idf_component_register(SRCS "esp_http_client.c" diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index d2b7f147f1f..05d6412c9be 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -25,6 +25,8 @@ #include "esp_transport_ssl.h" #endif +ESP_EVENT_DEFINE_BASE(ESP_HTTP_CLIENT_EVENT); + static const char *TAG = "HTTP_CLIENT"; /** @@ -183,6 +185,14 @@ static esp_err_t http_dispatch_event(esp_http_client_t *client, esp_http_client_ return ESP_OK; } +static void http_dispatch_event_to_event_loop(int32_t event_id, const void* event_data, size_t event_data_size) +{ + esp_err_t err = esp_event_post(ESP_HTTP_CLIENT_EVENT, event_id, event_data, event_data_size, portMAX_DELAY); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to post https_ota event: %"PRId32", error: %s", event_id, esp_err_to_name(err)); + } +} + static int http_on_message_begin(http_parser *parser) { esp_http_client_t *client = parser->data; @@ -211,6 +221,7 @@ static int http_on_header_event(esp_http_client_handle_t client) client->event.header_key = client->current_header_key; client->event.header_value = client->current_header_value; http_dispatch_event(client, HTTP_EVENT_ON_HEADER, NULL, 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ON_HEADER, &client, sizeof(esp_http_client_handle_t)); free(client->current_header_key); free(client->current_header_value); client->current_header_key = NULL; @@ -293,6 +304,10 @@ static int http_on_body(http_parser *parser, const char *at, size_t length) client->response->data_process += length; client->response->buffer->raw_len += length; http_dispatch_event(client, HTTP_EVENT_ON_DATA, (void *)at, length); + esp_http_client_on_data_t evt_data = {}; + evt_data.data_process = client->response->data_process; + evt_data.client = client; + http_dispatch_event_to_event_loop(HTTP_EVENT_ON_DATA, &evt_data, sizeof(esp_http_client_on_data_t)); return 0; } @@ -891,6 +906,11 @@ static esp_err_t esp_http_check_response(esp_http_client_handle_t client) return ESP_FAIL; }; } + esp_http_client_redirect_event_data_t evt_data = { + .status_code = client->response->status_code, + .client = client, + }; + http_dispatch_event_to_event_loop(HTTP_EVENT_REDIRECT, &evt_data, sizeof(esp_http_client_redirect_event_data_t)); break; case HttpStatus_Unauthorized: esp_http_client_add_auth(client); @@ -1138,6 +1158,7 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len) if (rlen < 0 && ridx == 0 && !esp_http_client_is_complete_data_received(client)) { http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); return ESP_FAIL; } return ridx; @@ -1172,6 +1193,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client) return ESP_ERR_HTTP_EAGAIN; } http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); return err; } /* falls through */ @@ -1181,6 +1203,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client) return ESP_ERR_HTTP_EAGAIN; } http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); return err; } /* falls through */ @@ -1190,6 +1213,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client) return ESP_ERR_HTTP_EAGAIN; } http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); return err; } /* falls through */ @@ -1209,9 +1233,11 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client) ESP_LOGW(TAG, "Close connection due to FIN received"); esp_http_client_close(client); http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); return ESP_ERR_HTTP_CONNECTION_CLOSED; } http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); return ESP_ERR_HTTP_FETCH_HEADER; } /* falls through */ @@ -1222,6 +1248,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client) if ((err = esp_http_check_response(client)) != ESP_OK) { ESP_LOGE(TAG, "Error response"); http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); return err; } while (client->response->is_chunked && !client->is_chunk_complete) { @@ -1243,6 +1270,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client) } } http_dispatch_event(client, HTTP_EVENT_ON_FINISH, NULL, 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ON_FINISH, &client, sizeof(esp_http_client_handle_t)); client->response->buffer->raw_len = 0; if (!http_should_keep_alive(client->parser)) { @@ -1340,6 +1368,7 @@ static esp_err_t esp_http_client_connect(esp_http_client_handle_t client) } client->state = HTTP_STATE_CONNECTED; http_dispatch_event(client, HTTP_EVENT_ON_CONNECTED, NULL, 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ON_CONNECTED, &client, sizeof(esp_http_client_handle_t)); } return ESP_OK; } @@ -1439,6 +1468,7 @@ static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, i client->data_written_index = 0; client->data_write_left = client->post_len; http_dispatch_event(client, HTTP_EVENT_HEADERS_SENT, NULL, 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_HEADERS_SENT, &client, sizeof(esp_http_client_handle_t)); client->state = HTTP_STATE_REQ_COMPLETE_HEADER; return ESP_OK; } @@ -1477,10 +1507,12 @@ esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len) esp_err_t err; if ((err = esp_http_client_connect(client)) != ESP_OK) { http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); return err; } if ((err = esp_http_client_request_send(client, write_len)) != ESP_OK) { http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); return err; } return ESP_OK; @@ -1510,6 +1542,7 @@ esp_err_t esp_http_client_close(esp_http_client_handle_t client) { if (client->state >= HTTP_STATE_INIT) { http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_DISCONNECTED, &client, sizeof(esp_http_client_handle_t)); client->state = HTTP_STATE_INIT; return esp_transport_close(client->transport); } diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index be20c79c480..5638b7c6817 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -18,6 +18,9 @@ extern "C" { #define DEFAULT_HTTP_BUF_SIZE (512) +#include "esp_event.h" +ESP_EVENT_DECLARE_BASE(ESP_HTTP_CLIENT_EVENT); + typedef struct esp_http_client *esp_http_client_handle_t; typedef struct esp_http_client_event *esp_http_client_event_handle_t; @@ -50,6 +53,21 @@ typedef struct esp_http_client_event { char *header_value; /*!< For HTTP_EVENT_ON_HEADER event_id, it's store current http header value */ } esp_http_client_event_t; +/** + * @brief Argument structure for HTTP_EVENT_ON_DATA event + */ +typedef struct esp_http_client_on_data { + esp_http_client_handle_t client; /*!< Client handle */ + int64_t data_process; /*!< Total data processed */ +} esp_http_client_on_data_t; + +/** + * @brief Argument structure for HTTP_EVENT_REDIRECT event + */ +typedef struct esp_http_client_redirect_event_data { + esp_http_client_handle_t client; /*!< Client handle */ + int status_code; /*!< Status Code */ +} esp_http_client_redirect_event_data_t; /** * @brief HTTP Client transport diff --git a/docs/en/api-reference/protocols/esp_http_client.rst b/docs/en/api-reference/protocols/esp_http_client.rst index b5bdc5332d1..8cb64768313 100644 --- a/docs/en/api-reference/protocols/esp_http_client.rst +++ b/docs/en/api-reference/protocols/esp_http_client.rst @@ -110,6 +110,33 @@ Examples of Authentication Configuration .auth_type = HTTP_AUTH_TYPE_BASIC, }; +Event Handling +-------------- + +ESP HTTP Client supports event handling by triggering an event handler corresponding to the event which took place. +:cpp:enum:`esp_http_client_event_id_t` contains all the events which could occur while performing an HTTP request using the ESP HTTP Client. + +To enable event handling, you just need to set a callback function using the :cpp:member:`esp_http_client_config_t::event_handler` member. + +ESP HTTP Client Diagnostic Information +-------------------------------------- +Diagnostic information could be helpful to gain insights into a problem. In the case of ESP HTTP Client, this diagnostic information can be collected by registering an event handler with :doc:`the Event Loop library <../system/esp_event>`. +This feature has been added by keeping in mind the `ESP Insights `_ framework which collects the diagnostic information. However, this feature can also be used without any dependency on ESP Insights framework for the diagnostic purpose. +Event handler can be registered to the event loop using the :cpp:func:`esp_event_handler_register` function. + +Expected data types for different HTTP Client events in the event loop: + + - HTTP_EVENT_ERROR : ``esp_http_client_handle_t`` + - HTTP_EVENT_ON_CONNECTED : ``esp_http_client_handle_t`` + - HTTP_EVENT_HEADERS_SENT : ``esp_http_client_handle_t`` + - HTTP_EVENT_ON_HEADER : ``esp_http_client_handle_t`` + - HTTP_EVENT_ON_DATA : ``esp_http_client_on_data_t`` + - HTTP_EVENT_ON_FINISH : ``esp_http_client_handle_t`` + - HTTP_EVENT_DISCONNECTED : ``esp_http_client_handle_t`` + - HTTP_EVENT_REDIRECT : ``esp_http_client_redirect_event_data_t`` + +The :cpp:type:`esp_http_client_handle_t` received along with the event data will be valid until :cpp:enumerator:`HTTP_EVENT_DISCONNECTED ` is not received. This handle has been sent primarily to differentiate between different client +connections and must not be used for any other purpose (as it may change based on client connection state). API Reference ------------- diff --git a/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c b/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c index 53116fcecf7..18bc472a15f 100644 --- a/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c +++ b/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c @@ -6,6 +6,7 @@ #include #include "esp_err.h" #include "esp_log.h" +#include "esp_event.h" extern void app_main(void); @@ -14,6 +15,12 @@ esp_err_t esp_event_loop_create_default(void) return ESP_OK; } +esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id, + const void* event_data, size_t event_data_size, TickType_t ticks_to_wait) +{ + return ESP_OK; +} + esp_err_t esp_netif_init(void) { return ESP_OK; diff --git a/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h b/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h index e909e800f6d..9eaa0e6db64 100644 --- a/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h +++ b/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h @@ -5,4 +5,13 @@ */ #include "esp_err.h" +typedef const char* esp_event_base_t; /**< unique pointer to a subsystem that exposes events */ +typedef unsigned long TickType_t; + +#define ESP_EVENT_DECLARE_BASE(id) extern esp_event_base_t id +#define ESP_EVENT_DEFINE_BASE(id) esp_event_base_t id = #id + esp_err_t esp_event_loop_create_default(void); + +esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id, + const void* event_data, size_t event_data_size, TickType_t ticks_to_wait); From 0cc243a8cc96d1bbc274691f6a29656830a59bb1 Mon Sep 17 00:00:00 2001 From: Harshit Malpani Date: Mon, 13 Mar 2023 10:43:34 +0530 Subject: [PATCH 2/2] esp_http_client: remove dependency of esp_stubs from esp_http_client. Add esp_event stubs in `linux` component --- components/esp_http_client/CMakeLists.txt | 2 +- components/linux/CMakeLists.txt | 3 ++- components/linux/esp_event_stubs.c | 18 ++++++++++++++++++ .../linux_stubs/esp_stubs/esp_stubs.c | 11 ----------- .../linux_stubs/esp_stubs/include/esp_event.h | 9 --------- 5 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 components/linux/esp_event_stubs.c diff --git a/components/esp_http_client/CMakeLists.txt b/components/esp_http_client/CMakeLists.txt index cd2361398ee..59fd0e57634 100644 --- a/components/esp_http_client/CMakeLists.txt +++ b/components/esp_http_client/CMakeLists.txt @@ -1,7 +1,7 @@ if(NOT ${IDF_TARGET} STREQUAL "linux") set(req lwip esp_event) else() - set(req esp_stubs) + set(req linux) endif() idf_component_register(SRCS "esp_http_client.c" diff --git a/components/linux/CMakeLists.txt b/components/linux/CMakeLists.txt index b7d2bd46a70..01594e97f4c 100644 --- a/components/linux/CMakeLists.txt +++ b/components/linux/CMakeLists.txt @@ -3,5 +3,6 @@ if(NOT "${target}" STREQUAL "linux") return() endif() -idf_component_register(INCLUDE_DIRS include +idf_component_register(SRCS esp_event_stubs.c + INCLUDE_DIRS include ${IDF_PATH}/components/esp_event/include REQUIRED_IDF_TARGETS linux) diff --git a/components/linux/esp_event_stubs.c b/components/linux/esp_event_stubs.c new file mode 100644 index 00000000000..2b622678e0e --- /dev/null +++ b/components/linux/esp_event_stubs.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "esp_err.h" +#include "esp_event.h" + +esp_err_t esp_event_loop_create_default(void) +{ + return ESP_OK; +} + +esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id, + const void* event_data, size_t event_data_size, TickType_t ticks_to_wait) +{ + return ESP_OK; +} diff --git a/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c b/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c index 18bc472a15f..989162f74e5 100644 --- a/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c +++ b/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c @@ -10,17 +10,6 @@ extern void app_main(void); -esp_err_t esp_event_loop_create_default(void) -{ - return ESP_OK; -} - -esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id, - const void* event_data, size_t event_data_size, TickType_t ticks_to_wait) -{ - return ESP_OK; -} - esp_err_t esp_netif_init(void) { return ESP_OK; diff --git a/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h b/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h index 9eaa0e6db64..e909e800f6d 100644 --- a/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h +++ b/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h @@ -5,13 +5,4 @@ */ #include "esp_err.h" -typedef const char* esp_event_base_t; /**< unique pointer to a subsystem that exposes events */ -typedef unsigned long TickType_t; - -#define ESP_EVENT_DECLARE_BASE(id) extern esp_event_base_t id -#define ESP_EVENT_DEFINE_BASE(id) esp_event_base_t id = #id - esp_err_t esp_event_loop_create_default(void); - -esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id, - const void* event_data, size_t event_data_size, TickType_t ticks_to_wait);