mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-15 12:40:25 +00:00
Update the body reading chapter
This commit is contained in:
parent
7839f13671
commit
bee1320700
2 changed files with 80 additions and 101 deletions
|
@ -258,7 +258,8 @@ QsVals = cowboy_req:parse_qs(Req),
|
||||||
|
|
||||||
Cowboy will only parse the query string, and not do any
|
Cowboy will only parse the query string, and not do any
|
||||||
transformation. This function may therefore return duplicates,
|
transformation. This function may therefore return duplicates,
|
||||||
or parameter names without an associated value.
|
or parameter names without an associated value. The order of
|
||||||
|
the list returned is undefined.
|
||||||
|
|
||||||
When a query string is `key=1&key=2`, the list returned will
|
When a query string is `key=1&key=2`, the list returned will
|
||||||
contain two parameters of name `key`.
|
contain two parameters of name `key`.
|
||||||
|
|
|
@ -1,152 +1,130 @@
|
||||||
[[req_body]]
|
[[req_body]]
|
||||||
== Reading the request body
|
== Reading the request body
|
||||||
|
|
||||||
The Req object also allows you to read the request body.
|
The request body can be read using the Req object.
|
||||||
|
|
||||||
Because the request body can be of any size, all body
|
Cowboy will not attempt to read the body until requested.
|
||||||
reading operations will only work once, as Cowboy will
|
You need to call the body reading functions in order to
|
||||||
not cache the result of these operations.
|
retrieve it.
|
||||||
|
|
||||||
Cowboy will not attempt to read the body until you do.
|
Cowboy will not cache the body, it is therefore only
|
||||||
If handler execution ends without reading it, Cowboy
|
possible to read it once.
|
||||||
will simply skip it.
|
|
||||||
|
|
||||||
Cowboy provides different ways to read the request body.
|
You are not required to read it, however. If a body is
|
||||||
You can read it directly, stream it, but also read and
|
present and was not read, Cowboy will either cancel or
|
||||||
parse in a single call for form urlencoded formats or
|
skip its download, depending on the protocol.
|
||||||
multipart. All of these except multipart are covered in
|
|
||||||
this chapter. Multipart is covered later on in the guide.
|
|
||||||
|
|
||||||
=== Check for request body
|
Cowboy provides functions for reading the body raw,
|
||||||
|
and read and parse form urlencoded or ^multipart^ bodies.
|
||||||
|
The latter is covered in its own chapter.
|
||||||
|
|
||||||
You can check whether a body was sent with the request.
|
=== Request body presence
|
||||||
|
|
||||||
|
Not all requests come with a body. You can check for
|
||||||
|
the presence of a request body with this function:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
cowboy_req:has_body(Req).
|
cowboy_req:has_body(Req).
|
||||||
|
|
||||||
It will return `true` if there is a request body, and
|
It returns `true` if there is a body; `false` otherwise.
|
||||||
`false` otherwise.
|
|
||||||
|
|
||||||
Note that it is generally safe to assume that a body is
|
In practice, this function is rarely used. When the
|
||||||
sent for `POST`, `PUT` and `PATCH` requests, without
|
method is `POST`, `PUT` or `PATCH`, the request body
|
||||||
having to explicitly check for it.
|
is often required by the application, which should
|
||||||
|
just attempt to read it directly.
|
||||||
|
|
||||||
=== Request body length
|
=== Request body length
|
||||||
|
|
||||||
You can obtain the body length if it was sent with the
|
You can obtain the length of the body:
|
||||||
request.
|
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
Length = cowboy_req:body_length(Req).
|
Length = cowboy_req:body_length(Req).
|
||||||
|
|
||||||
The value returned will be `undefined` if the length
|
Note that the length may not be known in advance. In
|
||||||
couldn't be figured out from the request headers. If
|
that case `undefined` will be returned. This can happen
|
||||||
there's a body but no length is given, this means that
|
with HTTP/1.1's chunked transfer-encoding, or HTTP/2
|
||||||
the chunked transfer-encoding was used. You can read
|
when no content-length was provided.
|
||||||
chunked bodies by using the stream functions.
|
|
||||||
|
Cowboy will update the body length in the Req object
|
||||||
|
once the body has been read completely. A length will
|
||||||
|
always be returned when attempting to call this function
|
||||||
|
after reading the body completely.
|
||||||
|
|
||||||
=== Reading the body
|
=== Reading the body
|
||||||
|
|
||||||
You can read the whole body directly in one call.
|
You can read the entire body with one function call:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
{ok, Body, Req2} = cowboy_req:body(Req).
|
{ok, Data, Req} = cowboy_req:read_body(Req0).
|
||||||
|
|
||||||
By default, Cowboy will attempt to read up to a
|
Cowboy returns an `ok` tuple when the body has been
|
||||||
size of 8MB. You can override this limit as needed.
|
read fully.
|
||||||
|
|
||||||
|
By default, Cowboy will attempt to read up to 8MB
|
||||||
|
of data, for up to 15 seconds. The call will return
|
||||||
|
once Cowboy has read at least 8MB of data, or at
|
||||||
|
the end of the 15 seconds period.
|
||||||
|
|
||||||
|
These values can be customized. For example, to read
|
||||||
|
only up to 1MB for up to 5 seconds:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
{ok, Body, Req2} = cowboy_req:body(Req, [{length, 100000000}]).
|
----
|
||||||
|
{ok, Data, Req} = cowboy_req:read_body(Req0,
|
||||||
|
#{length => 1000000, period => 5000}).
|
||||||
|
----
|
||||||
|
|
||||||
You can also disable it.
|
You may also disable the length limit:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
{ok, Body, Req2} = cowboy_req:body(Req, [{length, infinity}]).
|
{ok, Data, Req} = cowboy_req:read_body(Req0, #{length => infinity}).
|
||||||
|
|
||||||
It is recommended that you do not disable it for public
|
This makes the function wait 15 seconds and return with
|
||||||
facing websites.
|
whatever arrived during that period. This is not
|
||||||
|
recommended for public facing applications.
|
||||||
|
|
||||||
If the body is larger than the limit, then Cowboy will return
|
These two options can effectively be used to control
|
||||||
a `more` tuple instead, allowing you to stream it if you
|
the rate of transmission of the request body.
|
||||||
would like to.
|
|
||||||
|
|
||||||
=== Streaming the body
|
=== Streaming the body
|
||||||
|
|
||||||
You can stream the request body by chunks.
|
When the body is too large, the first call will return
|
||||||
|
a `more` tuple instead of `ok`. You can call the
|
||||||
Cowboy returns a `more` tuple when there is more body to
|
function again to read more of the body, reading
|
||||||
be read, and an `ok` tuple for the last chunk. This allows
|
it one chunk at a time.
|
||||||
you to loop over all chunks.
|
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
body_to_console(Req) ->
|
read_body_to_console(Req0) ->
|
||||||
case cowboy_req:body(Req) of
|
case cowboy_req:read_body(Req0) of
|
||||||
{ok, Data, Req2} ->
|
{ok, Data, Req} ->
|
||||||
io:format("~s", [Data]),
|
io:format("~s", [Data]),
|
||||||
Req2;
|
Req;
|
||||||
{more, Data, Req2} ->
|
{more, Data, Req} ->
|
||||||
io:format("~s", [Data]),
|
io:format("~s", [Data]),
|
||||||
body_to_console(Req2)
|
read_body_to_console(Req)
|
||||||
end.
|
end.
|
||||||
----
|
----
|
||||||
|
|
||||||
You can of course set the `length` option to configure the
|
The `length` and `period` options can also be used.
|
||||||
size of chunks.
|
They need to be passed for every call.
|
||||||
|
|
||||||
=== Rate of data transmission
|
|
||||||
|
|
||||||
You can control the rate of data transmission by setting
|
|
||||||
options when calling body functions. This applies not only
|
|
||||||
to the functions described in this chapter, but also to
|
|
||||||
the multipart functions.
|
|
||||||
|
|
||||||
The `read_length` option defines the maximum amount of data
|
|
||||||
to be received from the socket at once, in bytes.
|
|
||||||
|
|
||||||
The `read_timeout` option defines the time Cowboy waits
|
|
||||||
before that amount is received, in milliseconds.
|
|
||||||
|
|
||||||
=== Transfer and content decoding
|
|
||||||
|
|
||||||
Cowboy will by default decode the chunked transfer-encoding
|
|
||||||
if any. It will not decode any content-encoding by default.
|
|
||||||
|
|
||||||
The first time you call a body function you can set the
|
|
||||||
`transfer_decode` and `content_decode` options. If the body
|
|
||||||
was already started being read these options are simply
|
|
||||||
ignored.
|
|
||||||
|
|
||||||
The following example shows how to set both options.
|
|
||||||
|
|
||||||
[source,erlang]
|
|
||||||
----
|
|
||||||
{ok, Data, Req2} = cowboy_req:body(Req, [
|
|
||||||
{transfer_decode, fun transfer_decode/2, TransferState},
|
|
||||||
{content_decode, fun content_decode/1}
|
|
||||||
]).
|
|
||||||
----
|
|
||||||
|
|
||||||
=== Reading a form urlencoded body
|
=== Reading a form urlencoded body
|
||||||
|
|
||||||
You can directly obtain a list of key/value pairs if the
|
Cowboy provides a convenient function for reading and
|
||||||
body was sent using the application/x-www-form-urlencoded
|
parsing bodies sent as application/x-www-form-urlencoded.
|
||||||
content-type.
|
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
{ok, KeyValues, Req2} = cowboy_req:body_qs(Req).
|
{ok, KeyValues, Req} = cowboy_req:read_urlencoded_body(Req0).
|
||||||
|
|
||||||
You can then retrieve an individual value from that list.
|
This function returns a list of key/values, exactly like
|
||||||
|
the function `cowboy_req:parse_qs/1`.
|
||||||
|
|
||||||
|
The defaults for this function are different. Cowboy will
|
||||||
|
read for up to 64KB and up to 5 seconds. They can be modified:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
{_, Lang} = lists:keyfind(lang, 1, KeyValues).
|
----
|
||||||
|
{ok, KeyValues, Req} = cowboy_req:read_urlencoded_body(Req0,
|
||||||
You should not attempt to match on the list as the order
|
#{length => 4096, period => 3000}).
|
||||||
of the values is undefined.
|
----
|
||||||
|
|
||||||
By default Cowboy will reject bodies with a size above
|
|
||||||
64KB when using this function. You can override this limit
|
|
||||||
by setting the `length` option.
|
|
||||||
|
|
||||||
[source,erlang]
|
|
||||||
{ok, KeyValues, Req2} = cowboy_req:body_qs(Req, [{length, 2000000}]).
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue