From aea877d1a49951165856a46b702cafd2356a26b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 31 Aug 2016 17:10:57 +0200 Subject: Update documentation --- docs/en/cowboy/2.0/guide/resp/index.html | 343 ++++++++++++++++++++----------- 1 file changed, 222 insertions(+), 121 deletions(-) (limited to 'docs/en/cowboy/2.0/guide/resp') diff --git a/docs/en/cowboy/2.0/guide/resp/index.html b/docs/en/cowboy/2.0/guide/resp/index.html index 424a97d3..b87b1efa 100644 --- a/docs/en/cowboy/2.0/guide/resp/index.html +++ b/docs/en/cowboy/2.0/guide/resp/index.html @@ -69,219 +69,320 @@

Sending a response

-

The Req object also allows you to send a response.

-

You can only send one response. Any other attempt will -trigger a crash. The response may be sent in one go or -with its body streamed by chunks of arbitrary size.

-

You can also set headers or the response body in advance -and Cowboy will use them when you finally do reply.

+

The response must be sent using the Req object.

+

Cowboy provides two different ways of sending responses: +either directly or by streaming the body. Response headers +and body may be set in advance. The response is sent as +soon as one of the reply or stream reply function is +called.

+

Cowboy also provides a simplified interface for sending +files. It can also send only specific parts of a file.

+

While only one response is allowed for every request, +HTTP/2 introduced a mechanism that allows the server +to push additional resources related to the response. +This chapter also describes how this feature works in +Cowboy.

Reply

-

You can send a reply with no particular headers or body. -Cowboy will make sure to send the mandatory headers with -the response.

+

Cowboy provides three functions for sending the entire reply, +depending on whether you need to set headers and body. In all +cases, Cowboy will add any headers required by the protocol +(for example the date header will always be sent).

+

When you need to set only the status code, +use cowboy_req:reply/2:

-
Req2 = cowboy_req:reply(200, Req).
-

You can define headers to be sent with the response. Note -that header names must be lowercase. Again, Cowboy will -make sure to send the mandatory headers with the response.

+
Req = cowboy_req:reply(200, Req0).
+

When you need to set response headers at the same time, +use cowboy_req:reply/3:

-
Req2 = cowboy_req:reply(303, [
-    {<<"location">>, <<"http://ninenines.eu">>}
-], Req).
-

You can override headers that Cowboy would send otherwise. -Any header set by the user will be used over the ones set -by Cowboy. For example, you can advertise yourself as a -different server.

+
Req = cowboy_req:reply(303, #{
+    <<"location">> => <<"http://ninenines.eu">>
+}, Req0).
+

Note that the header name must always be a lowercase +binary.

+

When you also need to set the response body, +use cowboy_req:reply/4:

-
Req2 = cowboy_req:reply(200, [
-    {<<"server">>, <<"yaws">>}
-], Req).
-

We also saw earlier how to force close the connection by -overriding the connection header.

-

Finally, you can also send a body with the response. Cowboy -will automatically set the content-length header if you do. -We recommend that you set the content-type header so the -client may know how to read the body.

+
Req = cowboy_req:reply(200, #{
+    <<"content-type">> => <<"text/plain">>
+}, "Hello world!", Req0).
+

You should always set the content-type header when the +response has a body. There is however no need to set +the content-length header; Cowboy does it automatically.

+

The response body and the header values must be either +a binary or an iolist. An iolist is a list containing +binaries, characters, strings or other iolists. This +allows you to build a response from different parts +without having to do any concatenation:

-
Req2 = cowboy_req:reply(200, [
-    {<<"content-type">>, <<"text/plain">>}
-], "Hello world!", Req).
-

Here is the same example but sending HTML this time.

-
-
-
Req2 = cowboy_req:reply(200, [
-    {<<"content-type">>, <<"text/html">>}
-], "<html><head>Hello world!</head><body><p>Hats off!</p></body></html>", Req).
-

Note that the reply is sent immediately.

+
Title = "Hello world!",
+Body = <<"Hats off!">>,
+Req = cowboy_req:reply(200, #{
+    <<"content-type">> => <<"text/html">>
+}, ["<html><head><title>", Title, "</title></head>",
+        "<body><p>", Body, "</p></body></html>"], Req0).
+

This method of building responses is more efficient than +concatenating. Behind the scenes, each element of the list +is simply a pointer, and those pointers are used directly +when writing to the socket.

-

Chunked reply

+

Stream reply

-

You can also stream the response body. First, you need to -initiate the reply by sending the response status code. -Then you can send the body in chunks of arbitrary size.

+

