diff --git a/components/esp_http_client/CMakeLists.txt b/components/esp_http_client/CMakeLists.txt index 7a7fc52487c..59fd0e57634 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 linux) 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/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/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..989162f74e5 100644 --- a/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c +++ b/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c @@ -6,14 +6,10 @@ #include #include "esp_err.h" #include "esp_log.h" +#include "esp_event.h" extern void app_main(void); -esp_err_t esp_event_loop_create_default(void) -{ - return ESP_OK; -} - esp_err_t esp_netif_init(void) { return ESP_OK;