123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- = cowboy_stream(3)
- == Name
- cowboy_stream - Stream handlers
- == Description
- The module `cowboy_stream` defines a callback interface
- and a protocol for handling HTTP streams.
- An HTTP request and its associated response is called
- a stream. A connection may have many streams. In HTTP/1.1
- they are executed sequentially, while in HTTP/2 they are
- executed concurrently.
- Cowboy calls the stream handler for nearly all events
- related to a stream. Exceptions vary depending on the
- protocol.
- Extra care must be taken when implementing stream handlers
- to ensure compatibility. While some modification of the
- events and commands is allowed, it is generally not a good
- idea to completely discard them.
- == Callbacks
- Stream handlers must implement the following interface:
- [source,erlang]
- ----
- init(StreamID, Req, Opts) -> {Commands, State}
- data(StreamID, IsFin, Data, State) -> {Commands, State}
- info(StreamID, Info, State) -> {Commands, State}
- terminate(StreamID, Reason, State) -> any()
- early_error(StreamID, Reason, PartialReq, Resp, Opts) -> Resp
- StreamID :: cowboy_stream:streamid()
- Req :: cowboy_req:req()
- Opts :: cowboy:opts()
- Commands :: cowboy_stream:commands()
- State :: any()
- IsFin :: cowboy_stream:fin()
- Data :: binary()
- Info :: any()
- Reason :: cowboy_stream:reason()
- PartialReq - cowboy_req:req(), except all fields are optional
- Resp :: cowboy_stream:resp_command()
- ----
- HTTP/1.1 will initialize a stream only when the request-line
- and all headers have been received. When errors occur before
- that point Cowboy will call the callback `early_error/5`
- with a partial request, the error reason and the response
- Cowboy intends to send. All other events go throuh the
- stream handler using the normal callbacks.
- HTTP/2 will initialize the stream when the `HEADERS` block has
- been fully received and decoded. Any protocol error occuring
- before that will not result in a response being sent and
- will therefore not go through the stream handler. In addition
- Cowboy may terminate streams without sending an HTTP response
- back.
- The stream is initialized by calling `init/3`. All streams
- that are initialized will eventually be terminated by calling
- `terminate/3`.
- When Cowboy receives data for the stream it will call `data/4`.
- The data given is the request body after any transfer decoding
- has been applied.
- When Cowboy receives a message addressed to a stream, or when
- Cowboy needs to inform the stream handler that an internal
- event has occurred, it will call `info/3`.
- [[commands]]
- == Commands
- Stream handlers can return a list of commands to be executed
- from the `init/3`, `data/4` and `info/3` callbacks. In addition,
- the `early_error/5` callback must return a response command.
- // @todo The logger option and the {log, Level, Format, Args}
- // options need to be documented and tested.
- The following commands are defined:
- [[inform_command]]
- === inform
- Send an informational response to the client.
- [source,erlang]
- ----
- {inform, cowboy:http_status(), cowboy:http_headers()}
- ----
- Any number of informational responses may be sent,
- but only until the final response is sent.
- [[response_command]]
- === response
- Send a response to the client.
- [source,erlang]
- ----
- {response, cowboy:http_status(), cowboy:http_headers(),
- cowboy_req:resp_body()}
- ----
- No more data can be sent after this command.
- Note that in Cowboy it is the `cowboy_req` module that
- sets the date and server headers. When using the command
- directly those headers will not be added.
- [[headers_command]]
- === headers
- Initiate a response to the client.
- [source,erlang]
- ----
- {headers, cowboy:http_status(), cowboy:http_headers()}
- ----
- This initiates a response to the client. The stream
- will end when a data command with the `fin` flag or
- a trailer command is returned.
- Note that in Cowboy it is the `cowboy_req` module that
- sets the date and server headers. When using the command
- directly those headers will not be added.
- [[data_command]]
- === data
- Send data to the client.
- [source,erlang]
- ----
- {data, fin(), cowboy_req:resp_body()}
- ----
- [[trailers_command]]
- === trailers
- Send response trailers to the client.
- [source,erlang]
- ----
- {trailers, cowboy:http_headers()}
- ----
- [[push_command]]
- === push
- Push a resource to the client.
- [source,erlang]
- ----
- {push, Method, Scheme, Host, inet:port_number(),
- Path, Qs, cowboy:http_headers()}
- Method = Scheme = Host = Path = Qs = binary()
- ----
- The command will be ignored if the protocol does not provide
- any server push mechanism.
- === flow
- [source,erlang]
- ----
- {flow, pos_integer()}
- ----
- Request more data to be read from the request body. The
- exact behavior depends on the protocol.
- === spawn
- Inform Cowboy that a process was spawned and should be
- supervised.
- [source,erlang]
- ----
- {spawn, pid(), timeout()}
- ----
- === error_response
- Send an error response if no response was sent previously.
- [source,erlang]
- ----
- {error_response, cowboy:http_status(), cowboy:http_headers(), iodata()}
- ----
- [[switch_protocol_command]]
- === switch_protocol
- Switch to a different protocol.
- [source,erlang]
- ----
- {switch_protocol, cowboy:http_headers(), module(), state()}
- ----
- Contains the headers that will be sent in the 101 response,
- along with the module implementing the protocol we are
- switching to and its initial state.
- Note that the 101 informational response will not be sent
- after a final response.
- === stop
- Stop the stream.
- [source,erlang]
- ----
- stop
- ----
- While no more data can be sent after the `fin` flag was set,
- the stream is still tracked by Cowboy until it is stopped by
- the handler.
- The behavior when stopping a stream for which no response
- has been sent will vary depending on the protocol. The stream
- will end successfully as far as the client is concerned.
- To indicate that an error occurred, either use `error_response`
- before stopping, or use `internal_error`.
- === internal_error
- Stop the stream with an error.
- [source,erlang]
- ----
- {internal_error, Reason, HumanReadable}
- Reason = any()
- HumanReadable = atom()
- ----
- This command should be used when the stream cannot continue
- because of an internal error. An `error_response` command
- may be sent before that to advertise to the client why the
- stream is dropped.
- === log
- Log a message.
- [source,erlang]
- ----
- {log, logger:level(), io:format(), list()}
- ----
- This command can be used to log a message using the
- configured `logger` module.
- === set_options
- Set protocol options.
- [source,erlang]
- ----
- {set_options, map()}
- ----
- This can also be used to override stream handler
- options. For example this is supported by
- link:man:cowboy_compress_h(3)[cowboy_compress_h(3)].
- Not all options can be overriden. Please consult the
- relevant option's documentation for details.
- == Predefined events
- Cowboy will forward all messages sent to the stream to
- the `info/3` callback. To send a message to a stream,
- the function link:man:cowboy_req:cast(3)[cowboy_req:cast(3)]
- can be used.
- Cowboy will also forward the exit signals for the
- processes that the stream spawned.
- When Cowboy needs to send a response it will trigger
- an event that looks exactly like the corresponding
- command. This event must be returned to be processed
- by Cowboy (which is done automatically when using
- link:man:cowboy_stream_h(3)[cowboy_stream_h(3)]).
- Cowboy may trigger the following events on its own,
- regardless of the stream handlers configured:
- xref:inform_command[inform] (to send a 101
- informational response when upgrading to HTTP/2 or
- Websocket), xref:response_command[response],
- xref:headers_command[headers], xref:data_command[data]
- and xref:switch_protocol_command[switch_protocol].
- == Exports
- The following function should be called by modules implementing
- stream handlers to execute the next stream handler in the list:
- * link:man:cowboy_stream:init(3)[cowboy_stream:init(3)] - Initialize a stream
- * link:man:cowboy_stream:data(3)[cowboy_stream:data(3)] - Handle data for a stream
- * link:man:cowboy_stream:info(3)[cowboy_stream:info(3)] - Handle a message for a stream
- * link:man:cowboy_stream:terminate(3)[cowboy_stream:terminate(3)] - Terminate a stream
- * link:man:cowboy_stream:early_error(3)[cowboy_stream:early_error(3)] - Handle an early error for a stream
- == Types
- === commands()
- [source,erlang]
- ----
- commands() :: [Command]
- ----
- See the xref:commands[list of commands] for details.
- === fin()
- [source,erlang]
- ----
- fin() :: fin | nofin
- ----
- Used in commands and events to indicate that this is
- the end of the stream.
- === partial_req()
- [source,erlang]
- ----
- req() :: #{
- method => binary(), %% case sensitive
- version => cowboy:http_version() | atom(),
- scheme => binary(), %% lowercase; case insensitive
- host => binary(), %% lowercase; case insensitive
- port => inet:port_number(),
- path => binary(), %% case sensitive
- qs => binary(), %% case sensitive
- headers => cowboy:http_headers(),
- peer => {inet:ip_address(), inet:port_number()}
- }
- ----
- Partial request information received when an early error is
- detected.
- === reason()
- [source,erlang]
- ----
- reason() :: normal | switch_protocol
- | {internal_error, timeout | {error | exit | throw, any()}, HumanReadable}
- | {socket_error, closed | atom(), HumanReadable}
- | {stream_error, Error, HumanReadable}
- | {connection_error, Error, HumanReadable}
- | {stop, cow_http2:frame() | {exit, any()}, HumanReadable}
- Error = atom()
- HumanReadable = atom()
- ----
- Reason for the stream termination.
- === resp_command()
- [source,erlang]
- ----
- resp_command() :: {response, cowboy:http_status(),
- cowboy:http_headers(), cowboy_req:resp_body()}
- ----
- See the xref:response_command[response command] for details.
- === streamid()
- [source,erlang]
- ----
- streamid() :: any()
- ----
- The identifier for this stream.
- The identifier is unique over the connection process.
- It is possible to form a unique identifier node-wide and
- cluster-wide by wrapping it in a `{self(), StreamID}`
- tuple.
- == Changelog
- * *2.7*: The `log` and `set_options` commands were introduced.
- * *2.6*: The `data` command can now contain a sendfile tuple.
- * *2.6*: The `{stop, {exit, any()}, HumanReadable}` terminate reason was added.
- * *2.2*: The `trailers` command was introduced.
- * *2.0*: Module introduced.
- == See also
- link:man:cowboy(7)[cowboy(7)],
- link:man:cowboy_http(3)[cowboy_http(3)],
- link:man:cowboy_http2(3)[cowboy_http2(3)],
- link:man:cowboy_req:cast(3)[cowboy_req:cast(3)]
|