Cowboy provides two functions for initiating a response, +and an additional function for streaming the response body. +Cowboy will add any required headers to the response.

+

When you need to set only the status code, +use cowboy_req:stream_reply/2:

-
Req2 = cowboy_req:chunked_reply(200, Req),
-cowboy_req:chunk("Hello...", Req2),
-cowboy_req:chunk("chunked...", Req2),
-cowboy_req:chunk("world!!", Req2).
-

You should make sure to match on ok as an error may be -returned.

-

While it is possible to send a chunked response without -a content-type header, it is still recommended. You can -set this header or any other just like for normal replies.

+
Req = cowboy_req:stream_reply(200, Req0),
+
+cowboy_req:stream_body("Hello...", nofin, Req),
+cowboy_req:stream_body("chunked...", nofin, Req),
+cowboy_req:stream_body("world!!", fin, Req).
+

The second argument to cowboy_req:stream_body/3 indicates +whether this data terminates the body. Use fin for the +final flag, and nofin otherwise.

+

This snippet does not set a content-type header. This is +not recommended. All responses with a body should have +a content-type. The header can be set beforehand, or +using the cowboy_req:stream_reply/3:

-
Req2 = cowboy_req:chunked_reply(200, [
-    {<<"content-type">>, <<"text/html">>}
-], Req),
-cowboy_req:chunk("<html><head>Hello world!</head>", Req2),
-cowboy_req:chunk("<body><p>Hats off!</p></body></html>", Req2).
-

Note that the reply and each chunk following it are sent -immediately.

+
Req = cowboy_req:stream_reply(200, #{
+    <<"content-type">> => <<"text/html">>
+}, Req0),
+
+cowboy_req:stream_body("<html><head>Hello world!</head>", nofin, Req),
+cowboy_req:stream_body("<body><p>Hats off!</p></body></html>", fin, Req).
+

HTTP provides a few different ways to stream response bodies. +Cowboy will select the most appropriate one based on the HTTP +version and the request and response headers.

+

While not required by any means, it is recommended that you +set the content-length header in the response if you know it +in advance. This will ensure that the best response method +is selected and help clients understand when the response +is fully received.

Preset response headers

-

You can define response headers in advance. They will be -merged into the headers given in the reply call. Headers -in the reply call override preset response headers which -override the default Cowboy headers.

+

Cowboy provides functions to set response headers without +immediately sending them. They are stored in the Req object +and sent as part of the response when a reply function is +called.

+

To set response headers:

-
Req2 = cowboy_req:set_resp_header(<<"allow">>, "GET", Req).
-

You can check if a response header has already been set. -This will only check the response headers that you set, -and not the ones Cowboy will add when actually sending -the reply.

+
Req = cowboy_req:set_resp_header(<<"allow">>, "GET", Req0).
+

Header names must be a lowercase binary.

+

Do not use this function for setting cookies. Refer to +the Cookies chapter for more information.

+

To check if a response header has already been set:

cowboy_req:has_resp_header(<<"allow">>, Req).
-

It will return true if the header is defined, and false -otherwise.

-

Finally, you can also delete a preset response header if -needed. If you do, it will not be sent.

+

It returns true if the header was set, false otherwise.

+

To delete a response header that was set previously:

-
Req2 = cowboy_req:delete_resp_header(<<"allow">>, Req).
+
Req = cowboy_req:delete_resp_header(<<"allow">>, Req0).
+ + +
+

Overriding headers

+
+

As Cowboy provides different ways of setting response +headers and body, clashes may occur, so it’s important +to understand what happens when a header is set twice.

+

Headers come from five different origins:

+
    +
  • +

    +Protocol-specific headers (for example HTTP/1.1’s connection header) +

    +
  • +
  • +

    +Other required headers (for example the date header) +

    +
  • +
  • +

    +Preset headers +

    +
  • +
  • +

    +Headers given to the reply function +

    +
  • +
  • +

    +Set-cookie headers +

    +
  • +
+

Cowboy does not allow overriding protocol-specific headers.

+

Set-cookie headers will always be appended at the end of +the list of headers before sending the response.

+

Headers given to the reply function will always override +preset headers and required headers. If a header is found +in two or three of these, then the one in the reply function +is picked and the others are dropped.

+

Similarly, preset headers will always override required +headers.

+

To illustrate, look at the following snippet. Cowboy by +default sends the server header with the value "Cowboy". +We can override it:

+
+
+
Req = cowboy_req:reply(200, #{
+    <<"server">> => <<"yaws">>
+}, Req0).

Preset response body

-

You can set the response body in advance. Note that this -body will be ignored if you then choose to send a chunked -reply, or if you send a reply with an explicit body.

