diff --git a/components/esp_common/include/esp_check.h b/components/esp_common/include/esp_check.h index 7042f29d57..56f2cbbc47 100644 --- a/components/esp_common/include/esp_check.h +++ b/components/esp_common/include/esp_check.h @@ -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. */ diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index d54558ec16..be488f69f7 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -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; } } diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index 86274bdae5..1a2bc79436 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -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. diff --git a/components/esp_http_client/lib/http_header.c b/components/esp_http_client/lib/http_header.c index 578eb788e1..74cbbef0bc 100644 --- a/components/esp_http_client/lib/http_header.c +++ b/components/esp_http_client/lib/http_header.c @@ -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) { diff --git a/components/esp_http_client/lib/http_utils.c b/components/esp_http_client/lib/http_utils.c index a47796c187..8e53fb1fd6 100644 --- a/components/esp_http_client/lib/http_utils.c +++ b/components/esp_http_client/lib/http_utils.c @@ -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 #include +#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; diff --git a/components/esp_http_client/lib/include/http_utils.h b/components/esp_http_client/lib/include/http_utils.h index e3758e3f3d..113c76be59 100644 --- a/components/esp_http_client/lib/include/http_utils.h +++ b/components/esp_http_client/lib/include/http_utils.h @@ -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 diff --git a/components/esp_https_ota/src/esp_https_ota.c b/components/esp_https_ota/src/esp_https_ota.c index ba8a5e5fc6..197ab8170c 100644 --- a/components/esp_https_ota/src/esp_https_ota.c +++ b/components/esp_https_ota/src/esp_https_ota.c @@ -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;