feat(esp_https_server): Get the error codes on https_server error

Closes https://github.com/espressif/esp-idf/issues/12026
pull/13253/head
Harshit Malpani 2024-02-13 16:46:19 +05:30
rodzic 9274e3e620
commit 3e1a95a0a7
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 441A8ACC7853D493
4 zmienionych plików z 132 dodań i 27 usunięć

Wyświetl plik

@ -3,5 +3,5 @@ set(inc "include")
idf_component_register(SRCS ${src}
INCLUDE_DIRS ${inc}
REQUIRES esp_http_server esp-tls
REQUIRES esp_http_server esp-tls esp_event
PRIV_REQUIRES lwip)

Wyświetl plik

@ -12,10 +12,24 @@
#include "esp_http_server.h"
#include "esp_tls.h"
#include "esp_event.h"
#ifdef __cplusplus
extern "C" {
#endif
ESP_EVENT_DECLARE_BASE(ESP_HTTPS_SERVER_EVENT);
typedef enum {
HTTPS_SERVER_EVENT_ERROR = 0, /*!< This event occurs when there are any errors during execution */
HTTPS_SERVER_EVENT_START, /*!< This event occurs when HTTPS Server is started */
HTTPS_SERVER_EVENT_ON_CONNECTED, /*!< Once the HTTPS Server has been connected to the client */
HTTPS_SERVER_EVENT_ON_DATA, /*!< Occurs when receiving data from the client */
HTTPS_SERVER_EVENT_SENT_DATA, /*!< Occurs when an ESP HTTPS server sends data to the client */
HTTPS_SERVER_EVENT_DISCONNECTED, /*!< The connection has been disconnected */
HTTPS_SERVER_EVENT_STOP, /*!< This event occurs when HTTPS Server is stopped */
} esp_https_server_event_id_t;
typedef enum {
HTTPD_SSL_TRANSPORT_SECURE, // SSL Enabled
HTTPD_SSL_TRANSPORT_INSECURE // SSL disabled
@ -39,6 +53,8 @@ typedef struct esp_https_server_user_cb_arg {
esp_tls_t *tls; /*!< ESP-TLS connection handle */
} esp_https_server_user_cb_arg_t;
typedef esp_tls_last_error_t esp_https_server_last_error_t;
/**
* @brief Callback function prototype
* Can be used to get connection or client information (SSL context)

Wyświetl plik

@ -23,6 +23,16 @@ typedef struct httpd_ssl_transport_ctx {
httpd_ssl_ctx_t *global_ctx;
} httpd_ssl_transport_ctx_t;
ESP_EVENT_DEFINE_BASE(ESP_HTTPS_SERVER_EVENT);
static void http_dispatch_event_to_event_loop(int32_t event_id, const void* event_data, size_t event_data_size)
{
esp_err_t err = esp_event_post(ESP_HTTPS_SERVER_EVENT, event_id, event_data, event_data_size, portMAX_DELAY);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to post http_client event: %"PRId32", error: %s", event_id, esp_err_to_name(err));
}
}
/**
* SSL socket close handler
*
@ -46,6 +56,7 @@ static void httpd_ssl_close(void *ctx)
esp_tls_server_session_delete(tls);
free(ctx);
ESP_LOGD(TAG, "Secure socket closed");
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_DISCONNECTED, NULL, 0);
}
/**
@ -61,7 +72,16 @@ static int httpd_ssl_pending(httpd_handle_t server, int sockfd)
assert(transport_ctx != NULL);
esp_tls_t *tls = transport_ctx->tls;
assert(tls != NULL);
return esp_tls_get_bytes_avail(tls);
int ret = esp_tls_get_bytes_avail(tls);
if (ret < 0) {
esp_tls_error_handle_t error_handle;
if (esp_tls_get_error_handle(tls, &error_handle) == ESP_OK) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = esp_tls_get_and_clear_last_error(error_handle, &last_error.esp_tls_error_code, &last_error.esp_tls_flags);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
}
}
return ret;
}
/**
@ -80,7 +100,18 @@ static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t b
assert(transport_ctx != NULL);
esp_tls_t *tls = transport_ctx->tls;
assert(tls != NULL);
return esp_tls_conn_read(tls, buf, buf_len);
int ret = esp_tls_conn_read(tls, buf, buf_len);
if (ret < 0) {
esp_tls_error_handle_t error_handle;
if (esp_tls_get_error_handle(tls, &error_handle) == ESP_OK) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = esp_tls_get_and_clear_last_error(error_handle, &last_error.esp_tls_error_code, &last_error.esp_tls_flags);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
}
} else {
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ON_DATA, &ret, sizeof(int));
}
return ret;
}
/**
@ -99,7 +130,18 @@ static int httpd_ssl_send(httpd_handle_t server, int sockfd, const char *buf, si
assert(transport_ctx != NULL);
esp_tls_t *tls = transport_ctx->tls;
assert(tls != NULL);
return esp_tls_conn_write(tls, buf, buf_len);
int ret = esp_tls_conn_write(tls, buf, buf_len);
if (ret < 0) {
esp_tls_error_handle_t error_handle;
if (esp_tls_get_error_handle(tls, &error_handle) == ESP_OK) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = esp_tls_get_and_clear_last_error(error_handle, &last_error.esp_tls_error_code, &last_error.esp_tls_flags);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
}
} else {
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_SENT_DATA, NULL, 0);
}
return ret;
}
/**
@ -120,12 +162,15 @@ static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd)
esp_tls_t *tls = esp_tls_init();
if (!tls) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = ESP_ERR_NO_MEM;
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
return ESP_ERR_NO_MEM;
}
ESP_LOGI(TAG, "performing session handshake");
int ret = esp_tls_server_session_create(global_ctx->tls_cfg, sockfd, tls);
if (ret != 0) {
ESP_LOGE(TAG, "esp_tls_create_server_session failed");
ESP_LOGE(TAG, "esp_tls_create_server_session failed, 0x%04x", -ret);
goto fail;
}
@ -134,6 +179,9 @@ static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd)
// NOTE: allocated memory will be freed by httpd_ssl_close
httpd_ssl_transport_ctx_t *transport_ctx = (httpd_ssl_transport_ctx_t *)calloc(1, sizeof(httpd_ssl_transport_ctx_t));
if (!transport_ctx) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = ESP_ERR_NO_MEM;
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
return ESP_ERR_NO_MEM;
}
transport_ctx->tls = tls;
@ -160,10 +208,18 @@ static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd)
user_cb_data.tls = tls;
(global_ctx->user_cb)((void *)&user_cb_data);
}
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ON_CONNECTED, NULL, 0);
return ESP_OK;
fail:
esp_tls_server_session_delete(tls);
{
esp_tls_error_handle_t error_handle;
if (esp_tls_get_error_handle(tls, &error_handle) == ESP_OK) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = esp_tls_get_and_clear_last_error(error_handle, &last_error.esp_tls_error_code, &last_error.esp_tls_flags);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
}
esp_tls_server_session_delete(tls);
}
return ESP_FAIL;
}
@ -192,35 +248,35 @@ static void free_secure_context(void *ctx)
free(ssl_ctx);
}
static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *config)
static esp_err_t create_secure_context(const struct httpd_ssl_config *config, httpd_ssl_ctx_t **ssl_ctx)
{
httpd_ssl_ctx_t *ssl_ctx = calloc(1, sizeof(httpd_ssl_ctx_t));
if (!ssl_ctx) {
return NULL;
if (!ssl_ctx || !*ssl_ctx) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = ESP_OK;
esp_tls_cfg_server_t *cfg = (esp_tls_cfg_server_t *)calloc(1, sizeof(esp_tls_cfg_server_t));
if (!cfg) {
ret = ESP_ERR_NO_MEM;
goto exit;
}
if (config->session_tickets) {
if ( esp_tls_cfg_server_session_tickets_init(cfg) != ESP_OK ) {
ESP_LOGE(TAG, "Failed to init session ticket support");
ret = esp_tls_cfg_server_session_tickets_init(cfg);
if ( ret != ESP_OK ) {
ESP_LOGE(TAG, "Failed to init session ticket support. error: %s", esp_err_to_name(ret));
goto exit;
}
}
cfg->userdata = config->ssl_userdata;
cfg->alpn_protos = config->alpn_protos;
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
cfg->cert_select_cb = config->cert_select_cb;
#endif
ssl_ctx->tls_cfg = cfg;
ssl_ctx->user_cb = config->user_cb;
(*ssl_ctx)->tls_cfg = cfg;
(*ssl_ctx)->user_cb = config->user_cb;
/* cacert = CA which signs client cert, or client cert itself */
if (config->cacert_pem != NULL && config->cacert_len > 0) {
@ -231,6 +287,7 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con
cfg->cacert_bytes = config->cacert_len;
} else {
ESP_LOGE(TAG, "Could not allocate memory for client certificate authority");
ret = ESP_ERR_NO_MEM;
goto exit;
}
}
@ -244,6 +301,7 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con
cfg->servercert_bytes = config->servercert_len;
} else {
ESP_LOGE(TAG, "Could not allocate memory for server certificate");
ret = ESP_ERR_NO_MEM;
goto exit;
}
} else {
@ -251,6 +309,7 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con
if (config->cert_select_cb == NULL) {
#endif
ESP_LOGE(TAG, "No Server certificate supplied");
ret = ESP_ERR_INVALID_ARG;
goto exit;
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
} else {
@ -264,8 +323,8 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con
if (!cfg->use_secure_element) {
if (config->use_ecdsa_peripheral) {
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
ssl_ctx->tls_cfg->use_ecdsa_peripheral = config->use_ecdsa_peripheral;
ssl_ctx->tls_cfg->ecdsa_key_efuse_blk = config->ecdsa_key_efuse_blk;
(*ssl_ctx)->tls_cfg->use_ecdsa_peripheral = config->use_ecdsa_peripheral;
(*ssl_ctx)->tls_cfg->ecdsa_key_efuse_blk = config->ecdsa_key_efuse_blk;
#else
ESP_LOGE(TAG, "Please enable the support for signing using ECDSA peripheral in menuconfig.");
goto exit;
@ -278,24 +337,27 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con
cfg->serverkey_bytes = config->prvtkey_len;
} else {
ESP_LOGE(TAG, "Could not allocate memory for server key");
ret = ESP_ERR_NO_MEM;
goto exit;
}
} else {
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
if (config->cert_select_cb == NULL) {
ESP_LOGE(TAG, "No Server key supplied and no certificate selection hook is present");
ret = ESP_ERR_INVALID_ARG;
goto exit;
} else {
ESP_LOGW(TAG, "Server key not supplied, make sure to supply it in the certificate selection hook");
}
#else
ESP_LOGE(TAG, "No Server key supplied");
ret = ESP_ERR_INVALID_ARG;
goto exit;
#endif
}
}
return ssl_ctx;
return ret;
exit:
if (cfg) {
@ -303,8 +365,8 @@ exit:
free((void *) cfg->cacert_buf);
}
free(cfg);
free(ssl_ctx);
return NULL;
free(*ssl_ctx);
return ret;
}
/** Start the server */
@ -315,11 +377,16 @@ esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *conf
ESP_LOGI(TAG, "Starting server");
esp_err_t ret = ESP_OK;
if (HTTPD_SSL_TRANSPORT_SECURE == config->transport_mode) {
httpd_ssl_ctx_t *ssl_ctx = create_secure_context(config);
httpd_ssl_ctx_t *ssl_ctx = calloc(1, sizeof(httpd_ssl_ctx_t));
if (!ssl_ctx) {
return -1;
return ESP_ERR_NO_MEM;
}
ret = create_secure_context(config, &ssl_ctx);
if (ret != ESP_OK) {
return ret;
}
ESP_LOGD(TAG, "SSL context ready");
@ -342,17 +409,22 @@ esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *conf
httpd_handle_t handle = NULL;
esp_err_t ret = httpd_start(&handle, &config->httpd);
ret = httpd_start(&handle, &config->httpd);
if (ret != ESP_OK) return ret;
*pHandle = handle;
ESP_LOGI(TAG, "Server listening on port %d", config->httpd.server_port);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_START, NULL, 0);
return ESP_OK;
}
/** Stop the server */
esp_err_t httpd_ssl_stop(httpd_handle_t handle)
{
return httpd_stop(handle);
esp_err_t ret = httpd_stop(handle);
if (ret == ESP_OK) {
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_STOP, NULL, 0);
}
return ret;
}

Wyświetl plik

@ -46,6 +46,23 @@ Performance
The initial session setup can take about two seconds, or more with slower clock speed or more verbose logging. Subsequent requests through the open secure socket are much faster (down to under 100 ms).
Event Handling
--------------
ESP HTTPS Server has various events for which a handler can be triggered by :doc:`the Event Loop library <../system/esp_event>` when the particular event occurs. The handler has to be registered using :cpp:func:`esp_event_handler_register`. This helps in event handling for ESP HTTPS Server.
:cpp:enum:`esp_https_server_event_id_t` has all the events which can happen for ESP HTTPS server.
Expected data type for different ESP HTTP server events in event loop:
- HTTPS_SERVER_EVENT_ERROR : ``esp_https_server_last_error_t``
- HTTPS_SERVER_EVENT_START : ``NULL``
- HTTPS_SERVER_EVENT_ON_CONNECTED : ``NULL``
- HTTPS_SERVER_EVENT_ON_DATA : ``int``
- HTTPS_SERVER_EVENT_SENT_DATA : ``NULL``
- HTTPS_SERVER_EVENT_DISCONNECTED : ``NULL``
- HTTPS_SERVER_EVENT_STOP : ``NULL``
API Reference
-------------