aboutsummaryrefslogtreecommitdiffstats
path: root/src/cowboy_req.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/cowboy_req.erl')
-rw-r--r--src/cowboy_req.erl130
1 files changed, 54 insertions, 76 deletions
diff --git a/src/cowboy_req.erl b/src/cowboy_req.erl
index 966e463..4ec42f9 100644
--- a/src/cowboy_req.erl
+++ b/src/cowboy_req.erl
@@ -46,7 +46,6 @@
-export([method/1]).
-export([version/1]).
-export([peer/1]).
--export([peer_addr/1]).
-export([host/1]).
-export([host_info/1]).
-export([port/1]).
@@ -78,8 +77,8 @@
-export([has_body/1]).
-export([body_length/1]).
-export([init_stream/4]).
--export([init_stream/5]).
-export([stream_body/1]).
+-export([stream_body/2]).
-export([skip_body/1]).
-export([body/1]).
-export([body/2]).
@@ -155,8 +154,8 @@
meta = [] :: [{atom(), any()}],
%% Request body.
- body_state = waiting :: waiting | done | {stream,
- non_neg_integer(), non_neg_integer(), fun(), any(), fun()},
+ body_state = waiting :: waiting | done
+ | {stream, non_neg_integer(), fun(), any(), fun()},
multipart = undefined :: undefined | {non_neg_integer(), fun()},
buffer = <<>> :: binary(),
@@ -230,29 +229,6 @@ version(Req) ->
peer(Req) ->
{Req#http_req.peer, Req}.
-%% @doc Returns the peer address calculated from headers.
--spec peer_addr(Req) -> {inet:ip_address(), Req} when Req::req().
-peer_addr(Req = #http_req{}) ->
- {RealIp, Req1} = header(<<"x-real-ip">>, Req),
- {ForwardedForRaw, Req2} = header(<<"x-forwarded-for">>, Req1),
- {{PeerIp, _PeerPort}, Req3} = peer(Req2),
- ForwardedFor = case ForwardedForRaw of
- undefined ->
- undefined;
- ForwardedForRaw ->
- case re:run(ForwardedForRaw, "^(?<first_ip>[^\\,]+)",
- [{capture, [first_ip], binary}]) of
- {match, [FirstIp]} -> FirstIp;
- _Any -> undefined
- end
- end,
- {ok, PeerAddr} = if
- is_binary(RealIp) -> inet_parse:address(binary_to_list(RealIp));
- is_binary(ForwardedFor) -> inet_parse:address(binary_to_list(ForwardedFor));
- true -> {ok, PeerIp}
- end,
- {PeerAddr, Req3}.
-
%% @doc Return the host binary string.
-spec host(Req) -> {binary(), Req} when Req::req().
host(Req) ->
@@ -426,61 +402,61 @@ parse_header_default(_Name) -> undefined.
-spec parse_header(binary(), Req, any())
-> {ok, any(), Req} | {undefined, binary(), Req}
| {error, badarg} when Req::req().
-parse_header(Name, Req, Default) when Name =:= <<"accept">> ->
+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, Req, Default) when Name =:= <<"accept-charset">> ->
+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, Req, Default) when Name =:= <<"accept-encoding">> ->
+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, Req, Default) when Name =:= <<"accept-language">> ->
+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, Req, Default) when Name =:= <<"authorization">> ->
+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, Req, Default) when Name =:= <<"content-length">> ->
+parse_header(Name = <<"content-length">>, Req, Default) ->
parse_header(Name, Req, Default, fun cowboy_http:digits/1);
-parse_header(Name, Req, Default) when Name =:= <<"content-type">> ->
+parse_header(Name = <<"content-type">>, Req, Default) ->
parse_header(Name, Req, Default, fun cowboy_http:content_type/1);
parse_header(Name = <<"cookie">>, Req, Default) ->
parse_header(Name, Req, Default, fun cowboy_http:cookie_list/1);
-parse_header(Name, Req, Default) when Name =:= <<"expect">> ->
+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">> ->
+ 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, Req, Default) when Name =:= <<"sec-websocket-protocol">> ->
+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);
%% @todo Extension parameters.
-parse_header(Name, Req, Default) when Name =:= <<"transfer-encoding">> ->
- parse_header(Name, Req, Default,
- fun (Value) ->
- cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2)
- end);
-parse_header(Name, Req, Default) when Name =:= <<"upgrade">> ->
+parse_header(Name, Req, Default)
+ when Name =:= <<"transfer-encoding">>;
+ Name =:= <<"upgrade">> ->
parse_header(Name, Req, Default,
fun (Value) ->
cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2)
@@ -566,7 +542,7 @@ set_meta(Name, Value, Req=#http_req{meta=Meta}) ->
%% Request Body API.
%% @doc Return whether the request message has a body.
--spec has_body(cowboy_req:req()) -> boolean().
+-spec has_body(req()) -> boolean().
has_body(Req) ->
case lists:keyfind(<<"content-length">>, 1, Req#http_req.headers) of
{_, <<"0">>} ->
@@ -591,17 +567,11 @@ body_length(Req) ->
{undefined, Req2}
end.
-%% @equiv init_stream(1000000, TransferDecode, TransferState, ContentDecode, Req)
--spec init_stream(fun(), any(), fun(), Req)
- -> {ok, Req} when Req::req().
-init_stream(TransferDecode, TransferState, ContentDecode, Req) ->
- init_stream(1000000, TransferDecode, TransferState, ContentDecode, Req).
-
%% @doc Initialize body streaming and set custom decoding functions.
%%
%% Calling this function is optional. It should only be used if you
%% need to override the default behavior of Cowboy. Otherwise you
-%% should call stream_body/1 directly.
+%% should call stream_body/{1,2} directly.
%%
%% Two decodings happen. First a decoding function is applied to the
%% transferred data, and then another is applied to the actual content.
@@ -613,27 +583,36 @@ init_stream(TransferDecode, TransferState, ContentDecode, Req) ->
%% Content encoding is generally used for compression.
%%
%% Standard encodings can be found in cowboy_http.
--spec init_stream(non_neg_integer(), fun(), any(), fun(), Req)
+-spec init_stream(fun(), any(), fun(), Req)
-> {ok, Req} when Req::req().
-init_stream(MaxLength, TransferDecode, TransferState, ContentDecode, Req) ->
+init_stream(TransferDecode, TransferState, ContentDecode, Req) ->
{ok, Req#http_req{body_state=
- {stream, 0, MaxLength, TransferDecode, TransferState, ContentDecode}}}.
+ {stream, 0, TransferDecode, TransferState, ContentDecode}}}.
+
+%% @equiv stream_body(1000000, Req)
+-spec stream_body(Req) -> {ok, binary(), Req}
+ | {done, Req} | {error, atom()} when Req::req().
+stream_body(Req) ->
+ stream_body(1000000, Req).
%% @doc Stream the request's body.
%%
%% This is the most low level function to read the request body.
%%
-%% In most cases, if they weren't defined before using stream_body/4,
+%% In most cases, if they weren't defined before using init_stream/4,
%% this function will guess which transfer and content encodings were
%% used for building the request body, and configure the decoding
%% functions that will be used when streaming.
%%
%% It then starts streaming the body, returning {ok, Data, Req}
%% for each streamed part, and {done, Req} when it's finished streaming.
--spec stream_body(Req) -> {ok, binary(), Req}
+%%
+%% You can limit the size of the chunks being returned by using the
+%% second argument which is the size in bytes. It defaults to 1000000 bytes.
+-spec stream_body(non_neg_integer(), Req) -> {ok, binary(), Req}
| {done, Req} | {error, atom()} when Req::req().
-stream_body(Req=#http_req{body_state=waiting,
- version=Version, transport=Transport, socket=Socket}) ->
+stream_body(MaxLength, Req=#http_req{body_state=waiting, version=Version,
+ transport=Transport, socket=Socket}) ->
{ok, ExpectHeader, Req1} = parse_header(<<"expect">>, Req),
case ExpectHeader of
[<<"100-continue">>] ->
@@ -645,8 +624,8 @@ stream_body(Req=#http_req{body_state=waiting,
end,
case parse_header(<<"transfer-encoding">>, Req1) of
{ok, [<<"chunked">>], Req2} ->
- stream_body(Req2#http_req{body_state=
- {stream, 0, 1000000,
+ stream_body(MaxLength, Req2#http_req{body_state=
+ {stream, 0,
fun cowboy_http:te_chunked/2, {0, 0},
fun cowboy_http:ce_identity/1}});
{ok, [<<"identity">>], Req2} ->
@@ -655,25 +634,25 @@ stream_body(Req=#http_req{body_state=waiting,
0 ->
{done, Req3#http_req{body_state=done}};
Length ->
- stream_body(Req3#http_req{body_state=
- {stream, Length, 1000000,
+ stream_body(MaxLength, Req3#http_req{body_state=
+ {stream, Length,
fun cowboy_http:te_identity/2, {0, Length},
fun cowboy_http:ce_identity/1}})
end
end;
-stream_body(Req=#http_req{body_state=done}) ->
+stream_body(_, Req=#http_req{body_state=done}) ->
{done, Req};
-stream_body(Req=#http_req{buffer=Buffer})
+stream_body(_, Req=#http_req{buffer=Buffer})
when Buffer =/= <<>> ->
transfer_decode(Buffer, Req#http_req{buffer= <<>>});
-stream_body(Req) ->
- stream_body_recv(Req).
+stream_body(MaxLength, Req) ->
+ stream_body_recv(MaxLength, Req).
--spec stream_body_recv(Req)
+-spec stream_body_recv(non_neg_integer(), Req)
-> {ok, binary(), Req} | {error, atom()} when Req::req().
-stream_body_recv(Req=#http_req{
+stream_body_recv(MaxLength, Req=#http_req{
transport=Transport, socket=Socket, buffer=Buffer,
- body_state={stream, Length, MaxLength, _, _, _}}) ->
+ body_state={stream, Length, _, _, _}}) ->
%% @todo Allow configuring the timeout.
case Transport:recv(Socket, min(Length, MaxLength), 5000) of
{ok, Data} -> transfer_decode(<< Buffer/binary, Data/binary >>,
@@ -683,20 +662,20 @@ stream_body_recv(Req=#http_req{
-spec transfer_decode(binary(), Req)
-> {ok, binary(), Req} | {error, atom()} when Req::req().
-transfer_decode(Data, Req=#http_req{body_state={stream, _, MaxLength,
+transfer_decode(Data, Req=#http_req{body_state={stream, _,
TransferDecode, TransferState, ContentDecode}}) ->
case TransferDecode(Data, TransferState) of
{ok, Data2, Rest, TransferState2} ->
content_decode(ContentDecode, Data2,
- Req#http_req{buffer=Rest, body_state={stream, 0, MaxLength,
+ Req#http_req{buffer=Rest, body_state={stream, 0,
TransferDecode, TransferState2, ContentDecode}});
%% @todo {header(s) for chunked
more ->
- stream_body_recv(Req#http_req{buffer=Data, body_state={stream,
- 0, MaxLength, TransferDecode, TransferState, ContentDecode}});
+ stream_body_recv(0, Req#http_req{buffer=Data, body_state={stream,
+ 0, TransferDecode, TransferState, ContentDecode}});
{more, Length, Data2, TransferState2} ->
content_decode(ContentDecode, Data2,
- Req#http_req{body_state={stream, Length, MaxLength,
+ Req#http_req{body_state={stream, Length,
TransferDecode, TransferState2, ContentDecode}});
{done, Length, Rest} ->
Req2 = transfer_decode_done(Length, Rest, Req),
@@ -1010,8 +989,7 @@ reply(Status, Headers, Body, Req=#http_req{
reply_may_compress(Status, Headers, Body, Req,
RespHeaders, HTTP11Headers, Method) ->
BodySize = iolist_size(Body),
- {ok, Encodings, Req2}
- = cowboy_req:parse_header(<<"accept-encoding">>, Req),
+ {ok, Encodings, Req2} = parse_header(<<"accept-encoding">>, Req),
CanGzip = (BodySize > 300)
andalso (false =:= lists:keyfind(<<"content-encoding">>,
1, Headers))