Merge branch 'bugfix/update_macro_defination_for_mem_check' into 'master'

fix(esp_http_client): Enhance MEM_CHECK Macro to Include Memory Allocation Failure Logs and Safe Handling

See merge request espressif/esp-idf!33453
This commit is contained in:
Mahavir Jain 2024-12-23 16:08:57 +08:00
commit 706a445782
7 changed files with 243 additions and 79 deletions

View File

@ -307,6 +307,18 @@ extern "C" {
} \
} while(0)
/**
* Macro which can be used to check the error code. If the code is not ESP_OK, it prints the message and returns.
* It logs the message in debug mode.
*/
#define ESP_RETURN_ON_ERROR_DEBUG(x, log_tag, format, ...) do { \
esp_err_t err_rc_ = (x); \
if (unlikely(err_rc_ != ESP_OK)) { \
ESP_LOGD(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return err_rc_; \
} \
} while(0)
/**
* A version of ESP_RETURN_ON_ERROR() macro that can be called from ISR.
*/
@ -354,6 +366,20 @@ extern "C" {
} \
} while(0)
/**
* Macro which can be used to check the error code. If the code is not ESP_OK, it prints the message,
* sets the local variable 'ret' to the code, and then exits by jumping to 'goto_tag'.
* It logs the message in debug mode.
*/
#define ESP_GOTO_ON_ERROR_DEBUG(x, goto_tag, log_tag, format, ...) do { \
esp_err_t err_rc_ = (x); \
if (unlikely(err_rc_ != ESP_OK)) { \
ESP_LOGD(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = err_rc_; \
goto goto_tag; \
} \
} while(0)
/**
* A version of ESP_GOTO_ON_ERROR() macro that can be called from ISR.
*/
@ -377,6 +403,18 @@ extern "C" {
} \
} while(0)
/**
* Macro which can be used to check the condition. If the condition is not 'true', it prints the message
* and returns with the supplied 'err_code'.
* It logs the message in debug mode.
*/
#define ESP_RETURN_ON_FALSE_DEBUG(a, err_code, log_tag, format, ...) do { \
if (unlikely(!(a))) { \
ESP_LOGD(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return err_code; \
} \
} while(0)
/**
* A version of ESP_RETURN_ON_FALSE() macro that can be called from ISR.
*/
@ -420,6 +458,19 @@ extern "C" {
} \
} while (0)
/**
* Macro which can be used to check the condition. If the condition is not 'true', it prints the message,
* sets the local variable 'ret' to the supplied 'err_code', and then exits by jumping to 'goto_tag'.
* It logs the message in debug mode.
*/
#define ESP_GOTO_ON_FALSE_DEBUG(a, err_code, goto_tag, log_tag, format, ...) do { \
if (unlikely(!(a))) { \
ESP_LOGD(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = err_code; \
goto goto_tag; \
} \
} while (0)
/**
* A version of ESP_GOTO_ON_FALSE() macro that can be called from ISR.
*/

View File

