mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
fix(ws): enforce RFC 6455 §4.2.1 handshake requirements
This commit is contained in:
@@ -471,6 +471,129 @@ TEST_CASE("WS recv failure marks close without dispatching handler", "[HTTP SERV
|
||||
|
||||
free(hd.hd_req_aux.resp_hdrs);
|
||||
}
|
||||
|
||||
#if CONFIG_HTTPD_WS_STRICTER_RFC6455
|
||||
TEST_CASE("WS HTTP/1.0 upgrade request returns 400", "[HTTP SERVER][websocket]")
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
httpd_handle_t hd = start_test_ws_server(8091, ESP_HTTPD_DEF_CTRL_PORT + 10);
|
||||
mock_server_request_t req = {
|
||||
.data = "GET /ws HTTP/1.0\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n\r\n",
|
||||
};
|
||||
mock_server_response_t *resp = mock_server_send_request(8091, &req);
|
||||
TEST_ASSERT_NOT_NULL(resp);
|
||||
|
||||
mock_server_assert_status(resp, 400);
|
||||
mock_server_response_free(resp);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, httpd_stop(hd));
|
||||
}
|
||||
#endif /* CONFIG_HTTPD_WS_STRICTER_RFC6455 */
|
||||
|
||||
/* Regression test: enabling CONFIG_HTTPD_WS_SUPPORT must not reject HTTP/1.0
|
||||
* traffic on non-WS endpoints. The HTTP/1.1 requirement only applies once
|
||||
* an "Upgrade: websocket" header confirms the request is a WS handshake. */
|
||||
TEST_CASE("Non-WS HTTP/1.0 request is not rejected by WS version check", "[HTTP SERVER][websocket]")
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
httpd_handle_t hd = start_test_ws_server(8097, ESP_HTTPD_DEF_CTRL_PORT + 16);
|
||||
mock_server_request_t req = {
|
||||
.data = "GET /non-ws HTTP/1.0\r\n"
|
||||
"Host: localhost\r\n\r\n",
|
||||
};
|
||||
mock_server_response_t *resp = mock_server_send_request(8097, &req);
|
||||
TEST_ASSERT_NOT_NULL(resp);
|
||||
/* No handler is registered for /non-ws, so the server returns 404.
|
||||
* The crucial assertion is that it is NOT 400 from the WS version check —
|
||||
* i.e., HTTP/1.0 was accepted at the parser level. */
|
||||
mock_server_assert_status(resp, 404);
|
||||
mock_server_response_free(resp);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, httpd_stop(hd));
|
||||
}
|
||||
|
||||
#if CONFIG_HTTPD_WS_STRICTER_RFC6455
|
||||
TEST_CASE("WS handshake missing Host returns 400", "[HTTP SERVER][websocket]")
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
httpd_handle_t hd = start_test_ws_server(8090, ESP_HTTPD_DEF_CTRL_PORT + 9);
|
||||
mock_server_request_t req = {
|
||||
.data = "GET /ws HTTP/1.1\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n\r\n",
|
||||
};
|
||||
mock_server_response_t *resp = mock_server_send_request(8090, &req);
|
||||
TEST_ASSERT_NOT_NULL(resp);
|
||||
mock_server_assert_status(resp, 400);
|
||||
mock_server_response_free(resp);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, httpd_stop(hd));
|
||||
}
|
||||
#endif /* CONFIG_HTTPD_WS_STRICTER_RFC6455 */
|
||||
|
||||
TEST_CASE("WS handshake missing Sec-WebSocket-Version returns 400", "[HTTP SERVER][websocket]")
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
httpd_handle_t hd = start_test_ws_server(8094, ESP_HTTPD_DEF_CTRL_PORT + 13);
|
||||
mock_server_request_t req = {
|
||||
.data = "GET /ws HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n",
|
||||
};
|
||||
mock_server_response_t *resp = mock_server_send_request(8094, &req);
|
||||
TEST_ASSERT_NOT_NULL(resp);
|
||||
mock_server_assert_status(resp, 400);
|
||||
mock_server_response_free(resp);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, httpd_stop(hd));
|
||||
}
|
||||
|
||||
TEST_CASE("WS handshake unsupported version returns 426 with Sec-WebSocket-Version header", "[HTTP SERVER][websocket]")
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
httpd_handle_t hd = start_test_ws_server(8093, ESP_HTTPD_DEF_CTRL_PORT + 12);
|
||||
mock_server_request_t req = {
|
||||
.data = "GET /ws HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||
"Sec-WebSocket-Version: 12\r\n\r\n",
|
||||
};
|
||||
mock_server_response_t *resp = mock_server_send_request(8093, &req);
|
||||
TEST_ASSERT_NOT_NULL(resp);
|
||||
mock_server_assert_status(resp, 426);
|
||||
TEST_ASSERT_NOT_NULL(strstr(resp->data, "Sec-WebSocket-Version: 13"));
|
||||
mock_server_response_free(resp);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, httpd_stop(hd));
|
||||
}
|
||||
|
||||
#if CONFIG_HTTPD_WS_STRICTER_RFC6455
|
||||
TEST_CASE("WS handshake invalid Sec-WebSocket-Key returns 400", "[HTTP SERVER][websocket]")
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
httpd_handle_t hd = start_test_ws_server(8092, ESP_HTTPD_DEF_CTRL_PORT + 11);
|
||||
mock_server_request_t req = {
|
||||
.data = "GET /ws HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Key: AQID\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n\r\n",
|
||||
};
|
||||
mock_server_response_t *resp = mock_server_send_request(8092, &req);
|
||||
TEST_ASSERT_NOT_NULL(resp);
|
||||
mock_server_assert_status(resp, 400);
|
||||
mock_server_response_free(resp);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, httpd_stop(hd));
|
||||
}
|
||||
#endif /* CONFIG_HTTPD_WS_STRICTER_RFC6455 */
|
||||
|
||||
#endif /* CONFIG_HTTPD_WS_SUPPORT */
|
||||
|
||||
/********* URL query / header pointer-accessor tests *********
|
||||
|
||||
@@ -13,27 +13,6 @@
|
||||
* response. The server under test is started/stopped by the test itself using
|
||||
* the normal httpd_start() / httpd_stop() APIs; this module only provides the
|
||||
* "client" side.
|
||||
*
|
||||
* Typical usage:
|
||||
* @code
|
||||
* // 1. Start the server
|
||||
* httpd_config_t cfg = HTTPD_DEFAULT_CONFIG();
|
||||
* cfg.server_port = 8099;
|
||||
* httpd_handle_t server;
|
||||
* httpd_start(&server, &cfg);
|
||||
* httpd_register_uri_handler(server, &my_handler);
|
||||
*
|
||||
* // 2. Send a scripted request and capture the response
|
||||
* mock_server_request_t req = {
|
||||
* .data = "GET /path HTTP/1.1\r\nHost: localhost\r\n\r\n",
|
||||
* };
|
||||
* mock_server_response_t resp = {0};
|
||||
* mock_server_send_request(8099, &req, &resp);
|
||||
* TEST_ASSERT_EQUAL(200, resp.status_code);
|
||||
*
|
||||
* // 3. Stop the server
|
||||
* httpd_stop(server);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -8,3 +8,4 @@ CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
CONFIG_HTTPD_WS_SUPPORT=y
|
||||
CONFIG_HTTPD_WS_STRICTER_RFC6455=y
|
||||
|
||||
Reference in New Issue
Block a user