diff --git a/doc/src/guide/resource_design.asciidoc b/doc/src/guide/resource_design.asciidoc
index 954d87d5..125b437c 100644
--- a/doc/src/guide/resource_design.asciidoc
+++ b/doc/src/guide/resource_design.asciidoc
@@ -144,6 +144,16 @@ never be called.
Implement the `languages_provided` or `charsets_provided`
callbacks if applicable.
+Does the resource accept ranged requests? If it does,
+implement the `ranges_provided` callback. Resources that
+only accept `bytes` units can use the callback name
+`auto` and let Cowboy automatically do ranged responses.
+Other callbacks should have a name prefix of `ranged_`
+for clarity. For example, `ranged_bytes` or `ranged_pages`.
+If the resource needs to perform additional checks before
+accepting to do a ranged responses, implement the
+`range_satisfiable` callback.
+
Is there any other header that may make the representation
of the resource vary? Implement the `variances` callback.
@@ -191,10 +201,15 @@ the `options` method.
=== GET and HEAD methods
If you implement the methods GET and/or HEAD, you must
-implement one `ProvideResource` callback for each
+implement one `ProvideCallback` callback for each
content-type returned by the `content_types_provided`
callback.
+When range requests are accepted, you must implement one
+`RangeCallback` for each range unit returned by
+`ranges_provided` (unless `auto` was used). This is
+in addition to the `ProvideCallback` callback.
+
=== PUT, POST and PATCH methods
If you implement the methods PUT, POST and/or PATCH,
diff --git a/doc/src/guide/rest_conneg.png b/doc/src/guide/rest_conneg.png
index 65ecdcf3..79aa69b6 100644
Binary files a/doc/src/guide/rest_conneg.png and b/doc/src/guide/rest_conneg.png differ
diff --git a/doc/src/guide/rest_conneg.svg b/doc/src/guide/rest_conneg.svg
index 247567a0..97bba6a3 100644
--- a/doc/src/guide/rest_conneg.svg
+++ b/doc/src/guide/rest_conneg.svg
@@ -2,24 +2,23 @@
diff --git a/doc/src/guide/rest_flowcharts.asciidoc b/doc/src/guide/rest_flowcharts.asciidoc
index 308a919e..b8d0e0d5 100644
--- a/doc/src/guide/rest_flowcharts.asciidoc
+++ b/doc/src/guide/rest_flowcharts.asciidoc
@@ -95,6 +95,11 @@ callback will only be called at the end of the
"GET and HEAD methods" diagram, when all conditions
have been met.
+Optionally, the `ranges_provided` also returns the
+name of a callback for every range unit it accepts. This
+will be called at the end of the "GET and HEAD methods"
+diagram in the case of ranged requests.
+
The selected content-type, language and charset are
saved as meta values in the Req object. You *should*
use the appropriate representation if you set a
@@ -121,11 +126,18 @@ succeed, the resource can be retrieved.
Cowboy prepares the response by first retrieving
metadata about the representation, then by calling
-the `ProvideResource` callback. This is the callback
+the `ProvideCallback` callback. This is the callback
you defined for each content-types you returned from
`content_types_provided`. This callback returns the body
-that will be sent back to the client, or a fun if the
-body must be streamed.
+that will be sent back to the client.
+
+For ranged requests, but only when the `ranges_provided`
+callback was defined earlier, Cowboy will add the selected
+`range` information to the Req object and call the
+`range_satisfiable` callback. After confirming that the
+range can be provided, Cowboy calls the `RangeResource`
+callback and produces a ranged response using the
+ranged data from the callback.
When the resource does not exist, Cowboy will figure out
whether the resource existed previously, and if so whether
diff --git a/doc/src/guide/rest_get_head.png b/doc/src/guide/rest_get_head.png
index 211ab603..24f8de45 100644
Binary files a/doc/src/guide/rest_get_head.png and b/doc/src/guide/rest_get_head.png differ
diff --git a/doc/src/guide/rest_get_head.svg b/doc/src/guide/rest_get_head.svg
index 92030cf3..cf660897 100644
--- a/doc/src/guide/rest_get_head.svg
+++ b/doc/src/guide/rest_get_head.svg
@@ -2,24 +2,23 @@
diff --git a/doc/src/guide/rest_handlers.asciidoc b/doc/src/guide/rest_handlers.asciidoc
index baf8e6a2..19a98596 100644
--- a/doc/src/guide/rest_handlers.asciidoc
+++ b/doc/src/guide/rest_handlers.asciidoc
@@ -84,6 +84,8 @@ if it is undefined, moving directly to the next step. Similarly,
| multiple_choices | `false`
| options | `ok`
| previously_existed | `false`
+| ranges_provided | skip
+| range_satisfiable | `true`
| rate_limited | `false`
| resource_exists | `true`
| service_available | `true`
@@ -97,8 +99,9 @@ As you can see, Cowboy tries to move on with the request whenever
possible by using well thought out default values.
In addition to these, there can be any number of user-defined
-callbacks that are specified through `content_types_accepted/2`
-and `content_types_provided/2`. They can take any name, however
+callbacks that are specified through `content_types_accepted/2`,
+`content_types_provided/2` or `ranges_provided/2`. They can take
+any name (except `auto` for range callbacks), however
it is recommended to use a separate prefix for the callbacks of
each function. For example, `from_html` and `to_html` indicate
in the first case that we're accepting a resource given as HTML,
@@ -113,9 +116,10 @@ Req object directly. The values are defined in the following table:
[cols="<,<",options="header"]
|===
| Key | Details
-| media_type | The content-type negotiated for the response entity.
-| language | The language negotiated for the response entity.
-| charset | The charset negotiated for the response entity.
+| media_type | The content-type negotiated for the response entity
+| language | The language negotiated for the response entity
+| charset | The charset negotiated for the response entity
+| range | The range selected for the ranged response
|===
They can be used to send a proper body with the response to a
@@ -129,11 +133,16 @@ of the REST code. They are listed in the following table.
[cols="<,<",options="header"]
|===
| Header name | Details
+| accept-ranges | Range units accepted by the resource
+| allow | HTTP methods allowed by the resource
| content-language | Language used in the response body
+| content-range | Range of the content found in the response
| content-type | Media type and charset of the response body
| etag | Etag of the resource
| expires | Expiration date of the resource
| last-modified | Last modification date for the resource
| location | Relative or absolute URI to the requested resource
+| retry-after | Delay or time the client should wait before accessing the resource
| vary | List of headers that may change the representation of the resource
+| www-authenticate | Authentication information to access the resource
|===
diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl
index 003e5f9d..ace5986a 100644
--- a/src/cowboy_rest.erl
+++ b/src/cowboy_rest.erl
@@ -1196,6 +1196,7 @@ if_range(Req=#{headers := #{<<"if-range">> := _, <<"range">> := _}},
if_range(Req, State) ->
range(Req, State).
+%% @todo This can probably be moved to if_range directly.
range(Req, State=#state{ranges_a=[]}) ->
set_resp_body(Req, State);
range(Req, State) ->