diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index f26be0f1c..ffc78449f 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -182,7 +182,7 @@ receive_headers(#state{trail=Trail} = State) -> Data = SockMod:recv(Socket, 0, 300000), case State#state.sockmod of gen_tcp -> - NewState = process_header(State, Data), + NewState = process_header(State, Data, true), case NewState#state.end_of_request of true -> ok; @@ -207,7 +207,7 @@ parse_headers(#state{request_method = Method, trail = Data} = State) -> end, case decode_packet(PktType, Data) of {ok, Pkt, Rest} -> - NewState = process_header(State#state{trail = Rest}, {ok, Pkt}), + NewState = process_header(State#state{trail = Rest}, {ok, Pkt}, false), case NewState#state.end_of_request of true -> ok; @@ -220,7 +220,7 @@ parse_headers(#state{request_method = Method, trail = Data} = State) -> ok end. -process_header(State, Data) -> +process_header(State, Data, Normalize) -> SockMod = State#state.sockmod, Socket = State#state.socket, case Data of @@ -267,6 +267,8 @@ process_header(State, Data) -> {ok, {http_header, _, 'Host'=Name, _, Host}} -> State#state{request_host = Host, request_headers=add_header(Name, Host, State)}; + {ok, {http_header, _, Name, _, Value}} when is_list(Name) andalso Normalize -> + State#state{request_headers=add_header(normalize_header_name(Name), Value, State)}; {ok, {http_header, _, Name, _, Value}} -> State#state{request_headers=add_header(Name, Value, State)}; {ok, http_eoh} when State#state.request_host == undefined -> @@ -1117,14 +1119,28 @@ tolower(C) when C >= $A andalso C =< $Z -> tolower(C) -> C. +normalize_header_name(Name) -> + case parse_header_line(Name, "", true) of + {ok, RName, _} -> + lists:reverse(RName); + {eol, RName} -> + lists:reverse(RName) + end. + parse_header_line(Line) -> - parse_header_line(Line, "", true). + case parse_header_line(Line, "", true) of + {ok, Name, Rest} -> + encode_header(lists:reverse(Name), Rest); + _ -> + bad_request + end. -parse_header_line("", _, _) -> - bad_request; + +parse_header_line("", Name, _) -> + {eol, Name}; parse_header_line(":" ++ Rest, Name, _) -> - encode_header(lists:reverse(Name), Rest); + {ok, Name, Rest}; parse_header_line("-" ++ Rest, Name, _) -> parse_header_line(Rest, "-" ++ Name, true); parse_header_line([C | Rest], Name, true) -> diff --git a/src/web/ejabberd_websocket.erl b/src/web/ejabberd_websocket.erl index 83f8198fb..0d6af5977 100644 --- a/src/web/ejabberd_websocket.erl +++ b/src/web/ejabberd_websocket.erl @@ -54,7 +54,7 @@ check(_Path, Headers)-> % If origins not set, access is open. is_acceptable(#ws{origin=Origin, protocol=Protocol, headers = Headers, acceptable_origins = Origins, auth_module=undefined})-> - ClientProtocol = lists:keyfind("Sec-WebSocket-Protocol",1, Headers), + ClientProtocol = lists:keyfind("Sec-Websocket-Protocol",1, Headers), case {(Origins == []) or lists:member(Origin, Origins), ClientProtocol, Protocol } of {false, _, _} -> ?INFO_MSG("client does not come from authorized origin", []), @@ -136,7 +136,7 @@ check_websocket({'draft-hybi', 8} = Vsn, Headers) -> % set required headers RequiredHeaders = [ {'Upgrade', "websocket"}, {'Connection', ignore}, {'Host', ignore}, - {"Sec-WebSocket-Key", ignore}, {"Sec-WebSocket-Version", "8"} + {"Sec-Websocket-Key", ignore}, {"Sec-Websocket-Version", "8"} ], % check for headers existance case check_headers(Headers, RequiredHeaders) of @@ -150,7 +150,7 @@ check_websocket({'draft-hybi', 13} = Vsn, Headers) -> % set required headers RequiredHeaders = [ {'Upgrade', "websocket"}, {'Connection', ignore}, {'Host', ignore}, - {"Sec-WebSocket-Key", ignore}, {"Sec-WebSocket-Version", "13"} + {"Sec-Websocket-Key", ignore}, {"Sec-Websocket-Version", "13"} ], % check for headers existance case check_headers(Headers, RequiredHeaders) of @@ -161,26 +161,12 @@ check_websocket({'draft-hybi', 13} = Vsn, Headers) -> end; check_websocket(_Vsn, _Headers) -> false. % not implemented -tolower(T) when is_list(T) -> stringprep:tolower(T); -tolower(T) -> T. - -case_insensitive_keyfind(Name, List) when is_atom(Name) -> - lists:keyfind(Name, 1, List); -case_insensitive_keyfind(Name, []) -> - false; -case_insensitive_keyfind(Name, [{FName, Val}|T]) -> - FNameL = tolower(FName), - if - FNameL == Name -> {Name, Val}; - true -> case_insensitive_keyfind(Name, T) - end. - % Function: true | [{RequiredTag, RequiredVal}, ..] % Description: Check if headers correspond to headers requirements. check_headers(Headers, RequiredHeaders) -> F = fun({Tag, Val}) -> % see if the required Tag is in the Headers - case case_insensitive_keyfind(tolower(Tag), Headers) of + case lists:keyfind(Tag, 1, Headers) of false -> true; % header not found, keep in list {_, HVal} -> %?DEBUG("check: ~p", [{Tag, HVal,Val }]),