2026-02-24 15:57:32 +08:00

207 lines
7.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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;
}