mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 20:30:23 +00:00
Parse Connection header tokens in a case-insensitive manner
This commit is contained in:
parent
381c178073
commit
c589922ebd
3 changed files with 32 additions and 21 deletions
|
@ -16,7 +16,7 @@
|
|||
-module(cowboy_http).
|
||||
|
||||
%% Parsing.
|
||||
-export([list/2, nonempty_list/2, token/2]).
|
||||
-export([list/2, nonempty_list/2, token/2, token_ci/2]).
|
||||
|
||||
%% Interpretation.
|
||||
-export([connection_to_atom/1]).
|
||||
|
@ -73,31 +73,47 @@ list_separator(<< C, Rest/bits >>, Fun)
|
|||
list_separator(_Data, _Fun) ->
|
||||
{error, badarg}.
|
||||
|
||||
%% @doc Parse a case-insensitive token.
|
||||
%%
|
||||
%% Changes all characters to lowercase.
|
||||
-spec token_ci(binary(), fun()) -> any().
|
||||
token_ci(Data, Fun) ->
|
||||
token(Data, Fun, ci).
|
||||
|
||||
%% @doc Parse a token.
|
||||
-spec token(binary(), fun()) -> any().
|
||||
token(<< C, Rest/bits >>, Fun)
|
||||
when C =:= $\s; C =:= $\t ->
|
||||
token(Rest, Fun);
|
||||
token(Data, Fun) ->
|
||||
token(Data, Fun, <<>>).
|
||||
token(Data, Fun, cs).
|
||||
|
||||
-spec token(binary(), fun(), binary()) -> any().
|
||||
token(<<>>, Fun, Acc) ->
|
||||
-spec token(binary(), fun(), ci | cs) -> any().
|
||||
token(<< C, Rest/bits >>, Fun, Case)
|
||||
when C =:= $\s; C =:= $\t ->
|
||||
token(Rest, Fun, Case);
|
||||
token(Data, Fun, Case) ->
|
||||
token(Data, Fun, Case, <<>>).
|
||||
|
||||
-spec token(binary(), fun(), ci | cs, binary()) -> any().
|
||||
token(<<>>, Fun, _Case, Acc) ->
|
||||
Fun(<<>>, Acc);
|
||||
token(Data = << C, _Rest/bits >>, Fun, Acc)
|
||||
token(Data = << C, _Rest/bits >>, Fun, _Case, Acc)
|
||||
when C =:= $(; C =:= $); C =:= $<; C =:= $>; C =:= $@;
|
||||
C =:= $,; C =:= $;; C =:= $:; C =:= $\\; C =:= $";
|
||||
C =:= $/; C =:= $[; C =:= $]; C =:= $?; C =:= $=;
|
||||
C =:= ${; C =:= $}; C =:= $\s; C =:= $\t;
|
||||
C < 32; C =:= 127 ->
|
||||
Fun(Data, Acc);
|
||||
token(<< C, Rest/bits >>, Fun, Acc) ->
|
||||
token(Rest, Fun, << Acc/binary, C >>).
|
||||
token(<< C, Rest/bits >>, Fun, Case = ci, Acc) ->
|
||||
C2 = cowboy_bstr:char_to_lower(C),
|
||||
token(Rest, Fun, Case, << Acc/binary, C2 >>);
|
||||
token(<< C, Rest/bits >>, Fun, Case, Acc) ->
|
||||
token(Rest, Fun, Case, << Acc/binary, C >>).
|
||||
|
||||
%% Interpretation.
|
||||
|
||||
%% @doc Walk through a tokens list and return whether
|
||||
%% the connection is keepalive or closed.
|
||||
%%
|
||||
%% The connection token is expected to be lower-case.
|
||||
-spec connection_to_atom([binary()]) -> keepalive | close.
|
||||
connection_to_atom([]) ->
|
||||
keepalive;
|
||||
|
@ -105,12 +121,8 @@ connection_to_atom([<<"keep-alive">>|_Tail]) ->
|
|||
keepalive;
|
||||
connection_to_atom([<<"close">>|_Tail]) ->
|
||||
close;
|
||||
connection_to_atom([Connection|Tail]) ->
|
||||
case cowboy_bstr:to_lower(Connection) of
|
||||
<<"close">> -> close;
|
||||
<<"keep-alive">> -> keepalive;
|
||||
_Any -> connection_to_atom(Tail)
|
||||
end.
|
||||
connection_to_atom([_Any|Tail]) ->
|
||||
connection_to_atom(Tail).
|
||||
|
||||
%% Tests.
|
||||
|
||||
|
@ -136,9 +148,8 @@ connection_to_atom_test_() ->
|
|||
%% {Tokens, Result}
|
||||
Tests = [
|
||||
{[<<"close">>], close},
|
||||
{[<<"ClOsE">>], close},
|
||||
{[<<"Keep-Alive">>], keepalive},
|
||||
{[<<"Keep-Alive">>, <<"Upgrade">>], keepalive}
|
||||
{[<<"keep-alive">>], keepalive},
|
||||
{[<<"keep-alive">>, <<"upgrade">>], keepalive}
|
||||
],
|
||||
[{lists:flatten(io_lib:format("~p", [T])),
|
||||
fun() -> R = connection_to_atom(T) end} || {T, R} <- Tests].
|
||||
|
|
|
@ -221,7 +221,7 @@ parse_header(Name, Req=#http_req{p_headers=PHeaders}, Default)
|
|||
case header(Name, Req) of
|
||||
{undefined, Req2} -> {tokens, Default, Req2};
|
||||
{Value, Req2} ->
|
||||
case cowboy_http:nonempty_list(Value, fun cowboy_http:token/2) of
|
||||
case cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2) of
|
||||
{error, badarg} ->
|
||||
{error, badarg};
|
||||
P ->
|
||||
|
|
|
@ -79,7 +79,7 @@ upgrade(ListenerPid, Handler, Opts, Req) ->
|
|||
websocket_upgrade(State, Req) ->
|
||||
{tokens, ConnTokens, Req2}
|
||||
= cowboy_http_req:parse_header('Connection', Req),
|
||||
true = lists:member(<<"Upgrade">>, ConnTokens),
|
||||
true = lists:member(<<"upgrade">>, ConnTokens),
|
||||
{WS, Req3} = cowboy_http_req:header('Upgrade', Req2),
|
||||
<<"websocket">> = cowboy_bstr:to_lower(WS),
|
||||
{Version, Req4} = cowboy_http_req:header(<<"Sec-Websocket-Version">>, Req3),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue