aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2013-04-26 15:48:06 +0200
committerLoïc Hoguin <[email protected]>2013-04-26 15:48:06 +0200
commit9bc276df3bbd540be1594e4919f90d0a38aa09ad (patch)
tree4ac7649a76c20d90d94fc56627928181fac1fbbc
parent12bd1afeedab23ef0a4fef302896dca5ee638ac2 (diff)
parent2f40a69c116c778e4dbc5abeff13c3cbf9758ac8 (diff)
downloadcowboy-9bc276df3bbd540be1594e4919f90d0a38aa09ad.tar.gz
cowboy-9bc276df3bbd540be1594e4919f90d0a38aa09ad.tar.bz2
cowboy-9bc276df3bbd540be1594e4919f90d0a38aa09ad.zip
Merge branch 'range_header' of git://github.com/Egobrain/cowboy
-rw-r--r--src/cowboy_http.erl82
-rw-r--r--src/cowboy_req.erl2
2 files changed, 84 insertions, 0 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl
index c4d3d3d..f889b52 100644
--- a/src/cowboy_http.erl
+++ b/src/cowboy_http.erl
@@ -37,6 +37,7 @@
-export([token_ci/2]).
-export([quoted_string/2]).
-export([authorization/2]).
+-export([range/1]).
%% Decoding.
-export([te_chunked/2]).
@@ -843,6 +844,64 @@ authorization_basic_password(<<>>, Fun, Acc) ->
authorization_basic_password(<<C, Rest/binary>>, Fun, Acc) ->
authorization_basic_password(Rest, Fun, <<Acc/binary, C>>).
+%% @doc Parse range header according rfc 2616.
+-spec range(binary()) -> {Unit, [Range]} | {error, badarg} when
+ Unit :: binary(),
+ Range :: {non_neg_integer(), non_neg_integer() | infinity} | neg_integer().
+range(Data) ->
+ cowboy_http:token_ci(Data, fun range/2).
+
+range(Data, Token) ->
+ whitespace(Data,
+ fun(<<"=", Rest/binary>>) ->
+ case cowboy_http:list(Rest, fun range_beginning/2) of
+ {error, badarg} ->
+ {error, badarg};
+ Ranges ->
+ {Token, Ranges}
+ end;
+ (_) ->
+ {error, badarg}
+ end).
+
+range_beginning(Data, Fun) ->
+ range_digits(Data, suffix,
+ fun(D, RangeBeginning) ->
+ range_ending(D, Fun, RangeBeginning)
+ end).
+
+range_ending(Data, Fun, RangeBeginning) ->
+ whitespace(Data,
+ fun(<<"-", R/binary>>) ->
+ case RangeBeginning of
+ suffix ->
+ range_digits(R, fun(D, RangeEnding) -> Fun(D, -RangeEnding) end);
+ _ ->
+ range_digits(R, infinity,
+ fun(D, RangeEnding) ->
+ Fun(D, {RangeBeginning, RangeEnding})
+ end)
+ end;
+ (_) ->
+ {error, badarg}
+ end).
+
+-spec range_digits(binary(), fun()) -> any().
+range_digits(Data, Fun) ->
+ whitespace(Data,
+ fun(D) ->
+ digits(D, Fun)
+ end).
+
+-spec range_digits(binary(), any(), fun()) -> any().
+range_digits(Data, Default, Fun) ->
+ whitespace(Data,
+ fun(<< C, Rest/binary >>) when C >= $0, C =< $9 ->
+ digits(Rest, Fun, C - $0);
+ (_) ->
+ Fun(Data, Default)
+ end).
+
%% Decoding.
%% @doc Decode a stream of chunks.
@@ -1364,4 +1423,27 @@ http_authorization_test_() ->
],
[{V, fun() -> R = authorization(V,T) end} || {T, V, R} <- Tests].
+http_range_test_() ->
+ Tests = [
+ {<<"bytes=1-20">>,
+ {<<"bytes">>, [{1, 20}]}},
+ {<<"bytes=-100">>,
+ {<<"bytes">>, [-100]}},
+ {<<"bytes=1-">>,
+ {<<"bytes">>, [{1, infinity}]}},
+ {<<"bytes=1-20,30-40,50-">>,
+ {<<"bytes">>, [{1, 20}, {30, 40}, {50, infinity}]}},
+ {<<"bytes = 1 - 20 , 50 - , - 300 ">>,
+ {<<"bytes">>, [{1, 20}, {50, infinity}, -300]}},
+ {<<"bytes=1-20,-500,30-40">>,
+ {<<"bytes">>, [{1, 20}, -500, {30, 40}]}},
+ {<<"test=1-20,-500,30-40">>,
+ {<<"test">>, [{1, 20}, -500, {30, 40}]}},
+ {<<"bytes=-">>,
+ {error, badarg}},
+ {<<"bytes=-30,-">>,
+ {error, badarg}}
+ ],
+ [fun() -> R = range(V) end ||{V, R} <- Tests].
+
-endif.
diff --git a/src/cowboy_req.erl b/src/cowboy_req.erl
index 552048a..76c4085 100644
--- a/src/cowboy_req.erl
+++ b/src/cowboy_req.erl
@@ -441,6 +441,8 @@ parse_header(Name, Req, Default)
when Name =:= <<"if-modified-since">>;
Name =:= <<"if-unmodified-since">> ->
parse_header(Name, Req, Default, fun cowboy_http:http_date/1);
+parse_header(Name = <<"range">>, Req, Default) ->
+ parse_header(Name, Req, Default, fun cowboy_http:range/1);
parse_header(Name, Req, Default)
when Name =:= <<"sec-websocket-protocol">>;
Name =:= <<"x-forwarded-for">> ->