Skip to content

Commit

Permalink
Merge branch 'feature/esp_http_client_esp_events' into 'master'
Browse files Browse the repository at this point in the history
esp_http_client: Add support for esp_events

See merge request espressif/esp-idf!21113
  • Loading branch information
mahavirj committed Mar 16, 2023
2 parents 85b1efc + 0cc243a commit 361f682
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 7 deletions.
4 changes: 3 additions & 1 deletion 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"
Expand Down
33 changes: 33 additions & 0 deletions components/esp_http_client/esp_http_client.c
Expand Up @@ -25,6 +25,8 @@
#include "esp_transport_ssl.h"
#endif

ESP_EVENT_DEFINE_BASE(ESP_HTTP_CLIENT_EVENT);

static const char *TAG = "HTTP_CLIENT";

/**
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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 */
Expand All @@ -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 */
Expand All @@ -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 */
Expand All @@ -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) {
Expand All @@ -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)) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
18 changes: 18 additions & 0 deletions components/esp_http_client/include/esp_http_client.h
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion components/linux/CMakeLists.txt
Expand Up @@ -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)
18 changes: 18 additions & 0 deletions 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;
}
27 changes: 27 additions & 0 deletions docs/en/api-reference/protocols/esp_http_client.rst
Expand Up @@ -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 <https://github.com/espressif/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 <esp_http_client_event_id_t::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
-------------
Expand Down
6 changes: 1 addition & 5 deletions examples/protocols/linux_stubs/esp_stubs/esp_stubs.c
Expand Up @@ -6,14 +6,10 @@
#include <stdlib.h>
#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;
Expand Down

0 comments on commit 361f682

Please sign in to comment.