mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-21 00:56:38 +08:00
feat(http): Bring esp_http_client component and example from idf
Commit ID: dd3c0329
This commit is contained in:
@ -1,11 +1,8 @@
|
||||
set(COMPONENT_SRCS "esp_http_client.c"
|
||||
"lib/http_auth.c"
|
||||
"lib/http_header.c"
|
||||
"lib/http_utils.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include")
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS "lib/include")
|
||||
|
||||
set(COMPONENT_REQUIRES "http_parser")
|
||||
set(COMPONENT_PRIV_REQUIRES "mbedtls" "lwip" "esp-tls" "tcp_transport" "tcpip_adapter")
|
||||
|
||||
register_component()
|
||||
idf_component_register(SRCS "esp_http_client.c"
|
||||
"lib/http_auth.c"
|
||||
"lib/http_header.c"
|
||||
"lib/http_utils.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "lib/include"
|
||||
REQUIRES nghttp
|
||||
PRIV_REQUIRES mbedtls lwip esp-tls tcp_transport)
|
||||
|
@ -1,18 +1,17 @@
|
||||
menu "ESP HTTP client"
|
||||
|
||||
|
||||
config ESP_HTTP_CLIENT_ENABLE_HTTPS
|
||||
bool "Enable https"
|
||||
default y
|
||||
help
|
||||
This option will enable https protocol by linking mbedtls library and initializing SSL transport
|
||||
|
||||
config HTTP_BUF_SIZE
|
||||
int "Default HTTP Buffer Size (both send and receive)"
|
||||
default 512
|
||||
range 512 1460
|
||||
help
|
||||
Set HTTP Buffer Size. The larger buffer size will make send and receive more size packet once.
|
||||
config ESP_HTTP_CLIENT_ENABLE_HTTPS
|
||||
bool "Enable https"
|
||||
default y
|
||||
help
|
||||
This option will enable https protocol by linking mbedtls library and initializing SSL transport
|
||||
|
||||
config ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH
|
||||
bool "Enable HTTP Basic Authentication"
|
||||
default n
|
||||
help
|
||||
This option will enable HTTP Basic Authentication. It is disabled by default as Basic
|
||||
auth uses unencrypted encoding, so it introduces a vulnerability when not using TLS
|
||||
|
||||
endmenu
|
||||
|
@ -2,6 +2,5 @@
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_SRCDIRS := . lib
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_SRCDIRS := . lib
|
||||
COMPONENT_PRIV_INCLUDEDIRS := lib/include
|
||||
|
@ -110,7 +110,8 @@ struct esp_http_client {
|
||||
esp_http_state_t state;
|
||||
http_event_handle_cb event_handler;
|
||||
int timeout_ms;
|
||||
int buffer_size;
|
||||
int buffer_size_rx;
|
||||
int buffer_size_tx;
|
||||
bool disable_auto_redirect;
|
||||
esp_http_client_event_t event;
|
||||
int data_written_index;
|
||||
@ -152,20 +153,6 @@ static const char *HTTP_METHOD_MAPPING[] = {
|
||||
"OPTIONS"
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum for the HTTP status codes.
|
||||
*/
|
||||
enum HttpStatus_Code
|
||||
{
|
||||
/* 3xx - Redirection */
|
||||
HttpStatus_MovedPermanently = 301,
|
||||
HttpStatus_Found = 302,
|
||||
|
||||
/* 4xx - Client Error */
|
||||
HttpStatus_Unauthorized = 401
|
||||
};
|
||||
|
||||
|
||||
static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len);
|
||||
static esp_err_t esp_http_client_connect(esp_http_client_handle_t client);
|
||||
static esp_err_t esp_http_client_send_post_data(esp_http_client_handle_t client);
|
||||
@ -297,6 +284,63 @@ esp_err_t esp_http_client_delete_header(esp_http_client_handle_t client, const c
|
||||
return http_header_delete(client->request->headers, key);
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_get_username(esp_http_client_handle_t client, char **value)
|
||||
{
|
||||
if (client == NULL || value == NULL) {
|
||||
ESP_LOGE(TAG, "client or value must not be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
*value = client->connection_info.username;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_set_username(esp_http_client_handle_t client, const char *username)
|
||||
{
|
||||
if (client == NULL) {
|
||||
ESP_LOGE(TAG, "client must not be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (client->connection_info.username != NULL) {
|
||||
free(client->connection_info.username);
|
||||
}
|
||||
client->connection_info.username = username ? strdup(username) : NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_get_password(esp_http_client_handle_t client, char **value)
|
||||
{
|
||||
if (client == NULL || value == NULL) {
|
||||
ESP_LOGE(TAG, "client or value must not be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
*value = client->connection_info.password;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_set_password(esp_http_client_handle_t client, char *password)
|
||||
{
|
||||
if (client == NULL) {
|
||||
ESP_LOGE(TAG, "client must not be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (client->connection_info.password != NULL) {
|
||||
memset(client->connection_info.password, 0, strlen(client->connection_info.password));
|
||||
free(client->connection_info.password);
|
||||
}
|
||||
client->connection_info.password = password ? strdup(password) : NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_set_authtype(esp_http_client_handle_t client, esp_http_client_auth_type_t auth_type)
|
||||
{
|
||||
if (client == NULL) {
|
||||
ESP_LOGE(TAG, "client must not be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
client->connection_info.auth_type = auth_type;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t _set_config(esp_http_client_handle_t client, const esp_http_client_config_t *config)
|
||||
{
|
||||
client->connection_info.method = config->method;
|
||||
@ -306,11 +350,16 @@ static esp_err_t _set_config(esp_http_client_handle_t client, const esp_http_cli
|
||||
client->timeout_ms = config->timeout_ms;
|
||||
client->max_redirection_count = config->max_redirection_count;
|
||||
client->user_data = config->user_data;
|
||||
client->buffer_size = config->buffer_size;
|
||||
client->buffer_size_rx = config->buffer_size;
|
||||
client->buffer_size_tx = config->buffer_size_tx;
|
||||
client->disable_auto_redirect = config->disable_auto_redirect;
|
||||
|
||||
if (config->buffer_size == 0) {
|
||||
client->buffer_size = DEFAULT_HTTP_BUF_SIZE;
|
||||
client->buffer_size_rx = DEFAULT_HTTP_BUF_SIZE;
|
||||
}
|
||||
|
||||
if (config->buffer_size_tx == 0) {
|
||||
client->buffer_size_tx = DEFAULT_HTTP_BUF_SIZE;
|
||||
}
|
||||
|
||||
if (client->max_redirection_count == 0) {
|
||||
@ -461,8 +510,7 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
|
||||
|
||||
if (!_success) {
|
||||
ESP_LOGE(TAG, "Error allocate memory");
|
||||
esp_http_client_cleanup(client);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
_success = (
|
||||
@ -473,8 +521,7 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
|
||||
);
|
||||
if (!_success) {
|
||||
ESP_LOGE(TAG, "Error initialize transport");
|
||||
esp_http_client_cleanup(client);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
#ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS
|
||||
esp_transport_handle_t ssl;
|
||||
@ -486,41 +533,66 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
|
||||
|
||||
if (!_success) {
|
||||
ESP_LOGE(TAG, "Error initialize SSL Transport");
|
||||
esp_http_client_cleanup(client);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (config->cert_pem) {
|
||||
if (config->use_global_ca_store == true) {
|
||||
esp_transport_ssl_enable_global_ca_store(ssl);
|
||||
} else if (config->cert_pem) {
|
||||
esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem));
|
||||
}
|
||||
|
||||
if (config->client_cert_pem) {
|
||||
esp_transport_ssl_set_client_cert_data(ssl, config->client_cert_pem, strlen(config->client_cert_pem));
|
||||
}
|
||||
|
||||
if (config->client_key_pem) {
|
||||
esp_transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem));
|
||||
}
|
||||
|
||||
if (config->skip_cert_common_name_check) {
|
||||
esp_transport_ssl_skip_common_name_check(ssl);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_set_config(client, config) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error set configurations");
|
||||
esp_http_client_cleanup(client);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
_success = (
|
||||
(client->request->buffer->data = malloc(client->buffer_size)) &&
|
||||
(client->response->buffer->data = malloc(client->buffer_size))
|
||||
(client->request->buffer->data = malloc(client->buffer_size_tx)) &&
|
||||
(client->response->buffer->data = malloc(client->buffer_size_rx))
|
||||
);
|
||||
|
||||
if (!_success) {
|
||||
ESP_LOGE(TAG, "Allocation failed");
|
||||
esp_http_client_cleanup(client);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
_success = (
|
||||
(esp_http_client_set_url(client, config->url) == ESP_OK) &&
|
||||
(esp_http_client_set_header(client, "User-Agent", DEFAULT_HTTP_USER_AGENT) == ESP_OK) &&
|
||||
(esp_http_client_set_header(client, "Host", client->connection_info.host) == ESP_OK)
|
||||
);
|
||||
if (config->host != NULL && config->path != NULL) {
|
||||
_success = (
|
||||
(esp_http_client_set_header(client, "User-Agent", DEFAULT_HTTP_USER_AGENT) == ESP_OK) &&
|
||||
(esp_http_client_set_header(client, "Host", client->connection_info.host) == ESP_OK)
|
||||
);
|
||||
|
||||
if (!_success) {
|
||||
ESP_LOGE(TAG, "Error set default configurations");
|
||||
esp_http_client_cleanup(client);
|
||||
return NULL;
|
||||
if (!_success) {
|
||||
ESP_LOGE(TAG, "Error while setting default configurations");
|
||||
goto error;
|
||||
}
|
||||
} else if (config->url != NULL) {
|
||||
_success = (
|
||||
(esp_http_client_set_url(client, config->url) == ESP_OK) &&
|
||||
(esp_http_client_set_header(client, "User-Agent", DEFAULT_HTTP_USER_AGENT) == ESP_OK) &&
|
||||
(esp_http_client_set_header(client, "Host", client->connection_info.host) == ESP_OK)
|
||||
);
|
||||
|
||||
if (!_success) {
|
||||
ESP_LOGE(TAG, "Error while setting default configurations");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "config should have either URL or host & path");
|
||||
goto error;
|
||||
}
|
||||
|
||||
client->parser_settings->on_message_begin = http_on_message_begin;
|
||||
@ -537,6 +609,9 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
|
||||
|
||||
client->state = HTTP_STATE_INIT;
|
||||
return client;
|
||||
error:
|
||||
esp_http_client_cleanup(client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_cleanup(esp_http_client_handle_t client)
|
||||
@ -546,14 +621,22 @@ esp_err_t esp_http_client_cleanup(esp_http_client_handle_t client)
|
||||
}
|
||||
esp_http_client_close(client);
|
||||
esp_transport_list_destroy(client->transport_list);
|
||||
http_header_destroy(client->request->headers);
|
||||
free(client->request->buffer->data);
|
||||
free(client->request->buffer);
|
||||
free(client->request);
|
||||
http_header_destroy(client->response->headers);
|
||||
free(client->response->buffer->data);
|
||||
free(client->response->buffer);
|
||||
free(client->response);
|
||||
if (client->request) {
|
||||
http_header_destroy(client->request->headers);
|
||||
if (client->request->buffer) {
|
||||
free(client->request->buffer->data);
|
||||
}
|
||||
free(client->request->buffer);
|
||||
free(client->request);
|
||||
}
|
||||
if (client->response) {
|
||||
http_header_destroy(client->response->headers);
|
||||
if (client->response->buffer) {
|
||||
free(client->response->buffer->data);
|
||||
}
|
||||
free(client->response->buffer);
|
||||
free(client->response);
|
||||
}
|
||||
|
||||
free(client->parser);
|
||||
free(client->parser_settings);
|
||||
@ -567,10 +650,20 @@ esp_err_t esp_http_client_cleanup(esp_http_client_handle_t client)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client)
|
||||
{
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (client->location == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ESP_LOGD(TAG, "Redirect to %s", client->location);
|
||||
return esp_http_client_set_url(client, client->location);
|
||||
}
|
||||
|
||||
static esp_err_t esp_http_check_response(esp_http_client_handle_t client)
|
||||
{
|
||||
char *auth_header = NULL;
|
||||
|
||||
if (client->redirect_counter >= client->max_redirection_count || client->disable_auto_redirect) {
|
||||
ESP_LOGE(TAG, "Error, reach max_redirection_count count=%d", client->redirect_counter);
|
||||
return ESP_ERR_HTTP_MAX_REDIRECT;
|
||||
@ -578,44 +671,13 @@ static esp_err_t esp_http_check_response(esp_http_client_handle_t client)
|
||||
switch (client->response->status_code) {
|
||||
case HttpStatus_MovedPermanently:
|
||||
case HttpStatus_Found:
|
||||
ESP_LOGI(TAG, "Redirect to %s", client->location);
|
||||
esp_http_client_set_url(client, client->location);
|
||||
case HttpStatus_TemporaryRedirect:
|
||||
esp_http_client_set_redirection(client);
|
||||
client->redirect_counter ++;
|
||||
client->process_again = 1;
|
||||
break;
|
||||
case HttpStatus_Unauthorized:
|
||||
auth_header = client->auth_header;
|
||||
if (auth_header) {
|
||||
http_utils_trim_whitespace(&auth_header);
|
||||
ESP_LOGD(TAG, "UNAUTHORIZED: %s", auth_header);
|
||||
client->redirect_counter ++;
|
||||
if (http_utils_str_starts_with(auth_header, "Digest") == 0) {
|
||||
ESP_LOGD(TAG, "type = Digest");
|
||||
client->connection_info.auth_type = HTTP_AUTH_TYPE_DIGEST;
|
||||
} else if (http_utils_str_starts_with(auth_header, "Basic") == 0) {
|
||||
ESP_LOGD(TAG, "type = Basic");
|
||||
client->connection_info.auth_type = HTTP_AUTH_TYPE_BASIC;
|
||||
} else {
|
||||
client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
|
||||
ESP_LOGE(TAG, "This authentication method is not supported: %s", auth_header);
|
||||
break;
|
||||
}
|
||||
|
||||
_clear_auth_data(client);
|
||||
|
||||
client->auth_data->method = strdup(HTTP_METHOD_MAPPING[client->connection_info.method]);
|
||||
|
||||
client->auth_data->nc = 1;
|
||||
client->auth_data->realm = http_utils_get_string_between(auth_header, "realm=\"", "\"");
|
||||
client->auth_data->algorithm = http_utils_get_string_between(auth_header, "algorithm=", ",");
|
||||
client->auth_data->qop = http_utils_get_string_between(auth_header, "qop=\"", "\"");
|
||||
client->auth_data->nonce = http_utils_get_string_between(auth_header, "nonce=\"", "\"");
|
||||
client->auth_data->opaque = http_utils_get_string_between(auth_header, "opaque=\"", "\"");
|
||||
client->process_again = 1;
|
||||
} else {
|
||||
client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
|
||||
ESP_LOGW(TAG, "This request requires authentication, but does not provide header information for that");
|
||||
}
|
||||
esp_http_client_add_auth(client);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -639,23 +701,34 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
|
||||
ESP_LOGE(TAG, "Error parse url %s", url);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
old_host = client->connection_info.host;
|
||||
if (client->connection_info.host) {
|
||||
old_host = strdup(client->connection_info.host);
|
||||
}
|
||||
old_port = client->connection_info.port;
|
||||
|
||||
if (purl.field_data[UF_HOST].len) {
|
||||
http_utils_assign_string(&client->connection_info.host, url + purl.field_data[UF_HOST].off, purl.field_data[UF_HOST].len);
|
||||
HTTP_MEM_CHECK(TAG, client->connection_info.host, return ESP_ERR_NO_MEM);
|
||||
HTTP_MEM_CHECK(TAG, client->connection_info.host, {
|
||||
free(old_host);
|
||||
return ESP_ERR_NO_MEM;
|
||||
});
|
||||
}
|
||||
// Close the connection if host was changed
|
||||
if (old_host && client->connection_info.host
|
||||
&& strcasecmp(old_host, (const void *)client->connection_info.host) != 0) {
|
||||
ESP_LOGD(TAG, "New host assign = %s", client->connection_info.host);
|
||||
if (esp_http_client_set_header(client, "Host", client->connection_info.host) != ESP_OK) {
|
||||
free(old_host);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
esp_http_client_close(client);
|
||||
}
|
||||
|
||||
if (old_host) {
|
||||
free(old_host);
|
||||
old_host = NULL;
|
||||
}
|
||||
|
||||
if (purl.field_data[UF_SCHEMA].len) {
|
||||
http_utils_assign_string(&client->connection_info.scheme, url + purl.field_data[UF_SCHEMA].off, purl.field_data[UF_SCHEMA].len);
|
||||
HTTP_MEM_CHECK(TAG, client->connection_info.scheme, return ESP_ERR_NO_MEM);
|
||||
@ -693,13 +766,7 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
|
||||
} else {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
} else {
|
||||
free(client->connection_info.username);
|
||||
free(client->connection_info.password);
|
||||
client->connection_info.username = NULL;
|
||||
client->connection_info.password = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Reset path and query if there are no information
|
||||
if (purl.field_data[UF_PATH].len) {
|
||||
@ -740,13 +807,29 @@ static int esp_http_client_get_data(esp_http_client_handle_t client)
|
||||
|
||||
ESP_LOGD(TAG, "data_process=%d, content_length=%d", client->response->data_process, client->response->content_length);
|
||||
|
||||
int rlen = esp_transport_read(client->transport, res_buffer->data, client->buffer_size, client->timeout_ms);
|
||||
int rlen = esp_transport_read(client->transport, res_buffer->data, client->buffer_size_rx, client->timeout_ms);
|
||||
if (rlen >= 0) {
|
||||
http_parser_execute(client->parser, client->parser_settings, res_buffer->data, rlen);
|
||||
}
|
||||
return rlen;
|
||||
}
|
||||
|
||||
bool esp_http_client_is_complete_data_received(esp_http_client_handle_t client)
|
||||
{
|
||||
if (client->response->is_chunked) {
|
||||
if (!client->is_chunk_complete) {
|
||||
ESP_LOGD(TAG, "Chunks were not completely read");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (client->response->data_process != client->response->content_length) {
|
||||
ESP_LOGD(TAG, "Data processed %d != Data specified in content length %d", client->response->data_process, client->response->content_length);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len)
|
||||
{
|
||||
esp_http_buffer_t *res_buffer = client->response->buffer;
|
||||
@ -770,19 +853,36 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len)
|
||||
} else {
|
||||
is_data_remain = client->response->data_process < client->response->content_length;
|
||||
}
|
||||
ESP_LOGD(TAG, "is_data_remain=%d, is_chunked=%d", is_data_remain, client->response->is_chunked);
|
||||
ESP_LOGD(TAG, "is_data_remain=%d, is_chunked=%d, content_length=%d", is_data_remain, client->response->is_chunked, client->response->content_length);
|
||||
if (!is_data_remain) {
|
||||
break;
|
||||
}
|
||||
int byte_to_read = need_read;
|
||||
if (byte_to_read > client->buffer_size) {
|
||||
byte_to_read = client->buffer_size;
|
||||
if (byte_to_read > client->buffer_size_rx) {
|
||||
byte_to_read = client->buffer_size_rx;
|
||||
}
|
||||
errno = 0;
|
||||
rlen = esp_transport_read(client->transport, res_buffer->data, byte_to_read, client->timeout_ms);
|
||||
ESP_LOGD(TAG, "need_read=%d, byte_to_read=%d, rlen=%d, ridx=%d", need_read, byte_to_read, rlen, ridx);
|
||||
|
||||
if (rlen <= 0) {
|
||||
return ridx;
|
||||
if (errno != 0) {
|
||||
esp_log_level_t sev = ESP_LOG_WARN;
|
||||
/* On connection close from server, recv should ideally return 0 but we have error conversion
|
||||
* in `tcp_transport` SSL layer which translates it `-1` and hence below additional checks */
|
||||
if (rlen == -1 && errno == ENOTCONN && client->response->is_chunked) {
|
||||
/* Explicit call to parser for invoking `message_complete` callback */
|
||||
http_parser_execute(client->parser, client->parser_settings, res_buffer->data, 0);
|
||||
/* ...and lowering the message severity, as closed connection from server side is expected in chunked transport */
|
||||
sev = ESP_LOG_DEBUG;
|
||||
}
|
||||
ESP_LOG_LEVEL(sev, TAG, "esp_transport_read returned:%d and errno:%d ", rlen, errno);
|
||||
}
|
||||
if (rlen < 0 && ridx == 0) {
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return ridx;
|
||||
}
|
||||
}
|
||||
res_buffer->output_ptr = buffer + ridx;
|
||||
http_parser_execute(client->parser, client->parser_settings, res_buffer->data, rlen);
|
||||
@ -893,8 +993,8 @@ int esp_http_client_fetch_headers(esp_http_client_handle_t client)
|
||||
client->response->status_code = -1;
|
||||
|
||||
while (client->state < HTTP_STATE_RES_COMPLETE_HEADER) {
|
||||
buffer->len = esp_transport_read(client->transport, buffer->data, client->buffer_size, client->timeout_ms);
|
||||
if (buffer->len < 0) {
|
||||
buffer->len = esp_transport_read(client->transport, buffer->data, client->buffer_size_rx, client->timeout_ms);
|
||||
if (buffer->len <= 0) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
http_parser_execute(client->parser, client->parser_settings, buffer->data, buffer->len);
|
||||
@ -971,26 +1071,26 @@ static int http_client_prepare_first_line(esp_http_client_handle_t client, int w
|
||||
const char *method = HTTP_METHOD_MAPPING[client->connection_info.method];
|
||||
|
||||
int first_line_len = snprintf(client->request->buffer->data,
|
||||
client->buffer_size, "%s %s",
|
||||
client->buffer_size_tx, "%s %s",
|
||||
method,
|
||||
client->connection_info.path);
|
||||
if (first_line_len >= client->buffer_size) {
|
||||
if (first_line_len >= client->buffer_size_tx) {
|
||||
ESP_LOGE(TAG, "Out of buffer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (client->connection_info.query) {
|
||||
first_line_len += snprintf(client->request->buffer->data + first_line_len,
|
||||
client->buffer_size - first_line_len, "?%s", client->connection_info.query);
|
||||
if (first_line_len >= client->buffer_size) {
|
||||
client->buffer_size_tx - first_line_len, "?%s", client->connection_info.query);
|
||||
if (first_line_len >= client->buffer_size_tx) {
|
||||
ESP_LOGE(TAG, "Out of buffer");
|
||||
return -1;
|
||||
|
||||
}
|
||||
}
|
||||
first_line_len += snprintf(client->request->buffer->data + first_line_len,
|
||||
client->buffer_size - first_line_len, " %s\r\n", DEFAULT_HTTP_PROTOCOL);
|
||||
if (first_line_len >= client->buffer_size) {
|
||||
client->buffer_size_tx - first_line_len, " %s\r\n", DEFAULT_HTTP_PROTOCOL);
|
||||
if (first_line_len >= client->buffer_size_tx) {
|
||||
ESP_LOGE(TAG, "Out of buffer");
|
||||
return -1;
|
||||
}
|
||||
@ -1025,7 +1125,7 @@ static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, i
|
||||
}
|
||||
}
|
||||
|
||||
int wlen = client->buffer_size - first_line_len;
|
||||
int wlen = client->buffer_size_tx - first_line_len;
|
||||
while ((client->header_index = http_header_generate_string(client->request->headers, client->header_index, client->request->buffer->data + first_line_len, &wlen))) {
|
||||
if (wlen <= 0) {
|
||||
break;
|
||||
@ -1049,11 +1149,12 @@ static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, i
|
||||
client->data_write_left -= wret;
|
||||
client->data_written_index += wret;
|
||||
}
|
||||
wlen = client->buffer_size;
|
||||
wlen = client->buffer_size_tx;
|
||||
}
|
||||
|
||||
client->data_written_index = 0;
|
||||
client->data_write_left = client->post_len;
|
||||
http_dispatch_event(client, HTTP_EVENT_HEADERS_SENT, NULL, 0);
|
||||
client->state = HTTP_STATE_REQ_COMPLETE_HEADER;
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -1088,12 +1189,13 @@ success:
|
||||
|
||||
esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len)
|
||||
{
|
||||
client->post_len = write_len;
|
||||
esp_err_t err;
|
||||
if ((err = esp_http_client_connect(client)) != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if ((err = esp_http_client_request_send(client, write_len)) != ESP_OK) {
|
||||
return err;
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -1121,7 +1223,7 @@ int esp_http_client_write(esp_http_client_handle_t client, const char *buffer, i
|
||||
esp_err_t esp_http_client_close(esp_http_client_handle_t client)
|
||||
{
|
||||
if (client->state >= HTTP_STATE_INIT) {
|
||||
http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, NULL, 0);
|
||||
http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, esp_transport_get_error_handle(client->transport), 0);
|
||||
client->state = HTTP_STATE_INIT;
|
||||
return esp_transport_close(client->transport);
|
||||
}
|
||||
@ -1175,11 +1277,83 @@ bool esp_http_client_is_chunked_response(esp_http_client_handle_t client)
|
||||
|
||||
esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_handle_t client)
|
||||
{
|
||||
if (!strcmp(client->connection_info.scheme, "https") ) {
|
||||
if (!strcasecmp(client->connection_info.scheme, "https") ) {
|
||||
return HTTP_TRANSPORT_OVER_SSL;
|
||||
} else if (!strcmp(client->connection_info.scheme, "http")) {
|
||||
} else if (!strcasecmp(client->connection_info.scheme, "http")) {
|
||||
return HTTP_TRANSPORT_OVER_TCP;
|
||||
} else {
|
||||
return HTTP_TRANSPORT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_http_client_add_auth(esp_http_client_handle_t client)
|
||||
{
|
||||
if (client == NULL) {
|
||||
return;
|
||||
}
|
||||
if (client->state != HTTP_STATE_RES_COMPLETE_HEADER) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *auth_header = client->auth_header;
|
||||
if (auth_header) {
|
||||
http_utils_trim_whitespace(&auth_header);
|
||||
ESP_LOGD(TAG, "UNAUTHORIZED: %s", auth_header);
|
||||
client->redirect_counter++;
|
||||
if (http_utils_str_starts_with(auth_header, "Digest") == 0) {
|
||||
ESP_LOGD(TAG, "type = Digest");
|
||||
client->connection_info.auth_type = HTTP_AUTH_TYPE_DIGEST;
|
||||
#ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH
|
||||
} else if (http_utils_str_starts_with(auth_header, "Basic") == 0) {
|
||||
ESP_LOGD(TAG, "type = Basic");
|
||||
client->connection_info.auth_type = HTTP_AUTH_TYPE_BASIC;
|
||||
#endif
|
||||
} else {
|
||||
client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
|
||||
ESP_LOGE(TAG, "This authentication method is not supported: %s", auth_header);
|
||||
return;
|
||||
}
|
||||
|
||||
_clear_auth_data(client);
|
||||
|
||||
client->auth_data->method = strdup(HTTP_METHOD_MAPPING[client->connection_info.method]);
|
||||
|
||||
client->auth_data->nc = 1;
|
||||
client->auth_data->realm = http_utils_get_string_between(auth_header, "realm=\"", "\"");
|
||||
client->auth_data->algorithm = http_utils_get_string_between(auth_header, "algorithm=", ",");
|
||||
client->auth_data->qop = http_utils_get_string_between(auth_header, "qop=\"", "\"");
|
||||
client->auth_data->nonce = http_utils_get_string_between(auth_header, "nonce=\"", "\"");
|
||||
client->auth_data->opaque = http_utils_get_string_between(auth_header, "opaque=\"", "\"");
|
||||
client->process_again = 1;
|
||||
} else {
|
||||
client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
|
||||
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;
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_get_url(esp_http_client_handle_t client, char *url, const int len)
|
||||
{
|
||||
if (client == NULL || url == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (client->connection_info.host && client->connection_info.scheme && client->connection_info.path) {
|
||||
snprintf(url, len, "%s://%s%s", client->connection_info.scheme, client->connection_info.host, client->connection_info.path);
|
||||
return ESP_OK;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to get URL");
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DEFAULT_HTTP_BUF_SIZE CONFIG_HTTP_BUF_SIZE
|
||||
#define DEFAULT_HTTP_BUF_SIZE (512)
|
||||
|
||||
typedef struct esp_http_client *esp_http_client_handle_t;
|
||||
typedef struct esp_http_client_event *esp_http_client_event_handle_t;
|
||||
@ -35,7 +35,9 @@ typedef struct esp_http_client_event *esp_http_client_event_handle_t;
|
||||
typedef enum {
|
||||
HTTP_EVENT_ERROR = 0, /*!< This event occurs when there are any errors during execution */
|
||||
HTTP_EVENT_ON_CONNECTED, /*!< Once the HTTP has been connected to the server, no data exchange has been performed */
|
||||
HTTP_EVENT_HEADER_SENT, /*!< After sending all the headers to the server */
|
||||
HTTP_EVENT_HEADERS_SENT, /*!< After sending all the headers to the server */
|
||||
HTTP_EVENT_HEADER_SENT = HTTP_EVENT_HEADERS_SENT, /*!< This header has been kept for backward compatability
|
||||
and will be deprecated in future versions esp-idf */
|
||||
HTTP_EVENT_ON_HEADER, /*!< Occurs when receiving each header sent from the server */
|
||||
HTTP_EVENT_ON_DATA, /*!< Occurs when receiving data from the server, possibly multiple portions of the packet */
|
||||
HTTP_EVENT_ON_FINISH, /*!< Occurs when finish a HTTP session */
|
||||
@ -105,18 +107,35 @@ typedef struct {
|
||||
esp_http_client_auth_type_t auth_type; /*!< Http authentication type, see `esp_http_client_auth_type_t` */
|
||||
const char *path; /*!< HTTP Path, if not set, default is `/` */
|
||||
const char *query; /*!< HTTP query */
|
||||
const char *cert_pem; /*!< SSL Certification, PEM format as string, if the client requires to verify server */
|
||||
const char *cert_pem; /*!< SSL server certification, PEM format as string, if the client requires to verify server */
|
||||
const char *client_cert_pem; /*!< SSL client certification, PEM format as string, if the server requires to verify client */
|
||||
const char *client_key_pem; /*!< SSL client key, PEM format as string, if the server requires to verify client */
|
||||
esp_http_client_method_t method; /*!< HTTP Method */
|
||||
int timeout_ms; /*!< Network timeout in milliseconds */
|
||||
bool disable_auto_redirect; /*!< Disable HTTP automatic redirects */
|
||||
int max_redirection_count; /*!< Max redirection number, using default value if zero*/
|
||||
http_event_handle_cb event_handler; /*!< HTTP Event Handle */
|
||||
esp_http_client_transport_t transport_type; /*!< HTTP transport type, see `esp_http_client_transport_t` */
|
||||
int buffer_size; /*!< HTTP buffer size (both send and receive) */
|
||||
int buffer_size; /*!< HTTP receive buffer size */
|
||||
int buffer_size_tx; /*!< HTTP transmit buffer size */
|
||||
void *user_data; /*!< HTTP user_data context */
|
||||
bool is_async; /*!< Set asynchronous mode, only supported with HTTPS for now */
|
||||
bool use_global_ca_store; /*!< Use a global ca_store for all the connections in which this bool is set. */
|
||||
bool skip_cert_common_name_check; /*!< Skip any validation of server certificate CN field */
|
||||
} esp_http_client_config_t;
|
||||
|
||||
/**
|
||||
* Enum for the HTTP status codes.
|
||||
*/
|
||||
typedef enum {
|
||||
/* 3xx - Redirection */
|
||||
HttpStatus_MovedPermanently = 301,
|
||||
HttpStatus_Found = 302,
|
||||
HttpStatus_TemporaryRedirect = 307,
|
||||
|
||||
/* 4xx - Client Error */
|
||||
HttpStatus_Unauthorized = 401
|
||||
} HttpStatus_Code;
|
||||
|
||||
#define ESP_ERR_HTTP_BASE (0x7000) /*!< Starting number of HTTP error codes */
|
||||
#define ESP_ERR_HTTP_MAX_REDIRECT (ESP_ERR_HTTP_BASE + 1) /*!< The error exceeds the number of HTTP redirects */
|
||||
@ -232,13 +251,83 @@ esp_err_t esp_http_client_set_header(esp_http_client_handle_t client, const char
|
||||
*/
|
||||
esp_err_t esp_http_client_get_header(esp_http_client_handle_t client, const char *key, char **value);
|
||||
|
||||
/**
|
||||
* @brief Get http request username.
|
||||
* The address of username buffer will be assigned to value parameter.
|
||||
* This function must be called after `esp_http_client_init`.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[out] value The username value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t esp_http_client_get_username(esp_http_client_handle_t client, char **value);
|
||||
|
||||
/**
|
||||
* @brief Set http request username.
|
||||
* The value of username parameter will be assigned to username buffer.
|
||||
* If the username parameter is NULL then username buffer will be freed.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[in] username The username value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t esp_http_client_set_username(esp_http_client_handle_t client, const char *username);
|
||||
|
||||
/**
|
||||
* @brief Get http request password.
|
||||
* The address of password buffer will be assigned to value parameter.
|
||||
* This function must be called after `esp_http_client_init`.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[out] value The password value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t esp_http_client_get_password(esp_http_client_handle_t client, char **value);
|
||||
|
||||
/**
|
||||
* @brief Set http request password.
|
||||
* The value of password parameter will be assigned to password buffer.
|
||||
* If the password parameter is NULL then password buffer will be freed.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[in] password The password value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t esp_http_client_set_password(esp_http_client_handle_t client, char *password);
|
||||
|
||||
/**
|
||||
* @brief Set http request auth_type.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[in] auth_type The esp_http_client auth type
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t esp_http_client_set_authtype(esp_http_client_handle_t client, esp_http_client_auth_type_t auth_type);
|
||||
|
||||
/**
|
||||
* @brief Set http request method
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[in] method The method
|
||||
*
|
||||
* @return ESP_OK
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t esp_http_client_set_method(esp_http_client_handle_t client, esp_http_client_method_t method);
|
||||
|
||||
@ -373,6 +462,68 @@ esp_err_t esp_http_client_cleanup(esp_http_client_handle_t client);
|
||||
*/
|
||||
esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_handle_t client);
|
||||
|
||||
/**
|
||||
* @brief Set redirection URL.
|
||||
* When received the 30x code from the server, the client stores the redirect URL provided by the server.
|
||||
* This function will set the current URL to redirect to enable client to execute the redirection request.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_FAIL
|
||||
*/
|
||||
esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client);
|
||||
|
||||
/**
|
||||
* @brief On receiving HTTP Status code 401, this API can be invoked to add authorization
|
||||
* information.
|
||||
*
|
||||
* @note There is a possibility of receiving body message with redirection status codes, thus make sure
|
||||
* to flush off body data after calling this API.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
*/
|
||||
void esp_http_client_add_auth(esp_http_client_handle_t client);
|
||||
|
||||
/**
|
||||
* @brief Checks if entire data in the response has been read without any error.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
*
|
||||
* @return
|
||||
* - true
|
||||
* - false
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Get URL from client
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[inout] url The buffer to store URL
|
||||
* @param[in] len The buffer length
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_FAIL
|
||||
*/
|
||||
|
||||
esp_err_t esp_http_client_get_url(esp_http_client_handle_t client, char *url, const int len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -17,11 +17,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "tcpip_adapter.h"
|
||||
#include "esp_netif.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "rom/md5_hash.h"
|
||||
#include "esp32/rom/md5_hash.h"
|
||||
#include "mbedtls/base64.h"
|
||||
|
||||
#include "esp_base64.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
@ -81,10 +81,6 @@ char *http_auth_digest(const char *username, const char *password, esp_http_auth
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (auth_data->algorithm == NULL) {
|
||||
auth_data->algorithm = "md5";
|
||||
}
|
||||
|
||||
ha1 = calloc(1, MD5_MAX_LEN);
|
||||
HTTP_MEM_CHECK(TAG, ha1, goto _digest_exit);
|
||||
|
||||
@ -138,19 +134,17 @@ _digest_exit:
|
||||
|
||||
char *http_auth_basic(const char *username, const char *password)
|
||||
{
|
||||
int out;
|
||||
char *user_info = NULL;
|
||||
char *digest = NULL;
|
||||
size_t n = 0, size = 0;
|
||||
size_t n = 0;
|
||||
asprintf(&user_info, "%s:%s", username, password);
|
||||
HTTP_MEM_CHECK(TAG, user_info, return NULL);
|
||||
size = strlen(user_info);
|
||||
n = (size / 3) * 4 + 1; // String to Base64 length calculation
|
||||
if (size % 3 != 0)
|
||||
n += 4;
|
||||
digest = calloc(1, 6 + n);
|
||||
mbedtls_base64_encode(NULL, 0, &n, (const unsigned char *)user_info, strlen(user_info));
|
||||
digest = calloc(1, 6 + n + 1);
|
||||
HTTP_MEM_CHECK(TAG, digest, goto _basic_exit);
|
||||
strcpy(digest, "Basic ");
|
||||
n = esp_base64_encode((const unsigned char *)user_info, strlen(user_info), (unsigned char *)digest + 6, n);
|
||||
mbedtls_base64_encode((unsigned char *)digest + 6, n, (size_t *)&out, (const unsigned char *)user_info, strlen(user_info));
|
||||
_basic_exit:
|
||||
free(user_info);
|
||||
return digest;
|
||||
|
@ -37,7 +37,7 @@ typedef struct http_header_item {
|
||||
STAILQ_HEAD(http_header, http_header_item);
|
||||
|
||||
|
||||
http_header_handle_t http_header_init()
|
||||
http_header_handle_t http_header_init(void)
|
||||
{
|
||||
http_header_handle_t header = calloc(1, sizeof(struct http_header));
|
||||
HTTP_MEM_CHECK(TAG, header, return NULL);
|
||||
@ -178,6 +178,8 @@ int http_header_generate_string(http_header_handle_t header, int index, char *bu
|
||||
int idx = 0;
|
||||
int ret_idx = -1;
|
||||
bool is_end = false;
|
||||
|
||||
// iterate over the header entries to calculate buffer size and determine last item
|
||||
STAILQ_FOREACH(item, header, next) {
|
||||
if (item->value && idx >= index) {
|
||||
siz += strlen(item->key);
|
||||
@ -187,7 +189,10 @@ int http_header_generate_string(http_header_handle_t header, int index, char *bu
|
||||
idx ++;
|
||||
|
||||
if (siz + 1 > *buffer_len - 2) {
|
||||
// if this item would not fit to the buffer, return the index of the last fitting one
|
||||
ret_idx = idx - 1;
|
||||
ESP_LOGE(TAG, "Buffer length is small to fit all the headers");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,10 +200,12 @@ int http_header_generate_string(http_header_handle_t header, int index, char *bu
|
||||
return 0;
|
||||
}
|
||||
if (ret_idx < 0) {
|
||||
// all items would fit, mark this as the end of http header string
|
||||
ret_idx = idx;
|
||||
is_end = true;
|
||||
}
|
||||
|
||||
// iterate again over the header entries to write only the fitting indeces
|
||||
int str_len = 0;
|
||||
idx = 0;
|
||||
STAILQ_FOREACH(item, header, next) {
|
||||
@ -208,6 +215,7 @@ int http_header_generate_string(http_header_handle_t header, int index, char *bu
|
||||
idx ++;
|
||||
}
|
||||
if (is_end) {
|
||||
// write the http header terminator if all header entries have been written in this function call
|
||||
str_len += snprintf(buffer + str_len, *buffer_len - str_len, "\r\n");
|
||||
}
|
||||
*buffer_len = str_len;
|
||||
|
@ -15,7 +15,7 @@
|
||||
#ifndef _HTTP_HEADER_H_
|
||||
#define _HTTP_HEADER_H_
|
||||
|
||||
#include "rom/queue.h"
|
||||
#include "sys/queue.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -32,7 +32,7 @@ typedef struct http_header_item *http_header_item_handle_t;
|
||||
* - http_header_handle_t
|
||||
* - NULL if any errors
|
||||
*/
|
||||
http_header_handle_t http_header_init();
|
||||
http_header_handle_t http_header_init(void);
|
||||
|
||||
/**
|
||||
* @brief Cleanup and free all http header pairs
|
||||
|
3
components/esp_http_client/test/CMakeLists.txt
Normal file
3
components/esp_http_client/test/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity test_utils esp_http_client)
|
1
components/esp_http_client/test/component.mk
Normal file
1
components/esp_http_client/test/component.mk
Normal file
@ -0,0 +1 @@
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
139
components/esp_http_client/test/test_http_client.c
Normal file
139
components/esp_http_client/test/test_http_client.c
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_http_client.h>
|
||||
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#define HOST "httpbin.org"
|
||||
#define USERNAME "user"
|
||||
#define PASSWORD "challenge"
|
||||
|
||||
TEST_CASE("Test in common case: Only URL and hostname are specified.", "[ESP HTTP CLIENT]")
|
||||
{
|
||||
esp_http_client_config_t config_incorrect = {0};
|
||||
|
||||
test_case_uses_tcpip();
|
||||
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config_incorrect);
|
||||
TEST_ASSERT(client == NULL);
|
||||
|
||||
esp_http_client_config_t config_with_url = {
|
||||
.url = "http://httpbin.org/get",
|
||||
};
|
||||
client = esp_http_client_init(&config_with_url);
|
||||
TEST_ASSERT(client != NULL);
|
||||
TEST_ASSERT(esp_http_client_cleanup(client) == ESP_OK);
|
||||
|
||||
|
||||
esp_http_client_config_t config_with_hostname_path = {
|
||||
.host = HOST,
|
||||
.path = "/get",
|
||||
};
|
||||
client = esp_http_client_init(&config_with_hostname_path);
|
||||
TEST_ASSERT(client != NULL);
|
||||
TEST_ASSERT(esp_http_client_cleanup(client) == ESP_OK);
|
||||
}
|
||||
|
||||
TEST_CASE("Get username and password after initialization.", "[ESP HTTP CLIENT]")
|
||||
{
|
||||
esp_http_client_config_t config_with_auth = {
|
||||
.host = HOST,
|
||||
.path = "/",
|
||||
.username = USERNAME,
|
||||
.password = PASSWORD
|
||||
};
|
||||
char *value = NULL;
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config_with_auth);
|
||||
TEST_ASSERT_NOT_NULL(client);
|
||||
// Test with username
|
||||
esp_err_t r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(USERNAME, value);
|
||||
// Test with password
|
||||
value = NULL;
|
||||
r = esp_http_client_get_password(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(PASSWORD, value);
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case to test that, the esp_http_client_set_url won't drop username and password
|
||||
* when pass a path "/abc" for url.
|
||||
**/
|
||||
TEST_CASE("Username is unmodified when we change to new path", "[ESP HTTP CLIENT]")
|
||||
{
|
||||
esp_http_client_config_t config_with_auth = {
|
||||
.host = HOST,
|
||||
.path = "/",
|
||||
.username = USERNAME,
|
||||
.password = PASSWORD
|
||||
};
|
||||
char *value = NULL;
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config_with_auth);
|
||||
TEST_ASSERT_NOT_NULL(client);
|
||||
esp_err_t r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(USERNAME, value);
|
||||
esp_http_client_set_url(client, "/something-else/");
|
||||
r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(USERNAME, value);
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case to test that, the esp_http_client_set_url do not reset the auth credentials
|
||||
* Explicit APIs esp_http_client_set_username and esp_http_client_set_password are used to change
|
||||
* the auth credentials
|
||||
**/
|
||||
TEST_CASE("Username and password will not reset if new absolute URL doesnot specify auth credentials.", "[ESP HTTP CLIENT]")
|
||||
{
|
||||
esp_http_client_config_t config_with_auth = {
|
||||
.host = HOST,
|
||||
.path = "/",
|
||||
.username = USERNAME,
|
||||
.password = PASSWORD
|
||||
};
|
||||
char *value = NULL;
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config_with_auth);
|
||||
TEST_ASSERT_NOT_NULL(client);
|
||||
esp_err_t r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(USERNAME, value);
|
||||
esp_http_client_set_url(client, "http://" HOST "/get");
|
||||
esp_http_client_set_username(client, value);
|
||||
esp_http_client_set_password(client, value);
|
||||
//checks if username is set or not
|
||||
r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
//If username is set then value should not be NULL
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
//checks if password is set or not
|
||||
r = esp_http_client_get_password(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
//If password is set then value should not be NULL
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
67
examples/protocols/esp_http_client/esp_http_client_test.py
Normal file
67
examples/protocols/esp_http_client/esp_http_client_test.py
Normal file
@ -0,0 +1,67 @@
|
||||
import re
|
||||
import os
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag="Example_EthKitV1")
|
||||
def test_examples_protocol_esp_http_client(env, extra_data):
|
||||
"""
|
||||
steps: |
|
||||
1. join AP
|
||||
2. Send HTTP request to httpbin.org
|
||||
"""
|
||||
dut1 = env.get_dut("esp_http_client", "examples/protocols/esp_http_client", dut_class=ttfw_idf.ESP32DUT)
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut1.app.binary_path, "esp-http-client-example.bin")
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance("esp_http_client_bin_size", "{}KB".format(bin_size // 1024))
|
||||
ttfw_idf.check_performance("esp_http_client_bin_size", bin_size // 1024, dut1.TARGET)
|
||||
# start test
|
||||
dut1.start_app()
|
||||
dut1.expect("Connected to AP, begin http example", timeout=30)
|
||||
dut1.expect(re.compile(r"HTTP GET Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP POST Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP PUT Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP PATCH Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP DELETE Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP HEAD Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP Basic Auth Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP Basic Auth redirect Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP Digest Auth Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTPS Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP chunk encoding Status = 200, content_length = (-?\d)"))
|
||||
# content-len for chunked encoding is typically -1, could be a positive length in some cases
|
||||
dut1.expect(re.compile(r"HTTP Stream reader Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"Last esp error code: 0x8001"))
|
||||
dut1.expect("Finish http example")
|
||||
|
||||
# test mbedtls dynamic resource
|
||||
dut1 = env.get_dut("esp_http_client", "examples/protocols/esp_http_client", dut_class=ttfw_idf.ESP32DUT, app_config_name='ssldyn')
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut1.app.binary_path, "esp-http-client-example.bin")
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance("esp_http_client_bin_size", "{}KB".format(bin_size // 1024))
|
||||
ttfw_idf.check_performance("esp_http_client_bin_size", bin_size // 1024, dut1.TARGET)
|
||||
# start test
|
||||
dut1.start_app()
|
||||
dut1.expect("Connected to AP, begin http example", timeout=30)
|
||||
dut1.expect(re.compile(r"HTTP GET Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP POST Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP PUT Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP PATCH Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP DELETE Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP HEAD Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP Basic Auth Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP Basic Auth redirect Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP Digest Auth Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTPS Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"HTTP chunk encoding Status = 200, content_length = (-?\d)"))
|
||||
# content-len for chunked encoding is typically -1, could be a positive length in some cases
|
||||
dut1.expect(re.compile(r"HTTP Stream reader Status = 200, content_length = (\d)"))
|
||||
dut1.expect(re.compile(r"Last esp error code: 0x8001"))
|
||||
dut1.expect("Finish http example")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_protocol_esp_http_client()
|
@ -1,8 +1,6 @@
|
||||
set(COMPONENT_SRCS "esp_http_client_example.c")
|
||||
|
||||
# Embed the server root certificate into the final binary
|
||||
#
|
||||
# (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.)
|
||||
set(COMPONENT_EMBED_TXTFILES howsmyssl_com_root_cert.pem)
|
||||
|
||||
register_component()
|
||||
idf_component_register(SRCS "esp_http_client_example.c"
|
||||
INCLUDE_DIRS "."
|
||||
EMBED_TXTFILES howsmyssl_com_root_cert.pem)
|
@ -9,20 +9,20 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_event.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "nvs.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_tls.h"
|
||||
|
||||
#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
|
||||
@ -40,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");
|
||||
@ -55,27 +57,73 @@ 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_LOGD(TAG, "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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void http_rest()
|
||||
static void http_rest_with_url(void)
|
||||
{
|
||||
char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
/**
|
||||
* NOTE: All the configuration parameters for http_client must be spefied either in URL or as host and path parameters.
|
||||
* If host and path parameters are not set, query parameter will be ignored. In such cases,
|
||||
* query parameter should be specified in URL.
|
||||
*
|
||||
* If URL as well as host and path parameters are specified, values of host and path will be considered.
|
||||
*/
|
||||
esp_http_client_config_t config = {
|
||||
.url = "http://httpbin.org/get",
|
||||
.host = "httpbin.org",
|
||||
.path = "/get",
|
||||
.query = "esp",
|
||||
.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);
|
||||
|
||||
@ -86,13 +134,15 @@ static void http_rest()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP GET request failed: %d", err);
|
||||
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) {
|
||||
@ -100,7 +150,7 @@ static void http_rest()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP POST request failed: %d", err);
|
||||
ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
//PUT
|
||||
@ -112,7 +162,7 @@ static void http_rest()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP PUT request failed: %d", err);
|
||||
ESP_LOGE(TAG, "HTTP PUT request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
//PATCH
|
||||
@ -125,7 +175,7 @@ static void http_rest()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP PATCH request failed: %d", err);
|
||||
ESP_LOGE(TAG, "HTTP PATCH request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
//DELETE
|
||||
@ -137,7 +187,7 @@ static void http_rest()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP DELETE request failed: %d", err);
|
||||
ESP_LOGE(TAG, "HTTP DELETE request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
//HEAD
|
||||
@ -149,13 +199,100 @@ static void http_rest()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP HEAD request failed: %d", err);
|
||||
ESP_LOGE(TAG, "HTTP HEAD request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
static void http_auth_basic()
|
||||
static void http_rest_with_hostname_path(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.host = "httpbin.org",
|
||||
.path = "/get",
|
||||
.transport_type = HTTP_TRANSPORT_OVER_TCP,
|
||||
.event_handler = _http_event_handler,
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
// GET
|
||||
esp_err_t err = esp_http_client_perform(client);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// POST
|
||||
const char *post_data = "field1=value1&field2=value2";
|
||||
esp_http_client_set_url(client, "/post");
|
||||
esp_http_client_set_method(client, HTTP_METHOD_POST);
|
||||
esp_http_client_set_post_field(client, post_data, strlen(post_data));
|
||||
err = esp_http_client_perform(client);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
//PUT
|
||||
esp_http_client_set_url(client, "/put");
|
||||
esp_http_client_set_method(client, HTTP_METHOD_PUT);
|
||||
err = esp_http_client_perform(client);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTP PUT Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP PUT request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
//PATCH
|
||||
esp_http_client_set_url(client, "/patch");
|
||||
esp_http_client_set_method(client, HTTP_METHOD_PATCH);
|
||||
esp_http_client_set_post_field(client, NULL, 0);
|
||||
err = esp_http_client_perform(client);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTP PATCH Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP PATCH request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
//DELETE
|
||||
esp_http_client_set_url(client, "/delete");
|
||||
esp_http_client_set_method(client, HTTP_METHOD_DELETE);
|
||||
err = esp_http_client_perform(client);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTP DELETE Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP DELETE request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
//HEAD
|
||||
esp_http_client_set_url(client, "/get");
|
||||
esp_http_client_set_method(client, HTTP_METHOD_HEAD);
|
||||
err = esp_http_client_perform(client);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTP HEAD Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP HEAD request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
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 = {
|
||||
.url = "http://user:passwd@httpbin.org/basic-auth/user/passwd",
|
||||
@ -170,12 +307,12 @@ static void http_auth_basic()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %d", err);
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
static void http_auth_basic_redirect()
|
||||
static void http_auth_basic_redirect(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.url = "http://user:passwd@httpbin.org/basic-auth/user/passwd",
|
||||
@ -183,18 +320,19 @@ static void http_auth_basic_redirect()
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
esp_err_t err = esp_http_client_perform(client);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTP Basic Auth redirect Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %d", err);
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void http_auth_digest()
|
||||
static void http_auth_digest(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.url = "http://user:passwd@httpbin.org/digest-auth/auth/user/passwd/MD5/never",
|
||||
@ -202,17 +340,18 @@ static void http_auth_digest()
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
esp_err_t err = esp_http_client_perform(client);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTP Digest Auth Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %d", err);
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
static void https()
|
||||
static void https_with_url(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.url = "https://www.howsmyssl.com",
|
||||
@ -227,12 +366,34 @@ static void https()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %d", err);
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
static void http_relative_redirect()
|
||||
static void https_with_hostname_path(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.host = "www.howsmyssl.com",
|
||||
.path = "/",
|
||||
.transport_type = HTTP_TRANSPORT_OVER_SSL,
|
||||
.event_handler = _http_event_handler,
|
||||
.cert_pem = howsmyssl_com_root_cert_pem_start,
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
esp_err_t err = esp_http_client_perform(client);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
static void http_relative_redirect(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.url = "http://httpbin.org/relative-redirect/3",
|
||||
@ -246,12 +407,12 @@ static void http_relative_redirect()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %d", err);
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
static void http_absolute_redirect()
|
||||
static void http_absolute_redirect(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.url = "http://httpbin.org/absolute-redirect/3",
|
||||
@ -265,12 +426,12 @@ static void http_absolute_redirect()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %d", err);
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
static void http_redirect_to_https()
|
||||
static void http_redirect_to_https(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.url = "http://httpbin.org/redirect-to?url=https%3A%2F%2Fwww.howsmyssl.com",
|
||||
@ -284,13 +445,13 @@ static void http_redirect_to_https()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %d", err);
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
|
||||
static void http_download_chunk()
|
||||
static void http_download_chunk(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.url = "http://httpbin.org/stream-bytes/8912",
|
||||
@ -304,12 +465,12 @@ static void http_download_chunk()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %d", err);
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
static void http_perform_as_stream_reader()
|
||||
static void http_perform_as_stream_reader(void)
|
||||
{
|
||||
char *buffer = malloc(MAX_HTTP_RECV_BUFFER + 1);
|
||||
if (buffer == NULL) {
|
||||
@ -318,12 +479,11 @@ static void http_perform_as_stream_reader()
|
||||
}
|
||||
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;
|
||||
if ((err = esp_http_client_open(client, 0)) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to open HTTP connection: %d", err);
|
||||
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
@ -345,7 +505,7 @@ static void http_perform_as_stream_reader()
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void https_async()
|
||||
static void https_async(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.url = "https://postman-echo.com/post",
|
||||
@ -372,37 +532,135 @@ static void https_async()
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %d", err);
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
static void https_with_invalid_url(void)
|
||||
{
|
||||
esp_http_client_config_t config = {
|
||||
.url = "https://not.existent.url",
|
||||
.event_handler = _http_event_handler,
|
||||
};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
esp_err_t err = esp_http_client_perform(client);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
|
||||
}
|
||||
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)
|
||||
{
|
||||
ESP_LOGI(TAG, "Connected to AP, begin http example");
|
||||
http_rest();
|
||||
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();
|
||||
https();
|
||||
https_with_url();
|
||||
https_with_hostname_path();
|
||||
http_redirect_to_https();
|
||||
http_download_chunk();
|
||||
http_perform_as_stream_reader();
|
||||
https_async();
|
||||
https_with_invalid_url();
|
||||
http_native_request();
|
||||
|
||||
ESP_LOGI(TAG, "Finish http example");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main()
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
ESP_LOGI(TAG, "Connected to AP, begin http example");
|
||||
|
||||
xTaskCreate(&http_test_task, "http_test_task", 8192, NULL, 5, NULL);
|
||||
}
|
||||
|
10
examples/protocols/esp_http_client/sdkconfig.ci
Normal file
10
examples/protocols/esp_http_client/sdkconfig.ci
Normal file
@ -0,0 +1,10 @@
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH=y
|
13
examples/protocols/esp_http_client/sdkconfig.ci.ssldyn
Normal file
13
examples/protocols/esp_http_client/sdkconfig.ci.ssldyn
Normal file
@ -0,0 +1,13 @@
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH=y
|
||||
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
|
||||
CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT=y
|
||||
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
|
@ -1,3 +0,0 @@
|
||||
CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y
|
||||
CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=1024
|
||||
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
|
Reference in New Issue
Block a user