You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by wi...@apache.org on 2020/01/13 19:31:32 UTC

[couchdb-mochiweb] 03/08: refactor websocket init code a little. some style fixes

This is an automated email from the ASF dual-hosted git repository.

willholley pushed a commit to tag active-passive
in repository https://gitbox.apache.org/repos/asf/couchdb-mochiweb.git

commit 101bfc57cb80bfb0f265b322290987df38e3b4c8
Author: Richard Jones <rj...@metabrew.com>
AuthorDate: Sat Oct 9 00:09:45 2010 +0100

    refactor websocket init code a little. some style fixes
---
 src/mochiweb_http.erl | 100 +++++++++++++++++++++++++-------------------------
 1 file changed, 51 insertions(+), 49 deletions(-)

diff --git a/src/mochiweb_http.erl b/src/mochiweb_http.erl
index 8713235..d38c6d5 100644
--- a/src/mochiweb_http.erl
+++ b/src/mochiweb_http.erl
@@ -220,77 +220,79 @@ range_skip_length(Spec, Size) ->
             invalid_range
     end.
 
+%% Respond to the websocket upgrade request with valid signature
+%% or exit() if any of the sec- headers look suspicious.
 websocket_init(Socket, Path, Headers) ->
     Host     = mochiweb_headers:get_value("Host", Headers),
     %Origin  = mochiweb_headers:get_value("origin", Headers), % TODO
     SubProto = mochiweb_headers:get_value("Sec-Websocket-Protocol", Headers),
     Key1     = mochiweb_headers:get_value("Sec-Websocket-Key1", Headers),
     Key2     = mochiweb_headers:get_value("Sec-Websocket-Key2", Headers),
-    % read the 8 random bytes sent after the client headers for websockets:
+    %% read the 8 random bytes sent after the client headers for websockets:
     {ok, Key3} = mochiweb_socket:recv(Socket, 8, ?HEADERS_RECV_TIMEOUT),
-    %io:format("Key1,2,3: ~p ~p ~p~n", [Key1, Key2, Key3]),
     {N1,S1} = parse_seckey(Key1),
     {N2,S2} = parse_seckey(Key2),
-    %io:format("{N1,S1} {N2,S2}: ~p ~p~n",[ {N1,S1}, {N2,S2} ] ),
+    ok = websocket_verify_parsed_sec({N1,S1}, {N2,S2}),
+    Part1 = erlang:round(N1/S1),
+    Part2 = erlang:round(N2/S2),
+    Sig = crypto:md5( <<Part1:32/unsigned-integer, Part2:32/unsigned-integer,
+                        Key3/binary>> ),
+    Proto = case mochiweb_socket:type(Socket) of 
+                ssl   -> "wss://"; 
+                plain -> "ws://" 
+            end,
+    SubProtoHeader = case SubProto of 
+                         undefined  -> ""; 
+                         P          -> ["Sec-WebSocket-Protocol: ", P, "\r\n"]
+                     end,
+    Data = ["HTTP/1.1 101 Web Socket Protocol Handshake\r\n",
+            "Upgrade: WebSocket\r\n",
+            "Connection: Upgrade\r\n",
+            "Sec-WebSocket-Location: ", Proto,Host,Path, "\r\n",
+            "Sec-WebSocket-Origin: http://", Host, "\r\n",
+            SubProtoHeader,
+            "\r\n",
+            <<Sig/binary>>
+           ],
+    mochiweb_socket:send(Socket, Data),
+    ok.
+            
+%% websocket seckey parser:
+%% extract integer by only looking at [0-9]+ in the string
+%% count spaces in the string
+%% returns: {int, numspaces}
+parse_seckey(Str) ->
+    parse_seckey1(Str, {"",0}).
+
+parse_seckey1("", {NumStr,NumSpaces}) ->
+    {list_to_integer(lists:reverse(NumStr)), NumSpaces};
+parse_seckey1([32|T], {Ret,NumSpaces}) -> % ASCII/dec space
+    parse_seckey1(T, {Ret, 1+NumSpaces});
+parse_seckey1([N|T],  {Ret,NumSpaces}) when N >= 48, N =< 57 -> % ASCII/dec 0-9 
+    parse_seckey1(T, {[N|Ret], NumSpaces});
+parse_seckey1([_|T], Acc) -> 
+    parse_seckey1(T, Acc).
+
+%% exit if anything suspicious is detected
+websocket_verify_parsed_sec({N1,S1}, {N2,S2}) ->
     case N1 > 4294967295 orelse 
          N2 > 4294967295 orelse 
          S1 == 0 orelse
          S2 == 0 of
         true ->
-            %  This is a symptom of an attack.
+            %%  This is a symptom of an attack.
             exit(websocket_attack);
         false ->
             case N1 rem S1 /= 0 orelse
                  N2 rem S2 /= 0 of
                 true ->
-                    % This can only happen if the client is not a conforming
-                    % WebSocket client.
-                    exit(dodgy_client);
+                    %% This can only happen if the client is not a conforming
+                    %% WebSocket client.
+                    exit(websocket_client_misspoke);
                 false ->
-                    Part1 = erlang:round(N1/S1),
-                    Part2 = erlang:round(N2/S2),
-                    %io:format("Part1 : ~p  Part2: ~p~n", [Part1, Part2]),
-                    Sig = crypto:md5( <<Part1:32/unsigned-integer,
-                                        Part2:32/unsigned-integer,
-                                        Key3/binary>> ),
-                    Proto = case mochiweb_socket:type(Socket) of 
-                                ssl   -> "wss://"; 
-                                plain -> "ws://" 
-                            end,
-                    SubProtoHeader = case SubProto of 
-                                         undefined -> ""; 
-                                         P  -> ["Sec-WebSocket-Protocol: ", 
-                                                P, "\r\n"]
-                                     end,
-                    Data = ["HTTP/1.1 101 Web Socket Protocol Handshake\r\n",
-                            "Upgrade: WebSocket\r\n",
-                            "Connection: Upgrade\r\n",
-                            "Sec-WebSocket-Location: ", Proto,Host,Path, "\r\n",
-                            "Sec-WebSocket-Origin: http://", Host, "\r\n",
-                            SubProtoHeader,
-                            "\r\n",
-                            <<Sig/binary>>
-                           ],
-                    mochiweb_socket:send(Socket, Data),
-                    ok                    
+                    ok
             end
     end.
-            
-% websocket seckey parser:
-% extract integer by only looking at [0-9]+ in the string
-% count spaces in the string
-% returns: {int, numspaces}
-parse_seckey(Str) ->
-    parse_seckey1(Str, {"",0}).
-
-parse_seckey1("", {NumStr,NumSpaces}) ->
-    {list_to_integer(lists:reverse(NumStr)), NumSpaces};
-parse_seckey1([32|T], {Ret,NumSpaces}) -> % ASCII/dec space
-    parse_seckey1(T, {Ret, 1+NumSpaces});
-parse_seckey1([N|T],  {Ret,NumSpaces}) when N >= 48, N =< 57 -> % ASCII/dec 0-9 
-    parse_seckey1(T, {[N|Ret], NumSpaces});
-parse_seckey1([_|T], Acc) -> 
-    parse_seckey1(T, Acc).
   
 %%
 %% Tests