|  | @@ -11,7 +11,11 @@
 | 
	
		
			
				|  |  |  #include <stdint.h>
 | 
	
		
			
				|  |  |  #include <string.h>
 | 
	
		
			
				|  |  |  #include <ctype.h>
 | 
	
		
			
				|  |  | +#include "freertos/FreeRTOS.h"
 | 
	
		
			
				|  |  | +#include "freertos/task.h"
 | 
	
		
			
				|  |  |  #include "tools.h"
 | 
	
		
			
				|  |  | +#include "esp_tls.h"
 | 
	
		
			
				|  |  | +#include "esp_http_client.h"
 | 
	
		
			
				|  |  |  #include "esp_heap_caps.h"
 | 
	
		
			
				|  |  |  #include "esp_log.h"
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -171,3 +175,104 @@ char * strdup_psram(const char * source){
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	return ptr;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/****************************************************************************************
 | 
	
		
			
				|  |  | + * URL download 
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | + 
 | 
	
		
			
				|  |  | +typedef struct {
 | 
	
		
			
				|  |  | +	void *user_context;
 | 
	
		
			
				|  |  | +	http_download_cb_t callback;	
 | 
	
		
			
				|  |  | +	size_t max, bytes;
 | 
	
		
			
				|  |  | +	bool abort;
 | 
	
		
			
				|  |  | +	uint8_t *data;
 | 
	
		
			
				|  |  | +	char *url;
 | 
	
		
			
				|  |  | +} http_context_t;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void http_downloader(void *arg);
 | 
	
		
			
				|  |  | +static esp_err_t http_event_handler(esp_http_client_event_t *evt);
 | 
	
		
			
				|  |  | + 
 | 
	
		
			
				|  |  | +void http_download(char *url, size_t max, http_download_cb_t callback, void *context) {
 | 
	
		
			
				|  |  | +	http_context_t *http_context = (http_context_t*) heap_caps_calloc(sizeof(http_context_t), 1, MALLOC_CAP_SPIRAM);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	http_context->callback = callback;
 | 
	
		
			
				|  |  | +	http_context->user_context = context;
 | 
	
		
			
				|  |  | +	http_context->max = max;
 | 
	
		
			
				|  |  | +	http_context->url = strdup(url);
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	xTaskCreate(http_downloader, "downloader", 4*1024, http_context, ESP_TASK_PRIO_MIN + 1, NULL);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void http_downloader(void *arg) {
 | 
	
		
			
				|  |  | +	http_context_t *http_context = (http_context_t*) arg;
 | 
	
		
			
				|  |  | +	esp_http_client_config_t config = {
 | 
	
		
			
				|  |  | +		.url = http_context->url,
 | 
	
		
			
				|  |  | +		.event_handler = http_event_handler,
 | 
	
		
			
				|  |  | +		.user_data = http_context,
 | 
	
		
			
				|  |  | +		//.cert_pem = howsmyssl_com_root_cert_pem_start,
 | 
	
		
			
				|  |  | +		//.skip_cert_common_name_check = true,
 | 
	
		
			
				|  |  | +	};	
 | 
	
		
			
				|  |  | +		
 | 
	
		
			
				|  |  | +	esp_http_client_handle_t client = esp_http_client_init(&config);
 | 
	
		
			
				|  |  | +	esp_http_client_perform(client);
 | 
	
		
			
				|  |  | +//		esp_http_client_cleanup(client);
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	free(http_context->url);
 | 
	
		
			
				|  |  | +	free(http_context);
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	vTaskDelete(NULL);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static esp_err_t http_event_handler(esp_http_client_event_t *evt) {
 | 
	
		
			
				|  |  | +	http_context_t *http_context = (http_context_t*) evt->user_data;
 | 
	
		
			
				|  |  | +		
 | 
	
		
			
				|  |  | +	if (http_context->abort) return ESP_FAIL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	switch(evt->event_id) {
 | 
	
		
			
				|  |  | +	case HTTP_EVENT_ERROR:
 | 
	
		
			
				|  |  | +		http_context->callback(NULL, 0, http_context->user_context);
 | 
	
		
			
				|  |  | +		http_context->abort = true;
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +	case HTTP_EVENT_ON_HEADER:
 | 
	
		
			
				|  |  | +		if (!strcasecmp(evt->header_key, "Content-Length")) {
 | 
	
		
			
				|  |  | +			size_t len = atoi(evt->header_value);
 | 
	
		
			
				|  |  | +			if (!len || len > http_context->max) {
 | 
	
		
			
				|  |  | +				ESP_LOGI(TAG, "content-length null or too large %zu / %zu", len, http_context->max);			
 | 
	
		
			
				|  |  | +				http_context->abort = true;
 | 
	
		
			
				|  |  | +			}	
 | 
	
		
			
				|  |  | +		}	
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +	case HTTP_EVENT_ON_DATA: {
 | 
	
		
			
				|  |  | +		size_t len = esp_http_client_get_content_length(evt->client);
 | 
	
		
			
				|  |  | +		if (!http_context->data) {
 | 
	
		
			
				|  |  | +			if ((http_context->data = (uint8_t*) malloc(len)) == NULL) {
 | 
	
		
			
				|  |  | +				http_context->abort = true;
 | 
	
		
			
				|  |  | +				ESP_LOGE(TAG, "gailed to allocate memory for output buffer %zu", len);
 | 
	
		
			
				|  |  | +				return ESP_FAIL;
 | 
	
		
			
				|  |  | +			}	
 | 
	
		
			
				|  |  | +		}	
 | 
	
		
			
				|  |  | +		memcpy(http_context->data + http_context->bytes, evt->data, evt->data_len);
 | 
	
		
			
				|  |  | +		http_context->bytes += evt->data_len;
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +	}	
 | 
	
		
			
				|  |  | +	case HTTP_EVENT_ON_FINISH:
 | 
	
		
			
				|  |  | +		http_context->callback(http_context->data, http_context->bytes, http_context->user_context);			
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +	case HTTP_EVENT_DISCONNECTED: {
 | 
	
		
			
				|  |  | +		int mbedtls_err = 0;
 | 
	
		
			
				|  |  | +		esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
 | 
	
		
			
				|  |  | +		if (err != ESP_OK) {
 | 
	
		
			
				|  |  | +			ESP_LOGE(TAG, "HTTP download disconnect %d", err);				
 | 
	
		
			
				|  |  | +			if (http_context->data) free(http_context->data);
 | 
	
		
			
				|  |  | +			http_context->callback(NULL, 0, http_context->user_context);		
 | 
	
		
			
				|  |  | +			return ESP_FAIL;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +	default:
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +	}	
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	return ESP_OK;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | + 
 |