207 lines
7.8 KiB
C
207 lines
7.8 KiB
C
// Copyright (2025) Beijing Volcano Engine Technology Ltd.
|
||
// SPDX-License-Identifier: Apache-2.0
|
||
|
||
#include "volc_http.h"
|
||
|
||
#include <string.h>
|
||
#include <esp_log.h>
|
||
#include <esp_http_client.h>
|
||
#include "volc_platform.h"
|
||
#include "esp_crt_bundle.h"
|
||
|
||
static const char* TAG = "VOLC_HTTP";
|
||
|
||
// Response data structure for event handler
|
||
typedef struct {
|
||
char* buffer;
|
||
size_t buffer_size;
|
||
size_t total_read;
|
||
size_t max_size;
|
||
} response_data_t;
|
||
|
||
// HTTP client event handler to capture response data
|
||
static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
||
{
|
||
response_data_t *response_data = (response_data_t *)evt->user_data;
|
||
|
||
switch (evt->event_id) {
|
||
case HTTP_EVENT_ON_DATA:
|
||
if (response_data && evt->data && evt->data_len > 0) {
|
||
// Calculate available space in buffer
|
||
size_t available = response_data->max_size - response_data->total_read;
|
||
if (available > 0) {
|
||
// Copy data to buffer (don't exceed max size)
|
||
size_t copy_len = (evt->data_len < available) ? evt->data_len : available;
|
||
memcpy(response_data->buffer + response_data->total_read, evt->data, copy_len);
|
||
response_data->total_read += copy_len;
|
||
|
||
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA: read %d bytes, total: %d", evt->data_len, response_data->total_read);
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return ESP_OK;
|
||
}
|
||
|
||
char* volc_http_post(const char* uri, const char* post_data, int data_len)
|
||
{
|
||
char* response_buffer = NULL;
|
||
esp_http_client_handle_t client = NULL;
|
||
int response_status = 0;
|
||
esp_err_t err = ESP_OK;
|
||
int attempts = 0;
|
||
const int max_attempts = 3;
|
||
|
||
if (!uri || !post_data || data_len <= 0) {
|
||
ESP_LOGE(TAG, "Invalid parameters: uri=%p, post_data=%p, data_len=%d", uri, post_data, data_len);
|
||
return NULL;
|
||
}
|
||
|
||
ESP_LOGD(TAG, "HTTP POST: uri=%s, post_data=%s, data_len=%d", uri, post_data, data_len);
|
||
|
||
/* Perform HTTP request with retries */
|
||
while (attempts < max_attempts) {
|
||
ESP_LOGI(TAG, "HTTP POST attempt %d/%d", attempts + 1, max_attempts);
|
||
|
||
/* Allocate buffer for response */
|
||
const size_t max_response_size = 16384; // 增加缓冲区大小到16KB,解决响应被截断的问题
|
||
char *buffer = (char*)hal_malloc(max_response_size + 1);
|
||
if (!buffer) {
|
||
ESP_LOGE(TAG, "Failed to allocate buffer for response reading");
|
||
goto cleanup_attempt;
|
||
}
|
||
|
||
memset(buffer, 0, max_response_size + 1);
|
||
|
||
/* Initialize response data structure */
|
||
response_data_t response_data = {
|
||
.buffer = buffer,
|
||
.buffer_size = max_response_size + 1,
|
||
.total_read = 0,
|
||
.max_size = max_response_size
|
||
};
|
||
|
||
/* Configure HTTP client with event handler */
|
||
esp_http_client_config_t config = {
|
||
.url = uri,
|
||
.timeout_ms = 15000,
|
||
.transport_type = HTTP_TRANSPORT_OVER_SSL,
|
||
.crt_bundle_attach = esp_crt_bundle_attach,
|
||
.skip_cert_common_name_check = true,
|
||
.method = HTTP_METHOD_POST,
|
||
.event_handler = http_event_handler,
|
||
.user_data = &response_data, // Pass response data to event handler
|
||
.disable_auto_redirect = false, // Enable redirects
|
||
.max_redirection_count = 3, // Allow up to 3 redirects
|
||
};
|
||
|
||
/* Initialize HTTP client */
|
||
client = esp_http_client_init(&config);
|
||
if (client == NULL) {
|
||
ESP_LOGE(TAG, "Failed to initialize HTTP client");
|
||
hal_free(buffer);
|
||
goto cleanup_attempt;
|
||
}
|
||
|
||
/* Set content type to application/json */
|
||
err = esp_http_client_set_header(client, "Content-Type", "application/json");
|
||
if (err != ESP_OK) {
|
||
ESP_LOGE(TAG, "Failed to set Content-Type header: %s", esp_err_to_name(err));
|
||
goto cleanup_attempt;
|
||
}
|
||
|
||
/* Set POST data */
|
||
err = esp_http_client_set_post_field(client, post_data, data_len);
|
||
if (err != ESP_OK) {
|
||
ESP_LOGE(TAG, "Failed to set POST field: %s", esp_err_to_name(err));
|
||
goto cleanup_attempt;
|
||
}
|
||
|
||
/* Perform HTTP request */
|
||
/* The event handler will capture response data */
|
||
ESP_LOGI(TAG, "Performing HTTP request...");
|
||
err = esp_http_client_perform(client);
|
||
if (err != ESP_OK) {
|
||
ESP_LOGE(TAG, "Failed to perform HTTP request: %s", esp_err_to_name(err));
|
||
goto cleanup_attempt;
|
||
}
|
||
|
||
/* Get response status */
|
||
response_status = esp_http_client_get_status_code(client);
|
||
ESP_LOGI(TAG, "HTTP response status: %d", response_status);
|
||
|
||
if (response_status == 200) {
|
||
/* Get content length from response header */
|
||
int64_t content_length = esp_http_client_get_content_length(client);
|
||
ESP_LOGI(TAG, "Content-Length: %lld, actually read: %d", content_length, response_data.total_read);
|
||
|
||
if (response_data.total_read > 0) {
|
||
/* Ensure null termination */
|
||
buffer[response_data.total_read] = '\0';
|
||
|
||
ESP_LOGI(TAG, "Successfully read response: %d bytes", response_data.total_read);
|
||
ESP_LOGD(TAG, "Response data: %s", buffer);
|
||
|
||
/* Copy to final buffer */
|
||
response_buffer = (char*)hal_malloc(response_data.total_read + 1);
|
||
if (response_buffer) {
|
||
memcpy(response_buffer, buffer, response_data.total_read + 1);
|
||
} else {
|
||
ESP_LOGE(TAG, "Failed to allocate final response buffer");
|
||
}
|
||
} else {
|
||
ESP_LOGE(TAG, "Failed to read any response data via event handler");
|
||
|
||
/* Try a fallback method - read directly after perform */
|
||
ESP_LOGI(TAG, "Trying fallback: direct read after perform...");
|
||
int fallback_read = esp_http_client_read_response(client, buffer, max_response_size);
|
||
if (fallback_read > 0) {
|
||
ESP_LOGI(TAG, "Fallback successful: read %d bytes", fallback_read);
|
||
buffer[fallback_read] = '\0';
|
||
ESP_LOGD(TAG, "Response data: %s", buffer);
|
||
|
||
response_buffer = (char*)hal_malloc(fallback_read + 1);
|
||
if (response_buffer) {
|
||
memcpy(response_buffer, buffer, fallback_read + 1);
|
||
}
|
||
} else {
|
||
ESP_LOGE(TAG, "Fallback also failed: %d", fallback_read);
|
||
}
|
||
}
|
||
} else {
|
||
ESP_LOGW(TAG, "Non-200 status: %d", response_status);
|
||
}
|
||
|
||
cleanup_attempt:
|
||
/* Clean up client and buffer */
|
||
if (client != NULL) {
|
||
esp_http_client_cleanup(client);
|
||
client = NULL;
|
||
}
|
||
if (buffer != NULL) {
|
||
hal_free(buffer);
|
||
buffer = NULL;
|
||
}
|
||
|
||
/* If we got a response, break the retry loop */
|
||
if (response_buffer) {
|
||
break;
|
||
}
|
||
|
||
attempts++;
|
||
if (attempts < max_attempts) {
|
||
int backoff_ms = 500 * attempts;
|
||
ESP_LOGI(TAG, "Retrying in %d ms...", backoff_ms);
|
||
hal_thread_sleep(backoff_ms);
|
||
}
|
||
}
|
||
|
||
if (attempts == max_attempts) {
|
||
ESP_LOGE(TAG, "HTTP POST failed after %d attempts", max_attempts);
|
||
}
|
||
|
||
ESP_LOGI(TAG, "HTTP POST request completed, response_buffer=%p", response_buffer);
|
||
return response_buffer;
|
||
} |