@ -255,7 +255,7 @@ static int http_on_header_field(http_parser *parser, const char *at, size_t leng
{
esp_http_client_t *client = parser->data;
http_on_header_event(client);
http_utils_append_string(&client->current_header_key, at, length);
ESP_RETURN_ON_FALSE_DEBUG(http_utils_append_string(&client->current_header_key, at, length), -1, TAG, "Failed to append string");
return 0;
}
@ -267,14 +267,14 @@ static int http_on_header_value(http_parser *parser, const char *at, size_t leng
return 0;
}
if (strcasecmp(client->current_header_key, "Location") == 0) {
http_utils_append_string(&client->location, at, length);
ESP_RETURN_ON_FALSE_DEBUG(http_utils_append_string(&client->location, at, length), -1, TAG, "Failed to append string");
} else if (strcasecmp(client->current_header_key, "Transfer-Encoding") == 0
&& memcmp(at, "chunked", length) == 0) {
client->response->is_chunked = true;
} else if (strcasecmp(client->current_header_key, "WWW-Authenticate") == 0) {
http_utils_append_string(&client->auth_header, at, length);
ESP_RETURN_ON_FALSE_DEBUG(http_utils_append_string(&client->auth_header, at, length), -1, TAG, "Failed to append string");
}
http_utils_append_string(&client->current_header_value, at, length);
ESP_RETURN_ON_FALSE_DEBUG(http_utils_append_string(&client->current_header_value, at, length), -1, TAG, "Failed to append string");
return 0;
}
@ -554,12 +554,12 @@ static esp_err_t _set_config(esp_http_client_handle_t client, const esp_http_cli
}
if (config->transport_type == HTTP_TRANSPORT_OVER_SSL) {
http_utils_assign_string(&client->connection_info.scheme, "https", -1);
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->connection_info.scheme, "https", -1), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
if (client->connection_info.port == 0) {
client->connection_info.port = DEFAULT_HTTPS_PORT;
}
} else {
http_utils_assign_string(&client->connection_info.scheme, "http", -1);
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->connection_info.scheme, "http", -1), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
if (client->connection_info.port == 0) {
client->connection_info.port = DEFAULT_HTTP_PORT;
}
@ -611,8 +611,60 @@ static esp_err_t _clear_auth_data(esp_http_client_handle_t client)
return ESP_OK;
}
static esp_err_t esp_http_client_prepare_basic_auth(esp_http_client_handle_t client) {
char *auth_response = NULL;
esp_err_t ret = ESP_FAIL;
auth_response = http_auth_basic(client->connection_info.username, client->connection_info.password);
ESP_GOTO_ON_FALSE(auth_response, ESP_FAIL, error, TAG, "Failed to generate basic auth response");
ESP_LOGD(TAG, "auth_response=%s", auth_response);
ESP_GOTO_ON_FALSE(ESP_OK == esp_http_client_set_header(client, "Authorization", auth_response), ESP_FAIL, error, TAG, "Failed to set Authorization header");
ret = ESP_OK;
error:
if (auth_response) {
free(auth_response); // Free the auth_response after use
}
return ret;
}
#ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH
static esp_err_t esp_http_client_prepare_digest_auth(esp_http_client_handle_t client) {
char *auth_response = NULL;
esp_err_t ret = ESP_FAIL;
client->auth_data->uri = NULL;
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->auth_data->uri, client->connection_info.path, -1), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
if (client->connection_info.query) {
ESP_GOTO_ON_FALSE_DEBUG(http_utils_append_string(&client->auth_data->uri, "?", -1), ESP_ERR_NO_MEM, error, TAG, "Failed to append string");
ESP_GOTO_ON_FALSE_DEBUG(http_utils_append_string(&client->auth_data->uri, client->connection_info.query, -1), ESP_ERR_NO_MEM, error, TAG, "Failed to append string");
}
client->auth_data->cnonce = ((uint64_t)esp_random() << 32) + esp_random();
auth_response = http_auth_digest(client->connection_info.username, client->connection_info.password, client->auth_data);
ESP_GOTO_ON_FALSE(auth_response, ESP_FAIL, error, TAG, "Failed to generate digest auth response");
ESP_LOGD(TAG, "auth_response=%s", auth_response);
ESP_GOTO_ON_FALSE(ESP_OK == esp_http_client_set_header(client, "Authorization", auth_response), ESP_FAIL, error, TAG, "Failed to set Authorization header");
ret = ESP_OK;
error:
if (auth_response) {
free(auth_response); // Free the auth_response after use
}
return ret;
}
#endif
static esp_err_t esp_http_client_prepare(esp_http_client_handle_t client)
{
esp_err_t ret = ESP_OK;
client->process_again = 0;
client->response->data_process = 0;
client->first_line_prepared = false;
@ -632,30 +684,16 @@ static esp_err_t esp_http_client_prepare(esp_http_client_handle_t client)
}
http_parser_init(client->parser, HTTP_RESPONSE);
if (client->connection_info.username) {
char *auth_response = NULL;
if (client->connection_info.auth_type == HTTP_AUTH_TYPE_BASIC) {
auth_response = http_auth_basic(client->connection_info.username, client->connection_info.password);
ret = esp_http_client_prepare_basic_auth(client);
}
#ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH
} else if (client->connection_info.auth_type == HTTP_AUTH_TYPE_DIGEST && client->auth_data) {
client->auth_data->uri = NULL;
http_utils_assign_string(&client->auth_data->uri,client->connection_info.path,-1);
if (client->connection_info.query){
http_utils_append_string(&client->auth_data->uri,"?",-1);
http_utils_append_string(&client->auth_data->uri,client->connection_info.query,-1);
}
client->auth_data->cnonce = ((uint64_t)esp_random() << 32) + esp_random();
auth_response = http_auth_digest(client->connection_info.username, client->connection_info.password, client->auth_data);
else if (client->connection_info.auth_type == HTTP_AUTH_TYPE_DIGEST && client->auth_data) {
ret = esp_http_client_prepare_digest_auth(client);
}
#endif
}
if (auth_response) {
ESP_LOGD(TAG, "auth_response=%s", auth_response);
esp_http_client_set_header(client, "Authorization", auth_response);
free(auth_response);
}
}
return ESP_OK;
return ret;
}
static char *_get_host_header(char *host, int port)
@ -1030,7 +1068,7 @@ static esp_err_t esp_http_check_response(esp_http_client_handle_t 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);
return esp_http_client_add_auth(client);
}
return ESP_OK;
}
@ -1061,8 +1099,7 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
old_port = client->connection_info.port;
if (purl.field_data[UF_HOST].len) {
http_utils_assign_string(&client->connection_info.host, url + purl.field_data[UF_HOST].off, purl.field_data[UF_HOST].len);
ESP_GOTO_ON_FALSE(client->connection_info.host, ESP_ERR_NO_MEM, error, TAG, "Memory exhausted");
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->connection_info.host, url + purl.field_data[UF_HOST].off, purl.field_data[UF_HOST].len), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
}
// Close the connection if host was changed
if (old_host && client->connection_info.host
@ -1083,8 +1120,7 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
}
if (purl.field_data[UF_SCHEMA].len) {
http_utils_assign_string(&client->connection_info.scheme, url + purl.field_data[UF_SCHEMA].off, purl.field_data[UF_SCHEMA].len);
ESP_RETURN_ON_FALSE(client->connection_info.scheme, ESP_ERR_NO_MEM, TAG, "Memory exhausted");
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->connection_info.scheme, url + purl.field_data[UF_SCHEMA].off, purl.field_data[UF_SCHEMA].len), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
if (strcasecmp(client->connection_info.scheme, "http") == 0) {
client->connection_info.port = DEFAULT_HTTP_PORT;
@ -1105,18 +1141,16 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
if (purl.field_data[UF_USERINFO].len) {
char *user_info = NULL;
http_utils_assign_string(&user_info, url + purl.field_data[UF_USERINFO].off, purl.field_data[UF_USERINFO].len);
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&user_info, url + purl.field_data[UF_USERINFO].off, purl.field_data[UF_USERINFO].len), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
if (user_info) {
char *username = user_info;
char *password = strchr(user_info, ':');
if (password) {
*password = 0;
password ++;
http_utils_assign_string(&client->connection_info.password, password, -1);
ESP_RETURN_ON_FALSE(client->connection_info.password, ESP_ERR_NO_MEM, TAG, "Memory exhausted");
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->connection_info.password, password, -1), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
}
http_utils_assign_string(&client->connection_info.username, username, -1);
ESP_RETURN_ON_FALSE(client->connection_info.username, ESP_ERR_NO_MEM, TAG, "Memory exhausted");
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->connection_info.username, username, -1), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
free(user_info);
} else {
return ESP_ERR_NO_MEM;
@ -1125,15 +1159,13 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
//Reset path and query if there are no information
if (purl.field_data[UF_PATH].len) {
http_utils_assign_string(&client->connection_info.path, url + purl.field_data[UF_PATH].off, purl.field_data[UF_PATH].len);
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->connection_info.path, url + purl.field_data[UF_PATH].off, purl.field_data[UF_PATH].len), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
} else {
http_utils_assign_string(&client->connection_info.path, "/", -1);
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->connection_info.path, "/", -1), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
}
ESP_RETURN_ON_FALSE(client->connection_info.path, ESP_ERR_NO_MEM, TAG, "Memory exhausted");
if (purl.field_data[UF_QUERY].len) {
http_utils_assign_string(&client->connection_info.query, url + purl.field_data[UF_QUERY].off, purl.field_data[UF_QUERY].len);
ESP_RETURN_ON_FALSE(client->connection_info.query, ESP_ERR_NO_MEM, TAG, "Memory exhausted");
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&client->connection_info.query, url + purl.field_data[UF_QUERY].off, purl.field_data[UF_QUERY].len), ESP_ERR_NO_MEM, error, TAG, "failed to assign string");
} else if (client->connection_info.query) {
free(client->connection_info.query);
client->connection_info.query = NULL;
@ -1758,21 +1790,21 @@ esp_err_t esp_http_client_set_auth_data(esp_http_client_handle_t client, const c
if (client == NULL || auth_data == NULL || len <= 0) {
return ESP_ERR_INVALID_ARG;
}
http_utils_append_string(&client->auth_header, auth_data, len);
ESP_RETURN_ON_FALSE_DEBUG(http_utils_append_string(&client->auth_header, auth_data, len), ESP_ERR_NO_MEM, TAG, "Failed to append string");
return ESP_OK;
}
void esp_http_client_add_auth(esp_http_client_handle_t client)
esp_err_t esp_http_client_add_auth(esp_http_client_handle_t client)
{
if (client == NULL) {
return;
return ESP_ERR_INVALID_ARG;
}
if (client->state != HTTP_STATE_RES_ON_DATA_START) {
return;
return ESP_OK; // No action needed, return OK
}
if (client->redirect_counter >= client->max_authorization_retries) {
ESP_LOGE(TAG, "Error, reached max_authorization_retries count=%d", client->redirect_counter);
return;
return ESP_FAIL;
}
char *auth_header = client->auth_header;
@ -1794,7 +1826,7 @@ void esp_http_client_add_auth(esp_http_client_handle_t client)
#endif
client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
ESP_LOGE(TAG, "This authentication method is not supported: %s", auth_header);
return;
return ESP_ERR_NOT_SUPPORTED;
#ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH
}
#endif
@ -1807,21 +1839,27 @@ void esp_http_client_add_auth(esp_http_client_handle_t client)
client->auth_data->method = strdup(HTTP_METHOD_MAPPING[client->connection_info.method]);
client->auth_data->nc = 1;
client->auth_data->realm = http_utils_get_string_between(auth_header, "realm=\"", "\"");
client->auth_data->algorithm = http_utils_get_string_between(auth_header, "algorithm=", ",");
ESP_RETURN_ON_ERROR_DEBUG(http_utils_get_substring_between(auth_header, "realm=\"", "\"", &client->auth_data->realm), TAG, "Unable to extract substring between specified strings");
ESP_RETURN_ON_ERROR_DEBUG(http_utils_get_substring_between(auth_header, "algorithm=", ",", &client->auth_data->algorithm), TAG, "Unable to extract substring between specified strings");
if (client->auth_data->algorithm == NULL) {
client->auth_data->algorithm = http_utils_get_string_after(auth_header, "algorithm=");
ESP_RETURN_ON_ERROR_DEBUG(http_utils_get_substring_after(auth_header, "algorithm=", &client->auth_data->algorithm), TAG, "Unable to extract substring after specified string");
}
if (client->auth_data->algorithm == NULL) {
client->auth_data->algorithm = strdup("MD5");
}
client->auth_data->qop = http_utils_get_string_between(auth_header, "qop=\"", "\"");
client->auth_data->nonce = http_utils_get_string_between(auth_header, "nonce=\"", "\"");
client->auth_data->opaque = http_utils_get_string_between(auth_header, "opaque=\"", "\"");
ESP_RETURN_ON_ERROR_DEBUG(http_utils_get_substring_between(auth_header, "qop=\"", "\"", &client->auth_data->qop), TAG, "Unable to extract substring between specified strings");
ESP_RETURN_ON_ERROR_DEBUG(http_utils_get_substring_between(auth_header, "nonce=\"", "\"", &client->auth_data->nonce), TAG, "Unable to extract substring between specified strings");
ESP_RETURN_ON_ERROR_DEBUG(http_utils_get_substring_between(auth_header, "opaque=\"", "\"", &client->auth_data->opaque), TAG, "Unable to extract substring between specified strings");
client->process_again = 1;
return ESP_OK;
} else {
client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
ESP_LOGW(TAG, "This request requires authentication, but does not provide header information for that");
return ESP_ERR_NOT_SUPPORTED;
}
}

