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_http).
|
|
|
|
|
2017-01-16 14:22:43 +01:00
|
|
|
-export([init/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
|
|
|
|
|
|
|
-export([system_continue/3]).
|
|
|
|
-export([system_terminate/4]).
|
|
|
|
-export([system_code_change/4]).
|
|
|
|
|
2017-05-05 13:48:25 +02:00
|
|
|
-type opts() :: #{
|
|
|
|
connection_type => worker | supervisor,
|
|
|
|
env => cowboy_middleware:env(),
|
|
|
|
idle_timeout => timeout(),
|
|
|
|
inactivity_timeout => timeout(),
|
|
|
|
max_empty_lines => non_neg_integer(),
|
|
|
|
max_header_name_length => non_neg_integer(),
|
|
|
|
max_header_value_length => non_neg_integer(),
|
|
|
|
max_headers => non_neg_integer(),
|
|
|
|
max_keepalive => non_neg_integer(),
|
|
|
|
max_method_length => non_neg_integer(),
|
|
|
|
max_request_line_length => non_neg_integer(),
|
|
|
|
middlewares => [module()],
|
|
|
|
request_timeout => timeout(),
|
|
|
|
shutdown_timeout => timeout(),
|
|
|
|
stream_handlers => [module()]
|
|
|
|
}.
|
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_type([opts/0]).
|
|
|
|
|
|
|
|
-record(ps_request_line, {
|
|
|
|
empty_lines = 0 :: non_neg_integer()
|
|
|
|
}).
|
|
|
|
|
|
|
|
-record(ps_header, {
|
|
|
|
method = undefined :: binary(),
|
|
|
|
path = undefined :: binary(),
|
|
|
|
qs = undefined :: binary(),
|
|
|
|
version = undefined :: cowboy:http_version(),
|
|
|
|
headers = undefined :: map() | undefined, %% @todo better type than map()
|
2017-01-02 16:47:16 +01:00
|
|
|
name = undefined :: binary() | undefined
|
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-25 13:52:58 +02:00
|
|
|
%% @todo We need a state where we wait for the stream process to ask for the body
|
|
|
|
%% and do not attempt to read from the socket while in that state (we should read
|
|
|
|
%% up to a certain length, and then wait, basically implementing flow control but
|
|
|
|
%% by not reading from the socket when the window is empty).
|
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
|
|
|
|
|
|
|
-record(ps_body, {
|
|
|
|
%% @todo flow
|
|
|
|
transfer_decode_fun :: fun(), %% @todo better type
|
|
|
|
transfer_decode_state :: any() %% @todo better type
|
|
|
|
}).
|
|
|
|
|
|
|
|
-record(stream, {
|
|
|
|
id = undefined :: cowboy_stream:streamid(),
|
2017-01-16 14:22:43 +01:00
|
|
|
%% Stream handlers and their state.
|
|
|
|
state = undefined :: {module(), any()},
|
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
|
|
|
%% Client HTTP version for this stream.
|
|
|
|
version = undefined :: cowboy:http_version(),
|
2017-11-15 14:58:49 +01:00
|
|
|
%% Unparsed te header. Used to know if we can send trailers.
|
|
|
|
te :: undefined | binary(),
|
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
|
|
|
%% Commands queued.
|
2017-01-16 14:22:43 +01:00
|
|
|
queue = [] :: cowboy_stream:commands()
|
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
|
|
|
}).
|
|
|
|
|
|
|
|
-type stream() :: #stream{}.
|
|
|
|
|
|
|
|
-record(state, {
|
|
|
|
parent :: pid(),
|
|
|
|
ref :: ranch:ref(),
|
|
|
|
socket :: inet:socket(),
|
|
|
|
transport :: module(),
|
|
|
|
opts = #{} :: map(),
|
|
|
|
|
2016-06-20 17:28:59 +02:00
|
|
|
%% Remote address and port for the connection.
|
|
|
|
peer = undefined :: {inet:ip_address(), inet:port_number()},
|
|
|
|
|
2017-10-25 20:17:21 +01:00
|
|
|
%% Local address and port for the connection.
|
|
|
|
sock = undefined :: {inet:ip_address(), inet:port_number()},
|
|
|
|
|
|
|
|
%% Client certificate (TLS only).
|
|
|
|
cert :: undefined | binary(),
|
|
|
|
|
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
|
|
|
timer = undefined :: undefined | reference(),
|
|
|
|
|
|
|
|
%% Identifier for the stream currently being read (or waiting to be received).
|
|
|
|
in_streamid = 1 :: pos_integer(),
|
|
|
|
|
|
|
|
%% Parsing state for the current stream or stream-to-be.
|
|
|
|
in_state = #ps_request_line{} :: #ps_request_line{} | #ps_header{} | #ps_body{},
|
|
|
|
|
|
|
|
%% Identifier for the stream currently being written.
|
|
|
|
%% Note that out_streamid =< in_streamid.
|
|
|
|
out_streamid = 1 :: pos_integer(),
|
|
|
|
|
|
|
|
%% Whether we finished writing data for the current stream.
|
2017-10-20 13:16:04 +01:00
|
|
|
out_state = wait :: wait | chunked | done,
|
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
|
|
|
|
|
|
|
%% The connection will be closed after this stream.
|
|
|
|
last_streamid = undefined :: pos_integer(),
|
|
|
|
|
2016-08-10 11:49:31 +02:00
|
|
|
%% Currently active HTTP/1.1 streams.
|
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
|
|
|
streams = [] :: [stream()],
|
|
|
|
|
2017-05-03 18:31:28 +02:00
|
|
|
%% Children processes created by streams.
|
2017-08-08 16:59:33 +02:00
|
|
|
children = cowboy_children:init() :: cowboy_children:children()
|
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
|
|
|
}).
|
|
|
|
|
|
|
|
-include_lib("cowlib/include/cow_inline.hrl").
|
|
|
|
-include_lib("cowlib/include/cow_parse.hrl").
|
|
|
|
|
2017-01-16 14:22:43 +01:00
|
|
|
-spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts()) -> ok.
|
|
|
|
init(Parent, Ref, Socket, Transport, Opts) ->
|
2017-10-25 20:17:21 +01:00
|
|
|
Peer0 = Transport:peername(Socket),
|
|
|
|
Sock0 = Transport:sockname(Socket),
|
|
|
|
Cert1 = case Transport:name() of
|
|
|
|
ssl ->
|
|
|
|
case ssl:peercert(Socket) of
|
|
|
|
{error, no_peercert} ->
|
|
|
|
{ok, undefined};
|
|
|
|
Cert0 ->
|
|
|
|
Cert0
|
|
|
|
end;
|
|
|
|
_ ->
|
|
|
|
{ok, undefined}
|
|
|
|
end,
|
|
|
|
case {Peer0, Sock0, Cert1} of
|
|
|
|
{{ok, Peer}, {ok, Sock}, {ok, Cert}} ->
|
2016-06-20 17:28:59 +02:00
|
|
|
LastStreamID = maps:get(max_keepalive, Opts, 100),
|
2017-05-03 17:44:00 +02:00
|
|
|
before_loop(set_timeout(#state{
|
2016-06-20 17:28:59 +02:00
|
|
|
parent=Parent, ref=Ref, socket=Socket,
|
2017-01-16 14:22:43 +01:00
|
|
|
transport=Transport, opts=Opts,
|
2017-10-25 20:17:21 +01:00
|
|
|
peer=Peer, sock=Sock, cert=Cert,
|
|
|
|
last_streamid=LastStreamID}), <<>>);
|
|
|
|
{{error, Reason}, _, _} ->
|
|
|
|
terminate(undefined, {socket_error, Reason,
|
|
|
|
'A socket error occurred when retrieving the peer name.'});
|
|
|
|
{_, {error, Reason}, _} ->
|
|
|
|
terminate(undefined, {socket_error, Reason,
|
|
|
|
'A socket error occurred when retrieving the sock name.'});
|
|
|
|
{_, _, {error, Reason}} ->
|
|
|
|
terminate(undefined, {socket_error, Reason,
|
|
|
|
'A socket error occurred when retrieving the client TLS certificate.'})
|
2016-06-20 17:28:59 +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
|
|
|
|
|
|
|
before_loop(State=#state{socket=Socket, transport=Transport}, Buffer) ->
|
|
|
|
%% @todo disable this when we get to the body, until the stream asks for it?
|
|
|
|
%% Perhaps have a threshold for how much we're willing to read before waiting.
|
|
|
|
Transport:setopts(Socket, [{active, once}]),
|
|
|
|
loop(State, Buffer).
|
|
|
|
|
2017-05-05 13:48:25 +02:00
|
|
|
loop(State=#state{parent=Parent, socket=Socket, transport=Transport, opts=Opts,
|
2017-05-03 17:44:00 +02:00
|
|
|
timer=TimerRef, children=Children, streams=Streams}, 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
|
|
|
{OK, Closed, Error} = Transport:messages(),
|
2017-05-05 13:48:25 +02:00
|
|
|
InactivityTimeout = maps:get(inactivity_timeout, Opts, 300000),
|
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
|
|
|
receive
|
|
|
|
%% Socket messages.
|
|
|
|
{OK, Socket, Data} ->
|
2017-05-03 17:44:00 +02:00
|
|
|
%% Only reset the timeout if it is idle_timeout (active streams).
|
|
|
|
State1 = case Streams of
|
|
|
|
[] -> State;
|
|
|
|
_ -> set_timeout(State)
|
|
|
|
end,
|
|
|
|
parse(<< Buffer/binary, Data/binary >>, State1);
|
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
|
|
|
{Closed, Socket} ->
|
|
|
|
terminate(State, {socket_error, closed, 'The socket has been closed.'});
|
|
|
|
{Error, Socket, Reason} ->
|
|
|
|
terminate(State, {socket_error, Reason, 'An error has occurred on the socket.'});
|
|
|
|
%% Timeouts.
|
2017-08-08 16:59:33 +02:00
|
|
|
{timeout, Ref, {shutdown, Pid}} ->
|
|
|
|
cowboy_children:shutdown_timeout(Children, Ref, Pid),
|
|
|
|
loop(State, 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
|
|
|
{timeout, TimerRef, Reason} ->
|
|
|
|
timeout(State, Reason);
|
|
|
|
{timeout, _, _} ->
|
|
|
|
loop(State, Buffer);
|
|
|
|
%% System messages.
|
|
|
|
{'EXIT', Parent, Reason} ->
|
|
|
|
exit(Reason);
|
|
|
|
{system, From, Request} ->
|
|
|
|
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {State, Buffer});
|
|
|
|
%% Messages pertaining to a stream.
|
|
|
|
{{Pid, StreamID}, Msg} when Pid =:= self() ->
|
|
|
|
loop(info(State, StreamID, Msg), Buffer);
|
|
|
|
%% Exit signal from children.
|
|
|
|
Msg = {'EXIT', Pid, _} ->
|
|
|
|
loop(down(State, Pid, Msg), Buffer);
|
|
|
|
%% Calls from supervisor module.
|
|
|
|
{'$gen_call', {From, Tag}, which_children} ->
|
2017-08-08 16:59:33 +02:00
|
|
|
From ! {Tag, cowboy_children:which_children(Children, ?MODULE)},
|
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
|
|
|
loop(State, Buffer);
|
|
|
|
{'$gen_call', {From, Tag}, count_children} ->
|
2017-08-08 16:59:33 +02:00
|
|
|
From ! {Tag, cowboy_children:count_children(Children)},
|
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
|
|
|
loop(State, Buffer);
|
|
|
|
{'$gen_call', {From, Tag}, _} ->
|
|
|
|
From ! {Tag, {error, ?MODULE}},
|
|
|
|
loop(State, Buffer);
|
|
|
|
%% Unknown messages.
|
|
|
|
Msg ->
|
2016-08-10 11:49:31 +02:00
|
|
|
error_logger:error_msg("Received stray message ~p.~n", [Msg]),
|
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
|
|
|
loop(State, Buffer)
|
2017-05-05 13:48:25 +02:00
|
|
|
after InactivityTimeout ->
|
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
|
|
|
terminate(State, {internal_error, timeout, 'No message or data received before timeout.'})
|
|
|
|
end.
|
|
|
|
|
2017-05-03 17:44:00 +02:00
|
|
|
%% We set request_timeout when there are no active streams,
|
|
|
|
%% and idle_timeout otherwise.
|
|
|
|
set_timeout(State0=#state{opts=Opts, streams=Streams}) ->
|
|
|
|
State = cancel_timeout(State0),
|
|
|
|
{Name, Default} = case Streams of
|
|
|
|
[] -> {request_timeout, 5000};
|
|
|
|
_ -> {idle_timeout, 60000}
|
|
|
|
end,
|
|
|
|
Timeout = maps:get(Name, Opts, Default),
|
|
|
|
TimerRef = erlang:start_timer(Timeout, self(), Name),
|
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
|
|
|
State#state{timer=TimerRef}.
|
|
|
|
|
2017-05-03 17:44:00 +02:00
|
|
|
cancel_timeout(State=#state{timer=TimerRef}) ->
|
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
|
|
|
ok = case TimerRef of
|
|
|
|
undefined -> ok;
|
|
|
|
_ -> erlang:cancel_timer(TimerRef, [{async, true}, {info, false}])
|
|
|
|
end,
|
|
|
|
State#state{timer=undefined}.
|
|
|
|
|
2017-01-02 18:27:03 +01:00
|
|
|
-spec timeout(_, _) -> no_return().
|
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
|
|
|
timeout(State=#state{in_state=#ps_request_line{}}, request_timeout) ->
|
2017-05-03 17:44:00 +02:00
|
|
|
terminate(State, {connection_error, timeout,
|
|
|
|
'No request-line received before timeout.'});
|
2017-03-27 10:26:13 +02:00
|
|
|
timeout(State=#state{in_state=#ps_header{}}, request_timeout) ->
|
2017-05-03 17:44:00 +02:00
|
|
|
error_terminate(408, State, {connection_error, timeout,
|
|
|
|
'Request headers not received before timeout.'});
|
|
|
|
timeout(State, idle_timeout) ->
|
|
|
|
terminate(State, {connection_error, timeout,
|
|
|
|
'Connection idle longer than configuration allows.'}).
|
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-line.
|
|
|
|
parse(<<>>, State) ->
|
|
|
|
before_loop(State, <<>>);
|
|
|
|
parse(Buffer, State=#state{in_state=#ps_request_line{empty_lines=EmptyLines}}) ->
|
|
|
|
after_parse(parse_request(Buffer, State, EmptyLines));
|
|
|
|
parse(Buffer, State=#state{in_state=PS=#ps_header{headers=Headers, name=undefined}}) ->
|
|
|
|
after_parse(parse_header(Buffer,
|
|
|
|
State#state{in_state=PS#ps_header{headers=undefined}},
|
|
|
|
Headers));
|
|
|
|
parse(Buffer, State=#state{in_state=PS=#ps_header{headers=Headers, name=Name}}) ->
|
|
|
|
after_parse(parse_hd_before_value(Buffer,
|
|
|
|
State#state{in_state=PS#ps_header{headers=undefined, name=undefined}},
|
|
|
|
Headers, Name));
|
|
|
|
parse(Buffer, State=#state{in_state=#ps_body{}}) ->
|
|
|
|
%% @todo We do not want to get the body automatically if the request doesn't ask for it.
|
|
|
|
%% We may want to get bodies that are below a threshold without waiting, and buffer them
|
|
|
|
%% until the request asks, though.
|
|
|
|
after_parse(parse_body(Buffer, State)).
|
|
|
|
%% @todo Don't parse if body is finished but request isn't. Let's not parallelize for now.
|
|
|
|
|
|
|
|
after_parse({request, Req=#{streamid := StreamID, headers := Headers, version := Version},
|
2017-01-16 14:22:43 +01:00
|
|
|
State0=#state{opts=Opts, streams=Streams0}, Buffer}) ->
|
|
|
|
try cowboy_stream:init(StreamID, Req, Opts) of
|
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
|
|
|
{Commands, StreamState} ->
|
2017-11-15 14:58:49 +01:00
|
|
|
TE = maps:get(<<"te">>, Headers, undefined),
|
|
|
|
Streams = [#stream{id=StreamID, state=StreamState,
|
|
|
|
version=Version, te=TE}|Streams0],
|
2017-05-03 17:44:00 +02:00
|
|
|
State1 = case maybe_req_close(State0, Headers, Version) of
|
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
|
|
|
close -> State0#state{streams=Streams, last_streamid=StreamID};
|
|
|
|
keepalive -> State0#state{streams=Streams}
|
|
|
|
end,
|
2017-05-03 17:44:00 +02:00
|
|
|
State = set_timeout(State1),
|
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
|
|
|
parse(Buffer, commands(State, StreamID, Commands))
|
2017-09-21 12:53:21 +02:00
|
|
|
catch Class:Exception ->
|
|
|
|
cowboy_stream:report_error(init,
|
|
|
|
[StreamID, Req, Opts],
|
|
|
|
Class, Exception, erlang:get_stacktrace()),
|
2017-09-27 14:17:27 +02:00
|
|
|
early_error(500, State0, {internal_error, {Class, Exception},
|
|
|
|
'Unhandled exception in cowboy_stream:init/3.'}, Req),
|
|
|
|
parse(Buffer, State0)
|
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;
|
|
|
|
%% Streams are sequential so the body is always about the last stream created
|
|
|
|
%% unless that stream has terminated.
|
2017-01-16 14:22:43 +01:00
|
|
|
after_parse({data, StreamID, IsFin, Data, State=#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
|
|
|
streams=Streams0=[Stream=#stream{id=StreamID, state=StreamState0}|_]}, Buffer}) ->
|
2017-01-16 14:22:43 +01:00
|
|
|
try cowboy_stream:data(StreamID, IsFin, Data, StreamState0) of
|
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
|
|
|
{Commands, StreamState} ->
|
|
|
|
Streams = lists:keyreplace(StreamID, #stream.id, Streams0,
|
|
|
|
Stream#stream{state=StreamState}),
|
|
|
|
parse(Buffer, commands(State#state{streams=Streams}, StreamID, Commands))
|
2017-09-21 12:53:21 +02:00
|
|
|
catch Class:Exception ->
|
|
|
|
cowboy_stream:report_error(data,
|
|
|
|
[StreamID, IsFin, Data, StreamState0],
|
|
|
|
Class, Exception, erlang:get_stacktrace()),
|
2017-09-27 14:17:27 +02:00
|
|
|
stream_reset(State, StreamID, {internal_error, {Class, Exception},
|
|
|
|
'Unhandled exception in cowboy_stream:data/4.'})
|
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;
|
|
|
|
%% No corresponding stream, skip.
|
|
|
|
after_parse({data, _, _, _, State, Buffer}) ->
|
|
|
|
before_loop(State, Buffer);
|
|
|
|
after_parse({more, State, Buffer}) ->
|
|
|
|
before_loop(State, Buffer).
|
|
|
|
|
|
|
|
%% Request-line.
|
|
|
|
|
2017-01-02 18:27:03 +01:00
|
|
|
-spec parse_request(Buffer, State, non_neg_integer())
|
|
|
|
-> {request, cowboy_req:req(), State, Buffer}
|
|
|
|
| {data, cowboy_stream:streamid(), cowboy_stream:fin(), binary(), State, Buffer}
|
|
|
|
| {more, State, Buffer}
|
|
|
|
when Buffer::binary(), State::#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
|
|
|
%% Empty lines must be using \r\n.
|
|
|
|
parse_request(<< $\n, _/bits >>, State, _) ->
|
|
|
|
error_terminate(400, State, {connection_error, protocol_error,
|
2017-02-05 15:10:00 +01:00
|
|
|
'Empty lines between requests must use the CRLF line terminator. (RFC7230 3.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
|
|
|
parse_request(<< $\s, _/bits >>, State, _) ->
|
|
|
|
error_terminate(400, State, {connection_error, protocol_error,
|
2017-02-05 15:10:00 +01:00
|
|
|
'The request-line must not begin with a space. (RFC7230 3.1.1, RFC7230 3.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
|
|
|
%% We limit the length of the Request-line to MaxLength to avoid endlessly
|
|
|
|
%% reading from the socket and eventually crashing.
|
2016-03-10 23:30:49 +01:00
|
|
|
parse_request(Buffer, State=#state{opts=Opts, in_streamid=InStreamID}, EmptyLines) ->
|
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
|
|
|
MaxLength = maps:get(max_request_line_length, Opts, 8000),
|
|
|
|
MaxEmptyLines = maps:get(max_empty_lines, Opts, 5),
|
|
|
|
case match_eol(Buffer, 0) of
|
|
|
|
nomatch when byte_size(Buffer) > MaxLength ->
|
|
|
|
error_terminate(414, State, {connection_error, limit_reached,
|
2017-02-05 15:10:00 +01:00
|
|
|
'The request-line length is larger than configuration allows. (RFC7230 3.1.1)'});
|
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
|
|
|
nomatch ->
|
|
|
|
{more, State#state{in_state=#ps_request_line{empty_lines=EmptyLines}}, Buffer};
|
|
|
|
1 when EmptyLines =:= MaxEmptyLines ->
|
|
|
|
error_terminate(400, State, {connection_error, limit_reached,
|
2017-02-05 15:10:00 +01:00
|
|
|
'More empty lines were received than configuration allows. (RFC7230 3.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
|
|
|
1 ->
|
|
|
|
<< _:16, Rest/bits >> = Buffer,
|
|
|
|
parse_request(Rest, State, EmptyLines + 1);
|
|
|
|
_ ->
|
|
|
|
case Buffer of
|
|
|
|
%% @todo * is only for server-wide OPTIONS request (RFC7230 5.3.4); tests
|
|
|
|
<< "OPTIONS * ", Rest/bits >> ->
|
|
|
|
parse_version(Rest, State, <<"OPTIONS">>, <<"*">>, <<>>);
|
|
|
|
% << "CONNECT ", Rest/bits >> ->
|
|
|
|
% parse_authority( %% @todo
|
2016-03-10 23:30:49 +01:00
|
|
|
%% Accept direct HTTP/2 only at the beginning of the connection.
|
|
|
|
<< "PRI * HTTP/2.0\r\n", _/bits >> when InStreamID =:= 1 ->
|
|
|
|
%% @todo Might be worth throwing to get a clean stacktrace.
|
2016-03-12 18:25:35 +01:00
|
|
|
http2_upgrade(State, 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
|
|
|
_ ->
|
|
|
|
parse_method(Buffer, State, <<>>,
|
|
|
|
maps:get(max_method_length, Opts, 32))
|
|
|
|
end
|
|
|
|
end.
|
|
|
|
|
|
|
|
match_eol(<< $\n, _/bits >>, N) ->
|
|
|
|
N;
|
|
|
|
match_eol(<< _, Rest/bits >>, N) ->
|
|
|
|
match_eol(Rest, N + 1);
|
|
|
|
match_eol(_, _) ->
|
|
|
|
nomatch.
|
|
|
|
|
|
|
|
parse_method(_, State, _, 0) ->
|
|
|
|
error_terminate(501, State, {connection_error, limit_reached,
|
|
|
|
'The method name is longer than configuration allows. (RFC7230 3.1.1)'});
|
|
|
|
parse_method(<< C, Rest/bits >>, State, SoFar, Remaining) ->
|
|
|
|
case C of
|
|
|
|
$\r -> error_terminate(400, State, {connection_error, protocol_error,
|
2017-02-05 15:10:00 +01:00
|
|
|
'The method name must not be followed with a line break. (RFC7230 3.1.1)'});
|
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
|
|
|
$\s -> parse_uri(Rest, State, SoFar);
|
|
|
|
_ when ?IS_TOKEN(C) -> parse_method(Rest, State, << SoFar/binary, C >>, Remaining - 1);
|
|
|
|
_ -> error_terminate(400, State, {connection_error, protocol_error,
|
|
|
|
'The method name must contain only valid token characters. (RFC7230 3.1.1)'})
|
|
|
|
end.
|
|
|
|
|
|
|
|
parse_uri(<< H, T, T, P, "://", Rest/bits >>, State, Method)
|
|
|
|
when H =:= $h orelse H =:= $H, T =:= $t orelse T =:= $T;
|
|
|
|
P =:= $p orelse P =:= $P ->
|
|
|
|
parse_uri_skip_host(Rest, State, Method);
|
|
|
|
parse_uri(<< H, T, T, P, S, "://", Rest/bits >>, State, Method)
|
|
|
|
when H =:= $h orelse H =:= $H, T =:= $t orelse T =:= $T;
|
|
|
|
P =:= $p orelse P =:= $P; S =:= $s orelse S =:= $S ->
|
|
|
|
parse_uri_skip_host(Rest, State, Method);
|
|
|
|
parse_uri(<< $/, Rest/bits >>, State, Method) ->
|
|
|
|
parse_uri_path(Rest, State, Method, << $/ >>);
|
|
|
|
parse_uri(_, State, _) ->
|
|
|
|
error_terminate(400, State, {connection_error, protocol_error,
|
|
|
|
'Invalid request-line or request-target. (RFC7230 3.1.1, RFC7230 5.3)'}).
|
|
|
|
|
|
|
|
parse_uri_skip_host(<< C, Rest/bits >>, State, Method) ->
|
|
|
|
case C of
|
|
|
|
$\r -> error_terminate(400, State, {connection_error, protocol_error,
|
2017-02-05 15:10:00 +01:00
|
|
|
'The request-target must not be followed by a line break. (RFC7230 3.1.1)'});
|
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
|
|
|
$/ -> parse_uri_path(Rest, State, Method, <<"/">>);
|
|
|
|
$\s -> parse_version(Rest, State, Method, <<"/">>, <<>>);
|
|
|
|
$? -> parse_uri_query(Rest, State, Method, <<"/">>, <<>>);
|
|
|
|
$# -> skip_uri_fragment(Rest, State, Method, <<"/">>, <<>>);
|
|
|
|
_ -> parse_uri_skip_host(Rest, State, Method)
|
|
|
|
end.
|
|
|
|
|
|
|
|
parse_uri_path(<< C, Rest/bits >>, State, Method, SoFar) ->
|
|
|
|
case C of
|
|
|
|
$\r -> error_terminate(400, State, {connection_error, protocol_error,
|
2017-02-05 15:10:00 +01:00
|
|
|
'The request-target must not be followed by a line break. (RFC7230 3.1.1)'});
|
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
|
|
|
$\s -> parse_version(Rest, State, Method, SoFar, <<>>);
|
|
|
|
$? -> parse_uri_query(Rest, State, Method, SoFar, <<>>);
|
|
|
|
$# -> skip_uri_fragment(Rest, State, Method, SoFar, <<>>);
|
|
|
|
_ -> parse_uri_path(Rest, State, Method, << SoFar/binary, C >>)
|
|
|
|
end.
|
|
|
|
|
|
|
|
parse_uri_query(<< C, Rest/bits >>, State, M, P, SoFar) ->
|
|
|
|
case C of
|
|
|
|
$\r -> error_terminate(400, State, {connection_error, protocol_error,
|
2017-02-05 15:10:00 +01:00
|
|
|
'The request-target must not be followed by a line break. (RFC7230 3.1.1)'});
|
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
|
|
|
$\s -> parse_version(Rest, State, M, P, SoFar);
|
|
|
|
$# -> skip_uri_fragment(Rest, State, M, P, SoFar);
|
|
|
|
_ -> parse_uri_query(Rest, State, M, P, << SoFar/binary, C >>)
|
|
|
|
end.
|
|
|
|
|
|
|
|
skip_uri_fragment(<< C, Rest/bits >>, State, M, P, Q) ->
|
|
|
|
case C of
|
|
|
|
$\r -> error_terminate(400, State, {connection_error, protocol_error,
|
2017-02-05 15:10:00 +01:00
|
|
|
'The request-target must not be followed by a line break. (RFC7230 3.1.1)'});
|
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
|
|
|
$\s -> parse_version(Rest, State, M, P, Q);
|
|
|
|
_ -> skip_uri_fragment(Rest, State, M, P, Q)
|
|
|
|
end.
|
|
|
|
|
|
|
|
parse_version(<< "HTTP/1.1\r\n", Rest/bits >>, State, M, P, Q) ->
|
|
|
|
parse_headers(Rest, State, M, P, Q, 'HTTP/1.1');
|
|
|
|
parse_version(<< "HTTP/1.0\r\n", Rest/bits >>, State, M, P, Q) ->
|
|
|
|
parse_headers(Rest, State, M, P, Q, 'HTTP/1.0');
|
|
|
|
parse_version(<< "HTTP/1.", _, C, _/bits >>, State, _, _, _) when C =:= $\s; C =:= $\t ->
|
|
|
|
error_terminate(400, State, {connection_error, protocol_error,
|
|
|
|
'Whitespace is not allowed after the HTTP version. (RFC7230 3.1.1)'});
|
|
|
|
parse_version(<< C, _/bits >>, State, _, _, _) when C =:= $\s; C =:= $\t ->
|
|
|
|
error_terminate(400, State, {connection_error, protocol_error,
|
2017-02-05 15:10:00 +01:00
|
|
|
'The separator between request target and version must be a single SP. (RFC7230 3.1.1)'});
|
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
|
|
|
parse_version(_, State, _, _, _) ->
|
|
|
|
error_terminate(505, State, {connection_error, protocol_error,
|
2017-02-05 15:10:00 +01:00
|
|
|
'Unsupported HTTP version. (RFC7230 2.6)'}).
|
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
|
|
|
|
|
|
|
parse_headers(Rest, State, M, P, Q, V) ->
|
|
|
|
parse_header(Rest, State#state{in_state=#ps_header{
|
|
|
|
method=M, path=P, qs=Q, version=V}}, #{}).
|
|
|
|
|
|
|
|
%% Headers.
|
|
|
|
|
|
|
|
%% We need two or more bytes in the buffer to continue.
|
|
|
|
parse_header(Rest, State=#state{in_state=PS}, Headers) when byte_size(Rest) < 2 ->
|
|
|
|
{more, State#state{in_state=PS#ps_header{headers=Headers}}, Rest};
|
|
|
|
parse_header(<< $\r, $\n, Rest/bits >>, S, Headers) ->
|
|
|
|
request(Rest, S, Headers);
|
|
|
|
parse_header(Buffer, State=#state{opts=Opts, in_state=PS}, Headers) ->
|
|
|
|
MaxHeaders = maps:get(max_headers, Opts, 100),
|
2017-01-02 18:27:03 +01:00
|
|
|
NumHeaders = maps:size(Headers),
|
2017-11-20 00:22:41 +01:00
|
|
|
if
|
|
|
|
NumHeaders >= MaxHeaders ->
|
|
|
|
error_terminate(431, State#state{in_state=PS#ps_header{headers=Headers}},
|
|
|
|
{connection_error, limit_reached,
|
|
|
|
'The number of headers is larger than configuration allows. (RFC7230 3.2.5, RFC6585 5)'});
|
|
|
|
true ->
|
|
|
|
parse_header_colon(Buffer, State, Headers)
|
|
|
|
end.
|
|
|
|
|
|
|
|
parse_header_colon(Buffer, State=#state{opts=Opts, in_state=PS}, Headers) ->
|
|
|
|
MaxLength = maps:get(max_header_name_length, Opts, 64),
|
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
|
|
|
case match_colon(Buffer, 0) of
|
|
|
|
nomatch when byte_size(Buffer) > MaxLength ->
|
2017-03-27 10:26:13 +02:00
|
|
|
error_terminate(431, State#state{in_state=PS#ps_header{headers=Headers}},
|
|
|
|
{connection_error, limit_reached,
|
|
|
|
'A header name is larger than configuration allows. (RFC7230 3.2.5, RFC6585 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
|
|
|
nomatch ->
|
|
|
|
{more, State#state{in_state=PS#ps_header{headers=Headers}}, Buffer};
|
|
|
|
_ ->
|
|
|
|
parse_hd_name(Buffer, State, Headers, <<>>)
|
|
|
|
end.
|
|
|
|
|
|
|
|
match_colon(<< $:, _/bits >>, N) ->
|
|
|
|
N;
|
|
|
|
match_colon(<< _, Rest/bits >>, N) ->
|
|
|
|
match_colon(Rest, N + 1);
|
|
|
|
match_colon(_, _) ->
|
|
|
|
nomatch.
|
|
|
|
|
|
|
|
parse_hd_name(<< $:, Rest/bits >>, State, H, SoFar) ->
|
|
|
|
parse_hd_before_value(Rest, State, H, SoFar);
|
2017-03-27 10:26:13 +02:00
|
|
|
parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, <<>>) when ?IS_WS(C) ->
|
|
|
|
error_terminate(400, State#state{in_state=PS#ps_header{headers=H}},
|
|
|
|
{connection_error, protocol_error,
|
|
|
|
'Whitespace is not allowed between the header name and the colon. (RFC7230 3.2)'});
|
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
|
|
|
parse_hd_name(<< C, Rest/bits >>, State, H, SoFar) when ?IS_WS(C) ->
|
|
|
|
parse_hd_name_ws(Rest, State, H, SoFar);
|
|
|
|
parse_hd_name(<< C, Rest/bits >>, State, H, SoFar) ->
|
|
|
|
?LOWER(parse_hd_name, Rest, State, H, SoFar).
|
|
|
|
|
|
|
|
parse_hd_name_ws(<< C, Rest/bits >>, S, H, Name) ->
|
|
|
|
case C of
|
|
|
|
$\s -> parse_hd_name_ws(Rest, S, H, Name);
|
|
|
|
$\t -> parse_hd_name_ws(Rest, S, H, Name);
|
|
|
|
$: -> parse_hd_before_value(Rest, S, H, Name)
|
|
|
|
end.
|
|
|
|
|
|
|
|
parse_hd_before_value(<< $\s, Rest/bits >>, S, H, N) ->
|
|
|
|
parse_hd_before_value(Rest, S, H, N);
|
|
|
|
parse_hd_before_value(<< $\t, Rest/bits >>, S, H, N) ->
|
|
|
|
parse_hd_before_value(Rest, S, H, N);
|
|
|
|
parse_hd_before_value(Buffer, State=#state{opts=Opts, in_state=PS}, H, N) ->
|
|
|
|
MaxLength = maps:get(max_header_value_length, Opts, 4096),
|
|
|
|
case match_eol(Buffer, 0) of
|
|
|
|
nomatch when byte_size(Buffer) > MaxLength ->
|
2017-03-27 10:26:13 +02:00
|
|
|
error_terminate(431, State#state{in_state=PS#ps_header{headers=H}},
|
|
|
|
{connection_error, limit_reached,
|
|
|
|
'A header value is larger than configuration allows. (RFC7230 3.2.5, RFC6585 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
|
|
|
nomatch ->
|
|
|
|
{more, State#state{in_state=PS#ps_header{headers=H, name=N}}, Buffer};
|
|
|
|
_ ->
|
|
|
|
parse_hd_value(Buffer, State, H, N, <<>>)
|
|
|
|
end.
|
|
|
|
|
2016-03-13 11:18:27 +01:00
|
|
|
parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Name, SoFar) ->
|
|
|
|
Value = clean_value_ws_end(SoFar, byte_size(SoFar) - 1),
|
|
|
|
Headers = case maps:get(Name, Headers0, undefined) of
|
|
|
|
undefined -> Headers0#{Name => Value};
|
2016-08-10 11:49:31 +02:00
|
|
|
%% The cookie header does not use proper HTTP header lists.
|
|
|
|
Value0 when Name =:= <<"cookie">> -> Headers0#{Name => << Value0/binary, "; ", Value/binary >>};
|
2016-03-13 11:18:27 +01:00
|
|
|
Value0 -> Headers0#{Name => << Value0/binary, ", ", Value/binary >>}
|
|
|
|
end,
|
|
|
|
parse_header(Rest, S, Headers);
|
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
|
|
|
parse_hd_value(<< C, Rest/bits >>, S, H, N, SoFar) ->
|
|
|
|
parse_hd_value(Rest, S, H, N, << SoFar/binary, C >>).
|
|
|
|
|
|
|
|
clean_value_ws_end(_, -1) ->
|
|
|
|
<<>>;
|
|
|
|
clean_value_ws_end(Value, N) ->
|
|
|
|
case binary:at(Value, N) of
|
|
|
|
$\s -> clean_value_ws_end(Value, N - 1);
|
|
|
|
$\t -> clean_value_ws_end(Value, N - 1);
|
|
|
|
_ ->
|
|
|
|
S = N + 1,
|
|
|
|
<< Value2:S/binary, _/bits >> = Value,
|
|
|
|
Value2
|
|
|
|
end.
|
|
|
|
|
|
|
|
-ifdef(TEST).
|
|
|
|
clean_value_ws_end_test_() ->
|
|
|
|
Tests = [
|
|
|
|
{<<>>, <<>>},
|
|
|
|
{<<" ">>, <<>>},
|
|
|
|
{<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, "
|
|
|
|
"text/html;level=2;q=0.4, */*;q=0.5 \t \t ">>,
|
|
|
|
<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, "
|
|
|
|
"text/html;level=2;q=0.4, */*;q=0.5">>}
|
|
|
|
],
|
|
|
|
[{V, fun() -> R = clean_value_ws_end(V, byte_size(V) - 1) end} || {V, R} <- Tests].
|
|
|
|
|
|
|
|
horse_clean_value_ws_end() ->
|
|
|
|
horse:repeat(200000,
|
|
|
|
clean_value_ws_end(
|
|
|
|
<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, "
|
|
|
|
"text/html;level=2;q=0.4, */*;q=0.5 ">>,
|
|
|
|
byte_size(<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, "
|
|
|
|
"text/html;level=2;q=0.4, */*;q=0.5 ">>) - 1)
|
|
|
|
).
|
|
|
|
-endif.
|
|
|
|
|
|
|
|
request(Buffer, State=#state{transport=Transport, in_streamid=StreamID,
|
2017-03-27 10:26:13 +02:00
|
|
|
in_state=PS=#ps_header{version=Version}}, Headers) ->
|
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
|
|
|
case maps:get(<<"host">>, Headers, undefined) of
|
|
|
|
undefined when Version =:= 'HTTP/1.1' ->
|
|
|
|
%% @todo Might want to not close the connection on this and next one.
|
2017-03-27 10:26:13 +02:00
|
|
|
error_terminate(400, State#state{in_state=PS#ps_header{headers=Headers}},
|
|
|
|
{stream_error, StreamID, protocol_error,
|
|
|
|
'HTTP/1.1 requests must include a host header. (RFC7230 5.4)'});
|
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
|
|
|
undefined ->
|
|
|
|
request(Buffer, State, Headers, <<>>, default_port(Transport:secure()));
|
|
|
|
RawHost ->
|
2016-08-11 16:45:52 +02:00
|
|
|
try cow_http_hd:parse_host(RawHost) of
|
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
|
|
|
{Host, undefined} ->
|
|
|
|
request(Buffer, State, Headers, Host, default_port(Transport:secure()));
|
|
|
|
{Host, Port} ->
|
|
|
|
request(Buffer, State, Headers, Host, Port)
|
|
|
|
catch _:_ ->
|
2017-03-27 10:26:13 +02:00
|
|
|
error_terminate(400, State#state{in_state=PS#ps_header{headers=Headers}},
|
|
|
|
{stream_error, StreamID, protocol_error,
|
|
|
|
'The host header is invalid. (RFC7230 5.4)'})
|
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
|
|
|
|
end.
|
|
|
|
|
|
|
|
-spec default_port(boolean()) -> 80 | 443.
|
|
|
|
default_port(true) -> 443;
|
|
|
|
default_port(_) -> 80.
|
|
|
|
|
|
|
|
%% End of request parsing.
|
|
|
|
|
2017-10-25 20:17:21 +01:00
|
|
|
request(Buffer, State0=#state{ref=Ref, transport=Transport, peer=Peer, sock=Sock, cert=Cert,
|
|
|
|
in_streamid=StreamID, in_state=
|
|
|
|
PS=#ps_header{method=Method, path=Path, qs=Qs, version=Version}},
|
2017-11-20 21:07:04 +01:00
|
|
|
Headers0, Host, Port) ->
|
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
|
|
|
Scheme = case Transport:secure() of
|
|
|
|
true -> <<"https">>;
|
|
|
|
false -> <<"http">>
|
|
|
|
end,
|
2017-11-20 21:07:04 +01:00
|
|
|
{Headers, HasBody, BodyLength, TDecodeFun, TDecodeState} = case Headers0 of
|
|
|
|
#{<<"transfer-encoding">> := TransferEncoding0} ->
|
|
|
|
try cow_http_hd:parse_transfer_encoding(TransferEncoding0) of
|
|
|
|
[<<"chunked">>] ->
|
|
|
|
{maps:remove(<<"content-length">>, Headers0),
|
|
|
|
true, undefined, fun cow_http_te:stream_chunked/2, {0, 0}};
|
|
|
|
_ ->
|
|
|
|
error_terminate(400, State0#state{in_state=PS#ps_header{headers=Headers0}},
|
|
|
|
{stream_error, StreamID, protocol_error,
|
|
|
|
'Cowboy only supports transfer-encoding: chunked. (RFC7230 3.3.1)'})
|
|
|
|
catch _:_ ->
|
|
|
|
error_terminate(400, State0#state{in_state=PS#ps_header{headers=Headers0}},
|
|
|
|
{stream_error, StreamID, protocol_error,
|
|
|
|
'The transfer-encoding header is invalid. (RFC7230 3.3.1)'})
|
|
|
|
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
|
|
|
#{<<"content-length">> := <<"0">>} ->
|
2017-11-20 21:07:04 +01:00
|
|
|
{Headers0, false, 0, undefined, undefined};
|
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
|
|
|
#{<<"content-length">> := BinLength} ->
|
|
|
|
Length = try
|
|
|
|
cow_http_hd:parse_content_length(BinLength)
|
|
|
|
catch _:_ ->
|
2017-11-20 21:07:04 +01:00
|
|
|
error_terminate(400, State0#state{in_state=PS#ps_header{headers=Headers0}},
|
2017-03-27 10:26:13 +02:00
|
|
|
{stream_error, StreamID, protocol_error,
|
|
|
|
'The content-length header is invalid. (RFC7230 3.3.2)'})
|
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,
|
2017-11-20 21:07:04 +01:00
|
|
|
{Headers0, true, Length, fun cow_http_te:stream_identity/2, {0, Length}};
|
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-11-20 21:07:04 +01:00
|
|
|
{Headers0, false, 0, undefined, undefined}
|
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,
|
|
|
|
Req = #{
|
|
|
|
ref => Ref,
|
|
|
|
pid => self(),
|
|
|
|
streamid => StreamID,
|
2016-06-20 17:28:59 +02:00
|
|
|
peer => Peer,
|
2017-10-25 20:17:21 +01:00
|
|
|
sock => Sock,
|
|
|
|
cert => Cert,
|
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
|
|
|
method => Method,
|
|
|
|
scheme => Scheme,
|
|
|
|
host => Host,
|
|
|
|
port => Port,
|
|
|
|
path => Path,
|
|
|
|
qs => Qs,
|
|
|
|
version => Version,
|
|
|
|
%% We are transparently taking care of transfer-encodings so
|
|
|
|
%% the user code has no need to know about it.
|
|
|
|
headers => maps:remove(<<"transfer-encoding">>, Headers),
|
|
|
|
has_body => HasBody,
|
|
|
|
body_length => BodyLength
|
|
|
|
},
|
2016-03-12 18:25:35 +01:00
|
|
|
case is_http2_upgrade(Headers, Version) of
|
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
|
|
|
false ->
|
2016-03-12 18:25:35 +01:00
|
|
|
State = case HasBody of
|
|
|
|
true ->
|
2017-05-03 17:44:00 +02:00
|
|
|
State0#state{in_state=#ps_body{
|
2016-03-12 18:25:35 +01:00
|
|
|
transfer_decode_fun = TDecodeFun,
|
|
|
|
transfer_decode_state = TDecodeState
|
2017-05-03 17:44:00 +02:00
|
|
|
}};
|
2016-03-12 18:25:35 +01:00
|
|
|
false ->
|
2017-05-03 17:44:00 +02:00
|
|
|
State0#state{in_streamid=StreamID + 1, in_state=#ps_request_line{}}
|
2016-03-12 18:25:35 +01:00
|
|
|
end,
|
|
|
|
{request, Req, State, Buffer};
|
2016-03-13 11:18:27 +01:00
|
|
|
{true, HTTP2Settings} ->
|
2017-03-27 10:26:13 +02:00
|
|
|
%% We save the headers in case the upgrade will fail
|
|
|
|
%% and we need to pass them to cowboy_stream:early_error.
|
|
|
|
http2_upgrade(State0#state{in_state=PS#ps_header{headers=Headers}},
|
|
|
|
Buffer, HTTP2Settings, Req)
|
2016-03-12 18:25:35 +01: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
|
|
|
|
2016-03-10 23:30:49 +01:00
|
|
|
%% HTTP/2 upgrade.
|
|
|
|
|
2017-04-18 14:06:34 +02:00
|
|
|
%% @todo We must not upgrade to h2c over a TLS connection.
|
2016-03-12 18:25:35 +01:00
|
|
|
is_http2_upgrade(#{<<"connection">> := Conn, <<"upgrade">> := Upgrade,
|
|
|
|
<<"http2-settings">> := HTTP2Settings}, 'HTTP/1.1') ->
|
|
|
|
Conns = cow_http_hd:parse_connection(Conn),
|
|
|
|
case {lists:member(<<"upgrade">>, Conns), lists:member(<<"http2-settings">>, Conns)} of
|
|
|
|
{true, true} ->
|
|
|
|
Protocols = cow_http_hd:parse_upgrade(Upgrade),
|
|
|
|
case lists:member(<<"h2c">>, Protocols) of
|
|
|
|
true ->
|
2016-03-13 11:18:27 +01:00
|
|
|
{true, HTTP2Settings};
|
2016-03-12 18:25:35 +01:00
|
|
|
false ->
|
|
|
|
false
|
|
|
|
end;
|
|
|
|
_ ->
|
|
|
|
false
|
|
|
|
end;
|
|
|
|
is_http2_upgrade(_, _) ->
|
|
|
|
false.
|
|
|
|
|
|
|
|
%% Prior knowledge upgrade, without an HTTP/1.1 request.
|
2016-03-10 23:30:49 +01:00
|
|
|
http2_upgrade(State=#state{parent=Parent, ref=Ref, socket=Socket, transport=Transport,
|
2017-10-25 20:17:21 +01:00
|
|
|
opts=Opts, peer=Peer, sock=Sock, cert=Cert}, Buffer) ->
|
2016-03-10 23:30:49 +01:00
|
|
|
case Transport:secure() of
|
|
|
|
false ->
|
2017-05-03 17:44:00 +02:00
|
|
|
_ = cancel_timeout(State),
|
2017-10-25 20:17:21 +01:00
|
|
|
cowboy_http2:init(Parent, Ref, Socket, Transport, Opts,
|
|
|
|
Peer, Sock, Cert, Buffer);
|
2016-03-10 23:30:49 +01:00
|
|
|
true ->
|
|
|
|
error_terminate(400, State, {connection_error, protocol_error,
|
|
|
|
'Clients that support HTTP/2 over TLS MUST use ALPN. (RFC7540 3.4)'})
|
|
|
|
end.
|
|
|
|
|
2017-09-25 13:52:58 +02:00
|
|
|
%% Upgrade via an HTTP/1.1 request.
|
2016-03-12 18:25:35 +01:00
|
|
|
http2_upgrade(State=#state{parent=Parent, ref=Ref, socket=Socket, transport=Transport,
|
2017-10-25 20:17:21 +01:00
|
|
|
opts=Opts, peer=Peer, sock=Sock, cert=Cert}, Buffer, HTTP2Settings, Req) ->
|
2016-03-12 18:25:35 +01:00
|
|
|
%% @todo
|
|
|
|
%% 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.
|
|
|
|
%% Always half-closed stream coming from this side.
|
2016-03-13 11:18:27 +01:00
|
|
|
try cow_http_hd:parse_http2_settings(HTTP2Settings) of
|
|
|
|
Settings ->
|
2017-05-03 17:44:00 +02:00
|
|
|
_ = cancel_timeout(State),
|
2017-10-25 20:17:21 +01:00
|
|
|
cowboy_http2:init(Parent, Ref, Socket, Transport, Opts,
|
|
|
|
Peer, Sock, Cert, Buffer, Settings, Req)
|
2016-03-13 11:18:27 +01:00
|
|
|
catch _:_ ->
|
|
|
|
error_terminate(400, State, {connection_error, protocol_error,
|
2017-03-27 10:26:13 +02:00
|
|
|
'The HTTP2-Settings header must contain a base64 SETTINGS payload. (RFC7540 3.2, RFC7540 3.2.1)'})
|
2016-03-13 11:18:27 +01:00
|
|
|
end.
|
2016-03-12 18:25:35 +01:00
|
|
|
|
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 parsing.
|
|
|
|
|
|
|
|
parse_body(Buffer, State=#state{in_streamid=StreamID, in_state=
|
|
|
|
PS=#ps_body{transfer_decode_fun=TDecode, transfer_decode_state=TState0}}) ->
|
|
|
|
%% @todo Proper trailers.
|
2017-11-22 15:39:39 +01:00
|
|
|
try TDecode(Buffer, TState0) of
|
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
|
|
|
more ->
|
|
|
|
%% @todo Asks for 0 or more bytes.
|
|
|
|
{more, State, Buffer};
|
|
|
|
{more, Data, TState} ->
|
|
|
|
%% @todo Asks for 0 or more bytes.
|
|
|
|
{data, StreamID, nofin, Data, State#state{in_state=
|
|
|
|
PS#ps_body{transfer_decode_state=TState}}, <<>>};
|
|
|
|
{more, Data, _Length, TState} when is_integer(_Length) ->
|
|
|
|
%% @todo Asks for Length more bytes.
|
|
|
|
{data, StreamID, nofin, Data, State#state{in_state=
|
|
|
|
PS#ps_body{transfer_decode_state=TState}}, <<>>};
|
|
|
|
{more, Data, Rest, TState} ->
|
|
|
|
%% @todo Asks for 0 or more bytes.
|
|
|
|
{data, StreamID, nofin, Data, State#state{in_state=
|
|
|
|
PS#ps_body{transfer_decode_state=TState}}, Rest};
|
2017-11-20 11:28:22 +01:00
|
|
|
{done, _HasTrailers, Rest} ->
|
2017-09-25 12:34:44 +02:00
|
|
|
{data, StreamID, fin, <<>>, set_timeout(
|
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
|
|
|
State#state{in_streamid=StreamID + 1, in_state=#ps_request_line{}}), Rest};
|
2017-11-20 11:28:22 +01:00
|
|
|
{done, Data, _HasTrailers, Rest} ->
|
2017-09-25 12:34:44 +02:00
|
|
|
{data, StreamID, fin, Data, set_timeout(
|
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
|
|
|
State#state{in_streamid=StreamID + 1, in_state=#ps_request_line{}}), Rest}
|
2017-11-22 15:39:39 +01:00
|
|
|
catch _:_ ->
|
|
|
|
Reason = {connection_error, protocol_error,
|
|
|
|
'Failure to decode the content. (RFC7230 4)'},
|
|
|
|
terminate(stream_terminate(State, StreamID, Reason), Reason)
|
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.
|
|
|
|
|
|
|
|
%% Message handling.
|
|
|
|
|
|
|
|
down(State=#state{children=Children0}, Pid, Msg) ->
|
2017-08-08 16:59:33 +02:00
|
|
|
case cowboy_children:down(Children0, Pid) of
|
|
|
|
%% The stream was terminated already.
|
|
|
|
{ok, undefined, Children} ->
|
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
|
|
|
State#state{children=Children};
|
2017-08-08 16:59:33 +02:00
|
|
|
%% The stream is still running.
|
|
|
|
{ok, StreamID, Children} ->
|
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
|
|
|
info(State#state{children=Children}, StreamID, Msg);
|
2017-08-08 16:59:33 +02:00
|
|
|
%% The process was unknown.
|
|
|
|
error ->
|
2016-08-10 11:49:31 +02:00
|
|
|
error_logger:error_msg("Received EXIT signal ~p for unknown process ~p.~n", [Msg, Pid]),
|
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
|
|
|
State
|
|
|
|
end.
|
|
|
|
|
2017-01-16 14:22:43 +01:00
|
|
|
info(State=#state{streams=Streams0}, StreamID, Msg) ->
|
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
|
|
|
case lists:keyfind(StreamID, #stream.id, Streams0) of
|
|
|
|
Stream = #stream{state=StreamState0} ->
|
2017-01-16 14:22:43 +01:00
|
|
|
try cowboy_stream:info(StreamID, Msg, StreamState0) of
|
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
|
|
|
{Commands, StreamState} ->
|
|
|
|
Streams = lists:keyreplace(StreamID, #stream.id, Streams0,
|
|
|
|
Stream#stream{state=StreamState}),
|
|
|
|
commands(State#state{streams=Streams}, StreamID, Commands)
|
2017-09-21 12:53:21 +02:00
|
|
|
catch Class:Exception ->
|
|
|
|
cowboy_stream:report_error(info,
|
|
|
|
[StreamID, Msg, StreamState0],
|
|
|
|
Class, Exception, erlang:get_stacktrace()),
|
2017-09-27 14:17:27 +02:00
|
|
|
stream_reset(State, StreamID, {internal_error, {Class, Exception},
|
|
|
|
'Unhandled exception in cowboy_stream:info/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
|
|
|
end;
|
|
|
|
false ->
|
2016-08-10 11:49:31 +02:00
|
|
|
error_logger:error_msg("Received message ~p for unknown stream ~p.~n", [Msg, StreamID]),
|
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
|
|
|
State
|
|
|
|
end.
|
|
|
|
|
|
|
|
%% Commands.
|
|
|
|
|
|
|
|
commands(State, _, []) ->
|
|
|
|
State;
|
|
|
|
%% Supervise a child process.
|
|
|
|
commands(State=#state{children=Children}, StreamID, [{spawn, Pid, Shutdown}|Tail]) ->
|
2017-08-08 16:59:33 +02:00
|
|
|
commands(State#state{children=cowboy_children:up(Children, Pid, StreamID, Shutdown)},
|
|
|
|
StreamID, Tail);
|
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
|
|
|
%% Error handling.
|
|
|
|
commands(State, StreamID, [Error = {internal_error, _, _}|Tail]) ->
|
|
|
|
commands(stream_reset(State, StreamID, Error), StreamID, Tail);
|
|
|
|
%% Commands for a stream currently inactive.
|
|
|
|
commands(State=#state{out_streamid=Current, streams=Streams0}, StreamID, Commands)
|
|
|
|
when Current =/= StreamID ->
|
|
|
|
|
|
|
|
%% @todo We still want to handle some commands...
|
|
|
|
|
|
|
|
Stream = #stream{queue=Queue} = lists:keyfind(StreamID, #stream.id, Streams0),
|
|
|
|
Streams = lists:keyreplace(StreamID, #stream.id, Streams0,
|
|
|
|
Stream#stream{queue=Queue ++ Commands}),
|
|
|
|
State#state{streams=Streams};
|
|
|
|
%% Read the request body.
|
|
|
|
commands(State, StreamID, [{flow, _Length}|Tail]) ->
|
|
|
|
%% @todo We only read from socket if buffer is empty, otherwise
|
|
|
|
%% we decode the buffer.
|
|
|
|
|
|
|
|
%% @todo Set the body reading length to min(Length, BodyLength)
|
|
|
|
|
2016-08-10 17:15:02 +02:00
|
|
|
commands(State, StreamID, Tail);
|
|
|
|
%% Error responses are sent only if a response wasn't sent already.
|
2017-09-14 13:42:17 +02:00
|
|
|
commands(State=#state{out_state=wait}, StreamID, [{error_response, Status, Headers0, Body}|Tail]) ->
|
|
|
|
%% We close the connection when the error response is 408, as it
|
|
|
|
%% indicates a timeout and the RFC recommends that we stop here. (RFC7231 6.5.7)
|
|
|
|
Headers = case Status of
|
|
|
|
408 -> Headers0#{<<"connection">> => <<"close">>};
|
|
|
|
<<"408", _/bits>> -> Headers0#{<<"connection">> => <<"close">>};
|
|
|
|
_ -> Headers0
|
|
|
|
end,
|
|
|
|
commands(State, StreamID, [{response, Status, Headers, Body}|Tail]);
|
2016-08-10 17:15:02 +02:00
|
|
|
commands(State, StreamID, [{error_response, _, _, _}|Tail]) ->
|
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
|
|
|
commands(State, StreamID, Tail);
|
2017-05-05 16:10:15 +02:00
|
|
|
%% Send an informational response.
|
|
|
|
commands(State=#state{socket=Socket, transport=Transport, out_state=wait, streams=Streams},
|
|
|
|
StreamID, [{inform, StatusCode, Headers}|Tail]) ->
|
|
|
|
%% @todo I'm pretty sure the last stream in the list is the one we want
|
|
|
|
%% considering all others are queued.
|
|
|
|
#stream{version=Version} = lists:keyfind(StreamID, #stream.id, Streams),
|
|
|
|
_ = case Version of
|
|
|
|
'HTTP/1.1' ->
|
|
|
|
Transport:send(Socket, cow_http:response(StatusCode, 'HTTP/1.1',
|
|
|
|
headers_to_list(Headers)));
|
|
|
|
%% Do not send informational responses to HTTP/1.0 clients. (RFC7231 6.2)
|
|
|
|
'HTTP/1.0' ->
|
|
|
|
ok
|
|
|
|
end,
|
|
|
|
commands(State, StreamID, Tail);
|
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
|
|
|
%% Send a full response.
|
|
|
|
%%
|
|
|
|
%% @todo Kill the stream if it sent a response when one has already been sent.
|
|
|
|
%% @todo Keep IsFin in the state.
|
|
|
|
%% @todo Same two things above apply to DATA, possibly promise too.
|
2016-08-10 11:49:31 +02:00
|
|
|
commands(State0=#state{socket=Socket, transport=Transport, out_state=wait, streams=Streams}, StreamID,
|
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, StatusCode, Headers0, Body}|Tail]) ->
|
|
|
|
%% @todo I'm pretty sure the last stream in the list is the one we want
|
|
|
|
%% considering all others are queued.
|
|
|
|
#stream{version=Version} = lists:keyfind(StreamID, #stream.id, Streams),
|
|
|
|
{State, Headers} = connection(State0, Headers0, StreamID, Version),
|
|
|
|
%% @todo Ensure content-length is set.
|
2016-08-10 11:49:31 +02:00
|
|
|
Response = cow_http:response(StatusCode, 'HTTP/1.1', headers_to_list(Headers)),
|
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
|
|
|
case Body of
|
|
|
|
{sendfile, O, B, P} ->
|
|
|
|
Transport:send(Socket, Response),
|
2017-10-20 13:16:04 +01:00
|
|
|
commands(State, StreamID, [{sendfile, fin, O, B, P}|Tail]);
|
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
|
|
|
_ ->
|
|
|
|
Transport:send(Socket, [Response, Body]),
|
2017-10-20 13:16:04 +01:00
|
|
|
commands(State#state{out_state=done}, StreamID, Tail)
|
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;
|
|
|
|
%% Send response headers and initiate chunked encoding.
|
|
|
|
commands(State0=#state{socket=Socket, transport=Transport, streams=Streams}, StreamID,
|
|
|
|
[{headers, StatusCode, Headers0}|Tail]) ->
|
|
|
|
%% @todo Same as above.
|
|
|
|
#stream{version=Version} = lists:keyfind(StreamID, #stream.id, Streams),
|
|
|
|
{State1, Headers1} = case Version of
|
|
|
|
'HTTP/1.1' ->
|
|
|
|
{State0, Headers0#{<<"transfer-encoding">> => <<"chunked">>}};
|
|
|
|
%% Close the connection after streaming the data to HTTP/1.0 client.
|
|
|
|
%% @todo I'm guessing we need to differentiate responses with a content-length and others.
|
|
|
|
'HTTP/1.0' ->
|
|
|
|
{State0#state{last_streamid=StreamID}, Headers0}
|
|
|
|
end,
|
|
|
|
{State, Headers} = connection(State1, Headers1, StreamID, Version),
|
2016-08-10 11:49:31 +02:00
|
|
|
Transport:send(Socket, cow_http:response(StatusCode, 'HTTP/1.1', headers_to_list(Headers))),
|
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
|
|
|
commands(State#state{out_state=chunked}, StreamID, Tail);
|
|
|
|
%% Send a response body chunk.
|
|
|
|
%%
|
|
|
|
%% @todo WINDOW_UPDATE stuff require us to buffer some data.
|
2016-08-10 11:52:41 +02:00
|
|
|
%% @todo We probably want to allow Data to be the {sendfile, ...} tuple also.
|
2017-10-20 13:16:04 +01:00
|
|
|
commands(State0=#state{socket=Socket, transport=Transport, streams=Streams}, StreamID,
|
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
|
|
|
[{data, IsFin, Data}|Tail]) ->
|
2017-01-20 15:16:50 +01:00
|
|
|
%% Do not send anything when the user asks to send an empty
|
|
|
|
%% data frame, as that would break the protocol.
|
|
|
|
Size = iolist_size(Data),
|
|
|
|
case Size of
|
2017-11-01 15:33:10 +00:00
|
|
|
0 ->
|
|
|
|
%% We send the last chunk only if version is HTTP/1.1 and IsFin=fin.
|
|
|
|
case lists:keyfind(StreamID, #stream.id, Streams) of
|
|
|
|
#stream{version='HTTP/1.1'} when IsFin =:= fin ->
|
|
|
|
Transport:send(Socket, <<"0\r\n\r\n">>);
|
|
|
|
_ ->
|
|
|
|
ok
|
|
|
|
end;
|
2017-01-20 15:16:50 +01:00
|
|
|
_ ->
|
|
|
|
%% @todo We need to kill the stream if it tries to send data before headers.
|
|
|
|
%% @todo Same as above.
|
|
|
|
case lists:keyfind(StreamID, #stream.id, Streams) of
|
|
|
|
#stream{version='HTTP/1.1'} ->
|
2017-10-21 21:01:40 +01:00
|
|
|
Transport:send(Socket, [
|
|
|
|
integer_to_binary(Size, 16), <<"\r\n">>, Data,
|
|
|
|
case IsFin of
|
|
|
|
fin -> <<"\r\n0\r\n\r\n">>;
|
|
|
|
nofin -> <<"\r\n">>
|
|
|
|
end
|
|
|
|
]);
|
2017-01-20 15:16:50 +01:00
|
|
|
#stream{version='HTTP/1.0'} ->
|
|
|
|
Transport:send(Socket, Data)
|
|
|
|
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
|
|
|
end,
|
2017-10-20 13:16:04 +01:00
|
|
|
State = case IsFin of
|
|
|
|
fin -> State0#state{out_state=done};
|
|
|
|
nofin -> State0
|
|
|
|
end,
|
|
|
|
commands(State, StreamID, Tail);
|
2017-11-15 14:58:49 +01:00
|
|
|
%% Send trailers.
|
|
|
|
commands(State=#state{socket=Socket, transport=Transport, streams=Streams}, StreamID,
|
|
|
|
[{trailers, Trailers}|Tail]) ->
|
|
|
|
TE = case lists:keyfind(StreamID, #stream.id, Streams) of
|
|
|
|
%% HTTP/1.0 doesn't support chunked transfer-encoding.
|
|
|
|
#stream{version='HTTP/1.0'} ->
|
|
|
|
not_chunked;
|
|
|
|
%% No TE header was sent.
|
|
|
|
#stream{te=undefined} ->
|
|
|
|
no_trailers;
|
|
|
|
#stream{te=TE0} ->
|
|
|
|
try cow_http_hd:parse_te(TE0) of
|
|
|
|
{TE1, _} -> TE1
|
|
|
|
catch _:_ ->
|
|
|
|
%% If we can't parse the TE header, assume we can't send trailers.
|
|
|
|
no_trailers
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
case TE of
|
|
|
|
trailers ->
|
|
|
|
Transport:send(Socket, [
|
|
|
|
<<"0\r\n">>,
|
|
|
|
cow_http:headers(maps:to_list(Trailers)),
|
|
|
|
<<"\r\n">>
|
|
|
|
]);
|
|
|
|
no_trailers ->
|
|
|
|
Transport:send(Socket, <<"0\r\n\r\n">>);
|
|
|
|
not_chunked ->
|
|
|
|
ok
|
|
|
|
end,
|
|
|
|
commands(State#state{out_state=done}, StreamID, Tail);
|
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
|
|
|
%% Send a file.
|
2017-10-20 13:16:04 +01:00
|
|
|
commands(State0=#state{socket=Socket, transport=Transport}, StreamID,
|
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
|
|
|
[{sendfile, IsFin, Offset, Bytes, Path}|Tail]) ->
|
|
|
|
Transport:sendfile(Socket, Path, Offset, Bytes),
|
2017-10-20 13:16:04 +01:00
|
|
|
State = case IsFin of
|
|
|
|
fin -> State0#state{out_state=done};
|
|
|
|
nofin -> State0
|
|
|
|
end,
|
|
|
|
commands(State, StreamID, Tail);
|
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
|
|
|
%% Protocol takeover.
|
|
|
|
commands(State0=#state{ref=Ref, parent=Parent, socket=Socket, transport=Transport,
|
|
|
|
opts=Opts, children=Children}, StreamID,
|
|
|
|
[{switch_protocol, Headers, Protocol, InitialState}|_Tail]) ->
|
|
|
|
%% @todo This should be the last stream running otherwise we need to wait before switching.
|
|
|
|
%% @todo If there's streams opened after this one, fail instead of 101.
|
2017-10-31 22:36:37 +00:00
|
|
|
State = cancel_timeout(State0),
|
2017-11-13 18:03:25 +01:00
|
|
|
%% Before we send the 101 response we need to stop receiving data
|
|
|
|
%% from the socket, otherwise the data might be receive before the
|
|
|
|
%% call to flush/0 and we end up inadvertently dropping a packet.
|
|
|
|
%%
|
|
|
|
%% @todo Handle cases where the request came with a body. We need
|
|
|
|
%% to process or skip the body before the upgrade can be completed.
|
|
|
|
Transport:setopts(Socket, [{active, false}]),
|
2017-10-22 14:53:04 +01:00
|
|
|
%% Send a 101 response, then terminate the stream.
|
2017-10-31 22:36:37 +00:00
|
|
|
#state{streams=Streams} = info(State, StreamID, {inform, 101, Headers}),
|
2017-10-22 14:53:04 +01:00
|
|
|
#stream{state=StreamState} = lists:keyfind(StreamID, #stream.id, Streams),
|
|
|
|
%% @todo We need to shutdown processes here first.
|
|
|
|
stream_call_terminate(StreamID, switch_protocol, StreamState),
|
|
|
|
%% Terminate children processes and flush any remaining messages from the mailbox.
|
2017-08-08 16:59:33 +02:00
|
|
|
cowboy_children:terminate(Children),
|
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
|
|
|
flush(),
|
|
|
|
%% @todo This is no good because commands return a state normally and here it doesn't
|
|
|
|
%% we need to let this module go entirely. Perhaps it should be handled directly in
|
2017-10-22 14:53:04 +01:00
|
|
|
%% cowboy_clear/cowboy_tls?
|
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
|
|
|
Protocol:takeover(Parent, Ref, Socket, Transport, Opts, <<>>, InitialState);
|
|
|
|
%% Stream shutdown.
|
|
|
|
commands(State, StreamID, [stop|Tail]) ->
|
|
|
|
%% @todo Do we want to run the commands after a stop?
|
2017-10-20 13:16:04 +01:00
|
|
|
%% @todo We currently wait for the stop command before we
|
|
|
|
%% continue with the next request/response. In theory, if
|
|
|
|
%% the request body was read fully and the response body
|
|
|
|
%% was sent fully we should be able to start working on
|
|
|
|
%% the next request concurrently. This can be done as a
|
|
|
|
%% future optimization.
|
|
|
|
maybe_terminate(State, StreamID, Tail);
|
2016-08-10 11:49:31 +02:00
|
|
|
%% HTTP/1.1 does not support push; ignore.
|
|
|
|
commands(State, StreamID, [{push, _, _, _, _, _, _, _}|Tail]) ->
|
|
|
|
commands(State, StreamID, Tail).
|
|
|
|
|
|
|
|
%% The set-cookie header is special; we can only send one cookie per header.
|
|
|
|
headers_to_list(Headers0=#{<<"set-cookie">> := SetCookies}) ->
|
|
|
|
Headers1 = maps:to_list(maps:remove(<<"set-cookie">>, Headers0)),
|
|
|
|
Headers1 ++ [{<<"set-cookie">>, Value} || Value <- SetCookies];
|
|
|
|
headers_to_list(Headers) ->
|
|
|
|
maps:to_list(Headers).
|
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
|
|
|
|
|
|
|
flush() ->
|
|
|
|
receive _ -> flush() after 0 -> ok end.
|
|
|
|
|
|
|
|
%% @todo In these cases I'm not sure if we should continue processing commands.
|
2017-10-20 13:16:04 +01:00
|
|
|
maybe_terminate(State=#state{last_streamid=StreamID}, StreamID, _Tail) ->
|
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
|
|
|
terminate(stream_terminate(State, StreamID, normal), normal); %% @todo Reason ok?
|
2017-10-20 13:16:04 +01:00
|
|
|
maybe_terminate(State, StreamID, _Tail) ->
|
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
|
|
|
stream_terminate(State, StreamID, normal).
|
|
|
|
|
2016-06-06 17:26:00 +02:00
|
|
|
stream_reset(State, StreamID, StreamError={internal_error, _, _}) ->
|
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
|
|
|
%% @todo headers
|
|
|
|
%% @todo Don't send this if there are no streams left.
|
2016-06-06 17:26:00 +02:00
|
|
|
% Transport:send(Socket, cow_http:response(500, 'HTTP/1.1', [
|
|
|
|
% {<<"content-length">>, <<"0">>}
|
|
|
|
% ])),
|
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
|
|
|
%% @todo update IsFin local
|
2016-06-06 17:26:00 +02:00
|
|
|
% stream_terminate(State#state{out_state=done}, StreamID, StreamError).
|
|
|
|
stream_terminate(State, StreamID, StreamError).
|
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-11-01 15:33:10 +00:00
|
|
|
stream_terminate(State0=#state{out_streamid=OutStreamID, out_state=OutState,
|
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
|
|
|
streams=Streams0, children=Children0}, StreamID, Reason) ->
|
2017-10-21 13:09:20 +01:00
|
|
|
#stream{version=Version} = lists:keyfind(StreamID, #stream.id, Streams0),
|
|
|
|
State1 = #state{streams=Streams1} = case OutState of
|
2017-09-27 14:17:27 +02:00
|
|
|
wait when element(1, Reason) =:= internal_error ->
|
|
|
|
info(State0, StreamID, {response, 500, #{<<"content-length">> => <<"0">>}, <<>>});
|
2017-11-22 15:39:39 +01:00
|
|
|
wait when element(1, Reason) =:= connection_error ->
|
|
|
|
info(State0, StreamID, {response, 400, #{<<"content-length">> => <<"0">>}, <<>>});
|
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
|
|
|
wait ->
|
2017-04-18 16:07:01 +02:00
|
|
|
info(State0, StreamID, {response, 204, #{}, <<>>});
|
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
|
|
|
chunked when Version =:= 'HTTP/1.1' ->
|
2017-11-01 15:33:10 +00:00
|
|
|
info(State0, StreamID, {data, fin, <<>>});
|
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
|
|
|
_ -> %% done or Version =:= 'HTTP/1.0'
|
2017-04-18 16:07:01 +02:00
|
|
|
State0
|
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,
|
2017-10-21 13:09:20 +01:00
|
|
|
%% Remove the stream from the state.
|
|
|
|
{value, #stream{state=StreamState}, Streams}
|
|
|
|
= lists:keytake(StreamID, #stream.id, Streams1),
|
|
|
|
State2 = State1#state{streams=Streams},
|
|
|
|
%% Stop the stream.
|
|
|
|
stream_call_terminate(StreamID, Reason, StreamState),
|
|
|
|
Children = cowboy_children:shutdown(Children0, StreamID),
|
2017-05-03 17:44:00 +02:00
|
|
|
%% We reset the timeout if there are no active streams anymore.
|
|
|
|
State = case Streams of
|
2017-10-21 13:09:20 +01:00
|
|
|
[] -> set_timeout(State2);
|
|
|
|
_ -> State2
|
2017-05-03 17:44:00 +02:00
|
|
|
end,
|
2017-10-21 13:09:20 +01:00
|
|
|
%% Move on to the next 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
|
|
|
%% @todo Skip the body, if any, or drop the connection if too large.
|
|
|
|
%% @todo Only do this if Current =:= StreamID.
|
|
|
|
NextOutStreamID = OutStreamID + 1,
|
|
|
|
case lists:keyfind(NextOutStreamID, #stream.id, Streams) of
|
|
|
|
false ->
|
|
|
|
%% @todo This is clearly wrong, if the stream is gone we need to check if
|
|
|
|
%% there used to be such a stream, and if there was to send an error.
|
|
|
|
State#state{out_streamid=NextOutStreamID, out_state=wait, streams=Streams, children=Children};
|
|
|
|
#stream{queue=Commands} ->
|
|
|
|
%% @todo Remove queue from the stream.
|
|
|
|
commands(State#state{out_streamid=NextOutStreamID, out_state=wait,
|
|
|
|
streams=Streams, children=Children}, NextOutStreamID, Commands)
|
|
|
|
end.
|
|
|
|
|
|
|
|
%% @todo Taken directly from _http2
|
2017-01-16 14:22:43 +01:00
|
|
|
stream_call_terminate(StreamID, Reason, StreamState) ->
|
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
|
|
|
try
|
2017-01-16 14:22:43 +01:00
|
|
|
cowboy_stream:terminate(StreamID, Reason, StreamState)
|
2017-09-21 12:53:21 +02:00
|
|
|
catch Class:Exception ->
|
|
|
|
cowboy_stream:report_error(terminate,
|
|
|
|
[StreamID, Reason, StreamState],
|
|
|
|
Class, Exception, erlang:get_stacktrace())
|
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.
|
|
|
|
|
|
|
|
%% @todo max_reqs also
|
|
|
|
maybe_req_close(_, #{<<"connection">> := Conn}, 'HTTP/1.0') ->
|
|
|
|
Conns = cow_http_hd:parse_connection(Conn),
|
|
|
|
case lists:member(<<"keep-alive">>, Conns) of
|
|
|
|
true -> keepalive;
|
|
|
|
false -> close
|
|
|
|
end;
|
|
|
|
maybe_req_close(_, _, 'HTTP/1.0') ->
|
|
|
|
close;
|
|
|
|
maybe_req_close(_, #{<<"connection">> := Conn}, 'HTTP/1.1') ->
|
|
|
|
case connection_hd_is_close(Conn) of
|
|
|
|
true -> close;
|
|
|
|
false -> keepalive
|
|
|
|
end;
|
|
|
|
maybe_req_close(_State, _, _) ->
|
|
|
|
keepalive.
|
|
|
|
|
|
|
|
connection(State=#state{last_streamid=StreamID}, Headers=#{<<"connection">> := Conn}, StreamID, _) ->
|
|
|
|
case connection_hd_is_close(Conn) of
|
|
|
|
true -> {State, Headers};
|
|
|
|
%% @todo Here we need to remove keep-alive and add close, not just add close.
|
|
|
|
false -> {State, Headers#{<<"connection">> => [<<"close, ">>, Conn]}}
|
|
|
|
end;
|
|
|
|
connection(State=#state{last_streamid=StreamID}, Headers, StreamID, _) ->
|
|
|
|
{State, Headers#{<<"connection">> => <<"close">>}};
|
|
|
|
connection(State, Headers=#{<<"connection">> := Conn}, StreamID, _) ->
|
|
|
|
case connection_hd_is_close(Conn) of
|
|
|
|
true -> {State#state{last_streamid=StreamID}, Headers};
|
|
|
|
%% @todo Here we need to set keep-alive only if it wasn't set before.
|
|
|
|
false -> {State, Headers}
|
|
|
|
end;
|
|
|
|
connection(State, Headers, _, 'HTTP/1.0') ->
|
|
|
|
{State, Headers#{<<"connection">> => <<"keep-alive">>}};
|
|
|
|
connection(State, Headers, _, _) ->
|
|
|
|
{State, Headers}.
|
|
|
|
|
|
|
|
connection_hd_is_close(Conn) ->
|
|
|
|
Conns = cow_http_hd:parse_connection(iolist_to_binary(Conn)),
|
|
|
|
lists:member(<<"close">>, Conns).
|
|
|
|
|
2017-03-27 10:26:13 +02:00
|
|
|
%% This function is only called when an error occurs on a new stream.
|
2017-01-02 18:27:03 +01:00
|
|
|
-spec error_terminate(cowboy:http_status(), #state{}, _) -> no_return().
|
2017-09-27 14:17:27 +02:00
|
|
|
error_terminate(StatusCode, State=#state{ref=Ref, peer=Peer, in_state=StreamState}, Reason) ->
|
2017-03-27 10:26:13 +02:00
|
|
|
PartialReq = case StreamState of
|
2017-11-20 16:26:37 +01:00
|
|
|
#ps_request_line{} -> #{
|
|
|
|
ref => Ref,
|
|
|
|
peer => Peer
|
|
|
|
};
|
2017-03-27 10:26:13 +02:00
|
|
|
#ps_header{method=Method, path=Path, qs=Qs,
|
|
|
|
version=Version, headers=ReqHeaders} -> #{
|
|
|
|
ref => Ref,
|
|
|
|
peer => Peer,
|
|
|
|
method => Method,
|
|
|
|
path => Path,
|
|
|
|
qs => Qs,
|
|
|
|
version => Version,
|
|
|
|
headers => case ReqHeaders of
|
|
|
|
undefined -> #{};
|
|
|
|
_ -> ReqHeaders
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end,
|
2017-09-27 14:17:27 +02:00
|
|
|
early_error(StatusCode, State, Reason, PartialReq),
|
|
|
|
terminate(State, Reason).
|
|
|
|
|
|
|
|
early_error(StatusCode0, #state{socket=Socket, transport=Transport,
|
|
|
|
opts=Opts, in_streamid=StreamID}, Reason, PartialReq) ->
|
|
|
|
Resp = {response, StatusCode0, RespHeaders0=#{<<"content-length">> => <<"0">>}, <<>>},
|
2017-09-21 12:53:21 +02:00
|
|
|
try cowboy_stream:early_error(StreamID, Reason, PartialReq, Resp, Opts) of
|
|
|
|
{response, StatusCode, RespHeaders, RespBody} ->
|
|
|
|
Transport:send(Socket, [
|
|
|
|
cow_http:response(StatusCode, 'HTTP/1.1', maps:to_list(RespHeaders)),
|
|
|
|
RespBody
|
|
|
|
])
|
|
|
|
catch Class:Exception ->
|
|
|
|
cowboy_stream:report_error(early_error,
|
|
|
|
[StreamID, Reason, PartialReq, Resp, Opts],
|
2017-09-27 14:17:27 +02:00
|
|
|
Class, Exception, erlang:get_stacktrace()),
|
|
|
|
%% We still need to send an error response, so send what we initially
|
|
|
|
%% wanted to send. It's better than nothing.
|
|
|
|
Transport:send(Socket, cow_http:response(StatusCode0,
|
|
|
|
'HTTP/1.1', maps:to_list(RespHeaders0)))
|
2017-09-21 12:53:21 +02:00
|
|
|
end,
|
2017-09-27 14:17:27 +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
|
|
|
|
2017-01-02 18:27:03 +01:00
|
|
|
-spec terminate(_, _) -> no_return().
|
2017-06-02 12:31:00 +02:00
|
|
|
terminate(undefined, Reason) ->
|
|
|
|
exit({shutdown, Reason});
|
|
|
|
terminate(#state{streams=Streams, children=Children}, Reason) ->
|
|
|
|
terminate_all_streams(Streams, Reason),
|
2017-08-08 16:59:33 +02:00
|
|
|
cowboy_children:terminate(Children),
|
|
|
|
exit({shutdown, Reason}).
|
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-06-02 12:31:00 +02:00
|
|
|
terminate_all_streams([], _) ->
|
|
|
|
ok;
|
|
|
|
terminate_all_streams([#stream{id=StreamID, state=StreamState}|Tail], Reason) ->
|
|
|
|
stream_call_terminate(StreamID, Reason, StreamState),
|
|
|
|
terminate_all_streams(Tail, Reason).
|
|
|
|
|
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
|
|
|
%% System callbacks.
|
|
|
|
|
2017-01-02 16:47:16 +01:00
|
|
|
-spec system_continue(_, _, {#state{}, binary()}) -> 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
|
|
|
system_continue(_, _, {State, Buffer}) ->
|
|
|
|
loop(State, Buffer).
|
|
|
|
|
2017-08-08 16:59:33 +02:00
|
|
|
-spec system_terminate(any(), _, _, {#state{}, binary()}) -> no_return().
|
|
|
|
system_terminate(Reason, _, _, {State, _}) ->
|
|
|
|
terminate(State, Reason).
|
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
|
|
|
|
|
|
|
-spec system_code_change(Misc, _, _, _) -> {ok, Misc} when Misc::{#state{}, binary()}.
|
|
|
|
system_code_change(Misc, _, _, _) ->
|
|
|
|
{ok, Misc}.
|