From 098f6ba2975f73cd9c99c91c51e0dfbd764d8908 Mon Sep 17 00:00:00 2001 From: glmfe Date: Fri, 21 Feb 2025 12:04:09 -0300 Subject: [PATCH] feat(websocket): Add websocket HTTP redirect - Handle 301 status (moved permanently) and redirect the connection to the new host. --- .../esp_websocket_client.c | 51 ++++++++++++++----- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index 3b6ec19934..890cc25663 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -60,6 +60,12 @@ static const char *TAG = "websocket_client"; #define WS_OVER_TCP_SCHEME "ws" #define WS_OVER_TLS_SCHEME "wss" #define WS_HTTP_BASIC_AUTH "Basic " +#define WS_HTTP_REDIRECT(code) ((code >= 300) && (code < 400)) + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0) +// Features supported in 5.5.0 +#define WS_TRANSPORT_REDIRECT_HEADER_SUPPORT 1 +#endif const static int STOPPED_BIT = BIT0; const static int CLOSE_FRAME_SENT_BIT = BIT1; // Indicates that a close frame was sent by the client @@ -586,6 +592,23 @@ static esp_err_t esp_websocket_client_create_transport(esp_websocket_client_hand return ESP_OK; } +static void esp_websocket_client_prepare_transport(esp_websocket_client_handle_t client) +{ + //get transport by scheme + if (client->transport == NULL && client->config->ext_transport == NULL) { + client->transport = esp_transport_list_get_transport(client->transport_list, client->config->scheme); + } + + if (client->transport == NULL) { + ESP_LOGE(TAG, "There are no transports valid, stop websocket client"); + client->run = false; + } + //default port + if (client->config->port == 0) { + client->config->port = esp_transport_get_default_port(client->transport); + } +} + static int esp_websocket_client_send_with_exact_opcode(esp_websocket_client_handle_t client, ws_transport_opcodes_t opcode, const uint8_t *data, int len, TickType_t timeout) { int ret = -1; @@ -985,19 +1008,7 @@ static void esp_websocket_client_task(void *pv) esp_websocket_client_handle_t client = (esp_websocket_client_handle_t) pv; client->run = true; - //get transport by scheme - if (client->transport == NULL && client->config->ext_transport == NULL) { - client->transport = esp_transport_list_get_transport(client->transport_list, client->config->scheme); - } - - if (client->transport == NULL) { - ESP_LOGE(TAG, "There are no transports valid, stop websocket client"); - client->run = false; - } - //default port - if (client->config->port == 0) { - client->config->port = esp_transport_get_default_port(client->transport); - } + esp_websocket_client_prepare_transport(client); client->state = WEBSOCKET_STATE_INIT; xEventGroupClearBits(client->status_bits, STOPPED_BIT | CLOSE_FRAME_SENT_BIT); @@ -1035,6 +1046,20 @@ static void esp_websocket_client_task(void *pv) esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT); break; } +#if WS_TRANSPORT_REDIRECT_HEADER_SUPPORT + else if (WS_HTTP_REDIRECT(result)) { + // Redirecting to a new URI + client->config->port = 0; + client->config->uri = esp_transport_ws_get_redir_uri(client->transport); + esp_websocket_client_set_uri(client, client->config->uri); + esp_websocket_client_prepare_transport(client); + + // Rerun the connection with the redir uri. + client->state = WEBSOCKET_STATE_INIT; + ESP_LOGI(TAG, "Redirecting to %s", client->config->uri); + break; + } +#endif ESP_LOGD(TAG, "Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port); client->state = WEBSOCKET_STATE_CONNECTED;