From 89c47d3d6edc8aafb4c9c4a5a86fb0239dee8f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 4 Feb 2015 16:18:28 +0100 Subject: Use cowlib for parsing headers; remove cowboy_http --- src/cowboy_http.erl | 1066 -------------------------- src/cowboy_req.erl | 112 +-- src/cowboy_rest.erl | 4 +- test/http_SUITE.erl | 4 +- test/http_SUITE_data/rest_resource_etags.erl | 4 +- 5 files changed, 40 insertions(+), 1150 deletions(-) delete mode 100644 src/cowboy_http.erl diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl deleted file mode 100644 index 177787f..0000000 --- a/src/cowboy_http.erl +++ /dev/null @@ -1,1066 +0,0 @@ -%% Copyright (c) 2011-2014, Loïc Hoguin -%% Copyright (c) 2011, Anthony Ramine -%% -%% Permission to use, copy, modify, and/or distribute this software for any -%% purpose with or without fee is hereby granted, provided that the above -%% copyright notice and this permission notice appear in all copies. -%% -%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -%% Deprecated HTTP parsing API. --module(cowboy_http). - -%% Parsing. --export([list/2]). --export([nonempty_list/2]). --export([content_type/1]). --export([media_range/2]). --export([conneg/2]). --export([language_range/2]). --export([entity_tag_match/1]). --export([expectation/2]). --export([params/2]). --export([http_date/1]). --export([rfc1123_date/1]). --export([rfc850_date/1]). --export([asctime_date/1]). --export([whitespace/2]). --export([digits/1]). --export([token/2]). --export([token_ci/2]). --export([quoted_string/2]). --export([authorization/2]). --export([range/1]). --export([parameterized_tokens/1]). - -%% Decoding. --export([ce_identity/1]). - -%% Parsing. - --spec nonempty_list(binary(), fun()) -> [any(), ...] | {error, badarg}. -nonempty_list(Data, Fun) -> - case list(Data, Fun, []) of - {error, badarg} -> {error, badarg}; - [] -> {error, badarg}; - L -> lists:reverse(L) - end. - --spec list(binary(), fun()) -> list() | {error, badarg}. -list(Data, Fun) -> - case list(Data, Fun, []) of - {error, badarg} -> {error, badarg}; - L -> lists:reverse(L) - end. - --spec list(binary(), fun(), [binary()]) -> [any()] | {error, badarg}. -%% From the RFC: -%%
Wherever this construct is used, null elements are allowed, -%% but do not contribute to the count of elements present. -%% That is, "(element), , (element) " is permitted, but counts -%% as only two elements. Therefore, where at least one element is required, -%% at least one non-null element MUST be present.
-list(Data, Fun, Acc) -> - whitespace(Data, - fun (<<>>) -> Acc; - (<< $,, Rest/binary >>) -> list(Rest, Fun, Acc); - (Rest) -> Fun(Rest, - fun (D, I) -> whitespace(D, - fun (<<>>) -> [I|Acc]; - (<< $,, R/binary >>) -> list(R, Fun, [I|Acc]); - (_Any) -> {error, badarg} - end) - end) - end). - -%% We lowercase the charset header as we know it's case insensitive. --spec content_type(binary()) -> any(). -content_type(Data) -> - media_type(Data, - fun (Rest, Type, SubType) -> - params(Rest, - fun (<<>>, Params) -> - case lists:keyfind(<<"charset">>, 1, Params) of - false -> - {Type, SubType, Params}; - {_, Charset} -> - Charset2 = cowboy_bstr:to_lower(Charset), - Params2 = lists:keyreplace(<<"charset">>, - 1, Params, {<<"charset">>, Charset2}), - {Type, SubType, Params2} - end; - (_Rest2, _) -> - {error, badarg} - end) - end). - --spec media_range(binary(), fun()) -> any(). -media_range(Data, Fun) -> - media_type(Data, - fun (Rest, Type, SubType) -> - media_range_params(Rest, Fun, Type, SubType, []) - end). - --spec media_range_params(binary(), fun(), binary(), binary(), - [{binary(), binary()}]) -> any(). -media_range_params(Data, Fun, Type, SubType, Acc) -> - whitespace(Data, - fun (<< $;, Rest/binary >>) -> - whitespace(Rest, - fun (Rest2) -> - media_range_param_attr(Rest2, Fun, Type, SubType, Acc) - end); - (Rest) -> Fun(Rest, {{Type, SubType, lists:reverse(Acc)}, 1000, []}) - end). - --spec media_range_param_attr(binary(), fun(), binary(), binary(), - [{binary(), binary()}]) -> any(). -media_range_param_attr(Data, Fun, Type, SubType, Acc) -> - token_ci(Data, - fun (_Rest, <<>>) -> {error, badarg}; - (<< $=, Rest/binary >>, Attr) -> - media_range_param_value(Rest, Fun, Type, SubType, Acc, Attr) - end). - --spec media_range_param_value(binary(), fun(), binary(), binary(), - [{binary(), binary()}], binary()) -> any(). -media_range_param_value(Data, Fun, Type, SubType, Acc, <<"q">>) -> - qvalue(Data, - fun (Rest, Quality) -> - accept_ext(Rest, Fun, Type, SubType, Acc, Quality, []) - end); -media_range_param_value(Data, Fun, Type, SubType, Acc, Attr) -> - word(Data, - fun (Rest, Value) -> - media_range_params(Rest, Fun, - Type, SubType, [{Attr, Value}|Acc]) - end). - --spec media_type(binary(), fun()) -> any(). -media_type(Data, Fun) -> - token_ci(Data, - fun (_Rest, <<>>) -> {error, badarg}; - (<< $/, Rest/binary >>, Type) -> - token_ci(Rest, - fun (_Rest2, <<>>) -> {error, badarg}; - (Rest2, SubType) -> Fun(Rest2, Type, SubType) - end); - %% This is a non-strict parsing clause required by some user agents - %% that use * instead of */* in the list of media types. - (Rest, <<"*">> = Type) -> - token_ci(<<"*", Rest/binary>>, - fun (_Rest2, <<>>) -> {error, badarg}; - (Rest2, SubType) -> Fun(Rest2, Type, SubType) - end); - (_Rest, _Type) -> {error, badarg} - end). - --spec accept_ext(binary(), fun(), binary(), binary(), - [{binary(), binary()}], 0..1000, - [{binary(), binary()} | binary()]) -> any(). -accept_ext(Data, Fun, Type, SubType, Params, Quality, Acc) -> - whitespace(Data, - fun (<< $;, Rest/binary >>) -> - whitespace(Rest, - fun (Rest2) -> - accept_ext_attr(Rest2, Fun, - Type, SubType, Params, Quality, Acc) - end); - (Rest) -> - Fun(Rest, {{Type, SubType, lists:reverse(Params)}, - Quality, lists:reverse(Acc)}) - end). - --spec accept_ext_attr(binary(), fun(), binary(), binary(), - [{binary(), binary()}], 0..1000, - [{binary(), binary()} | binary()]) -> any(). -accept_ext_attr(Data, Fun, Type, SubType, Params, Quality, Acc) -> - token_ci(Data, - fun (_Rest, <<>>) -> {error, badarg}; - (<< $=, Rest/binary >>, Attr) -> - accept_ext_value(Rest, Fun, Type, SubType, Params, - Quality, Acc, Attr); - (Rest, Attr) -> - accept_ext(Rest, Fun, Type, SubType, Params, - Quality, [Attr|Acc]) - end). - --spec accept_ext_value(binary(), fun(), binary(), binary(), - [{binary(), binary()}], 0..1000, - [{binary(), binary()} | binary()], binary()) -> any(). -accept_ext_value(Data, Fun, Type, SubType, Params, Quality, Acc, Attr) -> - word(Data, - fun (Rest, Value) -> - accept_ext(Rest, Fun, - Type, SubType, Params, Quality, [{Attr, Value}|Acc]) - end). - --spec conneg(binary(), fun()) -> any(). -conneg(Data, Fun) -> - token_ci(Data, - fun (_Rest, <<>>) -> {error, badarg}; - (Rest, Conneg) -> - maybe_qparam(Rest, - fun (Rest2, Quality) -> - Fun(Rest2, {Conneg, Quality}) - end) - end). - --spec language_range(binary(), fun()) -> any(). -language_range(<< $*, Rest/binary >>, Fun) -> - language_range_ret(Rest, Fun, '*'); -language_range(Data, Fun) -> - language_tag(Data, - fun (Rest, LanguageTag) -> - language_range_ret(Rest, Fun, LanguageTag) - end). - --spec language_range_ret(binary(), fun(), '*' | {binary(), [binary()]}) -> any(). -language_range_ret(Data, Fun, LanguageTag) -> - maybe_qparam(Data, - fun (Rest, Quality) -> - Fun(Rest, {LanguageTag, Quality}) - end). - --spec language_tag(binary(), fun()) -> any(). -language_tag(Data, Fun) -> - alpha(Data, - fun (_Rest, Tag) when byte_size(Tag) =:= 0; byte_size(Tag) > 8 -> - {error, badarg}; - (<< $-, Rest/binary >>, Tag) -> - language_subtag(Rest, Fun, Tag, []); - (Rest, Tag) -> - Fun(Rest, Tag) - end). - --spec language_subtag(binary(), fun(), binary(), [binary()]) -> any(). -language_subtag(Data, Fun, Tag, Acc) -> - alphanumeric(Data, - fun (_Rest, SubTag) when byte_size(SubTag) =:= 0; - byte_size(SubTag) > 8 -> {error, badarg}; - (<< $-, Rest/binary >>, SubTag) -> - language_subtag(Rest, Fun, Tag, [SubTag|Acc]); - (Rest, SubTag) -> - %% Rebuild the full tag now that we know it's correct - Sub = << << $-, S/binary >> || S <- lists:reverse([SubTag|Acc]) >>, - Fun(Rest, << Tag/binary, Sub/binary >>) - end). - --spec maybe_qparam(binary(), fun()) -> any(). -maybe_qparam(Data, Fun) -> - whitespace(Data, - fun (<< $;, Rest/binary >>) -> - whitespace(Rest, - fun (Rest2) -> - %% This is a non-strict parsing clause required by some user agents - %% that use the wrong delimiter putting a charset where a qparam is - %% expected. - try qparam(Rest2, Fun) of - Result -> Result - catch - error:function_clause -> - Fun(<<",", Rest2/binary>>, 1000) - end - end); - (Rest) -> - Fun(Rest, 1000) - end). - --spec qparam(binary(), fun()) -> any(). -qparam(<< Q, $=, Data/binary >>, Fun) when Q =:= $q; Q =:= $Q -> - qvalue(Data, Fun). - --spec entity_tag_match(binary()) -> any(). -entity_tag_match(<< $*, Rest/binary >>) -> - whitespace(Rest, - fun (<<>>) -> '*'; - (_Any) -> {error, badarg} - end); -entity_tag_match(Data) -> - nonempty_list(Data, fun entity_tag/2). - --spec entity_tag(binary(), fun()) -> any(). -entity_tag(<< "W/", Rest/binary >>, Fun) -> - opaque_tag(Rest, Fun, weak); -entity_tag(Data, Fun) -> - opaque_tag(Data, Fun, strong). - --spec opaque_tag(binary(), fun(), weak | strong) -> any(). -opaque_tag(Data, Fun, Strength) -> - quoted_string(Data, - fun (_Rest, <<>>) -> {error, badarg}; - (Rest, OpaqueTag) -> Fun(Rest, {Strength, OpaqueTag}) - end). - --spec expectation(binary(), fun()) -> any(). -expectation(Data, Fun) -> - token_ci(Data, - fun (_Rest, <<>>) -> {error, badarg}; - (<< $=, Rest/binary >>, Expectation) -> - word(Rest, - fun (Rest2, ExtValue) -> - params(Rest2, fun (Rest3, ExtParams) -> - Fun(Rest3, {Expectation, ExtValue, ExtParams}) - end) - end); - (Rest, Expectation) -> - Fun(Rest, Expectation) - end). - --spec params(binary(), fun()) -> any(). -params(Data, Fun) -> - params(Data, Fun, []). - --spec params(binary(), fun(), [{binary(), binary()}]) -> any(). -params(Data, Fun, Acc) -> - whitespace(Data, - fun (<< $;, Rest/binary >>) -> - param(Rest, - fun (Rest2, Attr, Value) -> - params(Rest2, Fun, [{Attr, Value}|Acc]) - end); - (Rest) -> - Fun(Rest, lists:reverse(Acc)) - end). - --spec param(binary(), fun()) -> any(). -param(Data, Fun) -> - whitespace(Data, - fun (Rest) -> - token_ci(Rest, - fun (_Rest2, <<>>) -> {error, badarg}; - (<< $=, Rest2/binary >>, Attr) -> - word(Rest2, - fun (Rest3, Value) -> - Fun(Rest3, Attr, Value) - end); - (_Rest2, _Attr) -> {error, badarg} - end) - end). - -%% While this may not be the most efficient date parsing we can do, -%% it should work fine for our purposes because all HTTP dates should -%% be sent as RFC1123 dates in HTTP/1.1. --spec http_date(binary()) -> any(). -http_date(Data) -> - case rfc1123_date(Data) of - {error, badarg} -> - case rfc850_date(Data) of - {error, badarg} -> - case asctime_date(Data) of - {error, badarg} -> - {error, badarg}; - HTTPDate -> - HTTPDate - end; - HTTPDate -> - HTTPDate - end; - HTTPDate -> - HTTPDate - end. - --spec rfc1123_date(binary()) -> any(). -rfc1123_date(Data) -> - wkday(Data, - fun (<< ", ", Rest/binary >>, _WkDay) -> - date1(Rest, - fun (<< " ", Rest2/binary >>, Date) -> - time(Rest2, - fun (<< " GMT", Rest3/binary >>, Time) -> - http_date_ret(Rest3, {Date, Time}); - (_Any, _Time) -> - {error, badarg} - end); - (_Any, _Date) -> - {error, badarg} - end); - (_Any, _WkDay) -> - {error, badarg} - end). - --spec rfc850_date(binary()) -> any(). -%% From the RFC: -%% HTTP/1.1 clients and caches SHOULD assume that an RFC-850 date -%% which appears to be more than 50 years in the future is in fact -%% in the past (this helps solve the "year 2000" problem). -rfc850_date(Data) -> - weekday(Data, - fun (<< ", ", Rest/binary >>, _WeekDay) -> - date2(Rest, - fun (<< " ", Rest2/binary >>, Date) -> - time(Rest2, - fun (<< " GMT", Rest3/binary >>, Time) -> - http_date_ret(Rest3, {Date, Time}); - (_Any, _Time) -> - {error, badarg} - end); - (_Any, _Date) -> - {error, badarg} - end); - (_Any, _WeekDay) -> - {error, badarg} - end). - --spec asctime_date(binary()) -> any(). -asctime_date(Data) -> - wkday(Data, - fun (<< " ", Rest/binary >>, _WkDay) -> - date3(Rest, - fun (<< " ", Rest2/binary >>, PartialDate) -> - time(Rest2, - fun (<< " ", Rest3/binary >>, Time) -> - asctime_year(Rest3, - PartialDate, Time); - (_Any, _Time) -> - {error, badarg} - end); - (_Any, _PartialDate) -> - {error, badarg} - end); - (_Any, _WkDay) -> - {error, badarg1} - end). - --spec asctime_year(binary(), tuple(), tuple()) -> any(). -asctime_year(<< Y1, Y2, Y3, Y4, Rest/binary >>, {Month, Day}, Time) - when Y1 >= $0, Y1 =< $9, Y2 >= $0, Y2 =< $9, - Y3 >= $0, Y3 =< $9, Y4 >= $0, Y4 =< $9 -> - Year = (Y1 - $0) * 1000 + (Y2 - $0) * 100 + (Y3 - $0) * 10 + (Y4 - $0), - http_date_ret(Rest, {{Year, Month, Day}, Time}). - --spec http_date_ret(binary(), tuple()) -> any(). -http_date_ret(Data, DateTime = {Date, _Time}) -> - whitespace(Data, - fun (<<>>) -> - case calendar:valid_date(Date) of - true -> DateTime; - false -> {error, badarg} - end; - (_Any) -> - {error, badarg} - end). - -%% We never use it, pretty much just checks the wkday is right. --spec wkday(binary(), fun()) -> any(). -wkday(<< WkDay:3/binary, Rest/binary >>, Fun) - when WkDay =:= <<"Mon">>; WkDay =:= <<"Tue">>; WkDay =:= <<"Wed">>; - WkDay =:= <<"Thu">>; WkDay =:= <<"Fri">>; WkDay =:= <<"Sat">>; - WkDay =:= <<"Sun">> -> - Fun(Rest, WkDay); -wkday(_Any, _Fun) -> - {error, badarg}. - -%% We never use it, pretty much just checks the weekday is right. --spec weekday(binary(), fun()) -> any(). -weekday(<< "Monday", Rest/binary >>, Fun) -> - Fun(Rest, <<"Monday">>); -weekday(<< "Tuesday", Rest/binary >>, Fun) -> - Fun(Rest, <<"Tuesday">>); -weekday(<< "Wednesday", Rest/binary >>, Fun) -> - Fun(Rest, <<"Wednesday">>); -weekday(<< "Thursday", Rest/binary >>, Fun) -> - Fun(Rest, <<"Thursday">>); -weekday(<< "Friday", Rest/binary >>, Fun) -> - Fun(Rest, <<"Friday">>); -weekday(<< "Saturday", Rest/binary >>, Fun) -> - Fun(Rest, <<"Saturday">>); -weekday(<< "Sunday", Rest/binary >>, Fun) -> - Fun(Rest, <<"Sunday">>); -weekday(_Any, _Fun) -> - {error, badarg}. - --spec date1(binary(), fun()) -> any(). -date1(<< D1, D2, " ", M:3/binary, " ", Y1, Y2, Y3, Y4, Rest/binary >>, Fun) - when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9, - Y1 >= $0, Y1 =< $9, Y2 >= $0, Y2 =< $9, - Y3 >= $0, Y3 =< $9, Y4 >= $0, Y4 =< $9 -> - case month(M) of - {error, badarg} -> - {error, badarg}; - Month -> - Fun(Rest, { - (Y1 - $0) * 1000 + (Y2 - $0) * 100 + (Y3 - $0) * 10 + (Y4 - $0), - Month, - (D1 - $0) * 10 + (D2 - $0) - }) - end; -date1(_Data, _Fun) -> - {error, badarg}. - --spec date2(binary(), fun()) -> any(). -date2(<< D1, D2, "-", M:3/binary, "-", Y1, Y2, Rest/binary >>, Fun) - when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9, - Y1 >= $0, Y1 =< $9, Y2 >= $0, Y2 =< $9 -> - case month(M) of - {error, badarg} -> - {error, badarg}; - Month -> - Year = (Y1 - $0) * 10 + (Y2 - $0), - Year2 = case Year > 50 of - true -> Year + 1900; - false -> Year + 2000 - end, - Fun(Rest, { - Year2, - Month, - (D1 - $0) * 10 + (D2 - $0) - }) - end; -date2(_Data, _Fun) -> - {error, badarg}. - --spec date3(binary(), fun()) -> any(). -date3(<< M:3/binary, " ", D1, D2, Rest/binary >>, Fun) - when (D1 >= $0 andalso D1 =< $3) orelse D1 =:= $\s, - D2 >= $0, D2 =< $9 -> - case month(M) of - {error, badarg} -> - {error, badarg}; - Month -> - Day = case D1 of - $\s -> D2 - $0; - D1 -> (D1 - $0) * 10 + (D2 - $0) - end, - Fun(Rest, {Month, Day}) - end; -date3(_Data, _Fun) -> - {error, badarg}. - --spec month(<< _:24 >>) -> 1..12 | {error, badarg}. -month(<<"Jan">>) -> 1; -month(<<"Feb">>) -> 2; -month(<<"Mar">>) -> 3; -month(<<"Apr">>) -> 4; -month(<<"May">>) -> 5; -month(<<"Jun">>) -> 6; -month(<<"Jul">>) -> 7; -month(<<"Aug">>) -> 8; -month(<<"Sep">>) -> 9; -month(<<"Oct">>) -> 10; -month(<<"Nov">>) -> 11; -month(<<"Dec">>) -> 12; -month(_Any) -> {error, badarg}. - --spec time(binary(), fun()) -> any(). -time(<< H1, H2, ":", M1, M2, ":", S1, S2, Rest/binary >>, Fun) - when H1 >= $0, H1 =< $2, H2 >= $0, H2 =< $9, - M1 >= $0, M1 =< $5, M2 >= $0, M2 =< $9, - S1 >= $0, S1 =< $5, S2 >= $0, S2 =< $9 -> - Hour = (H1 - $0) * 10 + (H2 - $0), - case Hour < 24 of - true -> - Time = { - Hour, - (M1 - $0) * 10 + (M2 - $0), - (S1 - $0) * 10 + (S2 - $0) - }, - Fun(Rest, Time); - false -> - {error, badarg} - end. - --spec whitespace(binary(), fun()) -> any(). -whitespace(<< C, Rest/binary >>, Fun) - when C =:= $\s; C =:= $\t -> - whitespace(Rest, Fun); -whitespace(Data, Fun) -> - Fun(Data). - --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/binary >>, Fun) - when C >= $0, C =< $9 -> - digits(Rest, Fun, C - $0); -digits(_Data, _Fun) -> - {error, badarg}. - --spec digits(binary(), fun(), non_neg_integer()) -> any(). -digits(<< C, Rest/binary >>, Fun, Acc) - when C >= $0, C =< $9 -> - digits(Rest, Fun, Acc * 10 + (C - $0)); -digits(Data, Fun, Acc) -> - Fun(Data, Acc). - -%% Changes all characters to lowercase. --spec alpha(binary(), fun()) -> any(). -alpha(Data, Fun) -> - alpha(Data, Fun, <<>>). - --spec alpha(binary(), fun(), binary()) -> any(). -alpha(<<>>, Fun, Acc) -> - Fun(<<>>, Acc); -alpha(<< C, Rest/binary >>, Fun, Acc) - when C >= $a andalso C =< $z; - C >= $A andalso C =< $Z -> - C2 = cowboy_bstr:char_to_lower(C), - alpha(Rest, Fun, << Acc/binary, C2 >>); -alpha(Data, Fun, Acc) -> - Fun(Data, Acc). - --spec alphanumeric(binary(), fun()) -> any(). -alphanumeric(Data, Fun) -> - alphanumeric(Data, Fun, <<>>). - --spec alphanumeric(binary(), fun(), binary()) -> any(). -alphanumeric(<<>>, Fun, Acc) -> - Fun(<<>>, Acc); -alphanumeric(<< C, Rest/binary >>, Fun, Acc) - when C >= $a andalso C =< $z; - C >= $A andalso C =< $Z; - C >= $0 andalso C =< $9 -> - C2 = cowboy_bstr:char_to_lower(C), - alphanumeric(Rest, Fun, << Acc/binary, C2 >>); -alphanumeric(Data, Fun, Acc) -> - Fun(Data, Acc). - -%% @doc Parse either a token or a quoted string. --spec word(binary(), fun()) -> any(). -word(Data = << $", _/binary >>, Fun) -> - quoted_string(Data, Fun); -word(Data, Fun) -> - token(Data, - fun (_Rest, <<>>) -> {error, badarg}; - (Rest, Token) -> Fun(Rest, Token) - end). - -%% Changes all characters to lowercase. --spec token_ci(binary(), fun()) -> any(). -token_ci(Data, Fun) -> - token(Data, Fun, ci, <<>>). - --spec token(binary(), fun()) -> any(). -token(Data, Fun) -> - token(Data, Fun, cs, <<>>). - --spec token(binary(), fun(), ci | cs, binary()) -> any(). -token(<<>>, Fun, _Case, Acc) -> - Fun(<<>>, Acc); -token(Data = << C, _Rest/binary >>, 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/binary >>, Fun, Case = ci, Acc) -> - C2 = cowboy_bstr:char_to_lower(C), - token(Rest, Fun, Case, << Acc/binary, C2 >>); -token(<< C, Rest/binary >>, Fun, Case, Acc) -> - token(Rest, Fun, Case, << Acc/binary, C >>). - --spec quoted_string(binary(), fun()) -> any(). -quoted_string(<< $", Rest/binary >>, Fun) -> - quoted_string(Rest, Fun, <<>>). - --spec quoted_string(binary(), fun(), binary()) -> any(). -quoted_string(<<>>, _Fun, _Acc) -> - {error, badarg}; -quoted_string(<< $", Rest/binary >>, Fun, Acc) -> - Fun(Rest, Acc); -quoted_string(<< $\\, C, Rest/binary >>, Fun, Acc) -> - quoted_string(Rest, Fun, << Acc/binary, C >>); -quoted_string(<< C, Rest/binary >>, Fun, Acc) -> - quoted_string(Rest, Fun, << Acc/binary, C >>). - --spec qvalue(binary(), fun()) -> any(). -qvalue(<< $0, $., Rest/binary >>, Fun) -> - qvalue(Rest, Fun, 0, 100); -%% Some user agents use q=.x instead of q=0.x -qvalue(<< $., Rest/binary >>, Fun) -> - qvalue(Rest, Fun, 0, 100); -qvalue(<< $0, Rest/binary >>, Fun) -> - Fun(Rest, 0); -qvalue(<< $1, $., $0, $0, $0, Rest/binary >>, Fun) -> - Fun(Rest, 1000); -qvalue(<< $1, $., $0, $0, Rest/binary >>, Fun) -> - Fun(Rest, 1000); -qvalue(<< $1, $., $0, Rest/binary >>, Fun) -> - Fun(Rest, 1000); -qvalue(<< $1, Rest/binary >>, Fun) -> - Fun(Rest, 1000); -qvalue(_Data, _Fun) -> - {error, badarg}. - --spec qvalue(binary(), fun(), integer(), 1 | 10 | 100) -> any(). -qvalue(Data, Fun, Q, 0) -> - Fun(Data, Q); -qvalue(<< C, Rest/binary >>, Fun, Q, M) - when C >= $0, C =< $9 -> - qvalue(Rest, Fun, Q + (C - $0) * M, M div 10); -qvalue(Data, Fun, Q, _M) -> - Fun(Data, Q). - -%% Only RFC2617 Basic authorization is supported so far. --spec authorization(binary(), binary()) -> {binary(), any()} | {error, badarg}. -authorization(UserPass, Type = <<"basic">>) -> - whitespace(UserPass, - fun(D) -> - authorization_basic_userid(base64:mime_decode(D), - fun(Rest, Userid) -> - authorization_basic_password(Rest, - fun(Password) -> - {Type, {Userid, Password}} - end) - end) - end); -authorization(String, Type) -> - whitespace(String, fun(Rest) -> {Type, Rest} end). - --spec authorization_basic_userid(binary(), fun()) -> any(). -authorization_basic_userid(Data, Fun) -> - authorization_basic_userid(Data, Fun, <<>>). - -authorization_basic_userid(<<>>, _Fun, _Acc) -> - {error, badarg}; -authorization_basic_userid(<>, _Fun, Acc) - when C < 32; C =:= 127; (C =:=$: andalso Acc =:= <<>>) -> - {error, badarg}; -authorization_basic_userid(<<$:, Rest/binary>>, Fun, Acc) -> - Fun(Rest, Acc); -authorization_basic_userid(<>, Fun, Acc) -> - authorization_basic_userid(Rest, Fun, <>). - --spec authorization_basic_password(binary(), fun()) -> any(). -authorization_basic_password(Data, Fun) -> - authorization_basic_password(Data, Fun, <<>>). - -authorization_basic_password(<>, _Fun, _Acc) - when C < 32; C=:= 127 -> - {error, badarg}; -authorization_basic_password(<<>>, Fun, Acc) -> - Fun(Acc); -authorization_basic_password(<>, Fun, Acc) -> - authorization_basic_password(Rest, Fun, <>). - --spec range(binary()) -> {Unit, [Range]} | {error, badarg} when - Unit :: binary(), - Range :: {non_neg_integer(), non_neg_integer() | infinity} | neg_integer(). -range(Data) -> - token_ci(Data, fun range/2). - -range(Data, Token) -> - whitespace(Data, - fun(<<"=", Rest/binary>>) -> - case 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). - --spec parameterized_tokens(binary()) -> any(). -parameterized_tokens(Data) -> - nonempty_list(Data, - fun (D, Fun) -> - token(D, - fun (_Rest, <<>>) -> {error, badarg}; - (Rest, Token) -> - parameterized_tokens_params(Rest, - fun (Rest2, Params) -> - Fun(Rest2, {Token, Params}) - end, []) - end) - end). - --spec parameterized_tokens_params(binary(), fun(), [binary() | {binary(), binary()}]) -> any(). -parameterized_tokens_params(Data, Fun, Acc) -> - whitespace(Data, - fun (<< $;, Rest/binary >>) -> - parameterized_tokens_param(Rest, - fun (Rest2, Param) -> - parameterized_tokens_params(Rest2, Fun, [Param|Acc]) - end); - (Rest) -> - Fun(Rest, lists:reverse(Acc)) - end). - --spec parameterized_tokens_param(binary(), fun()) -> any(). -parameterized_tokens_param(Data, Fun) -> - whitespace(Data, - fun (Rest) -> - token(Rest, - fun (_Rest2, <<>>) -> {error, badarg}; - (<< $=, Rest2/binary >>, Attr) -> - word(Rest2, - fun (Rest3, Value) -> - Fun(Rest3, {Attr, Value}) - end); - (Rest2, Attr) -> - Fun(Rest2, Attr) - end) - end). - -%% Decoding. - -%% @todo Move this to cowlib too I suppose. :-) --spec ce_identity(Data) -> Data when Data::binary(). -ce_identity(Data) -> - Data. - -%% Tests. - --ifdef(TEST). -nonempty_charset_list_test_() -> - Tests = [ - {<<>>, {error, badarg}}, - {<<"iso-8859-5, unicode-1-1;q=0.8">>, [ - {<<"iso-8859-5">>, 1000}, - {<<"unicode-1-1">>, 800} - ]}, - %% Some user agents send this invalid value for the Accept-Charset header - {<<"ISO-8859-1;utf-8;q=0.7,*;q=0.7">>, [ - {<<"iso-8859-1">>, 1000}, - {<<"utf-8">>, 700}, - {<<"*">>, 700} - ]} - ], - [{V, fun() -> R = nonempty_list(V, fun conneg/2) end} || {V, R} <- Tests]. - -nonempty_language_range_list_test_() -> - Tests = [ - {<<"da, en-gb;q=0.8, en;q=0.7">>, [ - {<<"da">>, 1000}, - {<<"en-gb">>, 800}, - {<<"en">>, 700} - ]}, - {<<"en, en-US, en-cockney, i-cherokee, x-pig-latin, es-419">>, [ - {<<"en">>, 1000}, - {<<"en-us">>, 1000}, - {<<"en-cockney">>, 1000}, - {<<"i-cherokee">>, 1000}, - {<<"x-pig-latin">>, 1000}, - {<<"es-419">>, 1000} - ]} - ], - [{V, fun() -> R = nonempty_list(V, fun language_range/2) end} - || {V, R} <- Tests]. - -nonempty_token_list_test_() -> - Tests = [ - {<<>>, {error, badarg}}, - {<<" ">>, {error, badarg}}, - {<<" , ">>, {error, badarg}}, - {<<",,,">>, {error, badarg}}, - {<<"a b">>, {error, badarg}}, - {<<"a , , , ">>, [<<"a">>]}, - {<<" , , , a">>, [<<"a">>]}, - {<<"a, , b">>, [<<"a">>, <<"b">>]}, - {<<"close">>, [<<"close">>]}, - {<<"keep-alive, upgrade">>, [<<"keep-alive">>, <<"upgrade">>]} - ], - [{V, fun() -> R = nonempty_list(V, fun token/2) end} || {V, R} <- Tests]. - -media_range_list_test_() -> - Tests = [ - {<<"audio/*; q=0.2, audio/basic">>, [ - {{<<"audio">>, <<"*">>, []}, 200, []}, - {{<<"audio">>, <<"basic">>, []}, 1000, []} - ]}, - {<<"text/plain; q=0.5, text/html, " - "text/x-dvi; q=0.8, text/x-c">>, [ - {{<<"text">>, <<"plain">>, []}, 500, []}, - {{<<"text">>, <<"html">>, []}, 1000, []}, - {{<<"text">>, <<"x-dvi">>, []}, 800, []}, - {{<<"text">>, <<"x-c">>, []}, 1000, []} - ]}, - {<<"text/*, text/html, text/html;level=1, */*">>, [ - {{<<"text">>, <<"*">>, []}, 1000, []}, - {{<<"text">>, <<"html">>, []}, 1000, []}, - {{<<"text">>, <<"html">>, [{<<"level">>, <<"1">>}]}, 1000, []}, - {{<<"*">>, <<"*">>, []}, 1000, []} - ]}, - {<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, " - "text/html;level=2;q=0.4, */*;q=0.5">>, [ - {{<<"text">>, <<"*">>, []}, 300, []}, - {{<<"text">>, <<"html">>, []}, 700, []}, - {{<<"text">>, <<"html">>, [{<<"level">>, <<"1">>}]}, 1000, []}, - {{<<"text">>, <<"html">>, [{<<"level">>, <<"2">>}]}, 400, []}, - {{<<"*">>, <<"*">>, []}, 500, []} - ]}, - {<<"text/html;level=1;quoted=\"hi hi hi\";" - "q=0.123;standalone;complex=gits, text/plain">>, [ - {{<<"text">>, <<"html">>, - [{<<"level">>, <<"1">>}, {<<"quoted">>, <<"hi hi hi">>}]}, 123, - [<<"standalone">>, {<<"complex">>, <<"gits">>}]}, - {{<<"text">>, <<"plain">>, []}, 1000, []} - ]}, - {<<"text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2">>, [ - {{<<"text">>, <<"html">>, []}, 1000, []}, - {{<<"image">>, <<"gif">>, []}, 1000, []}, - {{<<"image">>, <<"jpeg">>, []}, 1000, []}, - {{<<"*">>, <<"*">>, []}, 200, []}, - {{<<"*">>, <<"*">>, []}, 200, []} - ]} - ], - [{V, fun() -> R = list(V, fun media_range/2) end} || {V, R} <- Tests]. - -entity_tag_match_test_() -> - Tests = [ - {<<"\"xyzzy\"">>, [{strong, <<"xyzzy">>}]}, - {<<"\"xyzzy\", W/\"r2d2xxxx\", \"c3piozzzz\"">>, - [{strong, <<"xyzzy">>}, - {weak, <<"r2d2xxxx">>}, - {strong, <<"c3piozzzz">>}]}, - {<<"*">>, '*'} - ], - [{V, fun() -> R = entity_tag_match(V) end} || {V, R} <- Tests]. - -http_date_test_() -> - Tests = [ - {<<"Sun, 06 Nov 1994 08:49:37 GMT">>, {{1994, 11, 6}, {8, 49, 37}}}, - {<<"Sunday, 06-Nov-94 08:49:37 GMT">>, {{1994, 11, 6}, {8, 49, 37}}}, - {<<"Sun Nov 6 08:49:37 1994">>, {{1994, 11, 6}, {8, 49, 37}}} - ], - [{V, fun() -> R = http_date(V) end} || {V, R} <- Tests]. - -rfc1123_date_test_() -> - Tests = [ - {<<"Sun, 06 Nov 1994 08:49:37 GMT">>, {{1994, 11, 6}, {8, 49, 37}}} - ], - [{V, fun() -> R = rfc1123_date(V) end} || {V, R} <- Tests]. - -rfc850_date_test_() -> - Tests = [ - {<<"Sunday, 06-Nov-94 08:49:37 GMT">>, {{1994, 11, 6}, {8, 49, 37}}} - ], - [{V, fun() -> R = rfc850_date(V) end} || {V, R} <- Tests]. - -asctime_date_test_() -> - Tests = [ - {<<"Sun Nov 6 08:49:37 1994">>, {{1994, 11, 6}, {8, 49, 37}}} - ], - [{V, fun() -> R = asctime_date(V) end} || {V, R} <- Tests]. - -content_type_test_() -> - Tests = [ - {<<"text/plain; charset=iso-8859-4">>, - {<<"text">>, <<"plain">>, [{<<"charset">>, <<"iso-8859-4">>}]}}, - {<<"multipart/form-data \t;Boundary=\"MultipartIsUgly\"">>, - {<<"multipart">>, <<"form-data">>, [ - {<<"boundary">>, <<"MultipartIsUgly">>} - ]}}, - {<<"foo/bar; one=FirstParam; two=SecondParam">>, - {<<"foo">>, <<"bar">>, [ - {<<"one">>, <<"FirstParam">>}, - {<<"two">>, <<"SecondParam">>} - ]}} - ], - [{V, fun () -> R = content_type(V) end} || {V, R} <- Tests]. - -parameterized_tokens_test_() -> - Tests = [ - {<<"foo">>, [{<<"foo">>, []}]}, - {<<"bar; baz=2">>, [{<<"bar">>, [{<<"baz">>, <<"2">>}]}]}, - {<<"bar; baz=2;bat">>, [{<<"bar">>, [{<<"baz">>, <<"2">>}, <<"bat">>]}]}, - {<<"bar; baz=2;bat=\"z=1,2;3\"">>, [{<<"bar">>, [{<<"baz">>, <<"2">>}, {<<"bat">>, <<"z=1,2;3">>}]}]}, - {<<"foo, bar; baz=2">>, [{<<"foo">>, []}, {<<"bar">>, [{<<"baz">>, <<"2">>}]}]} - ], - [{V, fun () -> R = parameterized_tokens(V) end} || {V, R} <- Tests]. - -digits_test_() -> - Tests = [ - {<<"42 ">>, 42}, - {<<"69\t">>, 69}, - {<<"1337">>, 1337} - ], - [{V, fun() -> R = digits(V) end} || {V, R} <- Tests]. - -http_authorization_test_() -> - Tests = [ - {<<"basic">>, <<"QWxsYWRpbjpvcGVuIHNlc2FtZQ==">>, - {<<"basic">>, {<<"Alladin">>, <<"open sesame">>}}}, - {<<"basic">>, <<"dXNlcm5hbWU6">>, - {<<"basic">>, {<<"username">>, <<>>}}}, - {<<"basic">>, <<"dXNlcm5hbWUK">>, - {error, badarg}}, - {<<"basic">>, <<"_[]@#$%^&*()-AA==">>, - {error, badarg}}, - {<<"basic">>, <<"dXNlcjpwYXNzCA==">>, - {error, badarg}}, - {<<"bearer">>, <<" some_secret_key">>, - {<<"bearer">>,<<"some_secret_key">>}} - ], - [{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 880c567..5e23a7b 100644 --- a/src/cowboy_req.erl +++ b/src/cowboy_req.erl @@ -289,91 +289,43 @@ headers(Req) -> -spec parse_header(binary(), Req) -> any() when Req::req(). parse_header(Name = <<"content-length">>, Req) -> - parse_header(Name, Req, 0); + parse_header(Name, Req, 0, fun cow_http_hd:parse_content_length/1); parse_header(Name = <<"cookie">>, Req) -> - parse_header(Name, Req, []); + parse_header(Name, Req, [], fun cow_cookie:parse_cookie/1); parse_header(Name = <<"transfer-encoding">>, Req) -> - parse_header(Name, Req, [<<"identity">>]); + parse_header(Name, Req, [<<"identity">>], fun cow_http_hd:parse_transfer_encoding/1); parse_header(Name, Req) -> parse_header(Name, Req, undefined). -spec parse_header(binary(), Req, any()) -> any() when Req::req(). -parse_header(Name = <<"accept">>, Req, Default) -> - parse_header(Name, Req, Default, fun (Value) -> - cowboy_http:list(Value, fun cowboy_http:media_range/2) end); -parse_header(Name = <<"accept-charset">>, Req, Default) -> - parse_header(Name, Req, Default, fun (Value) -> - cowboy_http:nonempty_list(Value, fun cowboy_http:conneg/2) end); -parse_header(Name = <<"accept-encoding">>, Req, Default) -> - parse_header(Name, Req, Default, fun (Value) -> - cowboy_http:list(Value, fun cowboy_http:conneg/2) end); -parse_header(Name = <<"accept-language">>, Req, Default) -> - parse_header(Name, Req, Default, fun (Value) -> - cowboy_http:nonempty_list(Value, fun cowboy_http:language_range/2) end); -parse_header(Name = <<"authorization">>, Req, Default) -> - parse_header(Name, Req, Default, fun (Value) -> - cowboy_http:token_ci(Value, fun cowboy_http:authorization/2) end); -parse_header(Name = <<"connection">>, Req, Default) -> - case header(Name, Req) of - undefined -> Default; - Value -> cow_http_hd:parse_connection(Value) - end; -parse_header(Name = <<"content-length">>, Req, Default) -> - case header(Name, Req) of - undefined -> Default; - Value -> cow_http_hd:parse_content_length(Value) - end; -parse_header(Name = <<"content-type">>, Req, Default) -> - parse_header(Name, Req, Default, fun cowboy_http:content_type/1); -parse_header(Name = <<"cookie">>, Req, Default) -> - case header(Name, Req) of - undefined -> Default; - %% Flash player incorrectly sends an empty Cookie header. - <<>> -> Default; - Value -> cow_cookie:parse_cookie(Value) - end; -parse_header(Name = <<"expect">>, Req, Default) -> - parse_header(Name, Req, Default, fun (Value) -> - cowboy_http:nonempty_list(Value, fun cowboy_http:expectation/2) end); -parse_header(Name, Req, Default) - when Name =:= <<"if-match">>; - Name =:= <<"if-none-match">> -> - parse_header(Name, Req, Default, fun cowboy_http:entity_tag_match/1); -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">> -> - parse_header(Name, Req, Default, fun (Value) -> - cowboy_http:nonempty_list(Value, fun cowboy_http:token/2) end); -parse_header(Name = <<"transfer-encoding">>, Req, Default) -> - case header(Name, Req) of - undefined -> Default; - Value -> cow_http_hd:parse_transfer_encoding(Value) - end; -%% @todo Product version. -parse_header(Name = <<"upgrade">>, Req, Default) -> - parse_header(Name, Req, Default, fun (Value) -> - cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2) end); -parse_header(Name = <<"sec-websocket-extensions">>, Req, Default) -> - parse_header(Name, Req, Default, fun cowboy_http:parameterized_tokens/1). - -%% @todo Remove this function when everything moved to cowlib. +parse_header(Name, Req, Default) -> + parse_header(Name, Req, Default, parse_header_fun(Name)). + +parse_header_fun(<<"accept">>) -> fun cow_http_hd:parse_accept/1; +parse_header_fun(<<"accept-charset">>) -> fun cow_http_hd:parse_accept_charset/1; +parse_header_fun(<<"accept-encoding">>) -> fun cow_http_hd:parse_accept_encoding/1; +parse_header_fun(<<"accept-language">>) -> fun cow_http_hd:parse_accept_language/1; +parse_header_fun(<<"authorization">>) -> fun cow_http_hd:parse_authorization/1; +parse_header_fun(<<"connection">>) -> fun cow_http_hd:parse_connection/1; +parse_header_fun(<<"content-length">>) -> fun cow_http_hd:parse_content_length/1; +parse_header_fun(<<"content-type">>) -> fun cow_http_hd:parse_content_type/1; +parse_header_fun(<<"cookie">>) -> fun cow_cookie:parse_cookie/1; +parse_header_fun(<<"expect">>) -> fun cow_http_hd:parse_expect/1; +parse_header_fun(<<"if-match">>) -> fun cow_http_hd:parse_if_match/1; +parse_header_fun(<<"if-modified-since">>) -> fun cow_http_hd:parse_if_modified_since/1; +parse_header_fun(<<"if-none-match">>) -> fun cow_http_hd:parse_if_none_match/1; +parse_header_fun(<<"if-unmodified-since">>) -> fun cow_http_hd:parse_if_unmodified_since/1; +parse_header_fun(<<"range">>) -> fun cow_http_hd:parse_range/1; +parse_header_fun(<<"sec-websocket-extensions">>) -> fun cow_http_hd:parse_sec_websocket_extensions/1; +parse_header_fun(<<"sec-websocket-protocol">>) -> fun cow_http_hd:parse_sec_websocket_protocol_req/1; +parse_header_fun(<<"transfer-encoding">>) -> fun cow_http_hd:parse_transfer_encoding/1; +parse_header_fun(<<"upgrade">>) -> fun cow_http_hd:parse_upgrade/1; +parse_header_fun(<<"x-forwarded-for">>) -> fun cow_http_hd:parse_x_forwarded_for/1. + parse_header(Name, Req, Default, ParseFun) -> case header(Name, Req) of - undefined -> - Default; - Value -> - case ParseFun(Value) of - {error, badarg} -> - error(badarg); - ParsedValue -> - ParsedValue - end + undefined -> Default; + Value -> ParseFun(Value) end. -spec parse_cookies(req()) -> [{binary(), binary()}]. @@ -443,7 +395,7 @@ body(Req=#http_req{body_state=waiting}, Opts) -> %% Initialize body streaming state. CFun = case lists:keyfind(content_decode, 1, Opts) of false -> - fun cowboy_http:ce_identity/1; + fun body_content_decode_identity/1; {_, CFun0} -> CFun0 end, @@ -484,6 +436,10 @@ body(Req, Opts) -> end, body_loop(Req, ReadTimeout, ReadLen, ChunkLen, <<>>). +%% Default identity function for content decoding. +%% @todo Move into cowlib when more content decode functions get implemented. +body_content_decode_identity(Data) -> Data. + body_loop(Req=#http_req{buffer=Buffer, body_state={stream, Length, _, _, _}}, ReadTimeout, ReadLength, ChunkLength, Acc) -> {Tag, Res, Req2} = case Buffer of diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl index dea47d8..b894354 100644 --- a/src/cowboy_rest.erl +++ b/src/cowboy_rest.erl @@ -234,7 +234,7 @@ content_types_provided(Req, State) -> normalize_content_types({ContentType, Callback}) when is_binary(ContentType) -> - {cowboy_http:content_type(ContentType), Callback}; + {cow_http_hd:parse_content_type(ContentType), Callback}; normalize_content_types(Normalized) -> Normalized. @@ -896,7 +896,7 @@ generate_etag(Req, State=#state{etag=undefined}) -> no_call -> {undefined, Req, State#state{etag=no_call}}; {Etag, Req2, HandlerState} when is_binary(Etag) -> - [Etag2] = cowboy_http:entity_tag_match(Etag), + Etag2 = cow_http_hd:parse_etag(Etag), {Etag2, Req2, State#state{handler_state=HandlerState, etag=Etag2}}; {Etag, Req2, HandlerState} -> {Etag, Req2, State#state{handler_state=HandlerState, etag=Etag}} diff --git a/test/http_SUITE.erl b/test/http_SUITE.erl index 1b819ae..12b974c 100644 --- a/test/http_SUITE.erl +++ b/test/http_SUITE.erl @@ -748,8 +748,8 @@ rest_resource_etags(Config) -> {200, <<"\"etag-header-value\"">>, "tuple-strong"}, {200, <<"W/\"etag-header-value\"">>, "binary-weak-quoted"}, {200, <<"\"etag-header-value\"">>, "binary-strong-quoted"}, - {500, false, "binary-strong-unquoted"}, - {500, false, "binary-weak-unquoted"} + {400, false, "binary-strong-unquoted"}, + {400, false, "binary-weak-unquoted"} ], _ = [{Status, ETag, Type} = begin {Ret, RespETag} = rest_resource_get_etag(Config, Type), diff --git a/test/http_SUITE_data/rest_resource_etags.erl b/test/http_SUITE_data/rest_resource_etags.erl index 1ea3005..0585761 100644 --- a/test/http_SUITE_data/rest_resource_etags.erl +++ b/test/http_SUITE_data/rest_resource_etags.erl @@ -23,10 +23,10 @@ generate_etag(Req, State) -> {<<"\"etag-header-value\"">>, Req, State}; %% Invalid return values from generate_etag/2. <<"binary-strong-unquoted">> -> - cowboy_error_h:ignore(cowboy_http, quoted_string, 2), + cowboy_error_h:ignore(cow_http_hd, parse_etag, 1), {<<"etag-header-value">>, Req, State}; <<"binary-weak-unquoted">> -> - cowboy_error_h:ignore(cowboy_http, quoted_string, 2), + cowboy_error_h:ignore(cow_http_hd, parse_etag, 1), {<<"W/etag-header-value">>, Req, State} end. -- cgit v1.2.3