+

Cowboy provides functions to set the response body without +immediately sending it. It is stored in the Req object and +sent when the reply function is called.

+

To set the response body:

-
Req2 = cowboy_req:set_resp_body("Hello world!", Req).
-

You can also set a fun that will be called when it is time -to send the body. There are three different ways of doing -that.

-

If you know the length of the body that needs to be sent, -you should specify it, as it will help clients determine -the remaining download time and allow them to inform the -user.

+
Req = cowboy_req:set_resp_body("Hello world!", Req0).
+

To check if a response body has already been set:

-
F = fun (Socket, Transport) ->
-    Transport:send(Socket, "Hello world!")
-end,
-Req2 = cowboy_req:set_resp_body_fun(12, F, Req).
-

If you do not know the length of the body, you should use -a chunked response body fun instead.

+
cowboy_req:has_resp_body(Req).
+

It returns true if the body was set and is non-empty, +false otherwise.

+

The preset response body is only sent if the reply function +used is cowboy_req:reply/2 or cowboy_req:reply/3.

+ + +
+

Sending files

+
+

Cowboy provides a shortcut for sending files. When +using cowboy_req:reply/4, or when presetting the +response header, you can give a sendfile tuple to +Cowboy:

-
F = fun (SendChunk) ->
-    Body = lists:duplicate(random:uniform(1024, $a)),
-    SendChunk(Body)
-end,
-Req2 = cowboy_req:set_resp_body_fun(chunked, F, Req).
-

Finally, you can also send data on the socket directly, -without knowing the length in advance. Cowboy may be -forced to close the connection at the end of the response -though depending on the protocol capabilities.

+
{sendfile, Offset, Length, Filename}
+

Depending on the values for Offset or Length, the +entire file may be sent, or just a part of it.

+

The length is required even for sending the entire file. +Cowboy sends it in the content-length header.

+

To send a file while replying:

-
F = fun (Socket, Transport) ->
-    Body = lists:duplicate(random:uniform(1024, $a)),
-    Transport:send(Socket, Body)
-end,
-Req2 = cowboy_req:set_resp_body_fun(F, Req).
+
Req = cowboy_req:reply(200, #{
+        <<"content-type">> => "image/png"
+}, {sendfile, 0, 12345, "path/to/logo.png"}, Req0).
-

Sending files

+

Push

-

You can send files directly from disk without having to -read them. Cowboy will use the sendfile syscall when -possible, which means that the file is sent to the socket -directly from the kernel, which is a lot more performant -than doing it from userland.

-

Again, it is recommended to set the size of the file if it -can be known in advance.

+

The HTTP/2 protocol introduced the ability to push resources +related to the one sent in the response. Cowboy provides two +functions for that purpose: cowboy_req:push/3,4.

+

Push is only available for HTTP/2. Cowboy will automatically +ignore push requests if the protocol doesn’t support it.

+

The push function must be called before any of the reply +functions. Doing otherwise will result in a crash.

+

To push a resource, you need to provide the same information +as a client performing a request would. This includes the +HTTP method, the URI and any necessary request headers.

+

Cowboy by default only requires you to give the path to +the resource and the request headers. The rest of the URI +is taken from the current request (excluding the query +string, set to empty) and the method is GET by default.

+

The following snippet pushes a CSS file that is linked to +in the response:

+
+
+
cowboy_req:push("/static/style.css", #{
+        <<"accept">> => <<"text/css">>
+}, Req0),
+Req = cowboy_req:reply(200, #{
+        <<"content-type">> => <<"text/html">>
+}, ["<html><head><title>My web page</title>",
+        "<link rel='stylesheet' type='text/css' href='/static/style.css'>",
+        "<body><p>Welcome to Erlang!</p></body></html>"], Req0).
+

To override the method, scheme, host, port or query string, +simply pass in a fourth argument. The following snippet +uses a different host name:

-
F = fun (Socket, Transport) ->
-    Transport:sendfile(Socket, "priv/styles.css")
-end,
-Req2 = cowboy_req:set_resp_body_fun(FileSize, F, Req).
-

Please see the Ranch guide for more information about -sending files.

+
cowboy_req:push("/static/style.css", #{
+        <<"accept">> => <<"text/css">>
+}, #{host => <<"cdn.example.org">>}, Req),
+

Pushed resources don’t have to be files. As long as the push +request is cacheable, safe and does not include a body, the +resource can be pushed.

+

Under the hood, Cowboy handles pushed requests the same as +normal requests: a different process is created which will +ultimately send a response to the client.

-- cgit v1.2.3