diff options
-rw-r--r-- | src/cowboy_http.erl | 45 | ||||
-rw-r--r-- | src/cowboy_http_req.erl | 11 |
2 files changed, 49 insertions, 7 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl index 9b8a178..e8017f2 100644 --- a/src/cowboy_http.erl +++ b/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. diff --git a/src/cowboy_http_req.erl b/src/cowboy_http_req.erl index 3a3dd2f..7a09bcb 100644 --- a/src/cowboy_http_req.erl +++ b/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. |