Browse Source

Fix parsing of the Cookie header

This should be equivalent to what we do in Set-Cookie. Real-world
testing is needed to confirm it works as intended.
Loïc Hoguin 12 years ago
parent
commit
8858ca240f
1 changed files with 54 additions and 10 deletions
  1. 54 10
      src/cowboy_http.erl

+ 54 - 10
src/cowboy_http.erl

@@ -121,7 +121,7 @@ cookie_list(Data, Acc) ->
 		fun (<<>>) -> Acc;
 			(<< $,, Rest/binary >>) -> cookie_list(Rest, Acc);
 			(<< $;, Rest/binary >>) -> cookie_list(Rest, Acc);
-			(Rest) -> param(Rest,
+			(Rest) -> cookie(Rest,
 				fun (Rest2, << $$, _/bits >>, _) ->
 						cookie_list(Rest2, Acc);
 					(Rest2, Name, Value) ->
@@ -129,6 +129,50 @@ cookie_list(Data, Acc) ->
 				end)
 		end).
 
+-spec cookie(binary(), fun()) -> any().
+cookie(Data, Fun) ->
+	whitespace(Data,
+		fun (Rest) ->
+				cookie_name(Rest,
+					fun (_Rest2, <<>>) -> {error, badarg};
+						(<< $=, Rest2/binary >>, Name) ->
+							cookie_value(Rest2,
+								fun (Rest3, Value) ->
+										Fun(Rest3, Name, Value)
+								end);
+						(_Rest2, _Attr) -> {error, badarg}
+					end)
+		end).
+
+-spec cookie_name(binary(), fun()) -> any().
+cookie_name(Data, Fun) ->
+	cookie_name(Data, Fun, <<>>).
+
+-spec cookie_name(binary(), fun(), binary()) -> any().
+cookie_name(<<>>, Fun, Acc) ->
+	Fun(<<>>, Acc);
+cookie_name(Data = << C, _Rest/binary >>, Fun, Acc)
+		when C =:= $=; C =:= $,; C =:= $;; C =:= $\s; C =:= $\t;
+			 C =:= $\r; C =:= $\n; C =:= $\013; C =:= $\014 ->
+	Fun(Data, Acc);
+cookie_name(<< C, Rest/binary >>, Fun, Acc) ->
+	C2 = cowboy_bstr:char_to_lower(C),
+	cookie_name(Rest, Fun, << Acc/binary, C2 >>).
+
+-spec cookie_value(binary(), fun()) -> any().
+cookie_value(Data, Fun) ->
+	cookie_value(Data, Fun, <<>>).
+
+-spec cookie_value(binary(), fun(), binary()) -> any().
+cookie_value(<<>>, Fun, Acc) ->
+	Fun(<<>>, Acc);
+cookie_value(Data = << C, _Rest/binary >>, Fun, Acc)
+		when C =:= $,; C =:= $;; C =:= $\s; C =:= $\t;
+			 C =:= $\r; C =:= $\n; C =:= $\013; C =:= $\014 ->
+	Fun(Data, Acc);
+cookie_value(<< C, Rest/binary >>, Fun, Acc) ->
+	cookie_value(Rest, Fun, << Acc/binary, C >>).
+
 %% @doc Parse a content type.
 -spec content_type(binary()) -> any().
 content_type(Data) ->
@@ -1016,24 +1060,24 @@ cookie_list_test_() ->
 			{<<"name">>, <<"value">>},
 			{<<"name2">>, <<"value2">>}
 		]},
-		{<<"$Version=\"1\"; Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"">>, [
+		{<<"$Version=1; Customer=WILE_E_COYOTE; $Path=/acme">>, [
 			{<<"customer">>, <<"WILE_E_COYOTE">>}
 		]},
-		{<<"$Version=\"1\"; Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"; "
-			"Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"; "
-			"Shipping=\"FedEx\"; $Path=\"/acme\"">>, [
+		{<<"$Version=1; Customer=WILE_E_COYOTE; $Path=/acme; "
+			"Part_Number=Rocket_Launcher_0001; $Path=/acme; "
+			"Shipping=FedEx; $Path=/acme">>, [
 			{<<"customer">>, <<"WILE_E_COYOTE">>},
 			{<<"part_number">>, <<"Rocket_Launcher_0001">>},
 			{<<"shipping">>, <<"FedEx">>}
 		]},
 		%% Potential edge cases (initially from Mochiweb).
-		{<<"foo=\"\\x\"">>, [{<<"foo">>, <<"x">>}]},
+		{<<"foo=\\x">>, [{<<"foo">>, <<"\\x">>}]},
 		{<<"=">>, {error, badarg}},
 		{<<"  foo ; bar  ">>, {error, badarg}},
-		{<<"foo=;bar=">>, {error, badarg}},
-		{<<"foo=\"\\\";\";bar ">>, {error, badarg}},
-		{<<"foo=\"\\\";\";bar=good ">>,
-			[{<<"foo">>, <<"\";">>}, {<<"bar">>, <<"good">>}]},
+		{<<"foo=;bar=">>, [{<<"foo">>, <<>>}, {<<"bar">>, <<>>}]},
+		{<<"foo=\\\";;bar ">>, {error, badarg}},
+		{<<"foo=\\\";;bar=good ">>,
+			[{<<"foo">>, <<"\\\"">>}, {<<"bar">>, <<"good">>}]},
 		{<<"foo=\"\\\";bar">>, {error, badarg}},
 		{<<"">>, {error, badarg}},
 		{<<"foo=bar , baz=wibble ">>,