mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 12:20:24 +00:00
Document range requests
This commit is contained in:
parent
e8b4715a9f
commit
4ffcbfbf43
2 changed files with 132 additions and 6 deletions
|
@ -605,17 +605,139 @@ The response body can be provided either as the actual data
|
||||||
to be sent or a tuple indicating which file to send.
|
to be sent or a tuple indicating which file to send.
|
||||||
|
|
||||||
This function is called for both GET and HEAD requests. For
|
This function is called for both GET and HEAD requests. For
|
||||||
the latter the body is not sent, however.
|
the latter the body is not sent: it is only used to calculate
|
||||||
|
the content length.
|
||||||
|
|
||||||
// @todo Perhaps we can optimize HEAD requests and just
|
// @todo Perhaps we can optimize HEAD requests and just
|
||||||
// allow calculating the length instead of returning the
|
// allow calculating the length instead of returning the
|
||||||
// whole thing.
|
// whole thing.
|
||||||
|
|
||||||
Note that there used to be a way to stream the response body.
|
It is possible to stream the response body either by manually
|
||||||
It was temporarily removed and will be added back in a later
|
sending the response and returning a `stop` value; or by
|
||||||
release.
|
switching to a different handler (for example a loop handler)
|
||||||
|
and manually sending the response. All headers already set
|
||||||
|
by Cowboy will also be included in the response.
|
||||||
|
|
||||||
// @todo Add a way to switch to loop handler for streaming the body.
|
== RangeCallback
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
RangeCallback(Req, State) -> {Result, Req, State}
|
||||||
|
|
||||||
|
Result :: [{Range, Body}]
|
||||||
|
Range :: {From, To, Total} | binary()
|
||||||
|
From :: non_neg_integer()
|
||||||
|
To :: non_neg_integer()
|
||||||
|
Total :: non_neg_integer() | '*'
|
||||||
|
Body :: cowboy_req:resp_body()
|
||||||
|
Default - crash
|
||||||
|
----
|
||||||
|
|
||||||
|
Return a list of ranges for the response body.
|
||||||
|
|
||||||
|
The range selected can be found in the key `range`
|
||||||
|
in the Req object, as indicated in `range_satisfiable`.
|
||||||
|
|
||||||
|
Instead of returning the full response body as would
|
||||||
|
be done in the `ProvideCallback`, a list of ranges
|
||||||
|
must be returned. There can be one or more range.
|
||||||
|
When one range is returned, a normal ranged response
|
||||||
|
is sent. When multiple ranges are returned, Cowboy
|
||||||
|
will automatically send a multipart/byteranges
|
||||||
|
response.
|
||||||
|
|
||||||
|
When the total is not known the atom `'*'` can be
|
||||||
|
returned.
|
||||||
|
|
||||||
|
== ranges_provided
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
ranges_provided(Req, State) -> {Result, Req, State}
|
||||||
|
|
||||||
|
Result :: [Range | Auto]
|
||||||
|
Range :: {
|
||||||
|
binary(), %% lowercase; case insensitive
|
||||||
|
RangeCallback :: atom()
|
||||||
|
}
|
||||||
|
Auto :: {<<"bytes">>, auto}
|
||||||
|
Default - skip this step
|
||||||
|
----
|
||||||
|
|
||||||
|
Return the list of range units the resource provides.
|
||||||
|
|
||||||
|
During content negotiation Cowboy will build an accept-ranges
|
||||||
|
response header with the list of ranges provided. Cowboy
|
||||||
|
does not choose a range at this time; ranges are choosen
|
||||||
|
when it comes time to call the `ProvideCallback`.
|
||||||
|
|
||||||
|
By default ranged requests will be handled the same as normal
|
||||||
|
requests: the `ProvideCallback` will be called and the full
|
||||||
|
response body will be sent.
|
||||||
|
|
||||||
|
It is possible to let Cowboy handle ranged responses
|
||||||
|
automatically when the range unit is bytes and the
|
||||||
|
atom returned is `auto` (instead of a callback name).
|
||||||
|
In that case Cowboy will call the `ProvideCallback`
|
||||||
|
and split the response automatically, including by
|
||||||
|
producing a multipart/byteranges response if necessary.
|
||||||
|
|
||||||
|
== range_satisfiable
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
range_satisfiable(Req, State) -> {Result, Req, State}
|
||||||
|
|
||||||
|
Result :: boolean() | {false, non_neg_integer() | iodata()}
|
||||||
|
Default :: true
|
||||||
|
----
|
||||||
|
|
||||||
|
Whether the range request is satisfiable.
|
||||||
|
|
||||||
|
When the time comes to send the response body, and when
|
||||||
|
ranges have been provided via the `ranges_provided`
|
||||||
|
callback, Cowboy will process the if-range and the
|
||||||
|
range request headers and ensure it is satisfiable.
|
||||||
|
|
||||||
|
This callback allows making resource-specific checks
|
||||||
|
before sending the ranged response. The default is
|
||||||
|
to accept sending a ranged response.
|
||||||
|
|
||||||
|
Cowboy adds the requested `range` to the Req object
|
||||||
|
just before calling this callback:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
req() :: #{
|
||||||
|
range => {
|
||||||
|
binary(), %% lowercase; case insensitive
|
||||||
|
Range
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Range :: ByteRange | binary()
|
||||||
|
|
||||||
|
ByteRange :: [{FirstByte, LastByte | infinity} | SuffixLen]
|
||||||
|
FirstByte :: non_neg_integer()
|
||||||
|
LastByte :: non_neg_integer()
|
||||||
|
SuffixLen :: neg_integer()
|
||||||
|
----
|
||||||
|
|
||||||
|
Only byte ranges are parsed. Other ranges are provided
|
||||||
|
as binary. Byte ranges may either be requested from first
|
||||||
|
to last bytes (inclusive); from first bytes to the end
|
||||||
|
(`infinity` is used to represent the last byte); or
|
||||||
|
the last bytes of the representation via a negative
|
||||||
|
integer (so -500 means the last 500 bytes).
|
||||||
|
|
||||||
|
Returning `false` will result in a 416 Range Not Satisfiable
|
||||||
|
response being sent. The content-range header will be
|
||||||
|
set automatically in the response if a tuple is
|
||||||
|
returned. The integer value represents the total
|
||||||
|
size (in the choosen unit) of the resource. An
|
||||||
|
iodata value may also be returned and will be
|
||||||
|
used as-is to build the content range header,
|
||||||
|
prepended with the unit choosen.
|
||||||
|
|
||||||
=== rate_limited
|
=== rate_limited
|
||||||
|
|
||||||
|
@ -625,7 +747,7 @@ rate_limited(Req, State) -> {Result, Req, State}
|
||||||
|
|
||||||
Result :: false | {true, RetryAfter}
|
Result :: false | {true, RetryAfter}
|
||||||
RetryAfter :: non_neg_integer() | calendar:datetime()
|
RetryAfter :: non_neg_integer() | calendar:datetime()
|
||||||
Default - false
|
Default :: false
|
||||||
----
|
----
|
||||||
|
|
||||||
Return whether the user is rate limited.
|
Return whether the user is rate limited.
|
||||||
|
@ -734,6 +856,8 @@ listed here, like the authorization header.
|
||||||
|
|
||||||
== Changelog
|
== Changelog
|
||||||
|
|
||||||
|
* *2.11*: The `ranges_provided`, `range_satisfiable` and
|
||||||
|
the `RangeCallback` callbacks have been added.
|
||||||
* *2.11*: The `generate_etag` callback can now return
|
* *2.11*: The `generate_etag` callback can now return
|
||||||
`undefined` to conditionally avoid generating
|
`undefined` to conditionally avoid generating
|
||||||
an etag.
|
an etag.
|
||||||
|
|
|
@ -129,6 +129,8 @@ when it fails to detect a file's MIME type.
|
||||||
|
|
||||||
== Changelog
|
== Changelog
|
||||||
|
|
||||||
|
* *2.11*: Support for range requests was added in 2.6 and
|
||||||
|
is now considered stable.
|
||||||
* *2.6*: The `charset` extra option was added.
|
* *2.6*: The `charset` extra option was added.
|
||||||
* *1.0*: Handler introduced.
|
* *1.0*: Handler introduced.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue