ESP32 only sends the first chunk

itsterit
Posts: 1
Joined: Wed Feb 15, 2023 7:16 am

ESP32 only sends the first chunk

Postby itsterit » Mon Oct 23, 2023 8:19 am

I'm using esp-idf 4.4 and olimex ESP32-EVB-EA-IND. When sending a document, the controller says that everything has been sent, but the client correctly receives only the first chunk. If you set the chunk size to be larger than the file being sent, then the sending occurs successfully.

when I receive the ip the following code is executed:
  1. #include "web_controller.h"
  2. #include "def_page.h"
  3. #include "esp_spiffs.h"
  4. static const char *TAG = "web_controller";
  5.  
  6. #define WEB_MAX_HTTP_CHUNK (128)
  7. #define MAIN_CONTENT_RAM_SIZE (1024 * 52)
  8. static int main_content_length;
  9. uint32_t *main_content_ram_clone;
  10.  
  11. esp_vfs_spiffs_conf_t config = {
  12.     .base_path = "/spiffs",
  13.     .partition_label = NULL,
  14.     .max_files = 3,
  15.     .format_if_mount_failed = true,
  16. };
  17.  
  18. /**
  19.  * @brief Set HTTP response content
  20.  */
  21. static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath)
  22. {
  23.     const char *type = "text/plain";
  24.     if (CHECK_FILE_EXTENSION(filepath, ".html"))
  25.     {
  26.         type = "text/html";
  27.     }
  28.     else if (CHECK_FILE_EXTENSION(filepath, ".js"))
  29.     {
  30.         type = "application/javascript";
  31.     }
  32.     else if (CHECK_FILE_EXTENSION(filepath, ".css"))
  33.     {
  34.         type = "text/css";
  35.     }
  36.     else if (CHECK_FILE_EXTENSION(filepath, ".png"))
  37.     {
  38.         type = "image/png";
  39.     }
  40.     else if (CHECK_FILE_EXTENSION(filepath, ".ico"))
  41.     {
  42.         type = "image/x-icon";
  43.     }
  44.     else if (CHECK_FILE_EXTENSION(filepath, ".svg"))
  45.     {
  46.         type = "text/xml";
  47.     }
  48.     else if (CHECK_FILE_EXTENSION(filepath, ".irz"))
  49.     {
  50.         type = "application/octet-stream";
  51.     }
  52.     return httpd_resp_set_type(req, type);
  53. }
  54.  
  55. void start_web_controller(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
  56. {
  57.     httpd_handle_t server = NULL;
  58.     httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  59.     config.lru_purge_enable = true;
  60.     config.uri_match_fn = httpd_uri_match_wildcard;
  61.     config.stack_size = 1024 * 22;
  62.     config.max_uri_handlers = 14;
  63.     config.max_open_sockets = 10;
  64.     config.backlog_conn = 0;
  65.  
  66.     ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
  67.     if (httpd_start(&server, &config) == ESP_OK)
  68.     {
  69.         ESP_LOGI(TAG, "Registering URI handlers");
  70.         httpd_register_uri_handler(server, &main_uri);
  71.         httpd_register_uri_handler(server, &get_uri);
  72.     }
  73.     else
  74.     {
  75.         ESP_LOGE(TAG, "Error starting server!");
  76.     }
  77. }
  78.  
  79. esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
  80. {
  81.     /* For any other URI send 404 and close socket */
  82.     httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Some 404 error message");
  83.     return ESP_FAIL;
  84. }
  85.  
  86. /**
  87.  * @brief обработчики запросов от клиента
  88.  *
  89.  * @param[in] filepath       путь до файла
  90.  * @param[in] content_clone  указатель на начало файла
  91.  * @param[in] content_length размерность файла
  92.  * @param[out] status        вернем 1, если смогли выделить память и считать файл
  93.  */
  94. bool read_file(const char *filepath, uint32_t *content_clone, int *content_length, const esp_vfs_spiffs_conf_t *conf, uint32_t ram_content_size)
  95. {
  96.     esp_vfs_spiffs_register(conf);
  97.     *content_clone = calloc(ram_content_size, 1);
  98.     int spiffs_file = open(filepath, O_RDONLY, 0);
  99.  
  100.     if (*content_clone == NULL)
  101.     {
  102.         ESP_LOGE(TAG, "Allocation failure!");
  103.     }
  104.     if (spiffs_file == -1)
  105.     {
  106.         ESP_LOGE(TAG, "File does not exist!");
  107.     }
  108.  
  109.     if (*content_clone != NULL && spiffs_file)
  110.     {
  111.         *content_length = read(spiffs_file, *content_clone, ram_content_size);
  112.         if (*content_length < ram_content_size)
  113.         {
  114.             ESP_LOGI(TAG, "File reading ok (%d bytes)", *content_length);
  115.             esp_vfs_spiffs_unregister(NULL);
  116.             close(spiffs_file);
  117.             return true;
  118.         }
  119.         else
  120.         {
  121.             ESP_LOGE(TAG, "Allocation failure! (content_length < ram_content_size)");
  122.         }
  123.     }
  124.  
  125.     free(*content_clone);
  126.     close(spiffs_file);
  127.     esp_vfs_spiffs_unregister(NULL);
  128.     return false;
  129. }
  130.  
  131. bool send_file(httpd_req_t *req, uint32_t chunk_size, int content_length, uint32_t *content_clone)
  132. {
  133.     httpd_resp_set_type(req, "text/html");
  134.     httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
  135.  
  136.     uint32_t cur_pos = 0;
  137.     uint32_t err_cnt = 0;
  138.  
  139.     while (1)
  140.     {
  141.         if (chunk_size > content_length - cur_pos)
  142.         {
  143.             ESP_LOGW(TAG, "Last package (%d bytes)", (content_length - cur_pos));
  144.             httpd_resp_send_chunk(req, (const char *)(content_clone + cur_pos), content_length - cur_pos);
  145.             ESP_LOGI(TAG, "File sent");
  146.             httpd_resp_send_chunk(req, NULL, 0);
  147.             return true;
  148.         }
  149.         else
  150.         {
  151.             if (httpd_resp_send_chunk(req, (const char *)(content_clone + cur_pos), chunk_size) != ESP_OK)
  152.             {
  153.                 ESP_LOGE(TAG, "Chunk not sent");
  154.                 if (err_cnt++ >= 100)
  155.                 {
  156.                     free(content_clone);
  157.                     return false;
  158.                 }
  159.             }
  160.             else
  161.             {
  162.                 cur_pos += chunk_size;
  163.             }
  164.         }
  165.     }
  166. }
  167.  
  168. static esp_err_t main_handler(httpd_req_t *req)
  169. {
  170.     // if (read_file("/spiffs/img.png", &main_content_ram_clone, &main_content_length, &config, MAIN_CONTENT_RAM_SIZE))
  171.     if (read_file("/spiffs/index.html.gz", &main_content_ram_clone, &main_content_length, &config, MAIN_CONTENT_RAM_SIZE))
  172.     {
  173.         if (send_file(req, WEB_MAX_HTTP_CHUNK, main_content_length, main_content_ram_clone))
  174.         {
  175.             free(main_content_ram_clone);
  176.             return ESP_OK;
  177.         }
  178.     }
  179.  
  180.     httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, error_page_404);
  181.     return ESP_FAIL;
  182. }
  183.  
  184. static esp_err_t common_get_uri(httpd_req_t *req)
  185. {
  186.     ESP_LOGW(TAG, "Request to receive: %s", req->uri);
  187.  
  188.     httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, error_page_404);
  189.     return ESP_FAIL;
  190. }
Attachments
image_file.png
image_file.png (89.77 KiB) Viewed 663 times
image_cons.png
image_cons.png (167.31 KiB) Viewed 663 times
image.png
image.png (67.67 KiB) Viewed 663 times

MicroController
Posts: 1708
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: ESP32 only sends the first chunk

Postby MicroController » Mon Oct 23, 2023 11:52 am

I find it confusing, and error-prone, to use uint32_t to pass around pointers.

MicroController
Posts: 1708
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: ESP32 only sends the first chunk

Postby MicroController » Mon Oct 23, 2023 1:35 pm

httpd_resp_send_chunk():
When you are finished sending all your chunks, you must call this function with buf_len as 0.

Who is online

Users browsing this forum: No registered users and 82 guests