esp_https_ota keeps trying to connect after max_authorization_retries

cseligy
Posts: 3
Joined: Thu Mar 16, 2023 8:37 pm

esp_https_ota keeps trying to connect after max_authorization_retries

Postby cseligy » Thu Mar 16, 2023 10:17 pm

I'm using https OTA with basic authentication and max_authorization_retries set to -1. After trying to connect to the server with an incorrect password, esp_https_ota_begin keeps attempting to connect to the server even though I get an error which says "HTTP_CLIENT: Error, reached max_authorization_retries count=0". The continued login attempts result in my server host blocking my IP address for too many failed login attempts.

I am using esp-idf-v5.0.1 with partial downloads disabled.

As far as I can tell, the problem is in _http_connect on esp_https_ota.c because process_again always returns true for the case where a 401 status (HttpStatus_Unauthorized) has been received from the server no matter what value has been set for max_authorization_retries so we never jump out of the loop in _http_connect.
  1.  
  2. static esp_err_t _http_connect(esp_http_client_handle_t http_client)
  3. {
  4.     esp_err_t err = ESP_FAIL;
  5.     int status_code, header_ret;
  6.     do {
  7.         char *post_data = NULL;
  8.         /* Send POST request if body is set.
  9.          * Note: Sending POST request is not supported if partial_http_download
  10.          * is enabled
  11.          */
  12.         int post_len = esp_http_client_get_post_field(http_client, &post_data);
  13.         err = esp_http_client_open(http_client, post_len);
  14.         if (err != ESP_OK) {
  15.             ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
  16.             return err;
  17.         }
  18.         if (post_len) {
  19.             int write_len = 0;
  20.             while (post_len > 0) {
  21.                 write_len = esp_http_client_write(http_client, post_data, post_len);
  22.                 if (write_len < 0) {
  23.                     ESP_LOGE(TAG, "Write failed");
  24.                     return ESP_FAIL;
  25.                 }
  26.                 post_len -= write_len;
  27.                 post_data += write_len;
  28.             }
  29.         }
  30.         header_ret = esp_http_client_fetch_headers(http_client);
  31.         if (header_ret < 0) {
  32.             return header_ret;
  33.         }
  34.         status_code = esp_http_client_get_status_code(http_client);
  35.         err = _http_handle_response_code(http_client, status_code);
  36.         if (err != ESP_OK) {
  37.             return err;
  38.         }
  39.     } while (process_again(status_code));
  40.     return err;
  41. }
  42. static bool process_again(int status_code)
  43. {
  44.     switch (status_code) {
  45.         case HttpStatus_MovedPermanently:
  46.         case HttpStatus_Found:
  47.         case HttpStatus_SeeOther:
  48.         case HttpStatus_TemporaryRedirect:
  49.         case HttpStatus_PermanentRedirect:
  50.         case HttpStatus_Unauthorized:
  51.             return true;
  52.         default:
  53.             return false;
  54.     }
  55.     return false;
  56. }
  57.  
Shouldn't _http_connect jump out of the loop and return an error if max_authorization_retries has been exceeded?

I was able to make it work by adding a function called "esp_http_client_n_retries_exceeded" in esp_http_client.c and then modifying _http_connect in esp_https_ota.c to check it when it checks process_again at the end of the loop. It will fail immediately for the case where max_authorization_retries has been set to 0 or -1 even if the username and password for basic authentication are correct.

