kopia lustrzana https://github.com/espressif/esp-idf
Merge branch 'feature/ws_server_subprotocols' into 'master'
http_server: adds support for setting websocket subprotocol See merge request espressif/esp-idf!10783pull/6275/head
commit
4f0428a811
|
@ -412,6 +412,11 @@ typedef struct httpd_uri {
|
|||
* This is used if a custom processing of the control frames is needed
|
||||
*/
|
||||
bool handle_ws_control_frames;
|
||||
|
||||
/**
|
||||
* Pointer to subprotocol supported by URI
|
||||
*/
|
||||
const char *supported_subprotocol;
|
||||
#endif
|
||||
} httpd_uri_t;
|
||||
|
||||
|
|
|
@ -492,7 +492,8 @@ int httpd_default_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len,
|
|||
/**
|
||||
* @brief This function is for responding a WebSocket handshake
|
||||
*
|
||||
* @param[in] req Pointer to handshake request that will be handled
|
||||
* @param[in] req Pointer to handshake request that will be handled
|
||||
* @param[in] supported_subprotocol Pointer to the subprotocol supported by this URI
|
||||
* @return
|
||||
* - ESP_OK : When handshake is sucessful
|
||||
* - ESP_ERR_NOT_FOUND : When some headers (Sec-WebSocket-*) are not found
|
||||
|
@ -501,7 +502,7 @@ int httpd_default_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len,
|
|||
* - ESP_ERR_INVALID_ARG : Argument is invalid (null or non-WebSocket)
|
||||
* - ESP_FAIL : Socket failures
|
||||
*/
|
||||
esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req);
|
||||
esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *supported_subprotocol);
|
||||
|
||||
/**
|
||||
* @brief This function is for getting a frame type
|
||||
|
|
|
@ -175,6 +175,11 @@ esp_err_t httpd_register_uri_handler(httpd_handle_t handle,
|
|||
#ifdef CONFIG_HTTPD_WS_SUPPORT
|
||||
hd->hd_calls[i]->is_websocket = uri_handler->is_websocket;
|
||||
hd->hd_calls[i]->handle_ws_control_frames = uri_handler->handle_ws_control_frames;
|
||||
if (uri_handler->supported_subprotocol) {
|
||||
hd->hd_calls[i]->supported_subprotocol = strdup(uri_handler->supported_subprotocol);
|
||||
} else {
|
||||
hd->hd_calls[i]->supported_subprotocol = NULL;
|
||||
}
|
||||
#endif
|
||||
ESP_LOGD(TAG, LOG_FMT("[%d] installed %s"), i, uri_handler->uri);
|
||||
return ESP_OK;
|
||||
|
@ -316,7 +321,7 @@ esp_err_t httpd_uri(struct httpd_data *hd)
|
|||
struct httpd_req_aux *aux = req->aux;
|
||||
if (uri->is_websocket && aux->ws_handshake_detect && uri->method == HTTP_GET) {
|
||||
ESP_LOGD(TAG, LOG_FMT("Responding WS handshake to sock %d"), aux->sd->fd);
|
||||
esp_err_t ret = httpd_ws_respond_server_handshake(&hd->hd_req);
|
||||
esp_err_t ret = httpd_ws_respond_server_handshake(&hd->hd_req, uri->supported_subprotocol);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/random.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
|
@ -44,7 +45,50 @@ static const char *TAG="httpd_ws";
|
|||
*/
|
||||
static const char ws_magic_uuid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req)
|
||||
/* Checks if any subprotocols from the comma seperated list matches the supported one
|
||||
*
|
||||
* Returns true if the response should contain a protocol field
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Checks if any subprotocols from the comma seperated list matches the supported one
|
||||
*
|
||||
* @param supported_subprotocol[in] The subprotocol supported by the URI
|
||||
* @param subprotocol[in], [in]: A comma seperate list of subprotocols requested
|
||||
* @param buf_len Length of the buffer
|
||||
* @return true: found a matching subprotocol
|
||||
* @return false
|
||||
*/
|
||||
static bool httpd_ws_get_response_subprotocol(const char *supported_subprotocol, char *subprotocol, size_t buf_len)
|
||||
{
|
||||
/* Request didnt contain any subprotocols */
|
||||
if (strnlen(subprotocol, buf_len) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (supported_subprotocol == NULL) {
|
||||
ESP_LOGW(TAG, "Sec-WebSocket-Protocol %s not supported, URI do not support any subprotocols", subprotocol);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get first subprotocol from comma seperated list */
|
||||
char *rest = NULL;
|
||||
char *s = strtok_r(subprotocol, ", ", &rest);
|
||||
do {
|
||||
if (strncmp(s, supported_subprotocol, sizeof(subprotocol)) == 0) {
|
||||
ESP_LOGD(TAG, "Requested subprotocol supported: %s", s);
|
||||
return true;
|
||||
}
|
||||
} while ((s = strtok_r(NULL, ", ", &rest)) != NULL);
|
||||
|
||||
ESP_LOGW(TAG, "Sec-WebSocket-Protocol %s not supported, supported subprotocol is %s", subprotocol, supported_subprotocol);
|
||||
|
||||
/* No matches */
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *supported_subprotocol)
|
||||
{
|
||||
/* Probe if input parameters are valid or not */
|
||||
if (!req || !req->aux) {
|
||||
|
@ -101,18 +145,56 @@ esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req)
|
|||
|
||||
ESP_LOGD(TAG, LOG_FMT("Generated server key: %s"), server_key_encoded);
|
||||
|
||||
char subprotocol[50] = { '\0' };
|
||||
if (httpd_req_get_hdr_value_str(req, "Sec-WebSocket-Protocol", subprotocol, sizeof(subprotocol) - 1) == ESP_ERR_HTTPD_RESULT_TRUNC) {
|
||||
ESP_LOGW(TAG, "Sec-WebSocket-Protocol length exceeded buffer size of %d, was trunctated", sizeof(subprotocol));
|
||||
}
|
||||
|
||||
|
||||
/* Prepare the Switching Protocol response */
|
||||
char tx_buf[192] = { '\0' };
|
||||
int fmt_len = snprintf(tx_buf, sizeof(tx_buf),
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: %s\r\n\r\n", server_key_encoded);
|
||||
"Sec-WebSocket-Accept: %s\r\n", server_key_encoded);
|
||||
|
||||
if (fmt_len < 0 || fmt_len > sizeof(tx_buf)) {
|
||||
ESP_LOGW(TAG, LOG_FMT("Failed to prepare Tx buffer"));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if ( httpd_ws_get_response_subprotocol(supported_subprotocol, subprotocol, sizeof(subprotocol))) {
|
||||
ESP_LOGD(TAG, "subprotocol: %s", subprotocol);
|
||||
int r = snprintf(tx_buf + fmt_len, sizeof(tx_buf) - fmt_len, "Sec-WebSocket-Protocol: %s\r\n", supported_subprotocol);
|
||||
if (r <= 0) {
|
||||
ESP_LOGE(TAG, "Error in response generation"
|
||||
"(snprintf of subprotocol returned %d, buffer size: %d", r, sizeof(tx_buf));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
fmt_len += r;
|
||||
|
||||
if (fmt_len >= sizeof(tx_buf)) {
|
||||
ESP_LOGE(TAG, "Error in response generation"
|
||||
"(snprintf of subprotocol returned %d, desired response len: %d, buffer size: %d", r, fmt_len, sizeof(tx_buf));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int r = snprintf(tx_buf + fmt_len, sizeof(tx_buf) - fmt_len, "\r\n");
|
||||
if (r <= 0) {
|
||||
ESP_LOGE(TAG, "Error in response generation"
|
||||
"(snprintf of subprotocol returned %d, buffer size: %d", r, sizeof(tx_buf));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
fmt_len += r;
|
||||
if (fmt_len >= sizeof(tx_buf)) {
|
||||
ESP_LOGE(TAG, "Error in response generation"
|
||||
"(snprintf of header terminal returned %d, desired response len: %d, buffer size: %d", r, fmt_len, sizeof(tx_buf));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Send off the response */
|
||||
if (httpd_send(req, tx_buf, fmt_len) < 0) {
|
||||
ESP_LOGW(TAG, LOG_FMT("Failed to send the response"));
|
||||
|
|
Ładowanie…
Reference in New Issue