diff --git a/include/libwebsockets/lws-client.h b/include/libwebsockets/lws-client.h index 9108484de..76c80069c 100644 --- a/include/libwebsockets/lws-client.h +++ b/include/libwebsockets/lws-client.h @@ -247,6 +247,18 @@ struct lws_client_connect_info { const char *auth_username; const char *auth_password; +#if defined(LWS_ROLE_WS) + uint8_t allow_reserved_bits; + /**< non-zero to allow reserved bits. You can get it by lws_get_reserved_bits(). + * Note: default zero means close the websocket connection for non-zero rsv. + */ + + uint8_t allow_unknown_opcode; + /**< non-zero to allow unknown opcode. You can get it by `lws_get_opcode`. + * None: default zero means close the websocket connection for unknown opcode. + */ +#endif + /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility * diff --git a/include/libwebsockets/lws-ws-state.h b/include/libwebsockets/lws-ws-state.h index d21c2a75b..b1cc54633 100644 --- a/include/libwebsockets/lws-ws-state.h +++ b/include/libwebsockets/lws-ws-state.h @@ -60,6 +60,13 @@ lws_is_first_fragment(struct lws *wsi); LWS_VISIBLE LWS_EXTERN unsigned char lws_get_reserved_bits(struct lws *wsi); +/** + * lws_get_opcode() - access opcode of ws frame + * \param wsi: lws connection + */ +LWS_VISIBLE LWS_EXTERN uint8_t +lws_get_opcode(struct lws *wsi); + /** * lws_partial_buffered() - find out if lws buffered the last write * \param wsi: websocket connection to check diff --git a/lib/roles/ws/client-parser-ws.c b/lib/roles/ws/client-parser-ws.c index f67927b2a..34dc69741 100644 --- a/lib/roles/ws/client-parser-ws.c +++ b/lib/roles/ws/client-parser-ws.c @@ -119,6 +119,8 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c) case 0xd: case 0xe: case 0xf: + if (wsi->ws->allow_unknown_opcode) + break; lwsl_wsi_info(wsi, "illegal opcode"); return -1; default: @@ -131,7 +133,7 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c) #if !defined(LWS_WITHOUT_EXTENSIONS) !wsi->ws->count_act_ext && #endif - wsi->ws->rsv) { + wsi->ws->rsv && !wsi->ws->allow_reserved_bits) { lwsl_wsi_info(wsi, "illegal rsv bits set"); return -1; } diff --git a/lib/roles/ws/client-ws.c b/lib/roles/ws/client-ws.c index 750aea96f..ddae6edbf 100644 --- a/lib/roles/ws/client-ws.c +++ b/lib/roles/ws/client-ws.c @@ -62,6 +62,12 @@ lws_create_client_ws_object(const struct lws_client_connect_info *i, wsi->ws->ietf_spec_revision = (uint8_t)v; + if (i->allow_reserved_bits) + wsi->ws->allow_reserved_bits = 1; + + if (i->allow_unknown_opcode) + wsi->ws->allow_unknown_opcode = 1; + return 0; } diff --git a/lib/roles/ws/ops-ws.c b/lib/roles/ws/ops-ws.c index 3282d3dfe..85eb8de3a 100644 --- a/lib/roles/ws/ops-ws.c +++ b/lib/roles/ws/ops-ws.c @@ -893,6 +893,12 @@ lws_get_reserved_bits(struct lws *wsi) return wsi->ws->rsv; } +uint8_t +lws_get_opcode(struct lws *wsi) +{ + return wsi->ws->opcode; +} + int lws_get_close_length(struct lws *wsi) { diff --git a/lib/roles/ws/private-lib-roles-ws.h b/lib/roles/ws/private-lib-roles-ws.h index 511547d1b..3814bf29d 100644 --- a/lib/roles/ws/private-lib-roles-ws.h +++ b/lib/roles/ws/private-lib-roles-ws.h @@ -148,6 +148,8 @@ struct _lws_websocket_related { uint8_t stashed_write_type; uint8_t tx_draining_stashed_wp; uint8_t ietf_spec_revision; + uint8_t allow_reserved_bits; + uint8_t allow_unknown_opcode; #if !defined(LWS_WITHOUT_EXTENSIONS) uint8_t count_act_ext; #endif