If there is a fix that doesn't involve modifying the esp-idf I would love to know. I could hook into http header events and check for 401 status but that seems like a clunky option. This also doesn't work for the case where partial downloads are enabled.
  1. bool esp_http_client_n_retries_exceeded(esp_http_client_handle_t client)
  2. {
  3.     if (client->redirect_counter >= client->max_authorization_retries)
  4.     {
  5.         return true;
  6.     }
  7.     return false;
  8. }
  1. static esp_err_t _http_connect(esp_http_client_handle_t http_client)
  2. {
  3.     esp_err_t err = ESP_FAIL;
  4.     int status_code, header_ret;
  5.     do {
  6.         char *post_data = NULL;
  7.         /* Send POST request if body is set.
  8.          * Note: Sending POST request is not supported if partial_http_download
  9.          * is enabled
  10.          */
  11.         int post_len = esp_http_client_get_post_field(http_client, &post_data);
  12.         err = esp_http_client_open(http_client, post_len);
  13.         if (err != ESP_OK) {
  14.             ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
  15.             return err;
  16.         }
  17.         if (post_len) {
  18.             int write_len = 0;
  19.             while (post_len > 0) {
  20.                 write_len = esp_http_client_write(http_client, post_data, post_len);
  21.                 if (write_len < 0) {
  22.                     ESP_LOGE(TAG, "Write failed");
  23.                     return ESP_FAIL;
  24.                 }
  25.                 post_len -= write_len;
  26.                 post_data += write_len;
  27.             }
  28.         }
  29.         header_ret = esp_http_client_fetch_headers(http_client);
  30.         if (header_ret < 0) {
  31.             return header_ret;
  32.         }
  33.         status_code = esp_http_client_get_status_code(http_client);
  34.         err = _http_handle_response_code(http_client, status_code);
  35.         if (err != ESP_OK) {
  36.             return err;
  37.         }
  38.     } while (process_again(status_code) && !esp_http_client_n_retries_exceeded(http_client));
  39.     // if we exceeded our number of authentication retries return an error
  40.     if (esp_http_client_n_retries_exceeded(http_client))
  41.     {
  42.         ESP_LOGE(TAG,"n retries exceeded");
  43.         err = ESP_FAIL;
  44.     }
  45.     return err;
  46. }

ESP_harshal
Posts: 24
Joined: Wed Jul 06, 2022 8:36 am

Re: esp_https_ota keeps trying to connect after max_authorization_retries

Postby ESP_harshal » Thu Mar 23, 2023 10:12 am

Hello @cseligy,

Thank you for the report!
Please find attached a patch that should solve the issue. Could you please try applying the patch and testing it in your setup? Do let me know if this solves your issue.

Thank you.

cseligy
Posts: 3
Joined: Thu Mar 16, 2023 8:37 pm

Re: esp_https_ota keeps trying to connect after max_authorization_retries

Postby cseligy » Fri Mar 24, 2023 2:06 pm

Hi @ESP_harshal,

thanks for the response.

Please pardon my ignorance but how exactly do I apply this patch?

I got an error when I tried the command below.

Code: Select all

C:\Espressif\frameworks\esp-idf-v5.0.1>git am --keep-cr ../0001-esp_https_ota-Set-user-configurable-ota-authorizatio.txt
error: patch failed: components/esp_https_ota/src/esp_https_ota.c:25
error: components/esp_https_ota/src/esp_https_ota.c: patch does not apply
hint: Use 'git am --show-current-patch' to see the failed patch
Applying: esp_https_ota: Set user configurable ota authorization retries
Patch failed at 0001 esp_https_ota: Set user configurable ota authorization retries
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

cseligy
Posts: 3
Joined: Thu Mar 16, 2023 8:37 pm

Re: esp_https_ota keeps trying to connect after max_authorization_retries

Postby cseligy » Fri Mar 24, 2023 3:24 pm

Hi @ESP_harshal,

I was able to apply the patch and it works. Thanks for your help!

ESP_harshal
Posts: 24
Joined: Wed Jul 06, 2022 8:36 am

Re: esp_https_ota keeps trying to connect after max_authorization_retries

Postby ESP_harshal » Mon Apr 03, 2023 4:18 am

The patch has now been merged. (ref: https://github.com/espressif/esp-idf/co ... ae9eee8fa5)

Who is online

Users browsing this forum: Bing [Bot] and 127 guests