2017-01-02 19:36:36 +01:00
|
|
|
%% Copyright (c) 2016-2017, Loïc Hoguin <essen@ninenines.eu>
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
%%
|
|
|
|
%% 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.
|
|
|
|
|
|
|
|
-module(cowboy_stream_h).
|
2017-01-16 14:22:43 +01:00
|
|
|
-behavior(cowboy_stream).
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
|
|
|
|
-export([init/3]).
|
|
|
|
-export([data/4]).
|
|
|
|
-export([info/3]).
|
|
|
|
-export([terminate/3]).
|
2017-03-27 10:26:13 +02:00
|
|
|
-export([early_error/5]).
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
|
2017-09-14 15:34:37 +02:00
|
|
|
-export([request_process/3]).
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
-export([resume/5]).
|
|
|
|
|
|
|
|
-record(state, {
|
2018-06-27 18:07:58 +02:00
|
|
|
next :: any(),
|
2016-06-06 17:20:30 +02:00
|
|
|
ref = undefined :: ranch:ref(),
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
pid = undefined :: pid(),
|
2017-10-30 16:21:25 +00:00
|
|
|
expect = undefined :: undefined | continue,
|
2019-10-02 19:12:05 +02:00
|
|
|
read_body_pid = undefined :: pid() | undefined,
|
2017-01-02 16:47:16 +01:00
|
|
|
read_body_ref = undefined :: reference() | undefined,
|
|
|
|
read_body_timer_ref = undefined :: reference() | undefined,
|
2018-04-04 17:23:37 +02:00
|
|
|
read_body_length = 0 :: non_neg_integer() | infinity | auto,
|
2017-01-02 16:47:16 +01:00
|
|
|
read_body_is_fin = nofin :: nofin | {fin, non_neg_integer()},
|
2017-09-25 12:34:44 +02:00
|
|
|
read_body_buffer = <<>> :: binary(),
|
2019-09-13 14:20:04 +02:00
|
|
|
body_length = 0 :: non_neg_integer(),
|
2019-10-02 20:30:32 +02:00
|
|
|
stream_body_pid = undefined :: pid() | undefined,
|
2019-09-13 14:20:04 +02:00
|
|
|
stream_body_status = normal :: normal | blocking | blocked
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
}).
|
|
|
|
|
2017-01-16 14:22:43 +01:00
|
|
|
-spec init(cowboy_stream:streamid(), cowboy_req:req(), cowboy:opts())
|
|
|
|
-> {[{spawn, pid(), timeout()}], #state{}}.
|
2018-06-27 18:07:58 +02:00
|
|
|
init(StreamID, Req=#{ref := Ref}, Opts) ->
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
Env = maps:get(env, Opts, #{}),
|
|
|
|
Middlewares = maps:get(middlewares, Opts, [cowboy_router, cowboy_handler]),
|
2017-05-05 13:48:25 +02:00
|
|
|
Shutdown = maps:get(shutdown_timeout, Opts, 5000),
|
2017-09-14 15:34:37 +02:00
|
|
|
Pid = proc_lib:spawn_link(?MODULE, request_process, [Req, Env, Middlewares]),
|
2017-10-30 16:21:25 +00:00
|
|
|
Expect = expect(Req),
|
2018-06-27 18:07:58 +02:00
|
|
|
{Commands, Next} = cowboy_stream:init(StreamID, Req, Opts),
|
|
|
|
{[{spawn, Pid, Shutdown}|Commands],
|
|
|
|
#state{next=Next, ref=Ref, pid=Pid, expect=Expect}}.
|
2017-10-30 16:21:25 +00:00
|
|
|
|
|
|
|
%% Ignore the expect header in HTTP/1.0.
|
|
|
|
expect(#{version := 'HTTP/1.0'}) ->
|
|
|
|
undefined;
|
|
|
|
expect(Req) ->
|
|
|
|
try cowboy_req:parse_header(<<"expect">>, Req) of
|
|
|
|
Expect ->
|
|
|
|
Expect
|
|
|
|
catch _:_ ->
|
|
|
|
undefined
|
|
|
|
end.
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
|
|
|
|
%% If we receive data and stream is waiting for data:
|
2018-04-04 17:23:37 +02:00
|
|
|
%% If we accumulated enough data or IsFin=fin, send it.
|
|
|
|
%% If we are in auto mode, send it and update flow control.
|
|
|
|
%% If not, buffer it.
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
%% If not, buffer it.
|
2017-10-30 16:21:25 +00:00
|
|
|
%%
|
|
|
|
%% We always reset the expect field when we receive data,
|
|
|
|
%% since the client started sending the request body before
|
|
|
|
%% we could send a 100 continue response.
|
2017-09-25 12:34:44 +02:00
|
|
|
|
2017-01-16 14:22:43 +01:00
|
|
|
-spec data(cowboy_stream:streamid(), cowboy_stream:fin(), cowboy_req:resp_body(), State)
|
|
|
|
-> {cowboy_stream:commands(), State} when State::#state{}.
|
2018-04-04 17:23:37 +02:00
|
|
|
%% Stream isn't waiting for data.
|
2018-06-27 18:07:58 +02:00
|
|
|
data(StreamID, IsFin, Data, State=#state{
|
2017-09-25 12:34:44 +02:00
|
|
|
read_body_ref=undefined, read_body_buffer=Buffer, body_length=BodyLen}) ->
|
2018-06-27 18:07:58 +02:00
|
|
|
do_data(StreamID, IsFin, Data, [], State#state{
|
2017-10-30 16:21:25 +00:00
|
|
|
expect=undefined,
|
2017-09-25 12:34:44 +02:00
|
|
|
read_body_is_fin=IsFin,
|
|
|
|
read_body_buffer= << Buffer/binary, Data/binary >>,
|
2018-06-27 18:07:58 +02:00
|
|
|
body_length=BodyLen + byte_size(Data)
|
|
|
|
});
|
2018-04-04 17:23:37 +02:00
|
|
|
%% Stream is waiting for data using auto mode.
|
|
|
|
%%
|
|
|
|
%% There is no buffering done in auto mode.
|
2019-10-02 19:12:05 +02:00
|
|
|
data(StreamID, IsFin, Data, State=#state{read_body_pid=Pid, read_body_ref=Ref,
|
2018-04-04 17:23:37 +02:00
|
|
|
read_body_length=auto, body_length=BodyLen}) ->
|
|
|
|
send_request_body(Pid, Ref, IsFin, BodyLen, Data),
|
2018-06-27 18:07:58 +02:00
|
|
|
do_data(StreamID, IsFin, Data, [{flow, byte_size(Data)}], State#state{
|
2018-04-04 17:23:37 +02:00
|
|
|
read_body_ref=undefined,
|
2019-12-04 11:17:34 +01:00
|
|
|
%% @todo This is wrong, it's missing byte_size(Data).
|
2018-06-27 18:07:58 +02:00
|
|
|
body_length=BodyLen
|
|
|
|
});
|
2018-04-04 17:23:37 +02:00
|
|
|
%% Stream is waiting for data but we didn't receive enough to send yet.
|
2018-06-27 18:07:58 +02:00
|
|
|
data(StreamID, IsFin=nofin, Data, State=#state{
|
2017-09-25 12:34:44 +02:00
|
|
|
read_body_length=ReadLen, read_body_buffer=Buffer, body_length=BodyLen})
|
|
|
|
when byte_size(Data) + byte_size(Buffer) < ReadLen ->
|
2018-06-27 18:07:58 +02:00
|
|
|
do_data(StreamID, IsFin, Data, [], State#state{
|
2017-10-30 16:21:25 +00:00
|
|
|
expect=undefined,
|
2017-09-25 12:34:44 +02:00
|
|
|
read_body_buffer= << Buffer/binary, Data/binary >>,
|
2018-06-27 18:07:58 +02:00
|
|
|
body_length=BodyLen + byte_size(Data)
|
|
|
|
});
|
2018-04-04 17:23:37 +02:00
|
|
|
%% Stream is waiting for data and we received enough to send.
|
2019-10-02 19:12:05 +02:00
|
|
|
data(StreamID, IsFin, Data, State=#state{read_body_pid=Pid, read_body_ref=Ref,
|
2017-09-25 12:34:44 +02:00
|
|
|
read_body_timer_ref=TRef, read_body_buffer=Buffer, body_length=BodyLen0}) ->
|
|
|
|
BodyLen = BodyLen0 + byte_size(Data),
|
2016-08-10 11:49:31 +02:00
|
|
|
ok = erlang:cancel_timer(TRef, [{async, true}, {info, false}]),
|
2017-09-25 12:34:44 +02:00
|
|
|
send_request_body(Pid, Ref, IsFin, BodyLen, <<Buffer/binary, Data/binary>>),
|
2018-06-27 18:07:58 +02:00
|
|
|
do_data(StreamID, IsFin, Data, [], State#state{
|
2017-10-30 16:21:25 +00:00
|
|
|
expect=undefined,
|
2017-09-25 12:34:44 +02:00
|
|
|
read_body_ref=undefined,
|
|
|
|
read_body_timer_ref=undefined,
|
|
|
|
read_body_buffer= <<>>,
|
2018-06-27 18:07:58 +02:00
|
|
|
body_length=BodyLen
|
|
|
|
}).
|
|
|
|
|
|
|
|
do_data(StreamID, IsFin, Data, Commands1, State=#state{next=Next0}) ->
|
|
|
|
{Commands2, Next} = cowboy_stream:data(StreamID, IsFin, Data, Next0),
|
|
|
|
{Commands1 ++ Commands2, State#state{next=Next}}.
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
|
2017-01-16 14:22:43 +01:00
|
|
|
-spec info(cowboy_stream:streamid(), any(), State)
|
|
|
|
-> {cowboy_stream:commands(), State} when State::#state{}.
|
2018-06-27 18:07:58 +02:00
|
|
|
info(StreamID, Info={'EXIT', Pid, normal}, State=#state{pid=Pid}) ->
|
|
|
|
do_info(StreamID, Info, [stop], State);
|
|
|
|
info(StreamID, Info={'EXIT', Pid, {{request_error, Reason, _HumanReadable}, _}},
|
|
|
|
State=#state{pid=Pid}) ->
|
2017-09-14 13:42:17 +02:00
|
|
|
Status = case Reason of
|
|
|
|
timeout -> 408;
|
|
|
|
payload_too_large -> 413;
|
|
|
|
_ -> 400
|
|
|
|
end,
|
2018-06-28 17:10:18 +02:00
|
|
|
%% @todo Headers? Details in body? Log the crash? More stuff in debug only?
|
2018-06-27 18:07:58 +02:00
|
|
|
do_info(StreamID, Info, [
|
|
|
|
{error_response, Status, #{<<"content-length">> => <<"0">>}, <<>>},
|
|
|
|
stop
|
|
|
|
], State);
|
|
|
|
info(StreamID, Exit={'EXIT', Pid, {Reason, Stacktrace}}, State=#state{ref=Ref, pid=Pid}) ->
|
2018-06-28 17:10:18 +02:00
|
|
|
Commands0 = [{internal_error, Exit, 'Stream process crashed.'}],
|
|
|
|
Commands = case Reason of
|
|
|
|
normal -> Commands0;
|
|
|
|
shutdown -> Commands0;
|
|
|
|
{shutdown, _} -> Commands0;
|
|
|
|
_ -> [{log, error,
|
|
|
|
"Ranch listener ~p, connection process ~p, stream ~p "
|
|
|
|
"had its request process ~p exit with reason "
|
|
|
|
"~999999p and stacktrace ~999999p~n",
|
|
|
|
[Ref, self(), StreamID, Pid, Reason, Stacktrace]}
|
|
|
|
|Commands0]
|
|
|
|
end,
|
2018-06-27 18:07:58 +02:00
|
|
|
do_info(StreamID, Exit, [
|
2018-06-28 17:10:18 +02:00
|
|
|
{error_response, 500, #{<<"content-length">> => <<"0">>}, <<>>}
|
|
|
|
|Commands], State);
|
2018-04-04 17:23:37 +02:00
|
|
|
%% Request body, auto mode, no body buffered.
|
2019-10-02 19:12:05 +02:00
|
|
|
info(StreamID, Info={read_body, Pid, Ref, auto, infinity}, State=#state{read_body_buffer= <<>>}) ->
|
2018-06-27 18:07:58 +02:00
|
|
|
do_info(StreamID, Info, [], State#state{
|
2019-10-02 19:12:05 +02:00
|
|
|
read_body_pid=Pid,
|
2018-04-04 17:23:37 +02:00
|
|
|
read_body_ref=Ref,
|
2018-06-27 18:07:58 +02:00
|
|
|
read_body_length=auto
|
|
|
|
});
|
2018-04-04 17:23:37 +02:00
|
|
|
%% Request body, auto mode, body buffered or complete.
|
2019-10-02 19:12:05 +02:00
|
|
|
info(StreamID, Info={read_body, Pid, Ref, auto, infinity}, State=#state{
|
2018-04-04 17:23:37 +02:00
|
|
|
read_body_is_fin=IsFin, read_body_buffer=Buffer, body_length=BodyLen}) ->
|
|
|
|
send_request_body(Pid, Ref, IsFin, BodyLen, Buffer),
|
2018-06-27 18:07:58 +02:00
|
|
|
do_info(StreamID, Info, [{flow, byte_size(Buffer)}],
|
|
|
|
State#state{read_body_buffer= <<>>});
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
%% Request body, body buffered large enough or complete.
|
2017-10-30 16:21:25 +00:00
|
|
|
%%
|
|
|
|
%% We do not send a 100 continue response if the client
|
|
|
|
%% already started sending the body.
|
2019-10-02 19:12:05 +02:00
|
|
|
info(StreamID, Info={read_body, Pid, Ref, Length, _}, State=#state{
|
2017-09-25 12:34:44 +02:00
|
|
|
read_body_is_fin=IsFin, read_body_buffer=Buffer, body_length=BodyLen})
|
|
|
|
when IsFin =:= fin; byte_size(Buffer) >= Length ->
|
|
|
|
send_request_body(Pid, Ref, IsFin, BodyLen, Buffer),
|
2018-06-27 18:07:58 +02:00
|
|
|
do_info(StreamID, Info, [], State#state{read_body_buffer= <<>>});
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
%% Request body, not enough to send yet.
|
2019-10-02 19:12:05 +02:00
|
|
|
info(StreamID, Info={read_body, Pid, Ref, Length, Period}, State=#state{expect=Expect}) ->
|
2017-10-30 16:21:25 +00:00
|
|
|
Commands = case Expect of
|
|
|
|
continue -> [{inform, 100, #{}}, {flow, Length}];
|
|
|
|
undefined -> [{flow, Length}]
|
|
|
|
end,
|
2016-08-10 11:49:31 +02:00
|
|
|
TRef = erlang:send_after(Period, self(), {{self(), StreamID}, {read_body_timeout, Ref}}),
|
2018-06-27 18:07:58 +02:00
|
|
|
do_info(StreamID, Info, Commands, State#state{
|
2019-10-02 19:12:05 +02:00
|
|
|
read_body_pid=Pid,
|
2017-10-30 16:21:25 +00:00
|
|
|
read_body_ref=Ref,
|
|
|
|
read_body_timer_ref=TRef,
|
2018-06-27 18:07:58 +02:00
|
|
|
read_body_length=Length
|
|
|
|
});
|
2016-08-10 11:49:31 +02:00
|
|
|
%% Request body reading timeout; send what we got.
|
2019-10-02 19:12:05 +02:00
|
|
|
info(StreamID, Info={read_body_timeout, Ref}, State=#state{read_body_pid=Pid, read_body_ref=Ref,
|
2017-09-25 12:34:44 +02:00
|
|
|
read_body_is_fin=IsFin, read_body_buffer=Buffer, body_length=BodyLen}) ->
|
|
|
|
send_request_body(Pid, Ref, IsFin, BodyLen, Buffer),
|
2018-06-27 18:07:58 +02:00
|
|
|
do_info(StreamID, Info, [], State#state{
|
|
|
|
read_body_ref=undefined,
|
|
|
|
read_body_timer_ref=undefined,
|
|
|
|
read_body_buffer= <<>>
|
|
|
|
});
|
|
|
|
info(StreamID, Info={read_body_timeout, _}, State) ->
|
|
|
|
do_info(StreamID, Info, [], State);
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
%% Response.
|
2017-10-30 16:21:25 +00:00
|
|
|
%%
|
|
|
|
%% We reset the expect field when a 100 continue response
|
|
|
|
%% is sent or when any final response is sent.
|
2018-06-27 18:07:58 +02:00
|
|
|
info(StreamID, Inform={inform, Status, _}, State0) ->
|
2018-05-18 18:03:56 +02:00
|
|
|
State = case cow_http:status_to_integer(Status) of
|
2017-10-30 16:21:25 +00:00
|
|
|
100 -> State0#state{expect=undefined};
|
|
|
|
_ -> State0
|
|
|
|
end,
|
2018-06-27 18:07:58 +02:00
|
|
|
do_info(StreamID, Inform, [Inform], State);
|
|
|
|
info(StreamID, Response={response, _, _, _}, State) ->
|
|
|
|
do_info(StreamID, Response, [Response], State#state{expect=undefined});
|
|
|
|
info(StreamID, Headers={headers, _, _}, State) ->
|
|
|
|
do_info(StreamID, Headers, [Headers], State#state{expect=undefined});
|
Fix HTTP/2 CVEs
A number of HTTP/2 CVEs were documented recently:
https://www.kb.cert.org/vuls/id/605641/
This commit, along with a few changes and additions in Cowlib,
fix or improve protection against all of them.
For CVE-2019-9511, also known as Data Dribble, the new option
stream_window_data_threshold can be used to control how little
the DATA frames that Cowboy sends can get.
For CVE-2019-9516, also known as 0-Length Headers Leak, Cowboy
will now simply reject streams containing 0-length header names.
For CVE-2019-9517, also known as Internal Data Buffering, the
backpressure changes were already pretty good at preventing this
issue, but a new option max_connection_buffer_size was added for
even better control over how much memory we are willing to allocate.
For CVE-2019-9512, also known as Ping Flood; CVE-2019-9515, also
known as Settings Flood; CVE-2019-9518, also known as Empty Frame
Flooding; and similar undocumented scenarios, a frame rate limiting
mechanism was added. By default Cowboy will now allow 1000 frames
every 10 seconds. This can be configured via max_received_frame_rate.
For CVE-2019-9514, also known as Reset Flood, another rate limiting
mechanism was added and can be configured via max_reset_stream_rate.
By default Cowboy will do up to 10 stream resets every 10 seconds.
Finally, nothing was done for CVE-2019-9513, also known as Resource
Loop, because Cowboy does not currently implement the HTTP/2
priority mechanism (in parts because these issues were well known
from the start).
Tests were added for all cases except Internal Data Buffering,
which I'm not sure how to test, and Resource Loop, which is not
currently relevant.
2019-10-02 10:44:45 +02:00
|
|
|
%% Sending data involves the data message, the stream_buffer_full alarm
|
|
|
|
%% and the connection_buffer_full alarm. We stop sending acks when an alarm is on.
|
2019-10-02 20:30:32 +02:00
|
|
|
%%
|
|
|
|
%% We only apply backpressure when the message includes a pid. Otherwise
|
|
|
|
%% it is a message from Cowboy, or the user circumventing the backpressure.
|
|
|
|
%%
|
|
|
|
%% We currently do not support sending data from multiple processes concurrently.
|
|
|
|
info(StreamID, Data={data, _, _}, State) ->
|
|
|
|
do_info(StreamID, Data, [Data], State);
|
|
|
|
info(StreamID, Data0={data, Pid, _, _}, State0=#state{stream_body_status=Status}) ->
|
2019-09-13 14:20:04 +02:00
|
|
|
State = case Status of
|
|
|
|
normal ->
|
|
|
|
Pid ! {data_ack, self()},
|
|
|
|
State0;
|
|
|
|
blocking ->
|
2019-10-02 20:30:32 +02:00
|
|
|
State0#state{stream_body_pid=Pid, stream_body_status=blocked};
|
2019-09-13 14:20:04 +02:00
|
|
|
blocked ->
|
|
|
|
State0
|
|
|
|
end,
|
2019-10-02 20:30:32 +02:00
|
|
|
Data = erlang:delete_element(2, Data0),
|
2018-06-27 18:07:58 +02:00
|
|
|
do_info(StreamID, Data, [Data], State);
|
Fix HTTP/2 CVEs
A number of HTTP/2 CVEs were documented recently:
https://www.kb.cert.org/vuls/id/605641/
This commit, along with a few changes and additions in Cowlib,
fix or improve protection against all of them.
For CVE-2019-9511, also known as Data Dribble, the new option
stream_window_data_threshold can be used to control how little
the DATA frames that Cowboy sends can get.
For CVE-2019-9516, also known as 0-Length Headers Leak, Cowboy
will now simply reject streams containing 0-length header names.
For CVE-2019-9517, also known as Internal Data Buffering, the
backpressure changes were already pretty good at preventing this
issue, but a new option max_connection_buffer_size was added for
even better control over how much memory we are willing to allocate.
For CVE-2019-9512, also known as Ping Flood; CVE-2019-9515, also
known as Settings Flood; CVE-2019-9518, also known as Empty Frame
Flooding; and similar undocumented scenarios, a frame rate limiting
mechanism was added. By default Cowboy will now allow 1000 frames
every 10 seconds. This can be configured via max_received_frame_rate.
For CVE-2019-9514, also known as Reset Flood, another rate limiting
mechanism was added and can be configured via max_reset_stream_rate.
By default Cowboy will do up to 10 stream resets every 10 seconds.
Finally, nothing was done for CVE-2019-9513, also known as Resource
Loop, because Cowboy does not currently implement the HTTP/2
priority mechanism (in parts because these issues were well known
from the start).
Tests were added for all cases except Internal Data Buffering,
which I'm not sure how to test, and Resource Loop, which is not
currently relevant.
2019-10-02 10:44:45 +02:00
|
|
|
info(StreamID, Alarm={alarm, Name, on}, State)
|
|
|
|
when Name =:= connection_buffer_full; Name =:= stream_buffer_full ->
|
2019-09-13 14:20:04 +02:00
|
|
|
do_info(StreamID, Alarm, [], State#state{stream_body_status=blocking});
|
2019-10-02 20:30:32 +02:00
|
|
|
info(StreamID, Alarm={alarm, Name, off}, State=#state{stream_body_pid=Pid, stream_body_status=Status})
|
Fix HTTP/2 CVEs
A number of HTTP/2 CVEs were documented recently:
https://www.kb.cert.org/vuls/id/605641/
This commit, along with a few changes and additions in Cowlib,
fix or improve protection against all of them.
For CVE-2019-9511, also known as Data Dribble, the new option
stream_window_data_threshold can be used to control how little
the DATA frames that Cowboy sends can get.
For CVE-2019-9516, also known as 0-Length Headers Leak, Cowboy
will now simply reject streams containing 0-length header names.
For CVE-2019-9517, also known as Internal Data Buffering, the
backpressure changes were already pretty good at preventing this
issue, but a new option max_connection_buffer_size was added for
even better control over how much memory we are willing to allocate.
For CVE-2019-9512, also known as Ping Flood; CVE-2019-9515, also
known as Settings Flood; CVE-2019-9518, also known as Empty Frame
Flooding; and similar undocumented scenarios, a frame rate limiting
mechanism was added. By default Cowboy will now allow 1000 frames
every 10 seconds. This can be configured via max_received_frame_rate.
For CVE-2019-9514, also known as Reset Flood, another rate limiting
mechanism was added and can be configured via max_reset_stream_rate.
By default Cowboy will do up to 10 stream resets every 10 seconds.
Finally, nothing was done for CVE-2019-9513, also known as Resource
Loop, because Cowboy does not currently implement the HTTP/2
priority mechanism (in parts because these issues were well known
from the start).
Tests were added for all cases except Internal Data Buffering,
which I'm not sure how to test, and Resource Loop, which is not
currently relevant.
2019-10-02 10:44:45 +02:00
|
|
|
when Name =:= connection_buffer_full; Name =:= stream_buffer_full ->
|
2019-09-13 14:20:04 +02:00
|
|
|
_ = case Status of
|
Fix HTTP/2 CVEs
A number of HTTP/2 CVEs were documented recently:
https://www.kb.cert.org/vuls/id/605641/
This commit, along with a few changes and additions in Cowlib,
fix or improve protection against all of them.
For CVE-2019-9511, also known as Data Dribble, the new option
stream_window_data_threshold can be used to control how little
the DATA frames that Cowboy sends can get.
For CVE-2019-9516, also known as 0-Length Headers Leak, Cowboy
will now simply reject streams containing 0-length header names.
For CVE-2019-9517, also known as Internal Data Buffering, the
backpressure changes were already pretty good at preventing this
issue, but a new option max_connection_buffer_size was added for
even better control over how much memory we are willing to allocate.
For CVE-2019-9512, also known as Ping Flood; CVE-2019-9515, also
known as Settings Flood; CVE-2019-9518, also known as Empty Frame
Flooding; and similar undocumented scenarios, a frame rate limiting
mechanism was added. By default Cowboy will now allow 1000 frames
every 10 seconds. This can be configured via max_received_frame_rate.
For CVE-2019-9514, also known as Reset Flood, another rate limiting
mechanism was added and can be configured via max_reset_stream_rate.
By default Cowboy will do up to 10 stream resets every 10 seconds.
Finally, nothing was done for CVE-2019-9513, also known as Resource
Loop, because Cowboy does not currently implement the HTTP/2
priority mechanism (in parts because these issues were well known
from the start).
Tests were added for all cases except Internal Data Buffering,
which I'm not sure how to test, and Resource Loop, which is not
currently relevant.
2019-10-02 10:44:45 +02:00
|
|
|
normal -> ok;
|
2019-09-13 14:20:04 +02:00
|
|
|
blocking -> ok;
|
|
|
|
blocked -> Pid ! {data_ack, self()}
|
|
|
|
end,
|
2019-10-02 20:30:32 +02:00
|
|
|
do_info(StreamID, Alarm, [], State#state{stream_body_pid=undefined, stream_body_status=normal});
|
2018-06-27 18:07:58 +02:00
|
|
|
info(StreamID, Trailers={trailers, _}, State) ->
|
|
|
|
do_info(StreamID, Trailers, [Trailers], State);
|
|
|
|
info(StreamID, Push={push, _, _, _, _, _, _, _}, State) ->
|
|
|
|
do_info(StreamID, Push, [Push], State);
|
|
|
|
info(StreamID, SwitchProtocol={switch_protocol, _, _, _}, State) ->
|
|
|
|
do_info(StreamID, SwitchProtocol, [SwitchProtocol], State#state{expect=undefined});
|
2018-11-15 18:53:42 +01:00
|
|
|
%% Convert the set_options message to a command.
|
|
|
|
info(StreamID, SetOptions={set_options, _}, State) ->
|
|
|
|
do_info(StreamID, SetOptions, [SetOptions], State);
|
2018-06-27 18:07:58 +02:00
|
|
|
%% Unknown message, either stray or meant for a handler down the line.
|
|
|
|
info(StreamID, Info, State) ->
|
|
|
|
do_info(StreamID, Info, [], State).
|
|
|
|
|
|
|
|
do_info(StreamID, Info, Commands1, State0=#state{next=Next0}) ->
|
|
|
|
{Commands2, Next} = cowboy_stream:info(StreamID, Info, Next0),
|
|
|
|
{Commands1 ++ Commands2, State0#state{next=Next}}.
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
|
2017-01-16 14:22:43 +01:00
|
|
|
-spec terminate(cowboy_stream:streamid(), cowboy_stream:reason(), #state{}) -> ok.
|
2018-06-27 18:07:58 +02:00
|
|
|
terminate(StreamID, Reason, #state{next=Next}) ->
|
|
|
|
cowboy_stream:terminate(StreamID, Reason, Next).
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
|
2017-03-27 10:26:13 +02:00
|
|
|
-spec early_error(cowboy_stream:streamid(), cowboy_stream:reason(),
|
|
|
|
cowboy_stream:partial_req(), Resp, cowboy:opts()) -> Resp
|
|
|
|
when Resp::cowboy_stream:resp_command().
|
|
|
|
early_error(StreamID, Reason, PartialReq, Resp, Opts) ->
|
|
|
|
cowboy_stream:early_error(StreamID, Reason, PartialReq, Resp, Opts).
|
|
|
|
|
2017-09-25 12:34:44 +02:00
|
|
|
send_request_body(Pid, Ref, nofin, _, Data) ->
|
|
|
|
Pid ! {request_body, Ref, nofin, Data},
|
|
|
|
ok;
|
|
|
|
send_request_body(Pid, Ref, fin, BodyLen, Data) ->
|
|
|
|
Pid ! {request_body, Ref, fin, BodyLen, Data},
|
|
|
|
ok.
|
|
|
|
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
%% Request process.
|
|
|
|
|
2019-12-31 15:10:38 +01:00
|
|
|
%% We add the stacktrace to exit exceptions here in order
|
|
|
|
%% to simplify the debugging of errors. The proc_lib library
|
|
|
|
%% already adds the stacktrace to other types of exceptions.
|
2019-10-10 15:53:26 +02:00
|
|
|
-spec request_process(cowboy_req:req(), cowboy_middleware:env(), [module()]) -> ok.
|
2017-09-14 15:34:37 +02:00
|
|
|
request_process(Req, Env, Middlewares) ->
|
2016-06-06 17:20:30 +02:00
|
|
|
try
|
|
|
|
execute(Req, Env, Middlewares)
|
2017-09-14 15:34:37 +02:00
|
|
|
catch
|
2019-12-31 15:10:38 +01:00
|
|
|
exit:Reason:Stacktrace ->
|
|
|
|
erlang:raise(exit, {Reason, Stacktrace}, Stacktrace)
|
2016-06-06 17:20:30 +02:00
|
|
|
end.
|
|
|
|
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
execute(_, _, []) ->
|
2019-10-10 15:53:26 +02:00
|
|
|
ok;
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
execute(Req, Env, [Middleware|Tail]) ->
|
|
|
|
case Middleware:execute(Req, Env) of
|
|
|
|
{ok, Req2, Env2} ->
|
|
|
|
execute(Req2, Env2, Tail);
|
|
|
|
{suspend, Module, Function, Args} ->
|
|
|
|
proc_lib:hibernate(?MODULE, resume, [Env, Tail, Module, Function, Args]);
|
|
|
|
{stop, _Req2} ->
|
2019-10-10 15:53:26 +02:00
|
|
|
ok
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
end.
|
|
|
|
|
2019-10-10 15:53:26 +02:00
|
|
|
-spec resume(cowboy_middleware:env(), [module()], module(), atom(), [any()]) -> ok.
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
resume(Env, Tail, Module, Function, Args) ->
|
|
|
|
case apply(Module, Function, Args) of
|
|
|
|
{ok, Req2, Env2} ->
|
|
|
|
execute(Req2, Env2, Tail);
|
|
|
|
{suspend, Module2, Function2, Args2} ->
|
|
|
|
proc_lib:hibernate(?MODULE, resume, [Env, Tail, Module2, Function2, Args2]);
|
|
|
|
{stop, _Req2} ->
|
2019-10-10 15:53:26 +02:00
|
|
|
ok
|
Initial commit with connection/streams
Breaking changes with previous commit. This is a very large change,
and I am giving up on making a single commit that fixes everything.
More commits will follow slowly adding back features, introducing
new tests and fixing the documentation.
This change contains most of the work toward unifying the interface
for handling both HTTP/1.1 and HTTP/2. HTTP/1.1 connections are now
no longer 1 process per connection; instead by default 1 process per
request is also created. This has a number of pros and cons.
Because it has cons, we also allow users to use a lower-level API
that acts on "streams" (requests/responses) directly at the connection
process-level. If performance is a concern, one can always write a
stream handler. The performance in this case will be even greater
than with Cowboy 1, although all the special handlers are unavailable.
When switching to Websocket, after the handler returns from init/2,
Cowboy stops the stream and the Websocket protocol takes over the
connection process. Websocket then calls websocket_init/2 for any
additional initialization such as timers, because the process is
different in init/2 and websocket_*/* functions. This however would
allow us to use websocket_init/2 for sending messages on connect,
instead of sending ourselves a message and be subject to races.
Note that websocket_init/2 is optional.
This is all a big change and while most of the tests pass, some
functionality currently doesn't. SPDY is broken and will be removed
soon in favor of HTTP/2. Automatic compression is currently disabled.
The cowboy_req interface probably still have a few functions that
need to be updated. The docs and examples do not refer the current
functionality anymore.
Everything will be fixed over time. Feedback is more than welcome.
Open a ticket!
2016-02-10 17:28:32 +01:00
|
|
|
end.
|