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

Fix cowboy_req:peer/1

This commit is contained in:
Loïc Hoguin 2016-06-20 17:28:59 +02:00
parent 57901a7116
commit 4fed8637b6
3 changed files with 44 additions and 43 deletions

View file

@ -90,6 +90,9 @@
opts = #{} :: map(), opts = #{} :: map(),
handler :: module(), handler :: module(),
%% Remote address and port for the connection.
peer = undefined :: {inet:ip_address(), inet:port_number()},
timer = undefined :: undefined | reference(), timer = undefined :: undefined | reference(),
%% Identifier for the stream currently being read (or waiting to be received). %% Identifier for the stream currently being read (or waiting to be received).
@ -124,11 +127,17 @@
-spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts(), module()) -> ok. -spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts(), module()) -> ok.
init(Parent, Ref, Socket, Transport, Opts, Handler) -> init(Parent, Ref, Socket, Transport, Opts, Handler) ->
LastStreamID = maps:get(max_keepalive, Opts, 100), case Transport:peername(Socket) of
before_loop(set_request_timeout(#state{ {ok, Peer} ->
parent=Parent, ref=Ref, socket=Socket, LastStreamID = maps:get(max_keepalive, Opts, 100),
transport=Transport, opts=Opts, handler=Handler, before_loop(set_request_timeout(#state{
last_streamid=LastStreamID}), <<>>). parent=Parent, ref=Ref, socket=Socket,
transport=Transport, opts=Opts, handler=Handler,
peer=Peer, last_streamid=LastStreamID}), <<>>);
{error, Reason} ->
%% Couldn't read the peer address; connection is gone.
terminate(undefined, {socket_error, Reason, 'An error has occurred on the socket.'})
end.
%% @todo Send a response depending on in_state and whether one was already sent. %% @todo Send a response depending on in_state and whether one was already sent.
@ -574,11 +583,7 @@ parse_host(<< C, Rest/bits >>, E, Acc) ->
%% End of request parsing. %% End of request parsing.
%% @todo We used to get the peername here, bad idea, should request(Buffer, State0=#state{ref=Ref, transport=Transport, peer=Peer, in_streamid=StreamID,
%% get it at the very start of the connection, or the first
%% time requested if we go the route of handler sending a
%% message to get it (we probably shouldn't).
request(Buffer, State0=#state{ref=Ref, transport=Transport, in_streamid=StreamID,
in_state=#ps_header{method=Method, path=Path, qs=Qs, version=Version}}, in_state=#ps_header{method=Method, path=Path, qs=Qs, version=Version}},
Headers, Host, Port) -> Headers, Host, Port) ->
Scheme = case Transport:secure() of Scheme = case Transport:secure() of
@ -607,19 +612,12 @@ request(Buffer, State0=#state{ref=Ref, transport=Transport, in_streamid=StreamID
ref => Ref, ref => Ref,
pid => self(), pid => self(),
streamid => StreamID, streamid => StreamID,
peer => Peer,
%% @todo peer
%% @todo sockname
%% @todo ssl client cert?
method => Method, method => Method,
scheme => Scheme, scheme => Scheme,
host => Host, host => Host,
%% host_info (cowboy_router)
port => Port, port => Port,
path => Path, path => Path,
%% path_info (cowboy_router)
%% bindings (cowboy_router)
qs => Qs, qs => Qs,
version => Version, version => Version,
%% We are transparently taking care of transfer-encodings so %% We are transparently taking care of transfer-encodings so
@ -673,18 +671,18 @@ is_http2_upgrade(_, _) ->
%% Prior knowledge upgrade, without an HTTP/1.1 request. %% Prior knowledge upgrade, without an HTTP/1.1 request.
http2_upgrade(State=#state{parent=Parent, ref=Ref, socket=Socket, transport=Transport, http2_upgrade(State=#state{parent=Parent, ref=Ref, socket=Socket, transport=Transport,
opts=Opts, handler=Handler}, Buffer) -> opts=Opts, handler=Handler, peer=Peer}, Buffer) ->
case Transport:secure() of case Transport:secure() of
false -> false ->
_ = cancel_request_timeout(State), _ = cancel_request_timeout(State),
cowboy_http2:init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer); cowboy_http2:init(Parent, Ref, Socket, Transport, Opts, Handler, Peer, Buffer);
true -> true ->
error_terminate(400, State, {connection_error, protocol_error, error_terminate(400, State, {connection_error, protocol_error,
'Clients that support HTTP/2 over TLS MUST use ALPN. (RFC7540 3.4)'}) 'Clients that support HTTP/2 over TLS MUST use ALPN. (RFC7540 3.4)'})
end. end.
http2_upgrade(State=#state{parent=Parent, ref=Ref, socket=Socket, transport=Transport, http2_upgrade(State=#state{parent=Parent, ref=Ref, socket=Socket, transport=Transport,
opts=Opts, handler=Handler}, Buffer, HTTP2Settings, Req) -> opts=Opts, handler=Handler, peer=Peer}, Buffer, HTTP2Settings, Req) ->
%% @todo %% @todo
%% However if the client sent a body, we need to read the body in full %% However if the client sent a body, we need to read the body in full
%% and if we can't do that, return a 413 response. Some options are in order. %% and if we can't do that, return a 413 response. Some options are in order.
@ -699,7 +697,7 @@ http2_upgrade(State=#state{parent=Parent, ref=Ref, socket=Socket, transport=Tran
%% @todo Possibly redirect the request if it was https. %% @todo Possibly redirect the request if it was https.
_ = cancel_request_timeout(State), _ = cancel_request_timeout(State),
cowboy_http2:init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer, Settings, Req) cowboy_http2:init(Parent, Ref, Socket, Transport, Opts, Handler, Peer, Buffer, Settings, Req)
catch _:_ -> catch _:_ ->
error_terminate(400, State, {connection_error, protocol_error, error_terminate(400, State, {connection_error, protocol_error,
'The HTTP2-Settings header contains a base64 SETTINGS payload. (RFC7540 3.2, RFC7540 3.2.1)'}) 'The HTTP2-Settings header contains a base64 SETTINGS payload. (RFC7540 3.2, RFC7540 3.2.1)'})

