aboutsummaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/src/guide/book.asciidoc16
-rw-r--r--doc/src/guide/connect.asciidoc119
-rw-r--r--doc/src/guide/http.asciidoc367
-rw-r--r--doc/src/guide/introduction.asciidoc28
-rw-r--r--doc/src/guide/protocols.asciidoc119
-rw-r--r--doc/src/guide/start.asciidoc67
-rw-r--r--doc/src/guide/websocket.asciidoc100
-rw-r--r--doc/src/manual/gun.asciidoc578
-rw-r--r--doc/src/manual/gun_app.asciidoc24
9 files changed, 1418 insertions, 0 deletions
diff --git a/doc/src/guide/book.asciidoc b/doc/src/guide/book.asciidoc
new file mode 100644
index 0000000..7e6a441
--- /dev/null
+++ b/doc/src/guide/book.asciidoc
@@ -0,0 +1,16 @@
+// a2x: --dblatex-opts "-P latex.output.revhistory=0 -P doc.publisher.show=0 -P index.numbered=0"
+// a2x: -d book --attribute tabsize=4
+
+= Gun User Guide
+
+include::introduction.asciidoc[Introduction]
+
+include::start.asciidoc[Starting and stopping]
+
+include::protocols.asciidoc[Supported protocols]
+
+include::connect.asciidoc[Connection]
+
+include::http.asciidoc[Using HTTP]
+
+include::websocket.asciidoc[Using Websocket]
diff --git a/doc/src/guide/connect.asciidoc b/doc/src/guide/connect.asciidoc
new file mode 100644
index 0000000..e1ad56e
--- /dev/null
+++ b/doc/src/guide/connect.asciidoc
@@ -0,0 +1,119 @@
+== Connection
+
+This chapter describes how to open, monitor and close
+a connection using the Gun client.
+
+=== Gun connections
+
+Gun is designed with the SPDY and Websocket protocols in mind.
+They are built for long-running connections that allow concurrent
+exchange of data, either in the form of request/responses for
+SPDY or in the form of messages for Websocket.
+
+A Gun connection is an Erlang process that manages a socket to
+a remote endpoint. This Gun connection is owned by a user
+process that is called the _owner_ of the connection, and is
+managed by the supervision tree of the `gun` application.
+
+The owner process communicates with the Gun connection
+by calling functions from the module `gun`. All functions
+perform their respective operations asynchronously. The Gun
+connection will send Erlang messages to the owner process
+whenever needed.
+
+When the remote endpoint closes the connection, Gun attempts
+to reconnect automatically.
+
+=== Opening a new connection
+
+The `gun:open/{2,3}` function must be used to open a connection.
+
+.Opening a connection to example.org on port 443
+
+[source,erlang]
+{ok, ConnPid} = gun:open("example.org", 443).
+
+@todo open/3
+@todo make opts a map
+
+If the port given is 80, Gun will attempt to connect using
+TCP and use the HTTP/1.1 protocol. For any other port, TLS
+will be used. The NPN extension for TLS allows Gun to select
+SPDY automatically if the server supports it. Otherwise,
+HTTP/1.1 will be used.
+
+@todo more about defaults
+
+=== Monitoring the connection process
+
+@todo Gun should detect the owner process being killed
+
+Because software errors are unavoidable, it is important to
+detect when the Gun process crashes. It is also important
+to detect when it exits normally. Erlang provides two ways
+to do that: links and monitors.
+
+Gun leaves you the choice as to which one will be used.
+However, if you use the `gun:await/{2,3}` or `gun:await_body/{2,3}`
+functions, a monitor may be used for you to avoid getting
+stuck waiting for a message that will never come.
+
+If you choose to monitor yourself you can do it on a permanent
+basis rather than on every message you will receive, saving
+resources. Indeed, the `gun:await/{3,4}` and `gun:await_body/{3,4}`
+functions both accept a monitor argument if you have one already.
+
+.Monitoring the connection process
+
+[source,erlang]
+{ok, ConnPid} = gun:open("example.org", 443).
+MRef = monitor(process, ConnPid).
+
+This monitor reference can be kept and used until the connection
+process exits.
+
+.Handling `DOWN` messages
+
+[source,erlang]
+receive
+ %% Receive Gun messages here...
+ {DOWN', Mref, process, ConnPid, Reason} ->
+ error_logger:error_msg("Oops!"),
+ exit(Reason);
+end.
+
+What to do when you receive a `DOWN` message is entirely up to you.
+
+=== Closing the connection abruptly
+
+The connection can be stopped abruptly at any time by calling
+the `gun:close/1` function.
+
+.Immediate closing of the connection
+
+[source,erlang]
+gun:close(ConnPid).
+
+The process is stopped immediately without having a chance to
+perform the protocol's closing handshake, if any.
+
+=== Closing the connection gracefully
+
+The connection can also be stopped gracefully by calling the
+`gun:shutdown/1` function.
+
+.Graceful shutdown of the connection
+
+[source,erlang]
+gun:shutdown(ConnPid).
+
+Gun will refuse any new requests or messages after you call
+this function. It will however continue to send you messages
+for existing streams until they are all completed.
+
+For example if you performed a GET request just before calling
+`gun:shutdown/1`, you will still receive the response before
+Gun closes the connection.
+
+If you set a monitor beforehand, you will receive a message
+when the connection has been closed.
diff --git a/doc/src/guide/http.asciidoc b/doc/src/guide/http.asciidoc
new file mode 100644
index 0000000..5a69fa1
--- /dev/null
+++ b/doc/src/guide/http.asciidoc
@@ -0,0 +1,367 @@
+== HTTP
+
+This chapter describes how to use the Gun client for
+communicating with an HTTP/1.1 or SPDY server.
+
+=== Streams
+
+Every time a request is initiated, Gun creates a _stream_.
+A _stream reference_ uniquely identifies a set of request and
+response(s) and must be used to perform additional operations
+with a stream or to identify its messages.
+
+Stream references use the Erlang _reference_ data type and
+are therefore unique.
+
+Streams can be canceled at any time. This will stop any further
+messages from being sent to the owner process. Depending on
+its capabilities, the server will also be instructed to cancel
+the request.
+
+Canceling a stream may result in Gun dropping the connection
+temporarily, to avoid uploading or downloading data that will
+not be used.
+
+.Cancelling a stream
+[source,erlang]
+gun:cancel(ConnPid, StreamRef).
+
+=== Sending requests
+
+Gun provides many convenient functions for performing common
+operations, like GET, POST or DELETE. It also provides a
+general purpose function in case you need other methods.
+
+The availability of these methods on the server can vary
+depending on the software used but also on a per-resource
+basis.
+
+Gun will automatically set a few headers depending on the
+method used. For all methods however it will set the host
+header if it has not been provided in the request arguments.
+
+This section focuses on the act of sending a request. The
+handling of responses will be explained further on.
+
+==== GET and HEAD
+
+Use `gun:get/{2,3}` to request a resource.
+
+.GET "/organizations/ninenines"
+
+[source,erlang]
+StreamRef = gun:get(ConnPid, "/organizations/ninenines").
+
+.GET "/organizations/ninenines" with custom headers
+
+[source,erlang]
+StreamRef = gun:get(ConnPid, "/organizations/ninenines", [
+ {<<"accept">>, "application/json"},
+ {<<"user-agent">>, "revolver/1.0"}
+]).
+
+Note that the list of headers has the field name as a binary.
+The field value is iodata, which is either a binary or an
+iolist.
+
+Use `gun:head/{2,3}` if you don't need the response body.
+
+.HEAD "/organizations/ninenines"
+
+[source,erlang]
+StreamRef = gun:head(ConnPid, "/organizations/ninenines").
+
+.HEAD "/organizations/ninenines" with custom headers
+
+[source,erlang]
+StreamRef = gun:head(ConnPid, "/organizations/ninenines", [
+ {<<"accept">>, "application/json"},
+ {<<"user-agent">>, "revolver/1.0"}
+]).
+
+It is not possible to send a request body with a GET or HEAD
+request.
+
+==== POST, PUT and PATCH
+
+HTTP defines three methods to create or update a resource.
+
+POST is generally used when the resource identifier (URI) isn't known
+in advance when creating the resource. POST can also be used to
+replace an existing resource, although PUT is more appropriate
+in that situation.
+
+PUT creates or replaces a resource identified by the URI.
+
+PATCH provides instructions on how to modify the resource.
+
+Both POST and PUT send the entire resource representation in their
+request body. The PATCH method can be used when this is not
+desirable. The request body of a PATCH method may be a partial
+representation or a list of instructions on how to update the
+resource.
+
+The `gun:post/4`, `gun:put/4` and `gun:patch/4` functions
+take a body as their fourth argument. These functions do
+not require any body-specific header to be set, although
+it is always recommended to set the content-type header.
+Gun will set the other headers automatically.
+
+In this and the following examples in this section, `gun:post`
+can be replaced by `gun:put` or `gun:patch` for performing
+a PUT or PATCH request, respectively.
+
+.POST "/organizations/ninenines"
+
+[source,erlang]
+Body = "{\"msg\": \"Hello world!\"}",
+StreamRef = gun:post(ConnPid, "/organizations/ninenines", [
+ {<<"content-type">>, "application/json"}
+], Body).
+
+The `gun:post/3`, `gun:put/3` and `gun:patch/3` functions
+do not take a body in their arguments. If a body is to be
+provided later on, using the `gun:data/4` function, then
+the request headers must indicate this. This can be done
+by setting the content-length or content-type request
+headers. If these headers are not set then Gun will assume
+the request has no body.
+
+It is recommended to send the content-length header if you
+know it in advance, although this is not required. If it
+is not set, HTTP/1.1 will use the chunked transfer-encoding,
+and SPDY will continue normally as it is chunked by design.
+
+@todo Stop relying on transfer encoding header in Gun
+
+@todo SPDY needs to remove invalid headers, and to detect
+a body if content-length is set
+
+.POST "/organizations/ninenines" with delayed body
+
+[source,erlang]
+Body = "{\"msg\": \"Hello world!\"}",
+StreamRef = gun:post(ConnPid, "/organizations/ninenines", [
+ {<<"content-length">>, integer_to_binary(length(Body))},
+ {<<"content-type">>, "application/json"}
+]),
+gun:data(ConnPid, StreamRef, fin, Body).
+
+The atom `fin` indicates this is the last chunk of data to
+be sent. You can call the `gun:data/4` function as many
+times as needed until you have sent the entire body. The
+last call must use `fin` and all the previous calls must
+use `nofin`. The last chunk may be empty.
+
+@todo what to do about empty chunk, ignore?
+
+.Streaming the request body
+
+[source,erlang]
+----
+sendfile(ConnPid, StreamRef, Filepath) ->
+ {ok, IoDevice} = file:open(Filepath, [read, binary, raw]),
+ do_sendfile(ConnPid, StreamRef, IoDevice).
+
+do_sendfile(ConnPid, StreamRef, IoDevice) ->
+ case file:read(IoDevice, 8000) of
+ eof ->
+ gun:data(ConnPid, StreamRef, fin, <<>>),
+ file:close(IoDevice);
+ {ok, Bin} ->
+ gun:data(ConnPid, StreamRef, nofin, Bin),
+ do_sendfile(ConnPid, StreamRef, IoDevice)
+ end.
+----
+
+==== DELETE
+
+Use `gun:delete/{2,3}` to delete a resource.
+
+.DELETE "/organizations/ninenines"
+
+[source,erlang]
+StreamRef = gun:delete(ConnPid, "/organizations/ninenines").
+
+.DELETE "/organizations/ninenines" with custom headers
+
+[source,erlang]
+StreamRef = gun:delete(ConnPid, "/organizations/ninenines", [
+ {<<"user-agent">>, "revolver/1.0"}
+]).
+
+==== OPTIONS
+
+Use `gun:options/{2,3}` to request information about a resource.
+
+.OPTIONS "/organizations/ninenines"
+
+[source,erlang]
+StreamRef = gun:options(ConnPid, "/organizations/ninenines").
+
+.OPTIONS "/organizations/ninenines" with custom headers
+
+[source,erlang]
+StreamRef = gun:options(ConnPid, "/organizations/ninenines", [
+ {<<"user-agent">>, "revolver/1.0"}
+]).
+
+You can also use this function to request information about
+the server itself.
+
+.OPTIONS "*"
+
+[source,erlang]
+StreamRef = gun:options(ConnPid, "*").
+
+==== Requests with an arbitrary method
+
+The `gun:request/{4,5}` function can be used to send requests
+with a configurable method name. It is mostly useful when you
+need a method that Gun does not understand natively.
+
+.Example of a TRACE request
+
+[source,erlang]
+gun:request(ConnPid, "TRACE", "/", [
+ {<<"max-forwards">>, "30"}
+]).
+
+=== Processing responses
+
+All data received from the server is sent to the owner
+process as a message. First a `gun_response` message is sent,
+followed by zero or more `gun_data` messages. If something goes wrong,
+a `gun_error` message is sent instead.
+
+The response message will inform you whether there will be
+data messages following. If it contains `fin` there will be
+no data messages. If it contains `nofin` then one or more data
+messages will follow.
+
+When using SPDY this value is sent with the frame and simply
+passed on in the message. When using HTTP/1.1 however Gun must
+guess whether data will follow by looking at the response headers.
+
+You can receive messages directly, or you can use the _await_
+functions to let Gun receive them for you.
+
+.Receiving a response using receive
+
+[source,erlang]
+----
+print_body(ConnPid, MRef) ->
+ StreamRef = gun:get(ConnPid, "/"),
+ receive
+ {gun_response, ConnPid, StreamRef, fin, Status, Headers} ->
+ no_data;
+ {gun_response, ConnPid, StreamRef, nofin, Status, Headers} ->
+ receive_data(ConnPid, MRef, StreamRef);
+ {'DOWN', MRef, process, ConnPid, Reason} ->
+ error_logger:error_msg("Oops!"),
+ exit(Reason)
+ after 1000 ->
+ exit(timeout)
+ end.
+
+receive_data(ConnPid, MRef, StreamRef) ->
+ receive
+ {gun_data, ConnPid, StreamRef, nofin, Data} ->
+ io:format("~s~n", [Data]),
+ receive_data(ConnPid, MRef, StreamRef);
+ {gun_data, ConnPid, StreamRef, fin, Data} ->
+ io:format("~s~n", [Data]);
+ {'DOWN', MRef, process, ConnPid, Reason} ->
+ error_logger:error_msg("Oops!"),
+ exit(Reason)
+ after 1000 ->
+ exit(timeout)
+ end.
+----
+
+While it may seem verbose, using messages like this has the
+advantage of never locking your process, allowing you to
+easily debug your code. It also allows you to start more than
+one connection and concurrently perform queries on all of them
+at the same time.
+
+You can also use Gun in a synchronous manner by using the _await_
+functions.
+
+The `gun:await/{2,3,4}` function will wait until it receives
+a response to, a pushed resource related to, or data from
+the given stream.
+
+When calling `gun:await/{2,3}` and not passing a monitor
+reference, one is automatically created for you for the
+duration of the call.
+
+The `gun:await_body/{2,3,4}` works similarly, but returns the
+body received. Both functions can be combined to receive the
+response and its body sequentially.
+
+.Receiving a response using await
+
+[source,erlang]
+StreamRef = gun:get(ConnPid, "/"),
+case gun:await(ConnPid, StreamRef) of
+ {response, fin, Status, Headers} ->
+ no_data;
+ {response, nofin, Status, Headers} ->
+ {ok, Body} = gun:await_body(ConnPid, StreamRef),
+ io:format("~s~n", [Body])
+end.
+
+=== Handling streams pushed by the server
+
+The SPDY protocol allows the server to push more than one
+resource for every request. It will start sending those
+extra resources before it starts sending the response itself,
+so Gun will send you `gun_push` messages before `gun_response`
+when that happens.
+
+You can safely choose to ignore `gun_push` messages, or
+you can handle them. If you do, you can either receive the
+messages directly or use _await_ functions.
+
+The `gun_push` message contains both the new stream reference
+and the stream reference of the original request.
+
+.Receiving a pushed response using receive
+
+[source,erlang]
+receive
+ {gun_push, ConnPid, OriginalStreamRef, PushedStreamRef,
+ Method, Host, Path, Headers} ->
+ enjoy()
+end.
+
+If you use the `gun:await/{2,3,4}` function, however, Gun
+will use the original reference to identify the message but
+will return a tuple that doesn't contain it.
+
+.Receiving a pushed response using await
+
+[source,erlang]
+{push, PushedStreamRef, Method, Host, Path, Headers}
+ = gun:await(ConnPid, OriginalStreamRef).
+
+The `PushedStreamRef` variable can then be used with `gun:await_body/{2,3,4}`
+if needed.
+
+=== Flushing unwanted messages
+
+Gun provides the function `gun:flush/1` to quickly get rid
+of unwanted messages sitting in the process mailbox. You
+can use it to get rid of all messages related to a connection,
+or just the messages related to a stream.
+
+.Flush all messages from a Gun connection
+
+[source,erlang]
+gun:flush(ConnPid).
+
+.Flush all messages from a specific stream
+
+[source,erlang]
+gun:flush(StreamRef).
diff --git a/doc/src/guide/introduction.asciidoc b/doc/src/guide/introduction.asciidoc
new file mode 100644
index 0000000..ade3d80
--- /dev/null
+++ b/doc/src/guide/introduction.asciidoc
@@ -0,0 +1,28 @@
+== Introduction
+
+Gun is an Erlang HTTP client with support for HTTP/1.1, SPDY and Websocket.
+
+=== Prerequisites
+
+Knowledge of Erlang, but also of the HTTP/1.1, SPDY and Websocket
+protocols is required in order to read this guide.
+
+=== Supported platforms
+
+Gun is tested and supported on Linux.
+
+Gun is developed for Erlang 17+.
+
+Gun may be compiled on earlier Erlang versions with small source code
+modifications but there is no guarantee that it will work as intended.
+
+=== Conventions
+
+In the HTTP protocol, the method name is case sensitive. All standard
+method names are uppercase.
+
+Header names are case insensitive. Gun converts all the header names
+to lowercase, and expects your application to provide lowercase header
+names.
+
+The same applies to any other case insensitive value.
diff --git a/doc/src/guide/protocols.asciidoc b/doc/src/guide/protocols.asciidoc
new file mode 100644
index 0000000..2180c5b
--- /dev/null
+++ b/doc/src/guide/protocols.asciidoc
@@ -0,0 +1,119 @@
+== Supported protocols
+
+This chapter describes the protocols supported and the
+operations available to them.
+
+=== HTTP/1.1
+
+HTTP/1.1 is a text request-response protocol. The client
+sends a request, the server sends back a response.
+
+Gun provides convenience functions for performing GET, HEAD,
+OPTIONS, POST, PATCH, PUT, and DELETE requests. All these
+functions are aliases of `gun:request/{4,5}` for each respective
+methods. Gun also provides a `gun:data/4` function for streaming
+the request body.
+
+Gun will send a `gun_response` message for every response
+received, followed by zero or more `gun_data` messages for
+the response body. If something goes wrong, a `gun_error`
+will be sent instead.
+
+Gun provides convenience functions for dealing with messages.
+The `gun:await/{2,3,4}` function waits for a response to the given
+request, and the `gun:await_body/{2,3,4}` function for the
+response's body. The `gun:flush/1` function can be used to clear all
+messages related to a request or a connection from the mailbox
+of the process.
+
+The function `gun:cancel/2` can be used to silence the
+response to a request previously sent if it is no longer
+needed. When using HTTP/1.1 there is no multiplexing so
+Gun will have to receive the response fully before any
+other response can be received.
+
+Finally, Gun can upgrade an HTTP/1.1 connection to Websocket.
+It provides the `gun:ws_upgrade/{2,3,4}` function for that
+purpose. A `gun_ws_upgrade` message will be sent on success;
+a `gun_response` message otherwise.
+
+=== SPDY
+
+SPDY is a binary protocol based on HTTP, compatible with
+the HTTP semantics, that reduces the complexity of parsing
+requests and responses, compresses the HTTP headers and
+allows the server to push multiple responses to a single
+request.
+
+The SPDY interface is very similar to HTTP/1.1, so this
+section instead focuses on the differences in the interface
+for the two protocols.
+
+Because a SPDY server can push multiple responses to a
+single request, Gun might send `gun_push` messages for
+every push received. They can be ignored safely if they
+are not needed.
+
+The `gun:cancel/2` function will use the SPDY stream
+cancellation mechanism which allows Gun to inform the
+server to stop sending a response for this particular
+request, saving resources.
+
+It is not possible to upgrade a SPDY connection to Websocket
+due to protocol limitations.
+
+=== Websocket
+
+Websocket is a binary protocol built on top of HTTP that
+allows asynchronous concurrent communication between the
+client and the server. A Websocket server can push data to
+the client at any time.
+
+Websocket is only available as a connection upgrade over
+an HTTP/1.1 connection.
+
+Once the Websocket connection is established, the only
+operation available on this connection is sending Websocket
+frames using `gun:ws_send/2`.
+
+Gun will send a `gun_ws` message for every frame received.
+
+=== Summary
+
+The two following tables summarize the supported operations
+and the messages Gun sends depending on the connection's
+current protocol.
+
+.Supported operations per protocol
+[cols="<,3*^",options="header"]
+|===
+| Operation | HTTP/1.1 | SPDY | Websocket
+| delete | yes | yes | no
+| get | yes | yes | no
+| head | yes | yes | no
+| options | yes | yes | no
+| patch | yes | yes | no
+| post | yes | yes | no
+| put | yes | yes | no
+| request | yes | yes | no
+| data | yes | yes | no
+| await | yes | yes | no
+| await_body | yes | yes | no
+| flush | yes | yes | no
+| cancel | yes | yes | no
+| ws_upgrade | yes | no | no
+| ws_send | no | no | yes
+|===
+
+.Messages sent per protocol
+[cols="<,3*^",options="header"]
+|===
+| Message | HTTP/1.1 | SPDY | Websocket
+| gun_push | no | yes | no
+| gun_response | yes | yes | no
+| gun_data | yes | yes | no
+| gun_error (StreamRef) | yes | yes | no
+| gun_error | yes | yes | yes
+| gun_ws_upgrade | yes | no | no
+| gun_ws | no | no | yes
+|===
diff --git a/doc/src/guide/start.asciidoc b/doc/src/guide/start.asciidoc
new file mode 100644
index 0000000..6d93e2e
--- /dev/null
+++ b/doc/src/guide/start.asciidoc
@@ -0,0 +1,67 @@
+== Starting and stopping
+
+This chapter describes how to start and stop the Gun application.
+
+=== Setting up
+
+Before Gun can be used it needs to be in Erlang's `ERL_LIBS` path variable.
+If you use `erlang.mk` or a similar build tool, you only need to specify
+Gun as a dependency to your application and the tool will take care
+of downloading Gun and setting up paths.
+
+With `erlang.mk` this is done by adding `gun` to the `DEPS` variable
+in your Makefile.
+
+.Adding Gun as an erlang.mk dependency
+
+[source,make]
+DEPS = gun
+
+=== Starting
+
+Gun is an _OTP application_. It needs to be started before you can
+use it.
+
+.Starting Gun in an Erlang shell
+
+[source,erlang]
+----
+1> application:ensure_all_started(gun).
+{ok,[ranch,crypto,cowlib,asn1,public_key,ssl,gun]}
+----
+
+=== Stopping
+
+You can stop Gun using the `application:stop/1` function, however
+only Gun will be stopped. This is the equivalent of `application:start/1`.
+The `application_ensure_all_started/1` function has no equivalent for
+stopping all applications.
+
+.Stopping Gun
+
+[source,erlang]
+application:stop(gun).
+
+=== Using Gun with releases
+
+An _OTP release_ starts applications automatically. All you need
+to do is to set up your application resource file so that Gun can
+be included in the release. The application resource file can be
+found in `ebin/your_application.app`, or in `src/your_application.app.src`
+if you are using a build tool like `erlang.mk`.
+
+The key you need to change is the `applications` key. By default
+it only includes `kernel` and `stdlib`. You need to add `gun` to
+that list.
+
+.Adding Gun to the application resource file
+
+[source,erlang]
+{applications, [
+ kernel,
+ stdlib,
+ gun
+]}
+
+Do not put an extra comma at the end, the comma is a separator
+between the elements of the list.
diff --git a/doc/src/guide/websocket.asciidoc b/doc/src/guide/websocket.asciidoc
new file mode 100644
index 0000000..011e457
--- /dev/null
+++ b/doc/src/guide/websocket.asciidoc
@@ -0,0 +1,100 @@
+== Websocket
+
+This chapter describes how to use the Gun client for
+communicating with a Websocket server.
+
+@todo recovering from connection failure
+reconnecting to Websocket etc.
+
+=== HTTP upgrade
+
+Websocket is a protocol built on top of HTTP. To use Websocket,
+you must first request for the connection to be upgraded. Only
+HTTP/1.1 connections can be upgraded to Websocket, so you might
+need to restrict the protocol to HTTP/1.1 if you are planning
+to use Websocket over TLS.
+
+@todo add option to disable specific protocols
+
+You must use the `gun_ws:upgrade/{2,3}` function to upgrade
+to Websocket. This function can be called anytime after connection,
+so you can send HTTP requests before upgrading to Websocket.
+
+.Upgrade to Websocket
+
+[source,erlang]
+gun:ws_upgrade(ConnPid, "/websocket").
+
+Gun will set all the necessary headers for performing the
+Websocket upgrade, but you can specify additional headers
+if needed. For example you can request a custom sub-protocol.
+
+.Upgrade to Websocket and request a protocol
+
+[source,erlang]
+gun:ws_upgrade(ConnPid, "/websocket", [
+ {<<"sec-websocket-protocol">>, "mychat"}
+]).
+
+The success or failure of this operation will be sent as a
+message.
+
+@todo hmm we want the headers to be sent in the gun_ws_upgrade ok message too
+
+[source,erlang]
+receive
+ {gun_ws_upgrade, ConnPid, ok} ->
+ upgrade_success(ConnPid);
+ {gun_ws_upgrade, ConnPid, error, IsFin, Status, Headers} ->
+ exit({ws_upgrade_failed, Status, Headers});
+ %% More clauses here as needed.
+after 1000 ->
+ exit(timeout);
+end.
+
+=== Sending data
+
+Once the Websocket upgrade has completed successfully, you no
+longer have access to functions for performing requests. You
+can only send and receive Websocket messages.
+
+Use `gun:ws_send/2` to send one or more messages to the server.
+
+@todo Implement sending of N frames
+
+.Send a text frame
+
+[source,erlang]
+gun:ws_send(ConnPid, {text, "Hello!"}).
+
+.Send a text frame, a binary frame and then close the connection
+
+[source,erlang]
+gun:ws_send(ConnPid, [
+ {text, "Hello!"},
+ {binary, BinaryValue},
+ close
+]).
+
+Note that if you send a close frame, Gun will close the connection
+cleanly and will not attempt to reconnect afterwards, similar to
+calling `gun:shutdown/1`.
+
+=== Receiving data
+
+Gun sends an Erlang message to the owner process for every
+Websocket message it receives.
+
+[source,erlang]
+receive
+ {gun_ws, ConnPid, Frame} ->
+ handle_frame(ConnPid, Frame)
+end.
+
+@todo auto ping has not been implemented yet
+
+Gun will automatically send ping messages to the server to keep
+the connection alive, however if the connection dies and Gun has
+to reconnect it will not upgrade to Websocket automatically, you
+need to perform the operation when you receive the `gun_error`
+message.
diff --git a/doc/src/manual/gun.asciidoc b/doc/src/manual/gun.asciidoc
new file mode 100644
index 0000000..14641ee
--- /dev/null
+++ b/doc/src/manual/gun.asciidoc
@@ -0,0 +1,578 @@
+= gun(3)
+
+== Name
+
+gun - asynchronous HTTP client
+
+== Description
+
+The `gun` module provides an asynchronous interface for
+connecting and communicating with Web servers over SPDY,
+HTTP or Websocket.
+
+== Types
+
+=== opts() = [opt()]
+
+Configuration for the connection.
+
+@todo Should be a map.
+
+With opt():
+
+keepalive => pos_integer()::
+ Time between pings in milliseconds.
+ Defaults to 5000.
+retry => non_neg_integer()::
+ Number of times Gun will try to reconnect on failure before giving up.
+ Defaults to 5.
+retry_timeout => pos_integer()::
+ Time between retries in milliseconds.
+ Defaults to 5000.
+type => ssl | tcp | tcp_spdy::
+ Whether to use SSL, plain TCP (for HTTP/Websocket) or SPDY over TCP.
+ The default varies depending on the port used. Port 443 defaults
+ to ssl. Port 6121 defaults to tcp_spdy (@todo). All other ports
+ default to tcp. (@todo)
+
+@todo We want to separate protocol and transport options.
+
+@todo We need to document Websocket options.
+
+== Messages
+
+Calling functions from this module may result in the following
+messages being sent.
+
+=== {gun_push, ConnPid, StreamRef, NewStreamRef, URI, Headers}
+
+ConnPid = pid():: The pid of the Gun connection process.
+StreamRef = reference():: Identifier of the stream initiated by the owner process.
+NewStreamRef = reference():: Identifier of the stream being pushed.
+URI = binary():: URI of the resource.
+Headers = [{binary(), binary()}]:: Headers @todo
+
+A resource pushed alongside an HTTP response.
+
+This message can only be sent when the protocol is SPDY.
+
+@todo we probably want a function to know what protocol we connected
+@todo with or perhaps a message on connect that tells us that
+
+@todo I fear we also need the scheme; resource is identified by URI
+@todo Perhaps we really should send the URI entirely, because cache
+@todo relies on URI to work and this feature is for caching...
+@todo Not sure why Method is there, spec says it is only for GET
+
+=== {gun_response, ConnPid, StreamRef, IsFin, Status, Headers}
+
+ConnPid = pid():: The pid of the Gun connection process.
+StreamRef = reference():: Identifier of the stream initiated by the owner process.
+IsFin = fin | nofin:: Whether this message terminates the response.
+Status = binary():: Status line for the response.
+Headers = [{binary(), binary()}]:: Headers sent with the response.
+
+A response to an HTTP request.
+
+=== {gun_data, ConnPid, StreamRef, IsFin, Data}
+
+ConnPid = pid():: The pid of the Gun connection process.
+StreamRef = reference():: Identifier of the stream this data belongs to.
+IsFin = fin | nofin:: Whether this message terminates the response.
+Data = binary():: Data from the stream.
+
+Data associated with a stream.
+
+The stream in question can be either one initiated by the owner
+process or a stream initiated by the server through the push
+mechanism. In any case a `gun_response` or a `gun_push` message
+will be sent before any `gun_data` message.
+
+=== {gun_error, ConnPid, StreamRef, Reason}
+
+ConnPid = pid():: The pid of the Gun connection process.
+StreamRef = reference():: Identifier of the stream this error relates to.
+Reason = any():: Error reason.
+
+Stream-specific error.
+
+=== {gun_error, ConnPid, Reason}
+
+ConnPid = pid():: The pid of the Gun connection process.
+Reason = any():: Error reason.
+
+General error.
+
+=== {gun_ws_upgrade, ConnPid, ok}
+
+ConnPid = pid():: The pid of the Gun connection process.
+
+Successful upgrade to the Websocket protocol.
+
+@todo Yeah we need the headers.
+
+=== {gun_ws_upgrade, ConnPid, error, IsFin, Status, Headers}
+
+ConnPid = pid():: The pid of the Gun connection process.
+IsFin = fin | nofin:: Whether this message terminates the response.
+Status = binary():: Status line for the response.
+Headers = [{binary(), binary()}]:: Headers sent with the response.
+
+Failed upgrade to the Websocket protocol.
+
+=== {gun_ws, ConnPid, Frame}
+
+ConnPid = pid():: The pid of the Gun connection process.
+Frame = @todo:: Frame.
+
+Websocket frame.
+
+== Exports
+
+=== open(Host, Port) -> open(Host, Port, [])
+
+Alias of `gun:open/3`.
+
+=== open(Host, Port, Opts) -> {ok, ConnPid} | {error, Reason}
+
+Host = inet:hostname():: Host to connect to.
+Port = inet:port_number():: Port to connect to.
+Opts = opts():: Options for this connection.
+ConnPid = pid():: The pid of the Gun connection process.
+Reason = any():: Error reason. @todo really any?
+
+Open a connection to the given host and port.
+
+=== close(ConnPid) -> ok
+
+ConnPid = pid():: The pid of the Gun connection process.
+
+Brutally close the connection.
+
+=== shutdown(ConnPid) -> ok
+
+ConnPid = pid():: The pid of the Gun connection process.
+
+Gracefully close the connection.
+
+A monitor can be used to be notified when the connection is
+effectively closed.
+
+=== delete(ConnPid, Path) -> delete(ConnPid, Path, [])
+
+Alias of `gun:delete/3`.
+
+=== delete(ConnPid, Path, Headers) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Delete a resource.
+
+=== get(ConnPid, Path) -> get(ConnPid, Path, [])
+
+Alias of `gun:get/3`.
+
+=== get(ConnPid, Path, Headers) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Get a resource.
+
+=== head(ConnPid, Path) -> head(ConnPid, Path, [])
+
+Alias of `gun:head/3`.
+
+=== head(ConnPid, Path, Headers) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Get headers of a resource.
+
+This function performs the same operation as `get/{2,3}` except
+the server will not send the resource representation, only the
+response's status line and headers.
+
+While servers should send the same headers they would if the
+request was a GET, like `content-length`, it is not always
+the case and differences may exist.
+
+=== options(ConnPid, Path) -> options(ConnPid, Path, [])
+
+Alias of `gun:options/3`.
+
+=== options(ConnPid, Path, Headers) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Obtain information about the capabilities of the server or of a resource.
+
+The special path `"*"` can be used to obtain information about
+the server as a whole. Any other path will return information
+about the resource only.
+
+=== patch(ConnPid, Path, Headers) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Request that a set of changes be applied to the resource.
+
+This function expects either `content-length` or `content-type`
+to be set to know a body is going to be sent afterwards.
+Gun will assume the request has no body otherwise. It is
+highly recommended to set both when possible.
+
+The body sent in this request should be a patch document
+with instructions on how to update the resource.
+
+You can use the `gun:data/4` function to send the body, if any.
+
+=== patch(ConnPid, Path, Headers, Body) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+Body = iodata():: Body of the request.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Request that a set of changes be applied to the resource.
+
+It is highly recommended to set the `content-type` header
+to inform the server what media type the body contains.
+Gun will automatically set the `content-length` header.
+
+The body sent in this request should be a patch document
+with instructions on how to update the resource.
+
+The complete request is sent when calling this function.
+It is not possible to stream more of the body after
+calling it.
+
+=== post(ConnPid, Path, Headers) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Process the enclosed representation according to the resource's own semantics.
+
+This function expects either `content-length` or `content-type`
+to be set to know a body is going to be sent afterwards.
+Gun will assume the request has no body otherwise. It is
+highly recommended to set both when possible.
+
+The body sent in this request will be processed
+according to the resource's own semantics. A new
+resource may be created as a result, and may be
+located at a different URI.
+
+You can use the `gun:data/4` function to send the body, if any.
+
+=== post(ConnPid, Path, Headers, Body) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+Body = iodata():: Body of the request.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Process the enclosed representation according to the resource's own semantics.
+
+It is highly recommended to set the `content-type` header
+to inform the server what media type the body contains.
+Gun will automatically set the `content-length` header.
+
+The body sent in this request will be processed
+according to the resource's own semantics. A new
+resource may be created as a result, and may be
+located at a different URI.
+
+The complete request is sent when calling this function.
+It is not possible to stream more of the body after
+calling it.
+
+=== put(ConnPid, Path, Headers) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Create or replace a resource.
+
+The body of the request is the entire representation of the resource.
+
+This function expects either `content-length` or `content-type`
+to be set to know a body is going to be sent afterwards.
+Gun will assume the request has no body otherwise. It is
+highly recommended to set both when possible.
+
+You can use the `gun:data/4` function to send the body, if any.
+
+=== put(ConnPid, Path, Headers, Body) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+Body = iodata():: Body of the request.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Create or replace a resource.
+
+The body of the request is the entire representation of the resource.
+
+It is highly recommended to set the `content-type` header
+to inform the server what media type the body contains.
+Gun will automatically set the `content-length` header.
+
+The complete request is sent when calling this function.
+It is not possible to stream more of the body after
+calling it.
+
+=== request(ConnPid, Method, Path, Headers) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Method = iodata():: Request method.
+Path = iodata():: Path of the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Perform the given request.
+
+This is a general purpose function that should only be used
+when existing method-specific functions don't apply.
+
+This function expects either `content-length` or `content-type`
+to be set to know a body is going to be sent afterwards.
+Gun will assume the request has no body otherwise. It is
+highly recommended to set both when possible.
+
+You can use the `gun:data/4` function to send the body, if any.
+
+=== request(ConnPid, Method, Path, Headers, Body) -> StreamRef
+
+ConnPid = pid():: The pid of the Gun connection process.
+Method = iodata():: Request method.
+Path = iodata():: Path of the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+Body = iodata():: Body of the request.
+StreamRef = reference():: Identifier of the stream for this request.
+
+Perform the given request.
+
+This is a general purpose function that should only be used
+when existing method-specific functions don't apply.
+
+It is highly recommended to set the `content-type` header
+to inform the server what media type the body contains.
+Gun will automatically set the `content-length` header.
+
+The complete request is sent when calling this function.
+It is not possible to stream more of the body after
+calling it.
+
+=== data(ConnPid, StreamRef, IsFin, Data) -> ok
+
+ConnPid = pid():: The pid of the Gun connection process.
+StreamRef = reference():: Identifier of the stream this data belongs to.
+IsFin = fin | nofin:: Whether this message terminates the request.
+Data = iodata():: Data to be sent with the request.
+
+Stream the body of a request.
+
+@todo empty chunks
+
+This function can only be used if the request identified by
+`StreamRef` came with headers indicating the presence of a
+body and that body not being given when creating the request.
+
+All calls to this function must use `nofin` except for the
+last which must use `fin` to indicate the end of the request
+body.
+
+Empty data is allowed regardless of the value of `IsFin`.
+Gun will not send empty data chunks unless required to
+indicate the request body is finished, however.
+
+=== await(ConnPid, StreamRef) -> await(ConnPid, StreamRef, 5000, MonitorRef)
+
+Alias of `gun:await/4`.
+
+A monitor `MonitorRef` is automatically created for the duration of
+this call and an error will be returned if the Gun connection process
+terminates.
+
+=== await(ConnPid, StreamRef, MonitorRef) -> await(ConnPid, StreamRef, 5000, MonitorRef)
+
+Alias of `gun:await/4`.
+
+=== await(ConnPid, StreamRef, Timeout) -> await(ConnPid, StreamRef, Timeout, MonitorRef)
+
+Alias of `gun:await/4`.
+
+A monitor `MonitorRef` is automatically created for the duration of
+this call and an error will be returned if the Gun connection process
+terminates.
+
+=== await(ConnPid, StreamRef, Timeout, MonitorRef) -> tuple() -- see below
+
+ConnPid = pid():: The pid of the Gun connection process.
+StreamRef = reference():: Identifier of the stream to await messages from.
+Timeout = timeout():: How long this function will wait for messages.
+MonitorRef = reference():: Monitor reference for the Gun connection process.
+
+Wait for a response message.
+
+This function can be used when a synchronous handling of
+responses is desired. It will only return when a message
+for the given stream is received, on error or on timeout.
+
+The return values are described in the next few subsections.
+
+==== {response, IsFin, Status, Headers}
+
+IsFin = fin | nofin:: Whether this message terminates the response.
+Status = binary():: Status line for the response.
+Headers = [{binary(), binary()}]:: Headers sent with the response.
+
+Equivalent of a `gun_response` message.
+
+==== {data, IsFin, Data}
+
+IsFin = fin | nofin:: Whether this message terminates the response.
+Data = binary():: Data from the stream.
+
+Equivalent of a `gun_data` message.
+
+==== {push, NewStreamRef, URI, Headers}
+
+NewStreamRef = reference():: Identifier of the stream being pushed.
+URI = binary():: URI of the resource.
+Headers = [{binary(), binary()}]:: Headers @todo
+
+Equivalent of a `gun_push` message.
+
+@todo Same changes as gun_push
+
+==== {error, Reason}
+
+Reason = any():: Error reason. @todo any?
+
+Equivalent of a `gun_error` message.
+
+@todo I think we want to distinguish a stream error, a general error,
+@todo a DOWN and a timeout error
+
+=== await_body(ConnPid, StreamRef) -> await_body(ConnPid, StreamRef, 5000, MonitorRef)
+
+Alias of `gun:await_body/4`.
+
+A monitor `MonitorRef` is automatically created for the duration of
+this call and an error will be returned if the Gun connection process
+terminates.
+
+=== await_body(ConnPid, StreamRef, MonitorRef) -> await_body(ConnPid, StreamRef, 5000, MonitorRef)
+
+Alias of `gun:await_body/4`.
+
+=== await_body(ConnPid, StreamRef, Timeout) -> await_body(ConnPid, StreamRef, Timeout, MonitorRef)
+
+Alias of `gun:await_body/4`.
+
+A monitor `MonitorRef` is automatically created for the duration of
+this call and an error will be returned if the Gun connection process
+terminates.
+
+=== await_body(ConnPid, StreamRef, Timeout, MonitorRef) -> {ok, Body} | {error, Reason}
+
+ConnPid = pid():: The pid of the Gun connection process.
+StreamRef = reference():: Identifier of the stream to await messages from.
+Timeout = timeout():: How long this function will wait for each message.
+MonitorRef = reference():: Monitor reference for the Gun connection process.
+Body = binary():: Body for the given stream.
+Reason = any():: Error reason. @todo any?
+
+Wait for a response body.
+
+This function can be used when a synchronous handling of
+responses is desired. It will only return when it has
+finished fetching the entire response body.
+
+The timeout value is *per message*. The actual function call
+can last much longer for large bodies.
+
+@todo I think we want to distinguish a stream error, a general error,
+@todo a DOWN and a timeout error
+
+@todo guide might be a little incorrect about await/await_body
+
+=== flush(ConnPid) -> ok
+
+ConnPid = pid():: The pid of the Gun connection process.
+
+Flush all messages from the Gun connection process from the mailbox.
+
+=== flush(StreamRef) -> ok
+
+StreamRef = reference():: Stream identifier.
+
+Flush all messages related to the given stream.
+
+=== cancel(ConnPid, StreamRef) -> ok
+
+ConnPid = pid():: The pid of the Gun connection process.
+StreamRef = reference():: Identifier of the stream to cancel.
+
+Cancel the given stream.
+
+HTTP/1.1 streams can't be cancelled. Gun will simply silence
+the stream and stop relaying messages.
+
+@todo Depending on the length
+@todo of a response Gun may also attempt to reconnect rather than
+@todo receive the entire response body.
+
+SPDY streams can however be cancelled at any time.
+
+=== ws_upgrade(ConnPid, Path) -> ws_upgrade(ConnPid, Path, [], #{})
+
+Alias of `gun:ws_upgrade/4`.
+
+=== ws_upgrade(ConnPid, Path, Headers) -> ws_upgrade(ConnPid, Path, Headers, #{})
+
+Alias of `gun:ws_upgrade/4`.
+
+=== ws_upgrade(ConnPid, Path, Headers, Opts) -> ok
+
+ConnPid = pid():: The pid of the Gun connection process.
+Path = iodata():: Path to the resource.
+Headers = [{binary(), iodata()}]:: Additional request headers.
+Opts = map():: Options for the Websocket connection.
+
+Request the connection to be upgraded to the Websocket protocol.
+
+@todo Only possible for HTTP.
+
+=== ws_send(ConnPid, Frames) -> ok
+
+ConnPid = pid():: The pid of the Gun connection process.
+Frames = @todo:: @todo
+
+Send one or more Websocket frames.
+
+This function can only be used following a successful `ws_upgrade` call.
diff --git a/doc/src/manual/gun_app.asciidoc b/doc/src/manual/gun_app.asciidoc
new file mode 100644
index 0000000..e4447d6
--- /dev/null
+++ b/doc/src/manual/gun_app.asciidoc
@@ -0,0 +1,24 @@
+= gun(7)
+
+== Name
+
+gun - Erlang HTTP client with support for HTTP/1.1, SPDY and Websocket.
+
+== Dependencies
+
+The `gun` application uses the Erlang applications `ranch`
+for abstracting TCP and TLS over a common interface, and
+the `ssl` application for TLS support, required for HTTPS
+and SPDY support. In addition, Gun requires the `crypto`
+application (a dependency of `ssl`) for Websocket.
+
+These dependencies must be started for the `gun`
+application to work. In an embedded environment
+this means that they need to be started with the
+`application:start/{1,2}` function before the `gun`
+application is started.
+
+== Environment
+
+The `gun` application does not define any application
+environment configuration parameters.