Merge branch 'feature/esp_http_client_add_example' into 'master'

Add example to demonstrate use of low level APIs in http client

Closes IDFGH-2773

See merge request espressif/esp-idf!7832
This commit is contained in:
Mahavir Jain 2020-03-23 21:14:13 +08:00
commit 4e0e15631d
3 changed files with 134 additions and 5 deletions

View file

@ -1315,3 +1315,16 @@ void esp_http_client_add_auth(esp_http_client_handle_t client)
ESP_LOGW(TAG, "This request requires authentication, but does not provide header information for that");
}
}
int esp_http_client_read_response(esp_http_client_handle_t client, char *buffer, int len)
{
int read_len = 0;
while (read_len < len) {
int data_read = esp_http_client_read(client, buffer + read_len, len - read_len);
if (data_read <= 0) {
return read_len;
}
read_len += data_read;
}
return read_len;
}

View file

@ -497,6 +497,20 @@ void esp_http_client_add_auth(esp_http_client_handle_t client);
*/
bool esp_http_client_is_complete_data_received(esp_http_client_handle_t client);
/**
* @brief Helper API to read larger data chunks
* This is a helper API which internally calls `esp_http_client_read` multiple times till the end of data is reached or till the buffer gets full.
*
* @param[in] client The esp_http_client handle
* @param buffer The buffer
* @param[in] len The buffer length
*
* @return
* - Length of data was read
*/
int esp_http_client_read_response(esp_http_client_handle_t client, char *buffer, int len);
#ifdef __cplusplus
}
#endif

View file

@ -22,6 +22,7 @@
#include "esp_http_client.h"
#define MAX_HTTP_RECV_BUFFER 512
#define MAX_HTTP_OUTPUT_BUFFER 2048
static const char *TAG = "HTTP_CLIENT";
/* Root cert for howsmyssl.com, taken from howsmyssl_com_root_cert.pem
@ -39,6 +40,8 @@ extern const char howsmyssl_com_root_cert_pem_end[] asm("_binary_howsmyssl_com
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
static char *output_buffer; // Buffer to store response of http request from event handler
static int output_len; // Stores number of bytes read
switch(evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
@ -54,20 +57,49 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt)
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
/*
* Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
* However, event handler can also be used in case chunked encoding is used.
*/
if (!esp_http_client_is_chunked_response(evt->client)) {
// Write out data
// printf("%.*s", evt->data_len, (char*)evt->data);
// If user_data buffer is configured, copy the response into the buffer
if (evt->user_data) {
memcpy(evt->user_data + output_len, evt->data, evt->data_len);
} else {
if (output_buffer == NULL) {
output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
output_len = 0;
if (output_buffer == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
return ESP_FAIL;
}
}
memcpy(output_buffer + output_len, evt->data, evt->data_len);
}
output_len += evt->data_len;
}
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
if (output_buffer != NULL) {
// Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
// ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
free(output_buffer);
output_buffer = NULL;
output_len = 0;
}
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "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 != 0) {
if (output_buffer != NULL) {
free(output_buffer);
output_buffer = NULL;
output_len = 0;
}
ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
}
@ -78,9 +110,11 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt)
static void http_rest_with_url(void)
{
char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
esp_http_client_config_t config = {
.url = "http://httpbin.org/get",
.event_handler = _http_event_handler,
.user_data = local_response_buffer, // Pass address of local buffer to get response
};
esp_http_client_handle_t client = esp_http_client_init(&config);
@ -93,11 +127,13 @@ static void http_rest_with_url(void)
} else {
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
}
ESP_LOG_BUFFER_HEX(TAG, local_response_buffer, strlen(local_response_buffer));
// POST
const char *post_data = "field1=value1&field2=value2";
const char *post_data = "{\"field1\":\"value1\"}";
esp_http_client_set_url(client, "http://httpbin.org/post");
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_http_client_set_post_field(client, post_data, strlen(post_data));
err = esp_http_client_perform(client);
if (err == ESP_OK) {
@ -246,7 +282,7 @@ static void http_rest_with_hostname_path(void)
esp_http_client_cleanup(client);
}
#if CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH
static void http_auth_basic(void)
{
esp_http_client_config_t config = {
@ -285,6 +321,7 @@ static void http_auth_basic_redirect(void)
}
esp_http_client_cleanup(client);
}
#endif
static void http_auth_digest(void)
{
@ -433,7 +470,6 @@ static void http_perform_as_stream_reader(void)
}
esp_http_client_config_t config = {
.url = "http://httpbin.org/get",
.event_handler = _http_event_handler,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_err_t err;
@ -511,13 +547,78 @@ static void https_with_invalid_url(void)
esp_http_client_cleanup(client);
}
/*
* http_native_request() demonstrates use of low level APIs to connect to a server,
* make a http request and read response. Event handler is not used in this case.
* Note: This approach should only be used in case use of low level APIs is required.
* The easiest way is to use esp_http_perform()
*/
static void http_native_request(void)
{
char output_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0}; // Buffer to store response of http request
int content_length = 0;
esp_http_client_config_t config = {
.url = "http://httpbin.org/get",
};
esp_http_client_handle_t client = esp_http_client_init(&config);
// GET Request
esp_http_client_set_method(client, HTTP_METHOD_GET);
esp_err_t err = esp_http_client_open(client, 0);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
} else {
content_length = esp_http_client_fetch_headers(client);
if (content_length < 0) {
ESP_LOGE(TAG, "HTTP client fetch headers failed");
} else {
int data_read = esp_http_client_read_response(client, output_buffer, MAX_HTTP_OUTPUT_BUFFER);
if (data_read >= 0) {
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
ESP_LOG_BUFFER_HEX(TAG, output_buffer, strlen(output_buffer));
} else {
ESP_LOGE(TAG, "Failed to read response");
}
}
}
esp_http_client_close(client);
// POST Request
const char *post_data = "{\"field1\":\"value1\"}";
esp_http_client_set_url(client, "http://httpbin.org/post");
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_header(client, "Content-Type", "application/json");
err = esp_http_client_open(client, strlen(post_data));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
} else {
int wlen = esp_http_client_write(client, post_data, strlen(post_data));
if (wlen < 0) {
ESP_LOGE(TAG, "Write failed");
}
int data_read = esp_http_client_read_response(client, output_buffer, MAX_HTTP_OUTPUT_BUFFER);
if (data_read >= 0) {
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
ESP_LOG_BUFFER_HEX(TAG, output_buffer, strlen(output_buffer));
} else {
ESP_LOGE(TAG, "Failed to read response");
}
}
esp_http_client_cleanup(client);
}
static void http_test_task(void *pvParameters)
{
http_rest_with_url();
http_rest_with_hostname_path();
#if CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH
http_auth_basic();
http_auth_basic_redirect();
#endif
http_auth_digest();
http_relative_redirect();
http_absolute_redirect();
@ -528,6 +629,7 @@ static void http_test_task(void *pvParameters)
http_perform_as_stream_reader();
https_async();
https_with_invalid_url();
http_native_request();
ESP_LOGI(TAG, "Finish http example");
vTaskDelete(NULL);