View file

@ -15,8 +15,8 @@
-module(cowboy_http2). -module(cowboy_http2).
-export([init/6]). -export([init/6]).
-export([init/7]). -export([init/8]).
-export([init/9]). -export([init/10]).
-export([system_continue/3]). -export([system_continue/3]).
-export([system_terminate/4]). -export([system_terminate/4]).
@ -46,6 +46,9 @@
opts = #{} :: map(), opts = #{} :: map(),
handler :: module(), handler :: module(),
%% Remote address and port for the connection.
peer = undefined :: {inet:ip_address(), inet:port_number()},
%% Settings are separate for each endpoint. In addition, settings %% Settings are separate for each endpoint. In addition, settings
%% must be acknowledged before they can be expected to be applied. %% must be acknowledged before they can be expected to be applied.
%% %%
@ -88,12 +91,19 @@
-spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts(), module()) -> ok. -spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts(), module()) -> ok.
init(Parent, Ref, Socket, Transport, Opts, Handler) -> init(Parent, Ref, Socket, Transport, Opts, Handler) ->
init(Parent, Ref, Socket, Transport, Opts, Handler, <<>>). case Transport:peername(Socket) of
{ok, Peer} ->
init(Parent, Ref, Socket, Transport, Opts, Handler, Peer, <<>>);
{error, Reason} ->
%% Couldn't read the peer address; connection is gone.
terminate(undefined, {socket_error, Reason, 'An error has occurred on the socket.'})
end.
-spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts(), module(), binary()) -> ok. -spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts(), module(),
init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer) -> {inet:ip_address(), inet:port_number()}, binary()) -> ok.
init(Parent, Ref, Socket, Transport, Opts, Handler, Peer, Buffer) ->
State = #state{parent=Parent, ref=Ref, socket=Socket, State = #state{parent=Parent, ref=Ref, socket=Socket,
transport=Transport, opts=Opts, handler=Handler, transport=Transport, opts=Opts, handler=Handler, peer=Peer,
parse_state={preface, sequence, preface_timeout(Opts)}}, parse_state={preface, sequence, preface_timeout(Opts)}},
preface(State), preface(State),
case Buffer of case Buffer of
@ -103,10 +113,10 @@ init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer) ->
%% @todo Add an argument for the request body. %% @todo Add an argument for the request body.
-spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts(), module(), -spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts(), module(),
binary(), binary() | undefined, cowboy_req:req()) -> ok. {inet:ip_address(), inet:port_number()}, binary(), binary() | undefined, cowboy_req:req()) -> ok.
init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer, _Settings, Req) -> init(Parent, Ref, Socket, Transport, Opts, Handler, Peer, Buffer, _Settings, Req) ->
State0 = #state{parent=Parent, ref=Ref, socket=Socket, State0 = #state{parent=Parent, ref=Ref, socket=Socket,
transport=Transport, opts=Opts, handler=Handler, transport=Transport, opts=Opts, handler=Handler, peer=Peer,
parse_state={preface, sequence, preface_timeout(Opts)}}, parse_state={preface, sequence, preface_timeout(Opts)}},
preface(State0), preface(State0),
%% @todo Apply settings. %% @todo Apply settings.
@ -490,7 +500,7 @@ terminate_all_streams([#stream{id=StreamID, state=StreamState}|Tail], Reason, Ha
%% Stream functions. %% Stream functions.
stream_init(State0=#state{ref=Ref, socket=Socket, transport=Transport, decode_state=DecodeState0}, stream_init(State0=#state{ref=Ref, socket=Socket, transport=Transport, peer=Peer, decode_state=DecodeState0},
StreamID, IsFin, HeaderBlock) -> StreamID, IsFin, HeaderBlock) ->
%% @todo Add clause for CONNECT requests (no scheme/path). %% @todo Add clause for CONNECT requests (no scheme/path).
try headers_decode(HeaderBlock, DecodeState0) of try headers_decode(HeaderBlock, DecodeState0) of
@ -513,19 +523,12 @@ stream_init(State0=#state{ref=Ref, socket=Socket, transport=Transport, decode_st
ref => Ref, ref => Ref,
pid => self(), pid => self(),
streamid => StreamID, streamid => StreamID,
peer => Peer,
%% @todo peer
%% @todo sockname
%% @todo ssl client cert?
method => Method, method => Method,
scheme => Scheme, scheme => Scheme,
host => Host, host => Host,
%% host_info (cowboy_router)
port => Port, port => Port,
path => Path, path => Path,
%% path_info (cowboy_router)
%% bindings (cowboy_router)
qs => Qs, qs => Qs,
version => 'HTTP/2', version => 'HTTP/2',
headers => Headers, headers => Headers,

View file

@ -194,9 +194,9 @@ method(#{method := Method}) ->
version(#{version := Version}) -> version(#{version := Version}) ->
Version. Version.
-spec peer(req()) -> {inet:ip_address(), inet:port_number()} | undefined. -spec peer(req()) -> {inet:ip_address(), inet:port_number()}.
peer(Req) -> peer(#{peer := Peer}) ->
Req#http_req.peer. Peer.
-spec host(req()) -> binary(). -spec host(req()) -> binary().
host(#{host := Host}) -> host(#{host := Host}) ->