0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 20:30:23 +00:00

Remove cowboy_req:fragment/1

Clients do not send it. We skip the value if we receive it now,
as it shouldn't happen, and won't for all the mainstream clients.
This commit is contained in:
Loïc Hoguin 2013-05-15 15:17:33 +02:00
parent 7577ce4920
commit e0b5526f1e
3 changed files with 102 additions and 126 deletions

View file

@ -41,8 +41,7 @@ The following access functions are defined in `cowboy_req`:
* `qs/1`: the entire query string unmodified * `qs/1`: the entire query string unmodified
* `qs_val/{2,3}`: the value for the requested query string key * `qs_val/{2,3}`: the value for the requested query string key
* `qs_vals/1`: all key/values found in the query string * `qs_vals/1`: all key/values found in the query string
* `fragment/1`: the fragment part of the URL (e.g. `#nav-links`) * `host_url/1`: the requested URL without the path and query string
* `host_url/1`: the requested URL without the path, qs and fragment
* `url/1`: the requested URL * `url/1`: the requested URL
* `binding/{2,3}`: the value for the requested binding found during routing * `binding/{2,3}`: the value for the requested binding found during routing
* `bindings/1`: all key/values found during routing * `bindings/1`: all key/values found during routing

View file

@ -202,7 +202,7 @@ parse_method(<< C, Rest/bits >>, State, SoFar) ->
parse_uri(<< $\r, _/bits >>, State, _) -> parse_uri(<< $\r, _/bits >>, State, _) ->
error_terminate(400, State); error_terminate(400, State);
parse_uri(<< "* ", Rest/bits >>, State, Method) -> parse_uri(<< "* ", Rest/bits >>, State, Method) ->
parse_version(Rest, State, Method, <<"*">>, <<>>, <<>>); parse_version(Rest, State, Method, <<"*">>, <<>>);
parse_uri(<< "http://", Rest/bits >>, State, Method) -> parse_uri(<< "http://", Rest/bits >>, State, Method) ->
parse_uri_skip_host(Rest, State, Method); parse_uri_skip_host(Rest, State, Method);
parse_uri(<< "https://", Rest/bits >>, State, Method) -> parse_uri(<< "https://", Rest/bits >>, State, Method) ->
@ -220,61 +220,61 @@ parse_uri_skip_host(<< C, Rest/bits >>, State, Method) ->
parse_uri_path(<< C, Rest/bits >>, State, Method, SoFar) -> parse_uri_path(<< C, Rest/bits >>, State, Method, SoFar) ->
case C of case C of
$\r -> error_terminate(400, State); $\r -> error_terminate(400, State);
$\s -> parse_version(Rest, State, Method, SoFar, <<>>, <<>>); $\s -> parse_version(Rest, State, Method, SoFar, <<>>);
$? -> parse_uri_query(Rest, State, Method, SoFar, <<>>); $? -> parse_uri_query(Rest, State, Method, SoFar, <<>>);
$# -> parse_uri_fragment(Rest, State, Method, SoFar, <<>>, <<>>); $# -> skip_uri_fragment(Rest, State, Method, SoFar, <<>>);
_ -> parse_uri_path(Rest, State, Method, << SoFar/binary, C >>) _ -> parse_uri_path(Rest, State, Method, << SoFar/binary, C >>)
end. end.
parse_uri_query(<< C, Rest/bits >>, S, M, P, SoFar) -> parse_uri_query(<< C, Rest/bits >>, S, M, P, SoFar) ->
case C of case C of
$\r -> error_terminate(400, S); $\r -> error_terminate(400, S);
$\s -> parse_version(Rest, S, M, P, SoFar, <<>>); $\s -> parse_version(Rest, S, M, P, SoFar);
$# -> parse_uri_fragment(Rest, S, M, P, SoFar, <<>>); $# -> skip_uri_fragment(Rest, S, M, P, SoFar);
_ -> parse_uri_query(Rest, S, M, P, << SoFar/binary, C >>) _ -> parse_uri_query(Rest, S, M, P, << SoFar/binary, C >>)
end. end.
parse_uri_fragment(<< C, Rest/bits >>, S, M, P, Q, SoFar) -> skip_uri_fragment(<< C, Rest/bits >>, S, M, P, Q) ->
case C of case C of
$\r -> error_terminate(400, S); $\r -> error_terminate(400, S);
$\s -> parse_version(Rest, S, M, P, Q, SoFar); $\s -> parse_version(Rest, S, M, P, Q);
_ -> parse_uri_fragment(Rest, S, M, P, Q, << SoFar/binary, C >>) _ -> skip_uri_fragment(Rest, S, M, P, Q)
end. end.
parse_version(<< "HTTP/1.1\r\n", Rest/bits >>, S, M, P, Q, F) -> parse_version(<< "HTTP/1.1\r\n", Rest/bits >>, S, M, P, Q) ->
parse_header(Rest, S, M, P, Q, F, {1, 1}, []); parse_header(Rest, S, M, P, Q, {1, 1}, []);
parse_version(<< "HTTP/1.0\r\n", Rest/bits >>, S, M, P, Q, F) -> parse_version(<< "HTTP/1.0\r\n", Rest/bits >>, S, M, P, Q) ->
parse_header(Rest, S, M, P, Q, F, {1, 0}, []); parse_header(Rest, S, M, P, Q, {1, 0}, []);
parse_version(_, State, _, _, _, _) -> parse_version(_, State, _, _, _) ->
error_terminate(505, State). error_terminate(505, State).
%% Stop receiving data if we have more than allowed number of headers. %% Stop receiving data if we have more than allowed number of headers.
wait_header(_, State=#state{max_headers=MaxHeaders}, _, _, _, _, _, Headers) wait_header(_, State=#state{max_headers=MaxHeaders}, _, _, _, _, Headers)
when length(Headers) >= MaxHeaders -> when length(Headers) >= MaxHeaders ->
error_terminate(400, State); error_terminate(400, State);
wait_header(Buffer, State=#state{socket=Socket, transport=Transport, wait_header(Buffer, State=#state{socket=Socket, transport=Transport,
until=Until}, M, P, Q, F, V, H) -> until=Until}, M, P, Q, V, H) ->
case recv(Socket, Transport, Until) of case recv(Socket, Transport, Until) of
{ok, Data} -> {ok, Data} ->
parse_header(<< Buffer/binary, Data/binary >>, parse_header(<< Buffer/binary, Data/binary >>,
State, M, P, Q, F, V, H); State, M, P, Q, V, H);
{error, timeout} -> {error, timeout} ->
error_terminate(408, State); error_terminate(408, State);
{error, _} -> {error, _} ->
terminate(State) terminate(State)
end. end.
parse_header(<< $\r, $\n, Rest/bits >>, S, M, P, Q, F, V, Headers) -> parse_header(<< $\r, $\n, Rest/bits >>, S, M, P, Q, V, Headers) ->
request(Rest, S, M, P, Q, F, V, lists:reverse(Headers)); request(Rest, S, M, P, Q, V, lists:reverse(Headers));
parse_header(Buffer, State=#state{max_header_name_length=MaxLength}, parse_header(Buffer, State=#state{max_header_name_length=MaxLength},
M, P, Q, F, V, H) -> M, P, Q, V, H) ->
case match_colon(Buffer, 0) of case match_colon(Buffer, 0) of
nomatch when byte_size(Buffer) > MaxLength -> nomatch when byte_size(Buffer) > MaxLength ->
error_terminate(400, State); error_terminate(400, State);
nomatch -> nomatch ->
wait_header(Buffer, State, M, P, Q, F, V, H); wait_header(Buffer, State, M, P, Q, V, H);
_ -> _ ->
parse_hd_name(Buffer, State, M, P, Q, F, V, H, <<>>) parse_hd_name(Buffer, State, M, P, Q, V, H, <<>>)
end. end.
match_colon(<< $:, _/bits >>, N) -> match_colon(<< $:, _/bits >>, N) ->
@ -290,73 +290,73 @@ match_colon(_, _) ->
%% ... Sorry for your eyes. %% ... Sorry for your eyes.
%% %%
%% But let's be honest, that's still pretty readable. %% But let's be honest, that's still pretty readable.
parse_hd_name(<< C, Rest/bits >>, S, M, P, Q, F, V, H, SoFar) -> parse_hd_name(<< C, Rest/bits >>, S, M, P, Q, V, H, SoFar) ->
case C of case C of
$: -> parse_hd_before_value(Rest, S, M, P, Q, F, V, H, SoFar); $: -> parse_hd_before_value(Rest, S, M, P, Q, V, H, SoFar);
$\s -> parse_hd_name_ws(Rest, S, M, P, Q, F, V, H, SoFar); $\s -> parse_hd_name_ws(Rest, S, M, P, Q, V, H, SoFar);
$\t -> parse_hd_name_ws(Rest, S, M, P, Q, F, V, H, SoFar); $\t -> parse_hd_name_ws(Rest, S, M, P, Q, V, H, SoFar);
$A -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $a >>); $A -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $a >>);
$B -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $b >>); $B -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $b >>);
$C -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $c >>); $C -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $c >>);
$D -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $d >>); $D -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $d >>);
$E -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $e >>); $E -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $e >>);
$F -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $f >>); $F -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $f >>);
$G -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $g >>); $G -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $g >>);
$H -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $h >>); $H -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $h >>);
$I -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $i >>); $I -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $i >>);
$J -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $j >>); $J -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $j >>);
$K -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $k >>); $K -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $k >>);
$L -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $l >>); $L -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $l >>);
$M -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $m >>); $M -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $m >>);
$N -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $n >>); $N -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $n >>);
$O -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $o >>); $O -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $o >>);
$P -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $p >>); $P -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $p >>);
$Q -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $q >>); $Q -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $q >>);
$R -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $r >>); $R -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $r >>);
$S -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $s >>); $S -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $s >>);
$T -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $t >>); $T -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $t >>);
$U -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $u >>); $U -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $u >>);
$V -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $v >>); $V -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $v >>);
$W -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $w >>); $W -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $w >>);
$X -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $x >>); $X -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $x >>);
$Y -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $y >>); $Y -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $y >>);
$Z -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, $z >>); $Z -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $z >>);
C -> parse_hd_name(Rest, S, M, P, Q, F, V, H, << SoFar/binary, C >>) C -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, C >>)
end. end.
parse_hd_name_ws(<< C, Rest/bits >>, S, M, P, Q, F, V, H, Name) -> parse_hd_name_ws(<< C, Rest/bits >>, S, M, P, Q, V, H, Name) ->
case C of case C of
$\s -> parse_hd_name_ws(Rest, S, M, P, Q, F, V, H, Name); $\s -> parse_hd_name_ws(Rest, S, M, P, Q, V, H, Name);
$\t -> parse_hd_name_ws(Rest, S, M, P, Q, F, V, H, Name); $\t -> parse_hd_name_ws(Rest, S, M, P, Q, V, H, Name);
$: -> parse_hd_before_value(Rest, S, M, P, Q, F, V, H, Name) $: -> parse_hd_before_value(Rest, S, M, P, Q, V, H, Name)
end. end.
wait_hd_before_value(Buffer, State=#state{ wait_hd_before_value(Buffer, State=#state{
socket=Socket, transport=Transport, until=Until}, socket=Socket, transport=Transport, until=Until},
M, P, Q, F, V, H, N) -> M, P, Q, V, H, N) ->
case recv(Socket, Transport, Until) of case recv(Socket, Transport, Until) of
{ok, Data} -> {ok, Data} ->
parse_hd_before_value(<< Buffer/binary, Data/binary >>, parse_hd_before_value(<< Buffer/binary, Data/binary >>,
State, M, P, Q, F, V, H, N); State, M, P, Q, V, H, N);
{error, timeout} -> {error, timeout} ->
error_terminate(408, State); error_terminate(408, State);
{error, _} -> {error, _} ->
terminate(State) terminate(State)
end. end.
parse_hd_before_value(<< $\s, Rest/bits >>, S, M, P, Q, F, V, H, N) -> parse_hd_before_value(<< $\s, Rest/bits >>, S, M, P, Q, V, H, N) ->
parse_hd_before_value(Rest, S, M, P, Q, F, V, H, N); parse_hd_before_value(Rest, S, M, P, Q, V, H, N);
parse_hd_before_value(<< $\t, Rest/bits >>, S, M, P, Q, F, V, H, N) -> parse_hd_before_value(<< $\t, Rest/bits >>, S, M, P, Q, V, H, N) ->
parse_hd_before_value(Rest, S, M, P, Q, F, V, H, N); parse_hd_before_value(Rest, S, M, P, Q, V, H, N);
parse_hd_before_value(Buffer, State=#state{ parse_hd_before_value(Buffer, State=#state{
max_header_value_length=MaxLength}, M, P, Q, F, V, H, N) -> max_header_value_length=MaxLength}, M, P, Q, V, H, N) ->
case match_eol(Buffer, 0) of case match_eol(Buffer, 0) of
nomatch when byte_size(Buffer) > MaxLength -> nomatch when byte_size(Buffer) > MaxLength ->
error_terminate(400, State); error_terminate(400, State);
nomatch -> nomatch ->
wait_hd_before_value(Buffer, State, M, P, Q, F, V, H, N); wait_hd_before_value(Buffer, State, M, P, Q, V, H, N);
_ -> _ ->
parse_hd_value(Buffer, State, M, P, Q, F, V, H, N, <<>>) parse_hd_value(Buffer, State, M, P, Q, V, H, N, <<>>)
end. end.
%% We completely ignore the first argument which is always %% We completely ignore the first argument which is always
@ -365,10 +365,10 @@ parse_hd_before_value(Buffer, State=#state{
%% operations for no reasons. %% operations for no reasons.
wait_hd_value(_, State=#state{ wait_hd_value(_, State=#state{
socket=Socket, transport=Transport, until=Until}, socket=Socket, transport=Transport, until=Until},
M, P, Q, F, V, H, N, SoFar) -> M, P, Q, V, H, N, SoFar) ->
case recv(Socket, Transport, Until) of case recv(Socket, Transport, Until) of
{ok, Data} -> {ok, Data} ->
parse_hd_value(Data, State, M, P, Q, F, V, H, N, SoFar); parse_hd_value(Data, State, M, P, Q, V, H, N, SoFar);
{error, timeout} -> {error, timeout} ->
error_terminate(408, State); error_terminate(408, State);
{error, _} -> {error, _} ->
@ -380,51 +380,51 @@ wait_hd_value(_, State=#state{
%% the critical path, but forces us to have a special function. %% the critical path, but forces us to have a special function.
wait_hd_value_nl(_, State=#state{ wait_hd_value_nl(_, State=#state{
socket=Socket, transport=Transport, until=Until}, socket=Socket, transport=Transport, until=Until},
M, P, Q, F, V, Headers, Name, SoFar) -> M, P, Q, V, Headers, Name, SoFar) ->
case recv(Socket, Transport, Until) of case recv(Socket, Transport, Until) of
{ok, << C, Data/bits >>} when C =:= $\s; C =:= $\t -> {ok, << C, Data/bits >>} when C =:= $\s; C =:= $\t ->
parse_hd_value(Data, State, M, P, Q, F, V, Headers, Name, SoFar); parse_hd_value(Data, State, M, P, Q, V, Headers, Name, SoFar);
{ok, Data} -> {ok, Data} ->
parse_header(Data, State, M, P, Q, F, V, [{Name, SoFar}|Headers]); parse_header(Data, State, M, P, Q, V, [{Name, SoFar}|Headers]);
{error, timeout} -> {error, timeout} ->
error_terminate(408, State); error_terminate(408, State);
{error, _} -> {error, _} ->
terminate(State) terminate(State)
end. end.
parse_hd_value(<< $\r, Rest/bits >>, S, M, P, Q, F, V, Headers, Name, SoFar) -> parse_hd_value(<< $\r, Rest/bits >>, S, M, P, Q, V, Headers, Name, SoFar) ->
case Rest of case Rest of
<< $\n >> -> << $\n >> ->
wait_hd_value_nl(<<>>, S, M, P, Q, F, V, Headers, Name, SoFar); wait_hd_value_nl(<<>>, S, M, P, Q, V, Headers, Name, SoFar);
<< $\n, C, Rest2/bits >> when C =:= $\s; C =:= $\t -> << $\n, C, Rest2/bits >> when C =:= $\s; C =:= $\t ->
parse_hd_value(Rest2, S, M, P, Q, F, V, Headers, Name, SoFar); parse_hd_value(Rest2, S, M, P, Q, V, Headers, Name, SoFar);
<< $\n, Rest2/bits >> -> << $\n, Rest2/bits >> ->
parse_header(Rest2, S, M, P, Q, F, V, [{Name, SoFar}|Headers]) parse_header(Rest2, S, M, P, Q, V, [{Name, SoFar}|Headers])
end; end;
parse_hd_value(<< C, Rest/bits >>, S, M, P, Q, F, V, H, N, SoFar) -> parse_hd_value(<< C, Rest/bits >>, S, M, P, Q, V, H, N, SoFar) ->
parse_hd_value(Rest, S, M, P, Q, F, V, H, N, << SoFar/binary, C >>); parse_hd_value(Rest, S, M, P, Q, V, H, N, << SoFar/binary, C >>);
parse_hd_value(<<>>, State=#state{max_header_value_length=MaxLength}, parse_hd_value(<<>>, State=#state{max_header_value_length=MaxLength},
_, _, _, _, _, _, _, SoFar) when byte_size(SoFar) > MaxLength -> _, _, _, _, _, _, SoFar) when byte_size(SoFar) > MaxLength ->
error_terminate(400, State); error_terminate(400, State);
parse_hd_value(<<>>, S, M, P, Q, F, V, H, N, SoFar) -> parse_hd_value(<<>>, S, M, P, Q, V, H, N, SoFar) ->
wait_hd_value(<<>>, S, M, P, Q, F, V, H, N, SoFar). wait_hd_value(<<>>, S, M, P, Q, V, H, N, SoFar).
request(B, State=#state{transport=Transport}, M, P, Q, F, Version, Headers) -> request(B, State=#state{transport=Transport}, M, P, Q, Version, Headers) ->
case lists:keyfind(<<"host">>, 1, Headers) of case lists:keyfind(<<"host">>, 1, Headers) of
false when Version =:= {1, 1} -> false when Version =:= {1, 1} ->
error_terminate(400, State); error_terminate(400, State);
false -> false ->
request(B, State, M, P, Q, F, Version, Headers, request(B, State, M, P, Q, Version, Headers,
<<>>, default_port(Transport:name())); <<>>, default_port(Transport:name()));
{_, RawHost} -> {_, RawHost} ->
case catch parse_host(RawHost, <<>>) of case catch parse_host(RawHost, <<>>) of
{'EXIT', _} -> {'EXIT', _} ->
error_terminate(400, State); error_terminate(400, State);
{Host, undefined} -> {Host, undefined} ->
request(B, State, M, P, Q, F, Version, Headers, request(B, State, M, P, Q, Version, Headers,
Host, default_port(Transport:name())); Host, default_port(Transport:name()));
{Host, Port} -> {Host, Port} ->
request(B, State, M, P, Q, F, Version, Headers, request(B, State, M, P, Q, Version, Headers,
Host, Port) Host, Port)
end end
end. end.
@ -476,11 +476,11 @@ parse_host(<< C, Rest/bits >>, Acc) ->
request(Buffer, State=#state{socket=Socket, transport=Transport, request(Buffer, State=#state{socket=Socket, transport=Transport,
req_keepalive=ReqKeepalive, max_keepalive=MaxKeepalive, req_keepalive=ReqKeepalive, max_keepalive=MaxKeepalive,
compress=Compress, onresponse=OnResponse}, compress=Compress, onresponse=OnResponse},
Method, Path, Query, Fragment, Version, Headers, Host, Port) -> Method, Path, Query, Version, Headers, Host, Port) ->
case Transport:peername(Socket) of case Transport:peername(Socket) of
{ok, Peer} -> {ok, Peer} ->
Req = cowboy_req:new(Socket, Transport, Peer, Method, Path, Req = cowboy_req:new(Socket, Transport, Peer, Method, Path,
Query, Fragment, Version, Headers, Host, Port, Buffer, Query, Version, Headers, Host, Port, Buffer,
ReqKeepalive < MaxKeepalive, Compress, OnResponse), ReqKeepalive < MaxKeepalive, Compress, OnResponse),
onrequest(Req, State); onrequest(Req, State);
{error, _} -> {error, _} ->
@ -583,7 +583,7 @@ error_terminate(Code, State=#state{socket=Socket, transport=Transport,
{cowboy_req, resp_sent} -> ok {cowboy_req, resp_sent} -> ok
after 0 -> after 0 ->
_ = cowboy_req:reply(Code, cowboy_req:new(Socket, Transport, _ = cowboy_req:reply(Code, cowboy_req:new(Socket, Transport,
undefined, <<"GET">>, <<>>, <<>>, <<>>, {1, 1}, [], <<>>, undefined, <<"GET">>, <<>>, <<>>, {1, 1}, [], <<>>,
undefined, <<>>, false, Compress, OnResponse)), undefined, <<>>, false, Compress, OnResponse)),
ok ok
end, end,

View file

@ -41,7 +41,7 @@
-module(cowboy_req). -module(cowboy_req).
%% Request API. %% Request API.
-export([new/15]). -export([new/14]).
-export([method/1]). -export([method/1]).
-export([version/1]). -export([version/1]).
-export([peer/1]). -export([peer/1]).
@ -54,7 +54,6 @@
-export([qs_val/2]). -export([qs_val/2]).
-export([qs_val/3]). -export([qs_val/3]).
-export([qs_vals/1]). -export([qs_vals/1]).
-export([fragment/1]).
-export([host_url/1]). -export([host_url/1]).
-export([url/1]). -export([url/1]).
-export([binding/2]). -export([binding/2]).
@ -143,7 +142,6 @@
path_info = undefined :: undefined | cowboy_router:tokens(), path_info = undefined :: undefined | cowboy_router:tokens(),
qs = undefined :: binary(), qs = undefined :: binary(),
qs_vals = undefined :: undefined | list({binary(), binary() | true}), qs_vals = undefined :: undefined | list({binary(), binary() | true}),
fragment = undefined :: binary(),
bindings = undefined :: undefined | cowboy_router:bindings(), bindings = undefined :: undefined | cowboy_router:bindings(),
headers = [] :: cowboy_http:headers(), headers = [] :: cowboy_http:headers(),
p_headers = [] :: [any()], %% @todo Improve those specs. p_headers = [] :: [any()], %% @todo Improve those specs.
@ -183,16 +181,16 @@
%% in an optimized way and add the parsed value to p_headers' cache. %% in an optimized way and add the parsed value to p_headers' cache.
-spec new(inet:socket(), module(), -spec new(inet:socket(), module(),
undefined | {inet:ip_address(), inet:port_number()}, undefined | {inet:ip_address(), inet:port_number()},
binary(), binary(), binary(), binary(), binary(), binary(), binary(),
cowboy_http:version(), cowboy_http:headers(), binary(), cowboy_http:version(), cowboy_http:headers(), binary(),
inet:port_number() | undefined, binary(), boolean(), boolean(), inet:port_number() | undefined, binary(), boolean(), boolean(),
undefined | cowboy_protocol:onresponse_fun()) undefined | cowboy_protocol:onresponse_fun())
-> req(). -> req().
new(Socket, Transport, Peer, Method, Path, Query, Fragment, new(Socket, Transport, Peer, Method, Path, Query,
Version, Headers, Host, Port, Buffer, CanKeepalive, Version, Headers, Host, Port, Buffer, CanKeepalive,
Compress, OnResponse) -> Compress, OnResponse) ->
Req = #http_req{socket=Socket, transport=Transport, pid=self(), peer=Peer, Req = #http_req{socket=Socket, transport=Transport, pid=self(), peer=Peer,
method=Method, path=Path, qs=Query, fragment=Fragment, version=Version, method=Method, path=Path, qs=Query, version=Version,
headers=Headers, host=Host, port=Port, buffer=Buffer, headers=Headers, host=Host, port=Port, buffer=Buffer,
resp_compress=Compress, onresponse=OnResponse}, resp_compress=Compress, onresponse=OnResponse},
case CanKeepalive and (Version =:= {1, 1}) of case CanKeepalive and (Version =:= {1, 1}) of
@ -289,11 +287,6 @@ qs_vals(Req=#http_req{qs=RawQs, qs_vals=undefined}) ->
qs_vals(Req=#http_req{qs_vals=QsVals}) -> qs_vals(Req=#http_req{qs_vals=QsVals}) ->
{QsVals, Req}. {QsVals, Req}.
%% @doc Return the raw fragment directly taken from the request.
-spec fragment(Req) -> {binary(), Req} when Req::req().
fragment(Req) ->
{Req#http_req.fragment, Req}.
%% @doc Return the request URL as a binary without the path and query string. %% @doc Return the request URL as a binary without the path and query string.
%% %%
%% The URL includes the scheme, host and port only. %% The URL includes the scheme, host and port only.
@ -316,7 +309,7 @@ host_url(Req=#http_req{transport=Transport, host=Host, port=Port}) ->
%% @doc Return the full request URL as a binary. %% @doc Return the full request URL as a binary.
%% %%
%% The URL includes the scheme, host, port, path, query string and fragment. %% The URL includes the scheme, host, port, path and query string.
-spec url(Req) -> {undefined | binary(), Req} when Req::req(). -spec url(Req) -> {undefined | binary(), Req} when Req::req().
url(Req=#http_req{}) -> url(Req=#http_req{}) ->
{HostURL, Req2} = host_url(Req), {HostURL, Req2} = host_url(Req),
@ -324,16 +317,12 @@ url(Req=#http_req{}) ->
url(undefined, Req=#http_req{}) -> url(undefined, Req=#http_req{}) ->
{undefined, Req}; {undefined, Req};
url(HostURL, Req=#http_req{path=Path, qs=QS, fragment=Fragment}) -> url(HostURL, Req=#http_req{path=Path, qs=QS}) ->
QS2 = case QS of QS2 = case QS of
<<>> -> <<>>; <<>> -> <<>>;
_ -> << "?", QS/binary >> _ -> << "?", QS/binary >>
end, end,
Fragment2 = case Fragment of {<< HostURL/binary, Path/binary, QS2/binary >>, Req}.
<<>> -> <<>>;
_ -> << "#", Fragment/binary >>
end,
{<< HostURL/binary, Path/binary, QS2/binary, Fragment2/binary >>, Req}.
%% @equiv binding(Name, Req, undefined) %% @equiv binding(Name, Req, undefined)
-spec binding(atom(), Req) -> {binary() | undefined, Req} when Req::req(). -spec binding(atom(), Req) -> {binary() | undefined, Req} when Req::req().
@ -1123,7 +1112,6 @@ g(body_state, #http_req{body_state=Ret}) -> Ret;
g(buffer, #http_req{buffer=Ret}) -> Ret; g(buffer, #http_req{buffer=Ret}) -> Ret;
g(connection, #http_req{connection=Ret}) -> Ret; g(connection, #http_req{connection=Ret}) -> Ret;
g(cookies, #http_req{cookies=Ret}) -> Ret; g(cookies, #http_req{cookies=Ret}) -> Ret;
g(fragment, #http_req{fragment=Ret}) -> Ret;
g(headers, #http_req{headers=Ret}) -> Ret; g(headers, #http_req{headers=Ret}) -> Ret;
g(host, #http_req{host=Ret}) -> Ret; g(host, #http_req{host=Ret}) -> Ret;
g(host_info, #http_req{host_info=Ret}) -> Ret; g(host_info, #http_req{host_info=Ret}) -> Ret;
@ -1154,7 +1142,6 @@ set([{body_state, Val}|Tail], Req) -> set(Tail, Req#http_req{body_state=Val});
set([{buffer, Val}|Tail], Req) -> set(Tail, Req#http_req{buffer=Val}); set([{buffer, Val}|Tail], Req) -> set(Tail, Req#http_req{buffer=Val});
set([{connection, Val}|Tail], Req) -> set(Tail, Req#http_req{connection=Val}); set([{connection, Val}|Tail], Req) -> set(Tail, Req#http_req{connection=Val});
set([{cookies, Val}|Tail], Req) -> set(Tail, Req#http_req{cookies=Val}); set([{cookies, Val}|Tail], Req) -> set(Tail, Req#http_req{cookies=Val});
set([{fragment, Val}|Tail], Req) -> set(Tail, Req#http_req{fragment=Val});
set([{headers, Val}|Tail], Req) -> set(Tail, Req#http_req{headers=Val}); set([{headers, Val}|Tail], Req) -> set(Tail, Req#http_req{headers=Val});
set([{host, Val}|Tail], Req) -> set(Tail, Req#http_req{host=Val}); set([{host, Val}|Tail], Req) -> set(Tail, Req#http_req{host=Val});
set([{host_info, Val}|Tail], Req) -> set(Tail, Req#http_req{host_info=Val}); set([{host_info, Val}|Tail], Req) -> set(Tail, Req#http_req{host_info=Val});
@ -1441,38 +1428,28 @@ status(B) when is_binary(B) -> B.
url_test() -> url_test() ->
{undefined, _} = {undefined, _} =
url(#http_req{transport=ranch_tcp, host= <<>>, port= undefined, url(#http_req{transport=ranch_tcp, host= <<>>, port= undefined,
path= <<>>, qs= <<>>, fragment= <<>>, pid=self()}), path= <<>>, qs= <<>>, pid=self()}),
{<<"http://localhost/path">>, _ } = {<<"http://localhost/path">>, _ } =
url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=80, url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=80,
path= <<"/path">>, qs= <<>>, fragment= <<>>, pid=self()}), path= <<"/path">>, qs= <<>>, pid=self()}),
{<<"http://localhost:443/path">>, _} = {<<"http://localhost:443/path">>, _} =
url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=443, url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=443,
path= <<"/path">>, qs= <<>>, fragment= <<>>, pid=self()}), path= <<"/path">>, qs= <<>>, pid=self()}),
{<<"http://localhost:8080/path">>, _} = {<<"http://localhost:8080/path">>, _} =
url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=8080, url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=8080,
path= <<"/path">>, qs= <<>>, fragment= <<>>, pid=self()}), path= <<"/path">>, qs= <<>>, pid=self()}),
{<<"http://localhost:8080/path?dummy=2785">>, _} = {<<"http://localhost:8080/path?dummy=2785">>, _} =
url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=8080, url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=8080,
path= <<"/path">>, qs= <<"dummy=2785">>, fragment= <<>>, path= <<"/path">>, qs= <<"dummy=2785">>, pid=self()}),
pid=self()}),
{<<"http://localhost:8080/path?dummy=2785#fragment">>, _} =
url(#http_req{transport=ranch_tcp, host= <<"localhost">>, port=8080,
path= <<"/path">>, qs= <<"dummy=2785">>, fragment= <<"fragment">>,
pid=self()}),
{<<"https://localhost/path">>, _} = {<<"https://localhost/path">>, _} =
url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=443, url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=443,
path= <<"/path">>, qs= <<>>, fragment= <<>>, pid=self()}), path= <<"/path">>, qs= <<>>, pid=self()}),
{<<"https://localhost:8443/path">>, _} = {<<"https://localhost:8443/path">>, _} =
url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=8443, url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=8443,
path= <<"/path">>, qs= <<>>, fragment= <<>>, pid=self()}), path= <<"/path">>, qs= <<>>, pid=self()}),
{<<"https://localhost:8443/path?dummy=2785">>, _} = {<<"https://localhost:8443/path?dummy=2785">>, _} =
url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=8443, url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=8443,
path= <<"/path">>, qs= <<"dummy=2785">>, fragment= <<>>, path= <<"/path">>, qs= <<"dummy=2785">>, pid=self()}),
pid=self()}),
{<<"https://localhost:8443/path?dummy=2785#fragment">>, _} =
url(#http_req{transport=ranch_ssl, host= <<"localhost">>, port=8443,
path= <<"/path">>, qs= <<"dummy=2785">>, fragment= <<"fragment">>,
pid=self()}),
ok. ok.
parse_connection_test_() -> parse_connection_test_() ->