esp_https_ota.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. /*
  2. * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <esp_https_ota.h>
  10. #include <esp_log.h>
  11. #include <esp_ota_ops.h>
  12. #include <errno.h>
  13. #include <sys/param.h>
  14. #define IMAGE_HEADER_SIZE (1024)
  15. /* This is kept sufficiently large enough to cover image format headers
  16. * and also this defines default minimum OTA buffer chunk size */
  17. #define DEFAULT_OTA_BUF_SIZE (IMAGE_HEADER_SIZE)
  18. _Static_assert(DEFAULT_OTA_BUF_SIZE > (sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1), "OTA data buffer too small");
  19. #define DEFAULT_REQUEST_SIZE (64 * 1024)
  20. static const char *TAG = "esp_https_ota";
  21. typedef enum {
  22. ESP_HTTPS_OTA_INIT,
  23. ESP_HTTPS_OTA_BEGIN,
  24. ESP_HTTPS_OTA_IN_PROGRESS,
  25. ESP_HTTPS_OTA_SUCCESS,
  26. } esp_https_ota_state;
  27. struct esp_https_ota_handle {
  28. esp_ota_handle_t update_handle;
  29. const esp_partition_t *update_partition;
  30. esp_http_client_handle_t http_client;
  31. char *ota_upgrade_buf;
  32. size_t ota_upgrade_buf_size;
  33. int binary_file_len;
  34. int image_length;
  35. int max_http_request_size;
  36. esp_https_ota_state state;
  37. bool bulk_flash_erase;
  38. bool partial_http_download;
  39. #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  40. decrypt_cb_t decrypt_cb;
  41. void *decrypt_user_ctx;
  42. #endif
  43. };
  44. typedef struct esp_https_ota_handle esp_https_ota_t;
  45. static bool redirection_required(int status_code)
  46. {
  47. switch (status_code) {
  48. case HttpStatus_MovedPermanently:
  49. case HttpStatus_Found:
  50. case HttpStatus_SeeOther:
  51. case HttpStatus_TemporaryRedirect:
  52. case HttpStatus_PermanentRedirect:
  53. return true;
  54. default:
  55. return false;
  56. }
  57. return false;
  58. }
  59. static bool process_again(int status_code)
  60. {
  61. switch (status_code) {
  62. case HttpStatus_MovedPermanently:
  63. case HttpStatus_Found:
  64. case HttpStatus_SeeOther:
  65. case HttpStatus_TemporaryRedirect:
  66. case HttpStatus_PermanentRedirect:
  67. case HttpStatus_Unauthorized:
  68. return true;
  69. default:
  70. return false;
  71. }
  72. return false;
  73. }
  74. static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client, int status_code)
  75. {
  76. esp_err_t err;
  77. if (redirection_required(status_code)) {
  78. err = esp_http_client_set_redirection(http_client);
  79. if (err != ESP_OK) {
  80. ESP_LOGE(TAG, "URL redirection Failed");
  81. return err;
  82. }
  83. } else if (status_code == HttpStatus_Unauthorized) {
  84. esp_http_client_add_auth(http_client);
  85. } else if(status_code == HttpStatus_NotFound || status_code == HttpStatus_Forbidden) {
  86. ESP_LOGE(TAG, "File not found(%d)", status_code);
  87. return ESP_FAIL;
  88. } else if (status_code >= HttpStatus_BadRequest && status_code < HttpStatus_InternalError) {
  89. ESP_LOGE(TAG, "Client error (%d)", status_code);
  90. return ESP_FAIL;
  91. } else if (status_code >= HttpStatus_InternalError) {
  92. ESP_LOGE(TAG, "Server error (%d)", status_code);
  93. return ESP_FAIL;
  94. }
  95. char upgrade_data_buf[256];
  96. // process_again() returns true only in case of redirection.
  97. if (process_again(status_code)) {
  98. while (1) {
  99. /*
  100. * In case of redirection, esp_http_client_read() is called
  101. * to clear the response buffer of http_client.
  102. */
  103. int data_read = esp_http_client_read(http_client, upgrade_data_buf, sizeof(upgrade_data_buf));
  104. if (data_read <= 0) {
  105. return ESP_OK;
  106. }
  107. }
  108. }
  109. return ESP_OK;
  110. }
  111. static esp_err_t _http_connect(esp_http_client_handle_t http_client)
  112. {
  113. esp_err_t err = ESP_FAIL;
  114. int status_code, header_ret;
  115. do {
  116. char *post_data = NULL;
  117. /* Send POST request if body is set.
  118. * Note: Sending POST request is not supported if partial_http_download
  119. * is enabled
  120. */
  121. int post_len = esp_http_client_get_post_field(http_client, &post_data);
  122. err = esp_http_client_open(http_client, post_len);
  123. if (err != ESP_OK) {
  124. ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
  125. return err;
  126. }
  127. if (post_len) {
  128. int write_len = 0;
  129. while (post_len > 0) {
  130. write_len = esp_http_client_write(http_client, post_data, post_len);
  131. if (write_len < 0) {
  132. ESP_LOGE(TAG, "Write failed");
  133. return ESP_FAIL;
  134. }
  135. post_len -= write_len;
  136. post_data += write_len;
  137. }
  138. }
  139. header_ret = esp_http_client_fetch_headers(http_client);
  140. if (header_ret < 0) {
  141. return header_ret;
  142. }
  143. status_code = esp_http_client_get_status_code(http_client);
  144. err = _http_handle_response_code(http_client, status_code);
  145. if (err != ESP_OK) {
  146. return err;
  147. }
  148. } while (process_again(status_code));
  149. return err;
  150. }
  151. static void _http_cleanup(esp_http_client_handle_t client)
  152. {
  153. esp_http_client_close(client);
  154. esp_http_client_cleanup(client);
  155. }
  156. #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  157. static esp_err_t esp_https_ota_decrypt_cb(esp_https_ota_t *handle, decrypt_cb_arg_t *args)
  158. {
  159. esp_err_t ret = handle->decrypt_cb(args, handle->decrypt_user_ctx);
  160. if (ret != ESP_OK) {
  161. ESP_LOGE(TAG, "Decrypt callback failed %d", ret);
  162. return ret;
  163. }
  164. if (args->data_out_len > 0) {
  165. return ESP_OK;
  166. } else {
  167. return ESP_HTTPS_OTA_IN_PROGRESS;
  168. }
  169. }
  170. static void esp_https_ota_decrypt_cb_free_buf(void *buffer)
  171. {
  172. free(buffer);
  173. }
  174. #endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  175. static esp_err_t _ota_write(esp_https_ota_t *https_ota_handle, const void *buffer, size_t buf_len)
  176. {
  177. if (buffer == NULL || https_ota_handle == NULL) {
  178. return ESP_FAIL;
  179. }
  180. esp_err_t err = esp_ota_write(https_ota_handle->update_handle, buffer, buf_len);
  181. if (err != ESP_OK) {
  182. ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err);
  183. } else {
  184. https_ota_handle->binary_file_len += buf_len;
  185. ESP_LOGD(TAG, "Written image length %d", https_ota_handle->binary_file_len);
  186. err = ESP_ERR_HTTPS_OTA_IN_PROGRESS;
  187. }
  188. #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  189. esp_https_ota_decrypt_cb_free_buf((void *) buffer);
  190. #endif
  191. return err;
  192. }
  193. static bool is_server_verification_enabled(const esp_https_ota_config_t *ota_config) {
  194. return (ota_config->http_config->cert_pem
  195. || ota_config->http_config->use_global_ca_store
  196. || ota_config->http_config->crt_bundle_attach != NULL);
  197. }
  198. esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_https_ota_handle_t *handle)
  199. {
  200. esp_err_t err;
  201. if (handle == NULL || ota_config == NULL || ota_config->http_config == NULL) {
  202. ESP_LOGE(TAG, "esp_https_ota_begin: Invalid argument");
  203. if (handle) {
  204. *handle = NULL;
  205. }
  206. return ESP_ERR_INVALID_ARG;
  207. }
  208. if (!is_server_verification_enabled(ota_config)) {
  209. #if CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP
  210. ESP_LOGW(TAG, "Continuing with insecure option because CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is set.");
  211. #else
  212. ESP_LOGE(TAG, "No option for server verification is enabled in esp_http_client config.");
  213. *handle = NULL;
  214. return ESP_ERR_INVALID_ARG;
  215. #endif
  216. }
  217. esp_https_ota_t *https_ota_handle = calloc(1, sizeof(esp_https_ota_t));
  218. if (!https_ota_handle) {
  219. ESP_LOGE(TAG, "Couldn't allocate memory to upgrade data buffer");
  220. *handle = NULL;
  221. return ESP_ERR_NO_MEM;
  222. }
  223. https_ota_handle->partial_http_download = ota_config->partial_http_download;
  224. https_ota_handle->max_http_request_size = (ota_config->max_http_request_size == 0) ? DEFAULT_REQUEST_SIZE : ota_config->max_http_request_size;
  225. /* Initiate HTTP Connection */
  226. https_ota_handle->http_client = esp_http_client_init(ota_config->http_config);
  227. if (https_ota_handle->http_client == NULL) {
  228. ESP_LOGE(TAG, "Failed to initialise HTTP connection");
  229. err = ESP_FAIL;
  230. goto failure;
  231. }
  232. if (https_ota_handle->partial_http_download) {
  233. esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_HEAD);
  234. err = esp_http_client_perform(https_ota_handle->http_client);
  235. if (err == ESP_OK) {
  236. int status = esp_http_client_get_status_code(https_ota_handle->http_client);
  237. if (status != HttpStatus_Ok) {
  238. ESP_LOGE(TAG, "Received incorrect http status %d", status);
  239. err = ESP_FAIL;
  240. goto http_cleanup;
  241. }
  242. } else {
  243. ESP_LOGE(TAG, "ESP HTTP client perform failed: %d", err);
  244. goto http_cleanup;
  245. }
  246. https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
  247. esp_http_client_close(https_ota_handle->http_client);
  248. if (https_ota_handle->image_length > https_ota_handle->max_http_request_size) {
  249. char *header_val = NULL;
  250. asprintf(&header_val, "bytes=0-%d", https_ota_handle->max_http_request_size - 1);
  251. if (header_val == NULL) {
  252. ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");
  253. err = ESP_ERR_NO_MEM;
  254. goto http_cleanup;
  255. }
  256. esp_http_client_set_header(https_ota_handle->http_client, "Range", header_val);
  257. free(header_val);
  258. }
  259. esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_GET);
  260. }
  261. if (ota_config->http_client_init_cb) {
  262. err = ota_config->http_client_init_cb(https_ota_handle->http_client);
  263. if (err != ESP_OK) {
  264. ESP_LOGE(TAG, "http_client_init_cb returned 0x%x", err);
  265. goto http_cleanup;
  266. }
  267. }
  268. err = _http_connect(https_ota_handle->http_client);
  269. if (err != ESP_OK) {
  270. ESP_LOGE(TAG, "Failed to establish HTTP connection");
  271. goto http_cleanup;
  272. }
  273. if (!https_ota_handle->partial_http_download) {
  274. https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
  275. }
  276. https_ota_handle->update_partition = NULL;
  277. ESP_LOGI(TAG, "Starting OTA...");
  278. https_ota_handle->update_partition = esp_ota_get_next_update_partition(NULL);
  279. if (https_ota_handle->update_partition == NULL) {
  280. ESP_LOGE(TAG, "Passive OTA partition not found");
  281. err = ESP_FAIL;
  282. goto http_cleanup;
  283. }
  284. ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
  285. https_ota_handle->update_partition->subtype, https_ota_handle->update_partition->address);
  286. const int alloc_size = MAX(ota_config->http_config->buffer_size, DEFAULT_OTA_BUF_SIZE);
  287. https_ota_handle->ota_upgrade_buf = (char *)malloc(alloc_size);
  288. if (!https_ota_handle->ota_upgrade_buf) {
  289. ESP_LOGE(TAG, "Couldn't allocate memory to upgrade data buffer");
  290. err = ESP_ERR_NO_MEM;
  291. goto http_cleanup;
  292. }
  293. #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  294. if (ota_config->decrypt_cb == NULL) {
  295. err = ESP_ERR_INVALID_ARG;
  296. goto http_cleanup;
  297. }
  298. https_ota_handle->decrypt_cb = ota_config->decrypt_cb;
  299. https_ota_handle->decrypt_user_ctx = ota_config->decrypt_user_ctx;
  300. #endif
  301. https_ota_handle->ota_upgrade_buf_size = alloc_size;
  302. https_ota_handle->bulk_flash_erase = ota_config->bulk_flash_erase;
  303. https_ota_handle->binary_file_len = 0;
  304. *handle = (esp_https_ota_handle_t)https_ota_handle;
  305. https_ota_handle->state = ESP_HTTPS_OTA_BEGIN;
  306. return ESP_OK;
  307. http_cleanup:
  308. _http_cleanup(https_ota_handle->http_client);
  309. failure:
  310. free(https_ota_handle);
  311. *handle = NULL;
  312. return err;
  313. }
  314. static esp_err_t read_header(esp_https_ota_t *handle)
  315. {
  316. /*
  317. * `data_read_size` holds number of bytes needed to read complete header.
  318. * `bytes_read` holds number of bytes read.
  319. */
  320. int data_read_size = IMAGE_HEADER_SIZE;
  321. int data_read = 0, bytes_read = 0;
  322. /*
  323. * while loop is added to download complete image headers, even if the headers
  324. * are not sent in a single packet.
  325. */
  326. while (data_read_size > 0 && !esp_http_client_is_complete_data_received(handle->http_client)) {
  327. data_read = esp_http_client_read(handle->http_client,
  328. (handle->ota_upgrade_buf + bytes_read),
  329. data_read_size);
  330. if (data_read < 0) {
  331. if (data_read == -ESP_ERR_HTTP_EAGAIN) {
  332. ESP_LOGD(TAG, "ESP_ERR_HTTP_EAGAIN invoked: Call timed out before data was ready");
  333. continue;
  334. }
  335. ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
  336. break;
  337. }
  338. data_read_size -= data_read;
  339. bytes_read += data_read;
  340. }
  341. if (data_read_size > 0) {
  342. ESP_LOGE(TAG, "Complete headers were not received");
  343. return ESP_FAIL;
  344. }
  345. handle->binary_file_len = bytes_read;
  346. return ESP_OK;
  347. }
  348. esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info)
  349. {
  350. #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  351. // This API is not supported in case firmware image is encrypted in nature.
  352. // It is recommended to retrieve image description through decryption callback in application layer.
  353. return ESP_ERR_NOT_SUPPORTED;
  354. #endif
  355. esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
  356. if (handle == NULL || new_app_info == NULL) {
  357. ESP_LOGE(TAG, "esp_https_ota_read_img_desc: Invalid argument");
  358. return ESP_ERR_INVALID_ARG;
  359. }
  360. if (handle->state < ESP_HTTPS_OTA_BEGIN) {
  361. ESP_LOGE(TAG, "esp_https_ota_read_img_desc: Invalid state");
  362. return ESP_ERR_INVALID_STATE;
  363. }
  364. if (read_header(handle) != ESP_OK) {
  365. return ESP_FAIL;
  366. }
  367. const int app_desc_offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t);
  368. esp_app_desc_t *app_info = (esp_app_desc_t *) &handle->ota_upgrade_buf[app_desc_offset];
  369. if (app_info->magic_word != ESP_APP_DESC_MAGIC_WORD) {
  370. ESP_LOGE(TAG, "Incorrect app descriptor magic");
  371. return ESP_FAIL;
  372. }
  373. memcpy(new_app_info, app_info, sizeof(esp_app_desc_t));
  374. return ESP_OK;
  375. }
  376. static esp_err_t esp_ota_verify_chip_id(const void *arg)
  377. {
  378. esp_image_header_t *data = (esp_image_header_t *)(arg);
  379. if (data->chip_id != CONFIG_IDF_FIRMWARE_CHIP_ID) {
  380. ESP_LOGE(TAG, "Mismatch chip id, expected %d, found %d", CONFIG_IDF_FIRMWARE_CHIP_ID, data->chip_id);
  381. return ESP_ERR_INVALID_VERSION;
  382. }
  383. return ESP_OK;
  384. }
  385. esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
  386. {
  387. esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
  388. if (handle == NULL) {
  389. ESP_LOGE(TAG, "esp_https_ota_perform: Invalid argument");
  390. return ESP_ERR_INVALID_ARG;
  391. }
  392. if (handle->state < ESP_HTTPS_OTA_BEGIN) {
  393. ESP_LOGE(TAG, "esp_https_ota_perform: Invalid state");
  394. return ESP_FAIL;
  395. }
  396. esp_err_t err;
  397. int data_read;
  398. const int erase_size = handle->bulk_flash_erase ? OTA_SIZE_UNKNOWN : OTA_WITH_SEQUENTIAL_WRITES;
  399. switch (handle->state) {
  400. case ESP_HTTPS_OTA_BEGIN:
  401. err = esp_ota_begin(handle->update_partition, erase_size, &handle->update_handle);
  402. if (err != ESP_OK) {
  403. ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
  404. return err;
  405. }
  406. handle->state = ESP_HTTPS_OTA_IN_PROGRESS;
  407. /* In case `esp_https_ota_read_img_desc` was invoked first,
  408. then the image data read there should be written to OTA partition
  409. */
  410. int binary_file_len = 0;
  411. if (handle->binary_file_len) {
  412. /*
  413. * Header length gets added to handle->binary_file_len in _ota_write
  414. * Clear handle->binary_file_len to avoid additional 289 bytes in binary_file_len
  415. */
  416. binary_file_len = handle->binary_file_len;
  417. handle->binary_file_len = 0;
  418. } else {
  419. if (read_header(handle) != ESP_OK) {
  420. return ESP_FAIL;
  421. }
  422. binary_file_len = IMAGE_HEADER_SIZE;
  423. }
  424. const void *data_buf = (const void *) handle->ota_upgrade_buf;
  425. #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  426. decrypt_cb_arg_t args = {};
  427. args.data_in = handle->ota_upgrade_buf;
  428. args.data_in_len = binary_file_len;
  429. err = esp_https_ota_decrypt_cb(handle, &args);
  430. if (err == ESP_OK) {
  431. data_buf = args.data_out;
  432. binary_file_len = args.data_out_len;
  433. } else {
  434. ESP_LOGE(TAG, "Decryption of image header failed");
  435. return ESP_FAIL;
  436. }
  437. #endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  438. err = esp_ota_verify_chip_id(data_buf);
  439. if (err != ESP_OK) {
  440. return err;
  441. }
  442. return _ota_write(handle, data_buf, binary_file_len);
  443. case ESP_HTTPS_OTA_IN_PROGRESS:
  444. data_read = esp_http_client_read(handle->http_client,
  445. handle->ota_upgrade_buf,
  446. handle->ota_upgrade_buf_size);
  447. if (data_read == 0) {
  448. /*
  449. * esp_http_client_is_complete_data_received is added to check whether
  450. * complete image is received.
  451. */
  452. if (!esp_http_client_is_complete_data_received(handle->http_client)) {
  453. ESP_LOGE(TAG, "Connection closed before complete data was received!");
  454. return ESP_FAIL;
  455. }
  456. ESP_LOGD(TAG, "Connection closed");
  457. } else if (data_read > 0) {
  458. const void *data_buf = (const void *) handle->ota_upgrade_buf;
  459. int data_len = data_read;
  460. #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  461. decrypt_cb_arg_t args = {};
  462. args.data_in = handle->ota_upgrade_buf;
  463. args.data_in_len = data_read;
  464. err = esp_https_ota_decrypt_cb(handle, &args);
  465. if (err == ESP_OK) {
  466. data_buf = args.data_out;
  467. data_len = args.data_out_len;
  468. } else {
  469. return err;
  470. }
  471. #endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
  472. return _ota_write(handle, data_buf, data_len);
  473. } else {
  474. if (data_read == -ESP_ERR_HTTP_EAGAIN) {
  475. ESP_LOGD(TAG, "ESP_ERR_HTTP_EAGAIN invoked: Call timed out before data was ready");
  476. return ESP_ERR_HTTPS_OTA_IN_PROGRESS;
  477. }
  478. ESP_LOGE(TAG, "data read %d, errno %d", data_read, errno);
  479. return ESP_FAIL;
  480. }
  481. if (!handle->partial_http_download || (handle->partial_http_download && handle->image_length == handle->binary_file_len)) {
  482. handle->state = ESP_HTTPS_OTA_SUCCESS;
  483. }
  484. break;
  485. default:
  486. ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State");
  487. return ESP_FAIL;
  488. break;
  489. }
  490. if (handle->partial_http_download) {
  491. if (handle->state == ESP_HTTPS_OTA_IN_PROGRESS && handle->image_length > handle->binary_file_len) {
  492. esp_http_client_close(handle->http_client);
  493. char *header_val = NULL;
  494. if ((handle->image_length - handle->binary_file_len) > handle->max_http_request_size) {
  495. asprintf(&header_val, "bytes=%d-%d", handle->binary_file_len, (handle->binary_file_len + handle->max_http_request_size - 1));
  496. } else {
  497. asprintf(&header_val, "bytes=%d-", handle->binary_file_len);
  498. }
  499. if (header_val == NULL) {
  500. ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");
  501. return ESP_ERR_NO_MEM;
  502. }
  503. esp_http_client_set_header(handle->http_client, "Range", header_val);
  504. free(header_val);
  505. err = _http_connect(handle->http_client);
  506. if (err != ESP_OK) {
  507. ESP_LOGE(TAG, "Failed to establish HTTP connection");
  508. return ESP_FAIL;
  509. }
  510. ESP_LOGD(TAG, "Connection start");
  511. return ESP_ERR_HTTPS_OTA_IN_PROGRESS;
  512. }
  513. }
  514. return ESP_OK;
  515. }
  516. bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle)
  517. {
  518. bool ret = false;
  519. esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
  520. if (handle->partial_http_download) {
  521. ret = (handle->image_length == handle->binary_file_len);
  522. } else {
  523. ret = esp_http_client_is_complete_data_received(handle->http_client);
  524. }
  525. return ret;
  526. }
  527. esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle)
  528. {
  529. esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
  530. if (handle == NULL) {
  531. return ESP_ERR_INVALID_ARG;
  532. }
  533. if (handle->state < ESP_HTTPS_OTA_BEGIN) {
  534. return ESP_FAIL;
  535. }
  536. esp_err_t err = ESP_OK;
  537. switch (handle->state) {
  538. case ESP_HTTPS_OTA_SUCCESS:
  539. case ESP_HTTPS_OTA_IN_PROGRESS:
  540. err = esp_ota_end(handle->update_handle);
  541. /* falls through */
  542. case ESP_HTTPS_OTA_BEGIN:
  543. if (handle->ota_upgrade_buf) {
  544. free(handle->ota_upgrade_buf);
  545. }
  546. if (handle->http_client) {
  547. _http_cleanup(handle->http_client);
  548. }
  549. break;
  550. default:
  551. ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State");
  552. break;
  553. }
  554. if ((err == ESP_OK) && (handle->state == ESP_HTTPS_OTA_SUCCESS)) {
  555. esp_err_t err = esp_ota_set_boot_partition(handle->update_partition);
  556. if (err != ESP_OK) {
  557. ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err);
  558. }
  559. }
  560. free(handle);
  561. return err;
  562. }
  563. esp_err_t esp_https_ota_abort(esp_https_ota_handle_t https_ota_handle)
  564. {
  565. esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
  566. if (handle == NULL) {
  567. return ESP_ERR_INVALID_ARG;
  568. }
  569. if (handle->state < ESP_HTTPS_OTA_BEGIN) {
  570. return ESP_FAIL;
  571. }
  572. esp_err_t err = ESP_OK;
  573. switch (handle->state) {
  574. case ESP_HTTPS_OTA_SUCCESS:
  575. case ESP_HTTPS_OTA_IN_PROGRESS:
  576. err = esp_ota_abort(handle->update_handle);
  577. /* falls through */
  578. case ESP_HTTPS_OTA_BEGIN:
  579. if (handle->ota_upgrade_buf) {
  580. free(handle->ota_upgrade_buf);
  581. }
  582. if (handle->http_client) {
  583. _http_cleanup(handle->http_client);
  584. }
  585. break;
  586. default:
  587. err = ESP_ERR_INVALID_STATE;
  588. ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State");
  589. break;
  590. }
  591. free(handle);
  592. return err;
  593. }
  594. int esp_https_ota_get_image_len_read(esp_https_ota_handle_t https_ota_handle)
  595. {
  596. esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
  597. if (handle == NULL) {
  598. return -1;
  599. }
  600. if (handle->state < ESP_HTTPS_OTA_IN_PROGRESS) {
  601. return -1;
  602. }
  603. return handle->binary_file_len;
  604. }
  605. int esp_https_ota_get_image_size(esp_https_ota_handle_t https_ota_handle)
  606. {
  607. esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
  608. if (handle == NULL) {
  609. return -1;
  610. }
  611. if (handle->state < ESP_HTTPS_OTA_BEGIN) {
  612. return -1;
  613. }
  614. return handle->image_length;
  615. }
  616. esp_err_t esp_https_ota(const esp_https_ota_config_t *ota_config)
  617. {
  618. if (ota_config == NULL || ota_config->http_config == NULL) {
  619. ESP_LOGE(TAG, "esp_https_ota: Invalid argument");
  620. return ESP_ERR_INVALID_ARG;
  621. }
  622. esp_https_ota_handle_t https_ota_handle = NULL;
  623. esp_err_t err = esp_https_ota_begin(ota_config, &https_ota_handle);
  624. if (https_ota_handle == NULL) {
  625. return ESP_FAIL;
  626. }
  627. while (1) {
  628. err = esp_https_ota_perform(https_ota_handle);
  629. if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
  630. break;
  631. }
  632. }
  633. if (err != ESP_OK) {
  634. esp_https_ota_abort(https_ota_handle);
  635. return err;
  636. }
  637. esp_err_t ota_finish_err = esp_https_ota_finish(https_ota_handle);
  638. if (ota_finish_err != ESP_OK) {
  639. return ota_finish_err;
  640. }
  641. return ESP_OK;
  642. }