aboutsummaryrefslogtreecommitdiffstats
path: root/src/gun.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/gun.erl')
-rw-r--r--src/gun.erl70
1 files changed, 58 insertions, 12 deletions
diff --git a/src/gun.erl b/src/gun.erl
index 16397c9..8267460 100644
--- a/src/gun.erl
+++ b/src/gun.erl
@@ -23,20 +23,28 @@
%% Requests.
-export([delete/2]).
-export([delete/3]).
+-export([delete/4]).
-export([get/2]).
-export([get/3]).
+-export([get/4]).
-export([head/2]).
-export([head/3]).
+-export([head/4]).
-export([options/2]).
-export([options/3]).
+-export([options/4]).
-export([patch/3]).
-export([patch/4]).
+-export([patch/5]).
-export([post/3]).
-export([post/4]).
+-export([post/5]).
-export([put/3]).
-export([put/4]).
+-export([put/5]).
-export([request/4]).
-export([request/5]).
+-export([request/6]).
%% Streaming data.
-export([data/4]).
@@ -84,6 +92,9 @@
-type opts() :: map().
-export_type([opts/0]).
+-type req_opts() :: map().
+-export_type([req_opts/0]).
+
-type http_opts() :: map().
-export_type([http_opts/0]).
@@ -226,6 +237,10 @@ delete(ServerPid, Path) ->
delete(ServerPid, Path, Headers) ->
request(ServerPid, <<"DELETE">>, Path, Headers).
+-spec delete(pid(), iodata(), headers(), req_opts()) -> reference().
+delete(ServerPid, Path, Headers, ReqOpts) ->
+ request(ServerPid, <<"DELETE">>, Path, Headers, <<>>, ReqOpts).
+
-spec get(pid(), iodata()) -> reference().
get(ServerPid, Path) ->
request(ServerPid, <<"GET">>, Path, []).
@@ -234,6 +249,10 @@ get(ServerPid, Path) ->
get(ServerPid, Path, Headers) ->
request(ServerPid, <<"GET">>, Path, Headers).
+-spec get(pid(), iodata(), headers(), req_opts()) -> reference().
+get(ServerPid, Path, Headers, ReqOpts) ->
+ request(ServerPid, <<"GET">>, Path, Headers, <<>>, ReqOpts).
+
-spec head(pid(), iodata()) -> reference().
head(ServerPid, Path) ->
request(ServerPid, <<"HEAD">>, Path, []).
@@ -242,6 +261,10 @@ head(ServerPid, Path) ->
head(ServerPid, Path, Headers) ->
request(ServerPid, <<"HEAD">>, Path, Headers).
+-spec head(pid(), iodata(), headers(), req_opts()) -> reference().
+head(ServerPid, Path, Headers, ReqOpts) ->
+ request(ServerPid, <<"HEAD">>, Path, Headers, <<>>, ReqOpts).
+
-spec options(pid(), iodata()) -> reference().
options(ServerPid, Path) ->
request(ServerPid, <<"OPTIONS">>, Path, []).
@@ -250,6 +273,10 @@ options(ServerPid, Path) ->
options(ServerPid, Path, Headers) ->
request(ServerPid, <<"OPTIONS">>, Path, Headers).
+-spec options(pid(), iodata(), headers(), req_opts()) -> reference().
+options(ServerPid, Path, Headers, ReqOpts) ->
+ request(ServerPid, <<"OPTIONS">>, Path, Headers, <<>>, ReqOpts).
+
-spec patch(pid(), iodata(), headers()) -> reference().
patch(ServerPid, Path, Headers) ->
request(ServerPid, <<"PATCH">>, Path, Headers).
@@ -258,6 +285,10 @@ patch(ServerPid, Path, Headers) ->
patch(ServerPid, Path, Headers, Body) ->
request(ServerPid, <<"PATCH">>, Path, Headers, Body).
+-spec patch(pid(), iodata(), headers(), iodata(), req_opts()) -> reference().
+patch(ServerPid, Path, Headers, Body, ReqOpts) ->
+ request(ServerPid, <<"PATCH">>, Path, Headers, Body, ReqOpts).
+
-spec post(pid(), iodata(), headers()) -> reference().
post(ServerPid, Path, Headers) ->
request(ServerPid, <<"POST">>, Path, Headers).
@@ -266,6 +297,10 @@ post(ServerPid, Path, Headers) ->
post(ServerPid, Path, Headers, Body) ->
request(ServerPid, <<"POST">>, Path, Headers, Body).
+-spec post(pid(), iodata(), headers(), iodata(), req_opts()) -> reference().
+post(ServerPid, Path, Headers, Body, ReqOpts) ->
+ request(ServerPid, <<"POST">>, Path, Headers, Body, ReqOpts).
+
-spec put(pid(), iodata(), headers()) -> reference().
put(ServerPid, Path, Headers) ->
request(ServerPid, <<"PUT">>, Path, Headers).
@@ -274,16 +309,23 @@ put(ServerPid, Path, Headers) ->
put(ServerPid, Path, Headers, Body) ->
request(ServerPid, <<"PUT">>, Path, Headers, Body).
+-spec put(pid(), iodata(), headers(), iodata(), req_opts()) -> reference().
+put(ServerPid, Path, Headers, Body, ReqOpts) ->
+ request(ServerPid, <<"PUT">>, Path, Headers, Body, ReqOpts).
+
-spec request(pid(), iodata(), iodata(), headers()) -> reference().
request(ServerPid, Method, Path, Headers) ->
- StreamRef = make_ref(),
- _ = ServerPid ! {request, self(), StreamRef, Method, Path, Headers},
- StreamRef.
+ request(ServerPid, Method, Path, Headers, <<>>, #{}).
-spec request(pid(), iodata(), iodata(), headers(), iodata()) -> reference().
request(ServerPid, Method, Path, Headers, Body) ->
+ request(ServerPid, Method, Path, Headers, Body, #{}).
+
+-spec request(pid(), iodata(), iodata(), headers(), iodata(), req_opts()) -> reference().
+request(ServerPid, Method, Path, Headers, Body, ReqOpts) ->
StreamRef = make_ref(),
- _ = ServerPid ! {request, self(), StreamRef, Method, Path, Headers, Body},
+ ReplyTo = maps:get(reply_to, ReqOpts, self()),
+ _ = ServerPid ! {request, ReplyTo, StreamRef, Method, Path, Headers, Body},
StreamRef.
%% Streaming data.
@@ -611,20 +653,22 @@ loop(State=#state{parent=Parent, owner=Owner, owner_ref=OwnerRef, host=Host, por
keepalive ->
ProtoState2 = Protocol:keepalive(ProtoState),
before_loop(State#state{protocol_state=ProtoState2});
- {request, Owner, StreamRef, Method, Path, Headers} ->
+ {request, ReplyTo, StreamRef, Method, Path, Headers, <<>>} ->
ProtoState2 = Protocol:request(ProtoState,
- StreamRef, Method, Host, Port, Path, Headers),
+ StreamRef, ReplyTo, Method, Host, Port, Path, Headers),
loop(State#state{protocol_state=ProtoState2});
- {request, Owner, StreamRef, Method, Path, Headers, Body} ->
+ {request, ReplyTo, StreamRef, Method, Path, Headers, Body} ->
ProtoState2 = Protocol:request(ProtoState,
- StreamRef, Method, Host, Port, Path, Headers, Body),
+ StreamRef, ReplyTo, Method, Host, Port, Path, Headers, Body),
loop(State#state{protocol_state=ProtoState2});
- {data, Owner, StreamRef, IsFin, Data} ->
+ %% @todo Do we want to reject ReplyTo if it's not the process
+ %% who initiated the connection? For both data and cancel.
+ {data, ReplyTo, StreamRef, IsFin, Data} ->
ProtoState2 = Protocol:data(ProtoState,
- StreamRef, IsFin, Data),
+ StreamRef, ReplyTo, IsFin, Data),
loop(State#state{protocol_state=ProtoState2});
- {cancel, Owner, StreamRef} ->
- ProtoState2 = Protocol:cancel(ProtoState, StreamRef),
+ {cancel, ReplyTo, StreamRef} ->
+ ProtoState2 = Protocol:cancel(ProtoState, StreamRef, ReplyTo),
loop(State#state{protocol_state=ProtoState2});
%% @todo Maybe make an interface in the protocol module instead of checking on protocol name.
%% An interface would also make sure that HTTP/1.0 can't upgrade.
@@ -662,6 +706,8 @@ loop(State=#state{parent=Parent, owner=Owner, owner_ref=OwnerRef, host=Host, por
"Connection needs to be upgraded to Websocket "
"before the gun:ws_send/1 function can be used."}},
loop(State);
+ %% @todo The ReplyTo patch disabled the notowner behavior.
+ %% We need to add an option to enforce this behavior if needed.
Any when is_tuple(Any), is_pid(element(2, Any)) ->
element(2, Any) ! {gun_error, self(), {notowner,
"Operations are restricted to the owner of the connection."}},