View File

@ -675,8 +675,15 @@ esp_err_t esp_http_client_set_auth_data(esp_http_client_handle_t client, const c
* to flush off body data after calling this API.
*
* @param[in] client The esp_http_client handle
*
* @return
* - ESP_OK: Successfully added the authentication information.
* - ESP_ERR_INVALID_ARG: Invalid client handle passed.
* - ESP_ERR_NO_MEM: Memory allocation failed for the required fields.
* - ESP_ERR_NOT_SUPPORTED: Unsupported authentication type in the header.
* - ESP_FAIL: Failed to add authentication information due to other reasons.
*/
void esp_http_client_add_auth(esp_http_client_handle_t client);
esp_err_t esp_http_client_add_auth(esp_http_client_handle_t client);
/**
* @brief Checks if entire data in the response has been read without any error.

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -81,11 +81,9 @@ static esp_err_t http_header_new_item(http_header_handle_t header, const char *k
item = calloc(1, sizeof(http_header_item_t));
ESP_RETURN_ON_FALSE(item, ESP_ERR_NO_MEM, TAG, "Memory exhausted");
http_utils_assign_string(&item->key, key, -1);
ESP_GOTO_ON_FALSE(item->key, ESP_ERR_NO_MEM, _header_new_item_exit, TAG, "Memory exhausted");
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&item->key, key, -1), ESP_ERR_NO_MEM, _header_new_item_exit, TAG, "Failed to assign string");
http_utils_trim_whitespace(&item->key);
http_utils_assign_string(&item->value, value, -1);
ESP_GOTO_ON_FALSE(item->value, ESP_ERR_NO_MEM, _header_new_item_exit, TAG, "Memory exhausted");
ESP_GOTO_ON_FALSE_DEBUG(http_utils_assign_string(&item->value, value, -1), ESP_ERR_NO_MEM, _header_new_item_exit, TAG, "Failed to assign string");
http_utils_trim_whitespace(&item->value);
STAILQ_INSERT_TAIL(header, item, next);
return ret;
@ -167,7 +165,7 @@ int http_header_set_format(http_header_handle_t header, const char *key, const c
int http_header_generate_string(http_header_handle_t header, int index, char *buffer, int *buffer_len)
{
http_header_item_handle_t item;
int siz = 0;
int size = 0;
int idx = 0;
int ret_idx = -1;
bool is_end = false;
@ -175,13 +173,13 @@ int http_header_generate_string(http_header_handle_t header, int index, char *bu
// iterate over the header entries to calculate buffer size and determine last item
STAILQ_FOREACH(item, header, next) {
if (item->value && idx >= index) {
siz += strlen(item->key);
siz += strlen(item->value);
siz += 4; //': ' and '\r\n'
size += strlen(item->key);
size += strlen(item->value);
size += 4; //': ' and '\r\n'
}
idx ++;
if (siz + 1 > *buffer_len - 2) {
if (size + 1 > *buffer_len - 2) {
// if this item would not fit to the buffer, return the index of the last fitting one
ret_idx = idx - 1;
ESP_LOGE(TAG, "Buffer length is small to fit all the headers");
@ -189,7 +187,7 @@ int http_header_generate_string(http_header_handle_t header, int index, char *bu
}
}
if (siz == 0) {
if (size == 0) {
return 0;
}
if (ret_idx < 0) {
@ -198,7 +196,7 @@ int http_header_generate_string(http_header_handle_t header, int index, char *bu
is_end = true;
}
// iterate again over the header entries to write only the fitting indeces
// iterate again over the header entries to write only the fitting indices
int str_len = 0;
idx = 0;
STAILQ_FOREACH(item, header, next) {

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -10,12 +10,16 @@
#include <stdio.h>
#include <assert.h>
#include "esp_log.h"
#include "esp_check.h"
#include "http_utils.h"
#ifndef mem_check
#define mem_check(x) assert(x)
#endif
static const char *TAG = "http_utils";
char *http_utils_join_string(const char *first_str, size_t len_first, const char *second_str, size_t len_second)
{
size_t first_str_len = len_first > 0 ? len_first : strlen(first_str);
@ -23,7 +27,7 @@ char *http_utils_join_string(const char *first_str, size_t len_first, const char
char *ret = NULL;
if (first_str_len + second_str_len > 0) {
ret = calloc(1, first_str_len + second_str_len + 1);
mem_check(ret);
ESP_RETURN_ON_FALSE(ret, NULL, TAG, "Memory exhausted");
memcpy(ret, first_str, first_str_len);
memcpy(ret + first_str_len, second_str, second_str_len);
}
@ -42,11 +46,11 @@ char *http_utils_assign_string(char **str, const char *new_str, int len)
}
if (old_str) {
old_str = realloc(old_str, l + 1);
mem_check(old_str);
ESP_RETURN_ON_FALSE(old_str, NULL, TAG, "Memory exhausted");
old_str[l] = 0;
} else {
old_str = calloc(1, l + 1);
mem_check(old_str);
ESP_RETURN_ON_FALSE(old_str, NULL, TAG, "Memory exhausted");
}
memcpy(old_str, new_str, l);
*str = old_str;
@ -65,11 +69,11 @@ char *http_utils_append_string(char **str, const char *new_str, int len)
if (old_str) {
old_len = strlen(old_str);
old_str = realloc(old_str, old_len + l + 1);
mem_check(old_str);
ESP_RETURN_ON_FALSE(old_str, NULL, TAG, "Memory exhausted");
old_str[old_len + l] = 0;
} else {
old_str = calloc(1, l + 1);
mem_check(old_str);
ESP_RETURN_ON_FALSE(old_str, NULL, TAG, "Memory exhausted");
}
memcpy(old_str + old_len, new_str, l);
*str = old_str;
@ -140,6 +144,38 @@ char *http_utils_get_string_after(const char *str, const char *begin)
return NULL;
}
esp_err_t http_utils_get_substring_between(const char *str, const char *begin, const char *end, char **out)
{
*out = NULL;
char *found = strcasestr(str, begin);
if (found) {
found += strlen(begin);
char *found_end = strcasestr(found, end);
if (found_end) {
*out = calloc(1, found_end - found + 1);
ESP_RETURN_ON_FALSE(*out, ESP_ERR_NO_MEM, TAG, "Memory exhausted");
memcpy(*out, found, found_end - found);
}
}
return ESP_OK;
}
esp_err_t http_utils_get_substring_after(const char *str, const char *begin, char **out)
{
*out = NULL;
char *found = strcasestr(str, begin);
if (found) {
found += strlen(begin);
char *found_end = (char *)str + strlen(str);
if (found_end) {
*out = calloc(1, found_end - found + 1);
ESP_RETURN_ON_FALSE(*out, ESP_ERR_NO_MEM, TAG, "Memory exhausted");
memcpy(*out, found, found_end - found);
}
}
return ESP_OK;
}
int http_utils_str_starts_with(const char *str, const char *start)
{
int i;

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -13,7 +13,7 @@
* @brief Assign new_str to *str pointer, and realloc *str if it not NULL
*
* @param str pointer to string pointer
* @param new_str assign this tring to str
* @param new_str assign this string to str
* @param len length of string, less than 0 if new_str is zero terminated
*
* @return
@ -53,7 +53,7 @@ void http_utils_trim_whitespace(char **str);
*
* @return The string between begin and end
*/
char *http_utils_get_string_between(const char *str, const char *begin, const char *end);
char *http_utils_get_string_between(const char *str, const char *begin, const char *end) __attribute__((deprecated("Use http_utils_get_substring_between instead.")));;
/**
* @brief Returns a string that contains the part after the search string till the end of the source string.
@ -64,7 +64,38 @@ char *http_utils_get_string_between(const char *str, const char *begin, const ch
*
* @return The string between begin and the end of str
*/
char *http_utils_get_string_after(const char *str, const char *begin);
char *http_utils_get_string_after(const char *str, const char *begin) __attribute__((deprecated("Use http_utils_get_substring_after instead.")));;
/**
* @brief Extracts the substring between two specified delimiters.
* Allocates memory for the extracted substring and stores it in `out`.
* The caller must free the allocated memory when no longer needed.
*
* @param[in] str The source string to search.
* @param[in] begin The starting delimiter string.
* @param[in] end The ending delimiter string.
* @param[out] out Pointer to store the allocated substring. Set to NULL if the substring is not found.
*
* @return
* - ESP_OK: Operation succeeded (even if no substring is found).
* - ESP_ERR_NO_MEM: Memory allocation failed.
*/
esp_err_t http_utils_get_substring_between(const char *str, const char *begin, const char *end, char **out);
/**
* @brief Extracts the substring starting after a specified delimiter until the end of the source string.
* Allocates memory for the extracted substring and stores it in `out`.
* The caller must free the allocated memory when no longer needed.
*
* @param[in] str The source string to search.
* @param[in] begin The delimiter string to search for.
* @param[out] out Pointer to store the allocated substring. Set to NULL if the substring is not found.
*
* @return
* - ESP_OK: Operation succeeded (even if no substring is found).
* - ESP_ERR_NO_MEM: Memory allocation failed.
*/
esp_err_t http_utils_get_substring_after(const char *str, const char *begin, char **out);
/**
* @brief Join 2 strings to one

View File

@ -96,8 +96,7 @@ static bool process_again(int status_code)
static esp_err_t _http_handle_response_code(esp_https_ota_t *https_ota_handle, int status_code)
{
esp_err_t err;
esp_err_t err = ESP_FAIL;
if (redirection_required(status_code)) {
err = esp_http_client_set_redirection(https_ota_handle->http_client);
if (err != ESP_OK) {
@ -113,7 +112,11 @@ static esp_err_t _http_handle_response_code(esp_https_ota_t *https_ota_handle, i
return ESP_FAIL;
}
https_ota_handle->max_authorization_retries--;
esp_http_client_add_auth(https_ota_handle->http_client);
err = esp_http_client_add_auth(https_ota_handle->http_client);
if (err!= ESP_OK) {
ESP_LOGE(TAG, "Authorization Failed");
return err;
}
} else if(status_code == HttpStatus_NotFound || status_code == HttpStatus_Forbidden) {
ESP_LOGE(TAG, "File not found(%d)", status_code);
return ESP_FAIL;