From 83d8b63b8abb46b374439c8c8571091968af6260 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= <essen@ninenines.eu>
Date: Wed, 25 Mar 2015 13:44:08 +0100
Subject: Update the guide

A number of @todo remain in it and will be worked on shortly.

The guide has been converted to Asciidoc and 'make asciidoc'
will generate a PDF and a chunked HTML version.
---
 doc/src/guide/http.asciidoc | 363 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 363 insertions(+)
 create mode 100644 doc/src/guide/http.asciidoc

(limited to 'doc/src/guide/http.asciidoc')

diff --git a/doc/src/guide/http.asciidoc b/doc/src/guide/http.asciidoc
new file mode 100644
index 0000000..929860a
--- /dev/null
+++ b/doc/src/guide/http.asciidoc
@@ -0,0 +1,363 @@
+== 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. The `gun:await/2` call will automatically monitor
+the process and use a timeout of 5000. The monitor and the
+timeout can be passed by using `gun:await/3` or `gun:await/4`.
+
+The `gun:await_body/{2,3,4}` works similarly, but returns the
+body received.
+
+.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).
-- 
cgit v1.2.3

