From eea6b2ab803cec304e55069d9e79b54615b69b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Thu, 22 Dec 2011 20:42:18 +0100 Subject: Websocket control frames payload length must be lower than 126 bytes --- src/cowboy_http_websocket.erl | 48 ++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'src/cowboy_http_websocket.erl') diff --git a/src/cowboy_http_websocket.erl b/src/cowboy_http_websocket.erl index dd1550e..08804b1 100644 --- a/src/cowboy_http_websocket.erl +++ b/src/cowboy_http_websocket.erl @@ -269,27 +269,43 @@ websocket_data(State=#state{version=Version}, Req, HandlerState, Data) websocket_data(State=#state{version=Version}, Req, HandlerState, Data) when Version =/= 0 -> << 1:1, 0:3, Opcode:4, Mask:1, PayloadLen:7, Rest/bits >> = Data, - {PayloadLen2, Rest2} = case {PayloadLen, Rest} of - {126, << L:16, R/bits >>} -> {L, R}; - {126, Rest} -> {undefined, Rest}; - {127, << 0:1, L:63, R/bits >>} -> {L, R}; - {127, Rest} -> {undefined, Rest}; - {PayloadLen, Rest} -> {PayloadLen, Rest} - end, - case {Mask, PayloadLen2} of + case {PayloadLen, Rest} of + {126, _} when Opcode >= 8 -> websocket_close( + State, Req, HandlerState, {error, protocol}); + {127, _} when Opcode >= 8 -> websocket_close( + State, Req, HandlerState, {error, protocol}); + {126, << L:16, R/bits >>} -> websocket_before_unmask( + State, Req, HandlerState, Data, R, Opcode, Mask, L); + {126, Rest} -> websocket_before_unmask( + State, Req, HandlerState, Data, Rest, Opcode, Mask, undefined); + {127, << 0:1, L:63, R/bits >>} -> websocket_before_unmask( + State, Req, HandlerState, Data, R, Opcode, Mask, L); + {127, Rest} -> websocket_before_unmask( + State, Req, HandlerState, Data, Rest, Opcode, Mask, undefined); + {PayloadLen, Rest} -> websocket_before_unmask( + State, Req, HandlerState, Data, Rest, Opcode, Mask, PayloadLen) + end; +%% Something was wrong with the frame. Close the connection. +websocket_data(State, Req, HandlerState, _Bad) -> + websocket_close(State, Req, HandlerState, {error, badframe}). + +%% hybi routing depending on whether unmasking is needed. +-spec websocket_before_unmask(#state{}, #http_req{}, any(), binary(), + binary(), opcode(), 0 | 1, non_neg_integer() | undefined) + -> closed | none(). +websocket_before_unmask(State, Req, HandlerState, Data, + Rest, Opcode, Mask, PayloadLen) -> + case {Mask, PayloadLen} of {0, 0} -> - websocket_dispatch(State, Req, HandlerState, Rest2, Opcode, <<>>); - {1, N} when N + 4 > byte_size(Rest2); N =:= undefined -> + websocket_dispatch(State, Req, HandlerState, Rest, Opcode, <<>>); + {1, N} when N + 4 > byte_size(Rest); N =:= undefined -> %% @todo We probably should allow limiting frame length. handler_before_loop(State, Req, HandlerState, Data); {1, _N} -> - << MaskKey:32, Payload:PayloadLen2/binary, Rest3/bits >> = Rest2, - websocket_unmask(State, Req, HandlerState, Rest3, + << MaskKey:32, Payload:PayloadLen/binary, Rest2/bits >> = Rest, + websocket_unmask(State, Req, HandlerState, Rest2, Opcode, Payload, MaskKey) - end; -%% Something was wrong with the frame. Close the connection. -websocket_data(State, Req, HandlerState, _Bad) -> - websocket_close(State, Req, HandlerState, {error, badframe}). + end. %% hybi unmasking. -spec websocket_unmask(#state{}, #http_req{}, any(), binary(), -- cgit v1.2.3