mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
feat(http_server): improve websocket server handling
1. Adds post handshake callback 2. Removes requirement to handle HTTP_GET message in websocket handler Closes https://github.com/espressif/esp-idf/issues/18215
This commit is contained in:
@@ -9,4 +9,15 @@ menu "Example Configuration"
|
||||
This will allow the server to register a callback function that will be
|
||||
called before the WebSocket handshake is processed.
|
||||
|
||||
config EXAMPLE_ENABLE_WS_POST_HANDSHAKE_CB
|
||||
bool "Enable WebSocket post-handshake callback"
|
||||
select HTTPD_WS_POST_HANDSHAKE_CB_SUPPORT
|
||||
default y
|
||||
help
|
||||
Enable this option to use WebSocket post-handshake callback.
|
||||
This will allow the server to register a callback function that will be
|
||||
called after the WebSocket handshake is processed.
|
||||
In this example, the post-handshake callback is used to send a welcome message
|
||||
to the client after the handshake is complete.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -87,16 +87,36 @@ static esp_err_t ws_pre_handshake_cb(httpd_req_t *req)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_ENABLE_WS_POST_HANDSHAKE_CB
|
||||
static esp_err_t ws_post_handshake_cb(httpd_req_t *req)
|
||||
{
|
||||
ESP_LOGI(TAG, "=== ws_post_handshake_cb called ===");
|
||||
|
||||
// Get the URI with query string
|
||||
const char *uri = req->uri;
|
||||
ESP_LOGI(TAG, "WebSocket connection established for URI: %s", uri ? uri : "NULL");
|
||||
|
||||
// Send a welcome message to the client
|
||||
httpd_ws_frame_t ws_pkt;
|
||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||
ws_pkt.payload = (uint8_t *)"Welcome to the WebSocket Echo Server (post-handshake)!";
|
||||
ws_pkt.len = strlen((char *)ws_pkt.payload);
|
||||
esp_err_t ret = httpd_ws_send_frame(req, &ws_pkt);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "httpd_ws_send_frame failed with %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* CONFIG_EXAMPLE_ENABLE_WS_POST_HANDSHAKE_CB */
|
||||
|
||||
/*
|
||||
* This handler echos back the received ws data
|
||||
* and triggers an async send if certain message received
|
||||
*/
|
||||
static esp_err_t echo_handler(httpd_req_t *req)
|
||||
{
|
||||
if (req->method == HTTP_GET) {
|
||||
ESP_LOGI(TAG, "Handshake done, the new connection was opened");
|
||||
return ESP_OK;
|
||||
}
|
||||
httpd_ws_frame_t ws_pkt;
|
||||
uint8_t *buf = NULL;
|
||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||
@@ -156,8 +176,11 @@ static const httpd_uri_t ws_auth = {
|
||||
.user_ctx = NULL,
|
||||
.is_websocket = true,
|
||||
#ifdef CONFIG_EXAMPLE_ENABLE_WS_PRE_HANDSHAKE_CB
|
||||
.ws_pre_handshake_cb = ws_pre_handshake_cb
|
||||
#endif
|
||||
.ws_pre_handshake_cb = ws_pre_handshake_cb,
|
||||
#endif /* CONFIG_EXAMPLE_ENABLE_WS_PRE_HANDSHAKE_CB */
|
||||
#ifdef CONFIG_EXAMPLE_ENABLE_WS_POST_HANDSHAKE_CB
|
||||
.ws_post_handshake_cb = ws_post_handshake_cb,
|
||||
#endif /* CONFIG_EXAMPLE_ENABLE_WS_POST_HANDSHAKE_CB */
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -119,11 +119,30 @@ def test_ws_auth_handshake(dut: Dut) -> None:
|
||||
handshake_success = False
|
||||
try:
|
||||
# Attempt to use WSClient, expecting it to fail handshake
|
||||
with WsClient(got_ip, int(got_port), uri='auth?token=valid') as ws: # type: ignore # noqa: F841
|
||||
with WsClient(got_ip, int(got_port), uri='auth?token=invalid') as ws: # type: ignore # noqa: F841
|
||||
handshake_success = True
|
||||
except Exception as e:
|
||||
logging.info(f'WebSocket handshake failed: {e}')
|
||||
handshake_success = False
|
||||
|
||||
if handshake_success is False:
|
||||
if handshake_success is True:
|
||||
raise RuntimeError('WebSocket handshake succeeded, but it should have been rejected by ws_pre_handshake_cb')
|
||||
|
||||
try:
|
||||
# Attempt to use WSClient, expecting it to succeed handshake
|
||||
with WsClient(got_ip, int(got_port), uri='auth?token=valid') as ws: # type: ignore # noqa: F841
|
||||
handshake_success = True
|
||||
dut.expect(r'ws_pre_handshake_cb called', timeout=10)
|
||||
dut.expect(r'Valid token found, accepting handshake', timeout=10)
|
||||
opcode, data = ws.read()
|
||||
logging.info(f'Received opcode:{opcode}, data:{data}')
|
||||
if opcode != OPCODE_TEXT or data.decode() != 'Welcome to the WebSocket Echo Server (post-handshake)!':
|
||||
raise RuntimeError(
|
||||
f'Failed to receive correct welcome message after handshake. Opcode:{opcode}, data:{data}'
|
||||
)
|
||||
except Exception as e:
|
||||
logging.info(f'WebSocket handshake failed: {e}')
|
||||
handshake_success = False
|
||||
|
||||
if handshake_success is False:
|
||||
raise RuntimeError('WebSocket handshake failed, but it should have succeeded with valid token')
|
||||
|
||||
Reference in New Issue
Block a user