#include #include "esp_crt_bundle.h" #include "esp_http_client.h" #include "esp_log.h" #include "esp_wifi.h" #include "freertos/semphr.h" #include #include "https_request.h" static SemaphoreHandle_t mutex = NULL; static char** output_buffer; static unsigned int output_len; static char*** output_headers; static unsigned int output_header_len; static int http_code; static EventGroupHandle_t https_event_group; esp_http_client_handle_t client; esp_err_t http_event_handler(esp_http_client_event_t *evt) { const char* TAG = "http_event_handler"; size_t copy_len; size_t content_len; size_t header_len; void* newptr; switch (evt->event_id) { case HTTP_EVENT_ERROR: ESP_LOGE(TAG, "HTTP_EVENT_ERROR, data=%s", (char*)evt->data); xEventGroupSetBits(https_event_group, HTTPS_ERROR_BIT); break; case HTTP_EVENT_ON_CONNECTED: ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); break; case HTTP_EVENT_HEADER_SENT: ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT"); break; case HTTP_EVENT_ON_HEADER: ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, %s=%s", evt->header_key, evt->header_value); header_len = strlen(evt->header_key) + strlen(evt->header_value) + 1; newptr = realloc(*output_headers, (output_header_len + 1) * sizeof(char*)); if(newptr == NULL) { ESP_LOGE(TAG, "Failed to realloc memory for output headers"); xEventGroupSetBits(https_event_group, HTTPS_ERROR_BIT); return ESP_FAIL; } *output_headers = (char**)newptr; newptr = malloc(header_len + 1); if(newptr == NULL) { ESP_LOGE(TAG, "Failed to alloc memory for output header"); xEventGroupSetBits(https_event_group, HTTPS_ERROR_BIT); return ESP_FAIL; } (*output_headers)[output_header_len] = (char*)newptr; snprintf((*output_headers)[output_header_len++], header_len + 1, "%s=%s", evt->header_key, evt->header_value); break; case HTTP_EVENT_ON_DATA: ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len); content_len = esp_http_client_get_content_length(evt->client); if (*output_buffer == NULL) { *output_buffer = (char*)malloc(content_len + 1); output_len = 0; if (*output_buffer == NULL) { ESP_LOGE(TAG, "Failed to allocate memory for output buffer"); xEventGroupSetBits(https_event_group, HTTPS_ERROR_BIT); return ESP_FAIL; } } copy_len = MIN(evt->data_len, (content_len - output_len)); if (copy_len) { memcpy((*output_buffer) + output_len, evt->data, copy_len); } output_len += copy_len; break; case HTTP_EVENT_ON_FINISH: ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH"); (*output_buffer)[output_len] = '\0'; http_code = esp_http_client_get_status_code(evt->client); newptr = realloc(*output_headers, (output_header_len + 1) * sizeof(char*)); if(newptr == NULL) { ESP_LOGE(TAG, "Failed to realloc memory for output headers"); xEventGroupSetBits(https_event_group, HTTPS_ERROR_BIT); return ESP_FAIL; } *output_headers = (char**)newptr; (*output_headers)[output_header_len++] = NULL; xEventGroupSetBits(https_event_group, HTTPS_FINISHED_BIT); break; case HTTP_EVENT_DISCONNECTED: ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED"); break; case HTTP_EVENT_REDIRECT: ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT"); break; } return ESP_OK; } esp_err_t init_https() { https_event_group = xEventGroupCreate(); mutex = xSemaphoreCreateMutex(); esp_http_client_config_t config = { .url = "https://ima.lol", .event_handler = http_event_handler, .crt_bundle_attach = esp_crt_bundle_attach, }; client = esp_http_client_init(&config); return ESP_OK; } void free_https_response(char*** response_headers, char** response) { unsigned int i; if(*response_headers != NULL) { for(i = 0; (*response_headers)[i] != NULL; ++i) { if((*response_headers)[i] != NULL) { free((*response_headers)[i]); (*response_headers)[i] = NULL; } } free(*response_headers); *response_headers = NULL; } if(*response != NULL) { free(*response); *response = NULL; } } esp_err_t do_https_request(const char* url, esp_http_client_method_t method, const char** headers, char*** response_headers, char** response, int* code) { const char* TAG = "do_https_request"; ESP_LOGI(TAG, "https request: method=%d url=%s", method, url); if(xSemaphoreTake(mutex, 5000 / portTICK_PERIOD_MS ) == pdTRUE) { ESP_LOGD(TAG, "obtained https mutex"); output_buffer = response; output_headers = response_headers; *output_buffer = NULL; *output_headers = NULL; output_len = 0; output_header_len = 0; esp_err_t err = esp_http_client_set_url(client, url); if(err != ESP_OK) { ESP_LOGE(TAG, "Unable to set HTTP client url"); return err; } err = esp_http_client_set_method(client, method); if(err != ESP_OK) { ESP_LOGE(TAG, "Unable to set HTTP client method"); return err; } for(unsigned int i = 0; headers[i] != NULL; ++i) { unsigned int j; char* header = strdup(headers[i]); for(j = 0; header[j] != '='; ++j) { // skip } header[j] = '\0'; ESP_LOGD(TAG, "setting header: key=%s, val=%s", header, header + j + 1); esp_http_client_set_header(client, header, header + j + 1); free(header); } esp_http_client_perform(client); EventBits_t bits = xEventGroupWaitBits( https_event_group, HTTPS_FINISHED_BIT | HTTPS_ERROR_BIT, pdFALSE, pdFALSE, portMAX_DELAY ); if (bits & HTTPS_ERROR_BIT) { ESP_LOGE(TAG, "Failed to complete https request: url=%s", url); //esp_http_client_cleanup(client); xSemaphoreGive(mutex); return ESP_FAIL; } *code = http_code; //esp_http_client_cleanup(client); xSemaphoreGive(mutex); } else { ESP_LOGE(TAG, "Failed to acquire https request mutex"); return ESP_ERR_NOT_FINISHED; } return ESP_OK; }