mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
fix(esp_http_server): let the WS control handler own the protocol reply
This commit is contained in:
@@ -90,7 +90,7 @@ struct sock_db {
|
||||
bool ws_close_sent; /*!< Set to true once this endpoint has sent its own WS Close frame */
|
||||
esp_err_t (*ws_handler)(httpd_req_t *r); /*!< WebSocket handler, leave to null if it's not WebSocket */
|
||||
bool ws_control_frames; /*!< WebSocket flag indicating that control frames should be passed to user handlers */
|
||||
esp_err_t (*ws_control_handler)(httpd_req_t *r, const httpd_ws_frame_t *frame); /*!< Dedicated WebSocket control-frame handler, NULL if not used */
|
||||
esp_err_t (*ws_control_handler)(httpd_req_t *r, httpd_ws_frame_t *frame); /*!< Dedicated WebSocket control-frame handler, NULL if not used */
|
||||
void *ws_user_ctx; /*!< Pointer to user context data which will be available to handler for websocket*/
|
||||
#endif
|
||||
};
|
||||
@@ -582,8 +582,10 @@ esp_err_t httpd_ws_recv_control_frame(httpd_req_t *req, httpd_ws_frame_t *frame,
|
||||
/**
|
||||
* @brief Send the protocol reply for a received WebSocket control frame.
|
||||
*
|
||||
* @note PING is answered with a PONG echoing the payload; CLOSE is answered with
|
||||
* an empty CLOSE; all other control frames (e.g. PONG) require no reply.
|
||||
* @note PING is answered with a PONG echoing the payload. CLOSE is answered with
|
||||
* a CLOSE that echoes the received status code and reason when
|
||||
* CONFIG_HTTPD_WS_STRICTER_RFC6455 is set, and with an empty CLOSE
|
||||
* otherwise. All other control frames (for example PONG) require no reply.
|
||||
*
|
||||
* @param[in] req WebSocket request
|
||||
* @param[in] frame Control frame previously received (modified in place)
|
||||
@@ -597,15 +599,18 @@ esp_err_t httpd_ws_reply_to_control_frame(httpd_req_t *req, httpd_ws_frame_t *fr
|
||||
* @brief Handle an incoming WebSocket control frame via the dedicated control handler.
|
||||
*
|
||||
* @note Used only when a ws_control_handler is registered (handle_ws_control_frames
|
||||
* must be true). The server receives the frame body, passes a read-only view
|
||||
* to the control handler, then performs the protocol reply itself. If the
|
||||
* control handler returns an error, the reply is still sent and the error is
|
||||
* propagated so the caller closes the socket.
|
||||
* must be true). The server receives the frame body and hands it to the
|
||||
* control handler, which owns the protocol reply. The server does not reply
|
||||
* on its own, so a handler that answers a PING cannot produce a duplicate
|
||||
* PONG on the wire. A handler error is propagated so the caller closes the
|
||||
* socket.
|
||||
*
|
||||
* @param[in] req WebSocket request
|
||||
* @return
|
||||
* - ESP_OK : Control frame handled and replied
|
||||
* - others : Control handler error, or frame could not be received/replied
|
||||
* - ESP_OK : Control frame received and handled
|
||||
* - ESP_ERR_INVALID_ARG : Argument is invalid (null request aux or session)
|
||||
* - ESP_ERR_INVALID_STATE : No control handler registered for this session
|
||||
* - others : Control handler error, or frame could not be received
|
||||
*/
|
||||
esp_err_t httpd_ws_handle_control_frame(httpd_req_t *req);
|
||||
#endif /* CONFIG_HTTPD_WS_SUPPORT */
|
||||
|
||||
@@ -853,7 +853,7 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
|
||||
|
||||
/* Dispatch the frame:
|
||||
* - Control frames (CLOSE/PING/PONG) go to the dedicated control handler
|
||||
* when one is registered; the server then sends the protocol reply.
|
||||
* when one is registered; that handler owns the protocol reply.
|
||||
* - Otherwise dispatch to the data handler for non-control frames, PONG
|
||||
* frames, or when the handler opted in to receiving control frames.
|
||||
* PONG must be dispatched so that user heartbeat code can track it and
|
||||
|
||||
@@ -878,6 +878,9 @@ esp_err_t httpd_ws_handle_control_frame(httpd_req_t *req)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
struct sock_db *sd = aux->sd;
|
||||
if (sd->ws_control_handler == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
/* The server receives the control-frame body itself. Oversized or malformed
|
||||
* frames are rejected by the max_len cap (zero-trust on client input). */
|
||||
@@ -888,17 +891,9 @@ esp_err_t httpd_ws_handle_control_frame(httpd_req_t *req)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Notify the user's control handler with a read-only view of the frame. */
|
||||
esp_err_t handler_ret = ESP_OK;
|
||||
if (sd->ws_control_handler != NULL) {
|
||||
handler_ret = sd->ws_control_handler(req, &frame);
|
||||
}
|
||||
|
||||
/* The server always performs the protocol reply (PONG for PING, CLOSE for
|
||||
* CLOSE). If the handler failed, still reply, then propagate the error so the
|
||||
* caller closes the socket. */
|
||||
esp_err_t reply_ret = httpd_ws_reply_to_control_frame(req, &frame);
|
||||
return (handler_ret != ESP_OK) ? handler_ret : reply_ret;
|
||||
/* Hand the frame over. The server deliberately does not reply: with
|
||||
* handle_ws_control_frames true the application owns the protocol reply */
|
||||
return sd->ws_control_handler(req, &frame);
|
||||
}
|
||||
|
||||
esp_err_t httpd_ws_get_frame_type(httpd_req_t *req)
|
||||
|
||||
Reference in New Issue
Block a user