Browse Source

Support 'Content-Length' in parse_header/2

Anthony Ramine 13 years ago
parent
commit
04bcbc444d
2 changed files with 49 additions and 7 deletions
  1. 41 4
      src/cowboy_http.erl
  2. 8 3
      src/cowboy_http_req.erl

+ 41 - 4
src/cowboy_http.erl

@@ -17,7 +17,7 @@
 
 %% Parsing.
 -export([list/2, nonempty_list/2,
-	media_range/2, charset/2,
+	media_range/2, charset/2, digits/1,
 	token/2, token_ci/2, quoted_string/2]).
 
 %% Interpretation.
@@ -28,6 +28,11 @@
 
 %% Parsing.
 
+%% Use only as a guard.
+-define(IS_DIGIT(C),
+	C =:= $0; C =:= $1; C =:= $2; C =:= $3; C =:= $4;
+	C =:= $5; C =:= $6; C =:= $7; C =:= $8; C =:= $9).
+
 %% @doc Parse a non-empty list of the given type.
 -spec nonempty_list(binary(), fun()) -> [any(), ...] | {error, badarg}.
 nonempty_list(Data, Fun) ->
@@ -240,6 +245,31 @@ whitespace(<< C, Rest/bits >>, Fun)
 whitespace(Data, Fun) ->
 	Fun(Data).
 
+%% @doc Parse a list of digits as a non negative integer.
+-spec digits(binary()) -> non_neg_integer() | {error, badarg}.
+digits(Data) ->
+	digits(Data,
+		fun (Rest, I) ->
+			whitespace(Rest,
+				fun (<<>>) ->
+						I;
+					(_Rest2) ->
+						{error, badarg}
+				end)
+		end).
+
+-spec digits(binary(), fun()) -> any().
+digits(<< C, Rest/bits >>, Fun) when ?IS_DIGIT(C) ->
+	digits(Rest, Fun, C - $0);
+digits(_Data, _Fun) ->
+	{error, badarg}.
+
+-spec digits(binary(), fun(), non_neg_integer()) -> any().
+digits(<< C, Rest/bits >>, Fun, Acc) when ?IS_DIGIT(C) ->
+	digits(Rest, Fun, Acc * 10 + (C - $0));
+digits(Data, Fun, Acc) ->
+	Fun(Data, Acc).
+
 %% @doc Parse a case-insensitive token.
 %%
 %% Changes all characters to lowercase.
@@ -303,9 +333,7 @@ qvalue(_Data, _Fun) ->
 -spec qvalue(binary(), fun(), integer(), 1 | 10 | 100) -> any().
 qvalue(Data, Fun, Q, 0) ->
 	Fun(Data, Q);
-qvalue(<< C, Rest/bits >>, Fun, Q, M)
-		when C =:= $0; C =:= $1; C =:= $2; C =:= $3; C =:= $4;
-			 C =:= $5; C =:= $6; C =:= $7; C =:= $8; C =:= $9 ->
+qvalue(<< C, Rest/bits >>, Fun, Q, M) when ?IS_DIGIT(C) ->
 	qvalue(Rest, Fun, Q + (C - $0) * M, M div 10);
 qvalue(Data, Fun, Q, _M) ->
 	Fun(Data, Q).
@@ -405,4 +433,13 @@ connection_to_atom_test_() ->
 	[{lists:flatten(io_lib:format("~p", [T])),
 		fun() -> R = connection_to_atom(T) end} || {T, R} <- Tests].
 
+digits_test_() ->
+	%% {Digits, Result}
+	Tests = [
+		{<<"42    ">>, 42},
+		{<<"69\t">>, 69},
+		{<<"1337">>, 1337}
+	],
+	[{V, fun() -> R = digits(V) end} || {V, R} <- Tests].
+
 -endif.

+ 8 - 3
src/cowboy_http_req.erl

@@ -231,6 +231,11 @@ parse_header(Name, Req, Default) when Name =:= 'Connection' ->
 		fun (Value) ->
 			cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2)
 		end);
+parse_header(Name, Req, Default) when Name =:= 'Content-Length' ->
+	parse_header(Name, Req, Default,
+		fun (Value) ->
+			cowboy_http:digits(Value)
+		end);
 parse_header(Name, Req, Default) ->
 	{Value, Req2} = header(Name, Req, Default),
 	{undefined, Value, Req2}.
@@ -292,12 +297,12 @@ cookies(Req=#http_req{cookies=Cookies}) ->
 %% @todo We probably want to allow a max length.
 -spec body(#http_req{}) -> {ok, binary(), #http_req{}} | {error, atom()}.
 body(Req) ->
-	{Length, Req2} = cowboy_http_req:header('Content-Length', Req),
+	{Length, Req2} = cowboy_http_req:parse_header('Content-Length', Req),
 	case Length of
 		undefined -> {error, badarg};
+		{error, badarg} -> {error, badarg};
 		_Any ->
-			Length2 = list_to_integer(binary_to_list(Length)),
-			body(Length2, Req2)
+			body(Length, Req2)
 	end.
 
 %% @doc Return <em>Length</em> bytes of the request body.