From f4705ecbb9b182e6eaad6b6af0c6fcc17b2251b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Mon, 9 Nov 2020 17:06:05 +0100 Subject: Add the gun_event manual --- doc/src/manual/gun_app.asciidoc | 1 + doc/src/manual/gun_event.asciidoc | 509 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 510 insertions(+) create mode 100644 doc/src/manual/gun_event.asciidoc (limited to 'doc') diff --git a/doc/src/manual/gun_app.asciidoc b/doc/src/manual/gun_app.asciidoc index 6ebbfe8..168d0e9 100644 --- a/doc/src/manual/gun_app.asciidoc +++ b/doc/src/manual/gun_app.asciidoc @@ -18,6 +18,7 @@ to the server and reconnects automatically when necessary. * link:man:gun(3)[gun(3)] - Asynchronous HTTP client * link:man:gun_cookies(3)[gun_cookies(3)] - Cookie store engine * link:man:gun_cookies_list(3)[gun_cookies_list(3)] - Cookie store backend: in-memory, per connection +* link:man:gun_event(3)[gun_event(3)] - Events == Dependencies diff --git a/doc/src/manual/gun_event.asciidoc b/doc/src/manual/gun_event.asciidoc new file mode 100644 index 0000000..c58ac8e --- /dev/null +++ b/doc/src/manual/gun_event.asciidoc @@ -0,0 +1,509 @@ += gun_event(3) + +== Name + +gun_event - Events + +== Description + +The `gun_event` module provides the callback interface +and types for implementing event handlers. + +== Callbacks + +Event handlers implement the following interface. +Because types are tied to specific events, they +are documented alongside them. All event types +are exported and can be referred to as `gun_event:Type()`. + +The events are ordered by the order they are likely +to be triggered, with the most frequent events listed +first. + +=== init + +[source,erlang] +---- +init_event() :: #{ + owner := pid(), + transport := tcp | tls, + origin_scheme := binary(), + origin_host := inet:hostname() | inet:ip_address(), + origin_port := inet:port_number(), + opts := gun:opts() +} + +init(init_event(), State) -> State +---- + +Gun is initializing. + +=== domain_lookup_start + +[source,erlang] +---- +domain_lookup_event() :: #{ + host := inet:hostname() | inet:ip_address(), + port := inet:port_number(), + tcp_opts := [gen_tcp:connect_option()], + timeout := timeout(), + lookup_info => gun_tcp:lookup_info(), + error => any() +} + +domain_lookup_start(domain_lookup_event(), State) -> State +---- + +Gun is starting to resolve the host address. + +The `lookup_info` and `error` keys are never set +for this event. + +=== domain_lookup_end + +[source,erlang] +---- +domain_lookup_end(domain_lookup_event(), State) -> State +---- + +Gun has finished resolving the host address. + +The `lookup_info` key is only set when the lookup is +successful. The `error` key is set otherwise. + +=== connect_start + +[source,erlang] +---- +connect_event() :: #{ + lookup_info := gun_tcp:lookup_info(), + timeout := timeout(), + socket => inet:socket(), + protocol => http | http2 | socks | raw, + error => any() +} + +connect_start(connect_event(), State) -> State +---- + +Gun is starting to connect to the host address and port. + +The `socket`, `protocol` and `error` keys are never set +for this event. + +=== connect_end + +[source,erlang] +---- +connect_end(connect_event(), State) -> State +---- + +Gun has finished connecting to the host address and port. + +The `socket` key is set on connect success. The `error` +key is set otherwise. + +The `protocol` key is only set when the transport is +`tcp` and the connection is successful. The protocol +is only known in the `tls_handshake_end` event otherwise. + +=== tls_handshake_start + +[source,erlang] +---- +tls_handshake_event() :: #{ + stream_ref => gun:stream_ref(), + reply_to => pid(), + socket := inet:socket() | ssl:sslsocket() | pid(), %% The socket before/after will be different. + tls_opts := [ssl:tls_client_option()], + timeout := timeout(), + protocol => http | http2 | socks | raw, + error => any() +} + +tls_handshake_start(tls_handshake_event(), State) -> State +---- + +Gun has started a TLS handshake. + +This and the `tls_handshake_end` event only occur when +connecting to a TLS server or when upgrading the connection +or a stream to use TLS, for example when using CONNECT or +when connecting to a secure SOCKS server. + +The `stream_ref` and `reply_to` keys are only set when the +TLS handshake occurs as a result of a CONNECT request or +inside an existing CONNECT tunnel. + +The `protocol` and `error` keys are never set for this event. + +=== tls_handshake_end + +[source,erlang] +---- +tls_handshake_end(tls_handshake_event(), State) -> State +---- + +Gun has finished a TLS handshake. + +The `protocol` key is set on TLS handshake success. The +`error` key is set otherwise. + +=== request_start + +[source,erlang] +---- +request_start_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + function := headers | request | ws_upgrade | connect, + method := iodata(), + scheme => binary(), + authority := iodata(), + path => iodata(), + headers := [{binary(), iodata()}] +} + +request_start(request_start_event(), State) -> State +---- + +Gun is starting to send a request. + +The `scheme` and `path` keys are never set when the `function` +is set to `connect`. + +=== request_headers + +[source,erlang] +---- +request_headers(request_start_event(), State) -> State +---- + +Gun has finished sending the request headers. + +=== request_end + +[source,erlang] +---- +request_end_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid() +} + +request_end(request_end_event(), State) -> State +---- + +Gun has finished sending the request. + +=== push_promise_start + +[source,erlang] +---- +push_promise_start_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid() +} + +push_promise_start(push_promise_start_event(), State) -> State +---- + +Gun has begun receiving a promised request (server push). + +=== push_promise_end + +[source,erlang] +---- +push_promise_end_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + promised_stream_ref => gun:stream_ref(), + method := binary(), + uri := binary(), + headers := [{binary(), iodata()}] +} + +push_promise_end(push_promise_end_event(), State) -> State +---- + +Gun has finished receiving a promised request (server push). +Promised requests never include a body. + +Promised requests received during the graceful shutdown of the +connection get canceled immediately. + +// @todo The cancel event should probably trigger as well. + +=== response_start + +[source,erlang] +---- +response_start_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid() +} + +response_start(response_start_event(), State) -> State +---- + +Gun has begun receiving a response. + +=== response_inform + +[source,erlang] +---- +response_headers_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + status := non_neg_integer(), + headers := [{binary(), binary()}] +} + +response_inform(response_headers_event(), State) -> State +---- + +Gun has received an informational response (1xx status code). + +A `status` with value 101 indicates that the response has +concluded as the stream will be upgraded to a new protocol. + +=== response_headers + +[source,erlang] +---- +response_headers(response_headers_event(), State) -> State +---- + +Gun has finished receiving response headers. + +=== response_trailers + +[source,erlang] +---- +response_trailers_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + headers := [{binary(), binary()}] +} + +response_trailers(response_trailers_event(), State) -> State +---- + +Gun has received response trailers. + +=== response_end + +[source,erlang] +---- +response_end_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid() +} + +response_end(response_end_event(), State) -> State +---- + +Gun has finished receiving a response. + +=== ws_upgrade + +[source,erlang] +---- +ws_upgrade_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + opts := gun:ws_opts() +} + +ws_upgrade(ws_upgrade_event(), State) -> State +---- + +A Websocket upgrade was requested. + +Success is indicated by a response (101 informational +if HTTP/1.1, 2xx if HTTP/2) followed by a `protocol_changed` +event. + +=== ws_recv_frame_start + +[source,erlang] +---- +ws_recv_frame_start_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + frag_state := cow_ws:frag_state(), + extensions := cow_ws:extensions() +} + +ws_recv_frame_start(ws_recv_frame_start_event(), State) -> State +---- + +Gun has begun receiving a Websocket frame. + +=== ws_recv_frame_header + +[source,erlang] +---- +ws_recv_frame_header_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + frag_state := cow_ws:frag_state(), + extensions := cow_ws:extensions(), + type := cow_ws:frame_type(), + rsv := cow_ws:rsv(), + len := non_neg_integer(), + mask_key := cow_ws:mask_key() +} + +ws_recv_frame_header(ws_recv_frame_header_event(), State) -> State +---- + +Gun has received the header part of a Websocket frame. + +It will be immediately be followed by the frame's payload. + +=== ws_recv_frame_end + +[source,erlang] +---- +ws_recv_frame_end_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + extensions := cow_ws:extensions(), + close_code := undefined | cow_ws:close_code(), + payload := binary() +} + +ws_recv_frame_end(ws_recv_frame_end_event(), State) -> State +---- + +Gun has finished receiving a Websocket frame. + +=== ws_send_frame_start + +[source,erlang] +---- +ws_send_frame_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + extensions := cow_ws:extensions(), + frame := gun:ws_frame() +} + +ws_send_frame_start(ws_send_frame_event(), State) -> State +---- + +Gun has started sending a Websocket frame. + +=== ws_send_frame_end + +[source,erlang] +---- +ws_send_frame_end(ws_send_frame_event(), State) -> State +---- + +Gun has finished sending a Websocket frame. + +=== protocol_changed + +[source,erlang] +---- +protocol_changed_event() :: #{ + stream_ref := gun:stream_ref(), + protocol := http | http2 | socks | raw | ws +} + +protocol_changed(protocol_changed_event(), State) -> State +---- + +The protocol has changed for either the entire Gun connection +or for a specific stream. + +The `stream_ref` key is only set when the protocol has +changed for a specific stream or inside a CONNECT tunnel. + +This event occurs during successful Websocket upgrades, +as a result of successful CONNECT requests or after a +SOCKS tunnel was successfully established. + +=== origin_changed + +[source,erlang] +---- +origin_changed_event() :: #{ + stream_ref => gun:stream_ref(), + type := connect | socks5, + origin_scheme := binary(), + origin_host := inet:hostname() | inet:ip_address(), + origin_port := inet:port_number() +} + +origin_changed(origin_changed_event(), State) -> State +---- + +The origin server has changed for either the Gun connection +or for a specific stream. + +The `stream_ref` key is only set when the origin has +changed for a specific stream or inside a CONNECT tunnel. + +=== cancel + +[source,erlang] +---- +cancel_event() :: #{ + stream_ref := gun:stream_ref(), + reply_to := pid(), + endpoint := local | remote, + reason := atom() +} + +cancel(cancel_event(), State) -> State +---- + +A stream has been canceled. + +HTTP/1.1 streams can't be canceled at the protocol level. In +this case Gun will silence the stream for the user but events +may still occur. + +HTTP/2 streams can be canceled both by the client and the +server. Events may still occur for a short time after the +stream has been canceled. + +=== disconnect + +[source,erlang] +---- +disconnect_event() :: #{ + reason := normal | closed | {error, any()} +} + +disconnect(disconnect_event(), State) -> State +---- + +Gun has been disconnected from the server. + +=== terminate + +[source,erlang] +---- +terminate_event() :: #{ + state := not_connected + | domain_lookup | connecting | initial_tls_handshake | tls_handshake + | connected | connected_data_only | connected_ws_only, + reason := normal | shutdown | {shutdown, any()} | any() +} + +terminate(terminate_event(), State) -> State +---- + +Gun is terminating. + +== Changelog + +* *2.0*: Module introduced. + +== See also + +link:man:gun(7)[gun(7)], +link:man:gun(3)[gun(3)] -- cgit v1.2.3