Merge branch 'feat/add_new_client_state_and_update_state_flow' into 'master'

feat(esp_http_client): added new HTTP state HTTP_STATE_CONNECTING and change state flow

Closes IDFGH-15423 and IDFGH-15362

See merge request espressif/esp-idf!40507
This commit is contained in:
Mahavir Jain
2025-08-13 11:29:18 +05:30
3 changed files with 73 additions and 12 deletions

View File

@@ -88,17 +88,7 @@ typedef struct {
int max_store_header_size; int max_store_header_size;
} connection_info_t; } connection_info_t;
typedef enum {
HTTP_STATE_UNINIT = 0,
HTTP_STATE_INIT,
HTTP_STATE_CONNECTED,
HTTP_STATE_REQ_COMPLETE_HEADER,
HTTP_STATE_REQ_COMPLETE_DATA,
HTTP_STATE_RES_COMPLETE_HEADER,
HTTP_STATE_RES_ON_DATA_START,
HTTP_STATE_RES_COMPLETE_DATA,
HTTP_STATE_CLOSE
} esp_http_state_t;
typedef enum { typedef enum {
SESSION_TICKET_UNUSED = 0, SESSION_TICKET_UNUSED = 0,
@@ -1429,6 +1419,8 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
then the esp_http_client_perform() API will return ESP_ERR_HTTP_EAGAIN error. The user may call then the esp_http_client_perform() API will return ESP_ERR_HTTP_EAGAIN error. The user may call
esp_http_client_perform API again, and for this reason, we maintain the states */ esp_http_client_perform API again, and for this reason, we maintain the states */
case HTTP_STATE_INIT: case HTTP_STATE_INIT:
/* falls through */
case HTTP_STATE_CONNECTING:
if ((err = esp_http_client_connect(client)) != ESP_OK) { if ((err = esp_http_client_connect(client)) != ESP_OK) {
if (client->is_async && err == ESP_ERR_HTTP_CONNECTING) { if (client->is_async && err == ESP_ERR_HTTP_CONNECTING) {
return ESP_ERR_HTTP_EAGAIN; return ESP_ERR_HTTP_EAGAIN;
@@ -1576,6 +1568,7 @@ static esp_err_t esp_http_client_connect(esp_http_client_handle_t client)
esp_http_client_close(client); esp_http_client_close(client);
return err; return err;
} }
client->state = HTTP_STATE_CONNECTING;
if (client->state < HTTP_STATE_CONNECTED) { if (client->state < HTTP_STATE_CONNECTED) {
#ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT #ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT
@@ -1815,7 +1808,7 @@ int esp_http_client_write(esp_http_client_handle_t client, const char *buffer, i
esp_err_t esp_http_client_close(esp_http_client_handle_t client) esp_err_t esp_http_client_close(esp_http_client_handle_t client)
{ {
if (client->state >= HTTP_STATE_INIT) { if (client->state > HTTP_STATE_INIT) {
http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, esp_transport_get_error_handle(client->transport), 0); 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)); http_dispatch_event_to_event_loop(HTTP_EVENT_DISCONNECTED, &client, sizeof(esp_http_client_handle_t));
client->state = HTTP_STATE_INIT; client->state = HTTP_STATE_INIT;
@@ -2025,3 +2018,11 @@ esp_err_t esp_http_client_get_chunk_length(esp_http_client_handle_t client, int
} }
return ESP_OK; return ESP_OK;
} }
esp_http_state_t esp_http_client_get_state(esp_http_client_handle_t client)
{
if (client == NULL) {
return HTTP_STATE_UNINIT;
}
return client->state;
}

View File

@@ -145,6 +145,22 @@ typedef enum {
HTTP_TLS_DYN_BUF_STRATEGY_MAX, /*!< to indicate max */ HTTP_TLS_DYN_BUF_STRATEGY_MAX, /*!< to indicate max */
} esp_http_client_tls_dyn_buf_strategy_t; } esp_http_client_tls_dyn_buf_strategy_t;
/**
* @brief HTTP Client states
*/
typedef enum {
HTTP_STATE_UNINIT = 0, /*!< HTTP client uninitialized */
HTTP_STATE_INIT, /*!< HTTP client initialized */
HTTP_STATE_CONNECTING, /*!< HTTP client connecting to server */
HTTP_STATE_CONNECTED, /*!< HTTP client connected to server */
HTTP_STATE_REQ_COMPLETE_HEADER, /*!< HTTP request headers sent */
HTTP_STATE_REQ_COMPLETE_DATA, /*!< HTTP request data sent */
HTTP_STATE_RES_COMPLETE_HEADER, /*!< HTTP response headers received */
HTTP_STATE_RES_ON_DATA_START, /*!< HTTP response data started */
HTTP_STATE_RES_COMPLETE_DATA, /*!< HTTP response data completed */
HTTP_STATE_CLOSE /*!< HTTP client connection closed */
} esp_http_state_t;
/** /**
* @brief HTTP configuration * @brief HTTP configuration
*/ */
@@ -822,6 +838,15 @@ esp_err_t esp_http_client_get_url(esp_http_client_handle_t client, char *url, co
*/ */
esp_err_t esp_http_client_get_chunk_length(esp_http_client_handle_t client, int *len); esp_err_t esp_http_client_get_chunk_length(esp_http_client_handle_t client, int *len);
/**
* @brief Get the current state of the HTTP client
*
* @param[in] client The HTTP client handle
*
* @return Current state of the HTTP client
*/
esp_http_state_t esp_http_client_get_state(esp_http_client_handle_t client);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -186,6 +186,41 @@ TEST_CASE("esp_http_client_set_header() should not return error if header value
esp_http_client_cleanup(client); esp_http_client_cleanup(client);
} }
static int disconnect_event_count = 0;
static esp_err_t disconnect_event_handler(esp_http_client_event_t *evt)
{
if (evt->event_id == HTTP_EVENT_DISCONNECTED) {
disconnect_event_count++;
}
return ESP_OK;
}
TEST_CASE("esp_http_client_close() and cleanup() should not dispatch duplicate disconnect events", "[esp_http_client]")
{
esp_http_client_config_t config = {
.url = "http://httpbin.org/get",
.event_handler = disconnect_event_handler,
};
// Reset event counter
disconnect_event_count = 0;
esp_http_client_handle_t client = esp_http_client_init(&config);
TEST_ASSERT_NOT_NULL(client);
// Close the client first
esp_err_t err = esp_http_client_close(client);
TEST_ASSERT_EQUAL(ESP_OK, err);
// Then cleanup - this should not dispatch another disconnect event
err = esp_http_client_cleanup(client);
TEST_ASSERT_EQUAL(ESP_OK, err);
// Verify that only one disconnect event was dispatched (or none if client was never connected)
TEST_ASSERT_LESS_OR_EQUAL(1, disconnect_event_count);
}
void app_main(void) void app_main(void)
{ {
unity_run_menu(); unity_run_menu();