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