zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

cowboy_rest.erl (59826B)


      1 %% Copyright (c) 2011-2017, Loïc Hoguin <essen@ninenines.eu>
      2 %%
      3 %% Permission to use, copy, modify, and/or distribute this software for any
      4 %% purpose with or without fee is hereby granted, provided that the above
      5 %% copyright notice and this permission notice appear in all copies.
      6 %%
      7 %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8 %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9 %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     10 %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11 %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     12 %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     13 %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     14 
     15 %% Originally based on the Webmachine Diagram from Alan Dean and
     16 %% Justin Sheehy.
     17 -module(cowboy_rest).
     18 -behaviour(cowboy_sub_protocol).
     19 
     20 -export([upgrade/4]).
     21 -export([upgrade/5]).
     22 
     23 -type switch_handler() :: {switch_handler, module()}
     24 	| {switch_handler, module(), any()}.
     25 
     26 %% Common handler callbacks.
     27 
     28 -callback init(Req, any())
     29 	-> {ok | module(), Req, any()}
     30 	| {module(), Req, any(), any()}
     31 	when Req::cowboy_req:req().
     32 
     33 -callback terminate(any(), cowboy_req:req(), any()) -> ok.
     34 -optional_callbacks([terminate/3]).
     35 
     36 %% REST handler callbacks.
     37 
     38 -callback allowed_methods(Req, State)
     39 	-> {[binary()], Req, State}
     40 	| {stop, Req, State}
     41 	| {switch_handler(), Req, State}
     42 	when Req::cowboy_req:req(), State::any().
     43 -optional_callbacks([allowed_methods/2]).
     44 
     45 -callback allow_missing_post(Req, State)
     46 	-> {boolean(), Req, State}
     47 	| {stop, Req, State}
     48 	| {switch_handler(), Req, State}
     49 	when Req::cowboy_req:req(), State::any().
     50 -optional_callbacks([allow_missing_post/2]).
     51 
     52 -callback charsets_provided(Req, State)
     53 	-> {[binary()], Req, State}
     54 	| {stop, Req, State}
     55 	| {switch_handler(), Req, State}
     56 	when Req::cowboy_req:req(), State::any().
     57 -optional_callbacks([charsets_provided/2]).
     58 
     59 -callback content_types_accepted(Req, State)
     60 	-> {[{'*' | binary() | {binary(), binary(), '*' | [{binary(), binary()}]}, atom()}], Req, State}
     61 	| {stop, Req, State}
     62 	| {switch_handler(), Req, State}
     63 	when Req::cowboy_req:req(), State::any().
     64 -optional_callbacks([content_types_accepted/2]).
     65 
     66 -callback content_types_provided(Req, State)
     67 	-> {[{binary() | {binary(), binary(), '*' | [{binary(), binary()}]}, atom()}], Req, State}
     68 	| {stop, Req, State}
     69 	| {switch_handler(), Req, State}
     70 	when Req::cowboy_req:req(), State::any().
     71 -optional_callbacks([content_types_provided/2]).
     72 
     73 -callback delete_completed(Req, State)
     74 	-> {boolean(), Req, State}
     75 	| {stop, Req, State}
     76 	| {switch_handler(), Req, State}
     77 	when Req::cowboy_req:req(), State::any().
     78 -optional_callbacks([delete_completed/2]).
     79 
     80 -callback delete_resource(Req, State)
     81 	-> {boolean(), Req, State}
     82 	| {stop, Req, State}
     83 	| {switch_handler(), Req, State}
     84 	when Req::cowboy_req:req(), State::any().
     85 -optional_callbacks([delete_resource/2]).
     86 
     87 -callback expires(Req, State)
     88 	-> {calendar:datetime() | binary() | undefined, Req, State}
     89 	when Req::cowboy_req:req(), State::any().
     90 -optional_callbacks([expires/2]).
     91 
     92 -callback forbidden(Req, State)
     93 	-> {boolean(), Req, State}
     94 	| {stop, Req, State}
     95 	| {switch_handler(), Req, State}
     96 	when Req::cowboy_req:req(), State::any().
     97 -optional_callbacks([forbidden/2]).
     98 
     99 -callback generate_etag(Req, State)
    100 	-> {binary() | {weak | strong, binary()}, Req, State}
    101 	when Req::cowboy_req:req(), State::any().
    102 -optional_callbacks([generate_etag/2]).
    103 
    104 -callback is_authorized(Req, State)
    105 	-> {true | {false, iodata()}, Req, State}
    106 	| {stop, Req, State}
    107 	| {switch_handler(), Req, State}
    108 	when Req::cowboy_req:req(), State::any().
    109 -optional_callbacks([is_authorized/2]).
    110 
    111 -callback is_conflict(Req, State)
    112 	-> {boolean(), Req, State}
    113 	| {stop, Req, State}
    114 	| {switch_handler(), Req, State}
    115 	when Req::cowboy_req:req(), State::any().
    116 -optional_callbacks([is_conflict/2]).
    117 
    118 -callback known_methods(Req, State)
    119 	-> {[binary()], Req, State}
    120 	| {stop, Req, State}
    121 	| {switch_handler(), Req, State}
    122 	when Req::cowboy_req:req(), State::any().
    123 -optional_callbacks([known_methods/2]).
    124 
    125 -callback languages_provided(Req, State)
    126 	-> {[binary()], Req, State}
    127 	| {stop, Req, State}
    128 	| {switch_handler(), Req, State}
    129 	when Req::cowboy_req:req(), State::any().
    130 -optional_callbacks([languages_provided/2]).
    131 
    132 -callback last_modified(Req, State)
    133 	-> {calendar:datetime(), Req, State}
    134 	when Req::cowboy_req:req(), State::any().
    135 -optional_callbacks([last_modified/2]).
    136 
    137 -callback malformed_request(Req, State)
    138 	-> {boolean(), Req, State}
    139 	| {stop, Req, State}
    140 	| {switch_handler(), Req, State}
    141 	when Req::cowboy_req:req(), State::any().
    142 -optional_callbacks([malformed_request/2]).
    143 
    144 -callback moved_permanently(Req, State)
    145 	-> {{true, iodata()} | false, Req, State}
    146 	| {stop, Req, State}
    147 	| {switch_handler(), Req, State}
    148 	when Req::cowboy_req:req(), State::any().
    149 -optional_callbacks([moved_permanently/2]).
    150 
    151 -callback moved_temporarily(Req, State)
    152 	-> {{true, iodata()} | false, Req, State}
    153 	| {stop, Req, State}
    154 	| {switch_handler(), Req, State}
    155 	when Req::cowboy_req:req(), State::any().
    156 -optional_callbacks([moved_temporarily/2]).
    157 
    158 -callback multiple_choices(Req, State)
    159 	-> {boolean(), Req, State}
    160 	| {stop, Req, State}
    161 	| {switch_handler(), Req, State}
    162 	when Req::cowboy_req:req(), State::any().
    163 -optional_callbacks([multiple_choices/2]).
    164 
    165 -callback options(Req, State)
    166 	-> {ok, Req, State}
    167 	| {stop, Req, State}
    168 	| {switch_handler(), Req, State}
    169 	when Req::cowboy_req:req(), State::any().
    170 -optional_callbacks([options/2]).
    171 
    172 -callback previously_existed(Req, State)
    173 	-> {boolean(), Req, State}
    174 	| {stop, Req, State}
    175 	| {switch_handler(), Req, State}
    176 	when Req::cowboy_req:req(), State::any().
    177 -optional_callbacks([previously_existed/2]).
    178 
    179 -callback range_satisfiable(Req, State)
    180 	-> {boolean() | {false, non_neg_integer() | iodata()}, Req, State}
    181 	| {stop, Req, State}
    182 	| {switch_handler(), Req, State}
    183 	when Req::cowboy_req:req(), State::any().
    184 -optional_callbacks([range_satisfiable/2]).
    185 
    186 -callback ranges_provided(Req, State)
    187 	-> {[{binary(), atom()}], Req, State}
    188 	| {stop, Req, State}
    189 	| {switch_handler(), Req, State}
    190 	when Req::cowboy_req:req(), State::any().
    191 -optional_callbacks([ranges_provided/2]).
    192 
    193 -callback rate_limited(Req, State)
    194 	-> {{true, non_neg_integer() | calendar:datetime()} | false, Req, State}
    195 	| {stop, Req, State}
    196 	| {switch_handler(), Req, State}
    197 	when Req::cowboy_req:req(), State::any().
    198 -optional_callbacks([rate_limited/2]).
    199 
    200 -callback resource_exists(Req, State)
    201 	-> {boolean(), Req, State}
    202 	| {stop, Req, State}
    203 	| {switch_handler(), Req, State}
    204 	when Req::cowboy_req:req(), State::any().
    205 -optional_callbacks([resource_exists/2]).
    206 
    207 -callback service_available(Req, State)
    208 	-> {boolean(), Req, State}
    209 	| {stop, Req, State}
    210 	| {switch_handler(), Req, State}
    211 	when Req::cowboy_req:req(), State::any().
    212 -optional_callbacks([service_available/2]).
    213 
    214 -callback uri_too_long(Req, State)
    215 	-> {boolean(), Req, State}
    216 	| {stop, Req, State}
    217 	| {switch_handler(), Req, State}
    218 	when Req::cowboy_req:req(), State::any().
    219 -optional_callbacks([uri_too_long/2]).
    220 
    221 -callback valid_content_headers(Req, State)
    222 	-> {boolean(), Req, State}
    223 	| {stop, Req, State}
    224 	| {switch_handler(), Req, State}
    225 	when Req::cowboy_req:req(), State::any().
    226 -optional_callbacks([valid_content_headers/2]).
    227 
    228 -callback valid_entity_length(Req, State)
    229 	-> {boolean(), Req, State}
    230 	| {stop, Req, State}
    231 	| {switch_handler(), Req, State}
    232 	when Req::cowboy_req:req(), State::any().
    233 -optional_callbacks([valid_entity_length/2]).
    234 
    235 -callback variances(Req, State)
    236 	-> {[binary()], Req, State}
    237 	when Req::cowboy_req:req(), State::any().
    238 -optional_callbacks([variances/2]).
    239 
    240 %% End of REST callbacks. Whew!
    241 
    242 -record(state, {
    243 	method = undefined :: binary(),
    244 
    245 	%% Handler.
    246 	handler :: atom(),
    247 	handler_state :: any(),
    248 
    249 	%% Allowed methods. Only used for OPTIONS requests.
    250 	allowed_methods :: [binary()] | undefined,
    251 
    252 	%% Media type.
    253 	content_types_p = [] ::
    254 		[{binary() | {binary(), binary(), [{binary(), binary()}] | '*'},
    255 			atom()}],
    256 	content_type_a :: undefined
    257 		| {binary() | {binary(), binary(), [{binary(), binary()}] | '*'},
    258 			atom()},
    259 
    260 	%% Language.
    261 	languages_p = [] :: [binary()],
    262 	language_a :: undefined | binary(),
    263 
    264 	%% Charset.
    265 	charsets_p = undefined :: undefined | [binary()],
    266 	charset_a :: undefined | binary(),
    267 
    268 	%% Range units.
    269 	ranges_a = [] :: [{binary(), atom()}],
    270 
    271 	%% Whether the resource exists.
    272 	exists = false :: boolean(),
    273 
    274 	%% Cached resource calls.
    275 	etag :: undefined | no_call | {strong | weak, binary()},
    276 	last_modified :: undefined | no_call | calendar:datetime(),
    277 	expires :: undefined | no_call | calendar:datetime() | binary()
    278 }).
    279 
    280 -spec upgrade(Req, Env, module(), any())
    281 	-> {ok, Req, Env} when Req::cowboy_req:req(), Env::cowboy_middleware:env().
    282 upgrade(Req0, Env, Handler, HandlerState0) ->
    283 	Method = cowboy_req:method(Req0),
    284 	case service_available(Req0, #state{method=Method,
    285 			handler=Handler, handler_state=HandlerState0}) of
    286 		{ok, Req, Result} ->
    287 			{ok, Req, Env#{result => Result}};
    288 		{Mod, Req, HandlerState} ->
    289 			Mod:upgrade(Req, Env, Handler, HandlerState);
    290 		{Mod, Req, HandlerState, Opts} ->
    291 			Mod:upgrade(Req, Env, Handler, HandlerState, Opts)
    292 	end.
    293 
    294 -spec upgrade(Req, Env, module(), any(), any())
    295 	-> {ok, Req, Env} when Req::cowboy_req:req(), Env::cowboy_middleware:env().
    296 %% cowboy_rest takes no options.
    297 upgrade(Req, Env, Handler, HandlerState, _Opts) ->
    298 	upgrade(Req, Env, Handler, HandlerState).
    299 
    300 service_available(Req, State) ->
    301 	expect(Req, State, service_available, true, fun known_methods/2, 503).
    302 
    303 %% known_methods/2 should return a list of binary methods.
    304 known_methods(Req, State=#state{method=Method}) ->
    305 	case call(Req, State, known_methods) of
    306 		no_call when Method =:= <<"HEAD">>; Method =:= <<"GET">>;
    307 				Method =:= <<"POST">>; Method =:= <<"PUT">>;
    308 				Method =:= <<"PATCH">>; Method =:= <<"DELETE">>;
    309 				Method =:= <<"OPTIONS">> ->
    310 			next(Req, State, fun uri_too_long/2);
    311 		no_call ->
    312 			next(Req, State, 501);
    313 		{stop, Req2, State2} ->
    314 			terminate(Req2, State2);
    315 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    316 			switch_handler(Switch, Req2, State2);
    317 		{List, Req2, State2} ->
    318 			case lists:member(Method, List) of
    319 				true -> next(Req2, State2, fun uri_too_long/2);
    320 				false -> next(Req2, State2, 501)
    321 			end
    322 	end.
    323 
    324 uri_too_long(Req, State) ->
    325 	expect(Req, State, uri_too_long, false, fun allowed_methods/2, 414).
    326 
    327 %% allowed_methods/2 should return a list of binary methods.
    328 allowed_methods(Req, State=#state{method=Method}) ->
    329 	case call(Req, State, allowed_methods) of
    330 		no_call when Method =:= <<"HEAD">>; Method =:= <<"GET">> ->
    331 			next(Req, State, fun malformed_request/2);
    332 		no_call when Method =:= <<"OPTIONS">> ->
    333 			next(Req, State#state{allowed_methods=
    334 				[<<"HEAD">>, <<"GET">>, <<"OPTIONS">>]},
    335 				fun malformed_request/2);
    336 		no_call ->
    337 			method_not_allowed(Req, State,
    338 				[<<"HEAD">>, <<"GET">>, <<"OPTIONS">>]);
    339 		{stop, Req2, State2} ->
    340 			terminate(Req2, State2);
    341 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    342 			switch_handler(Switch, Req2, State2);
    343 		{List, Req2, State2} ->
    344 			case lists:member(Method, List) of
    345 				true when Method =:= <<"OPTIONS">> ->
    346 					next(Req2, State2#state{allowed_methods=List},
    347 						fun malformed_request/2);
    348 				true ->
    349 					next(Req2, State2, fun malformed_request/2);
    350 				false ->
    351 					method_not_allowed(Req2, State2, List)
    352 			end
    353 	end.
    354 
    355 method_not_allowed(Req, State, []) ->
    356 	Req2 = cowboy_req:set_resp_header(<<"allow">>, <<>>, Req),
    357 	respond(Req2, State, 405);
    358 method_not_allowed(Req, State, Methods) ->
    359 	<< ", ", Allow/binary >> = << << ", ", M/binary >> || M <- Methods >>,
    360 	Req2 = cowboy_req:set_resp_header(<<"allow">>, Allow, Req),
    361 	respond(Req2, State, 405).
    362 
    363 malformed_request(Req, State) ->
    364 	expect(Req, State, malformed_request, false, fun is_authorized/2, 400).
    365 
    366 %% is_authorized/2 should return true or {false, WwwAuthenticateHeader}.
    367 is_authorized(Req, State) ->
    368 	case call(Req, State, is_authorized) of
    369 		no_call ->
    370 			forbidden(Req, State);
    371 		{stop, Req2, State2} ->
    372 			terminate(Req2, State2);
    373 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    374 			switch_handler(Switch, Req2, State2);
    375 		{true, Req2, State2} ->
    376 			forbidden(Req2, State2);
    377 		{{false, AuthHead}, Req2, State2} ->
    378 			Req3 = cowboy_req:set_resp_header(
    379 				<<"www-authenticate">>, AuthHead, Req2),
    380 			respond(Req3, State2, 401)
    381 	end.
    382 
    383 forbidden(Req, State) ->
    384 	expect(Req, State, forbidden, false, fun rate_limited/2, 403).
    385 
    386 rate_limited(Req, State) ->
    387 	case call(Req, State, rate_limited) of
    388 		no_call ->
    389 			valid_content_headers(Req, State);
    390 		{stop, Req2, State2} ->
    391 			terminate(Req2, State2);
    392 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    393 			switch_handler(Switch, Req2, State2);
    394 		{false, Req2, State2} ->
    395 			valid_content_headers(Req2, State2);
    396 		{{true, RetryAfter0}, Req2, State2} ->
    397 			RetryAfter = if
    398 				is_integer(RetryAfter0), RetryAfter0 >= 0 ->
    399 					integer_to_binary(RetryAfter0);
    400 				is_tuple(RetryAfter0) ->
    401 					cowboy_clock:rfc1123(RetryAfter0)
    402 			end,
    403 			Req3 = cowboy_req:set_resp_header(<<"retry-after">>, RetryAfter, Req2),
    404 			respond(Req3, State2, 429)
    405 	end.
    406 
    407 valid_content_headers(Req, State) ->
    408 	expect(Req, State, valid_content_headers, true,
    409 		fun valid_entity_length/2, 501).
    410 
    411 valid_entity_length(Req, State) ->
    412 	expect(Req, State, valid_entity_length, true, fun options/2, 413).
    413 
    414 %% If you need to add additional headers to the response at this point,
    415 %% you should do it directly in the options/2 call using set_resp_headers.
    416 options(Req, State=#state{allowed_methods=Methods, method= <<"OPTIONS">>}) ->
    417 	case call(Req, State, options) of
    418 		no_call when Methods =:= [] ->
    419 			Req2 = cowboy_req:set_resp_header(<<"allow">>, <<>>, Req),
    420 			respond(Req2, State, 200);
    421 		no_call ->
    422 			<< ", ", Allow/binary >>
    423 				= << << ", ", M/binary >> || M <- Methods >>,
    424 			Req2 = cowboy_req:set_resp_header(<<"allow">>, Allow, Req),
    425 			respond(Req2, State, 200);
    426 		{stop, Req2, State2} ->
    427 			terminate(Req2, State2);
    428 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    429 			switch_handler(Switch, Req2, State2);
    430 		{ok, Req2, State2} ->
    431 			respond(Req2, State2, 200)
    432 	end;
    433 options(Req, State) ->
    434 	content_types_provided(Req, State).
    435 
    436 %% content_types_provided/2 should return a list of content types and their
    437 %% associated callback function as a tuple: {{Type, SubType, Params}, Fun}.
    438 %% Type and SubType are the media type as binary. Params is a list of
    439 %% Key/Value tuple, with Key and Value a binary. Fun is the name of the
    440 %% callback that will be used to return the content of the response. It is
    441 %% given as an atom.
    442 %%
    443 %% An example of such return value would be:
    444 %%    {{<<"text">>, <<"html">>, []}, to_html}
    445 %%
    446 %% Note that it is also possible to return a binary content type that will
    447 %% then be parsed by Cowboy. However note that while this may make your
    448 %% resources a little more readable, this is a lot less efficient.
    449 %%
    450 %% An example of such return value would be:
    451 %%    {<<"text/html">>, to_html}
    452 content_types_provided(Req, State) ->
    453 	case call(Req, State, content_types_provided) of
    454 		no_call ->
    455 			State2 = State#state{
    456 				content_types_p=[{{<<"text">>, <<"html">>, '*'}, to_html}]},
    457 			try cowboy_req:parse_header(<<"accept">>, Req) of
    458 				undefined ->
    459 					languages_provided(
    460 						Req#{media_type => {<<"text">>, <<"html">>, []}},
    461 						State2#state{content_type_a={{<<"text">>, <<"html">>, []}, to_html}});
    462 				Accept ->
    463 					choose_media_type(Req, State2, prioritize_accept(Accept))
    464 			catch _:_ ->
    465 				respond(Req, State2, 400)
    466 			end;
    467 		{stop, Req2, State2} ->
    468 			terminate(Req2, State2);
    469 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    470 			switch_handler(Switch, Req2, State2);
    471 		{[], Req2, State2} ->
    472 			not_acceptable(Req2, State2);
    473 		{CTP, Req2, State2} ->
    474 			CTP2 = [normalize_content_types(P) || P <- CTP],
    475 			State3 = State2#state{content_types_p=CTP2},
    476 			try cowboy_req:parse_header(<<"accept">>, Req2) of
    477 				undefined ->
    478 					{PMT0, _Fun} = HeadCTP = hd(CTP2),
    479 					%% We replace the wildcard by an empty list of parameters.
    480 					PMT = case PMT0 of
    481 						{Type, SubType, '*'} -> {Type, SubType, []};
    482 						_ -> PMT0
    483 					end,
    484 					languages_provided(
    485 						Req2#{media_type => PMT},
    486 						State3#state{content_type_a=HeadCTP});
    487 				Accept ->
    488 					choose_media_type(Req2, State3, prioritize_accept(Accept))
    489 			catch _:_ ->
    490 				respond(Req2, State3, 400)
    491 			end
    492 	end.
    493 
    494 normalize_content_types({ContentType, Callback})
    495 		when is_binary(ContentType) ->
    496 	{cow_http_hd:parse_content_type(ContentType), Callback};
    497 normalize_content_types(Normalized) ->
    498 	Normalized.
    499 
    500 prioritize_accept(Accept) ->
    501 	lists:sort(
    502 		fun ({MediaTypeA, Quality, _AcceptParamsA},
    503 			 {MediaTypeB, Quality, _AcceptParamsB}) ->
    504 				%% Same quality, check precedence in more details.
    505 				prioritize_mediatype(MediaTypeA, MediaTypeB);
    506 			({_MediaTypeA, QualityA, _AcceptParamsA},
    507 			 {_MediaTypeB, QualityB, _AcceptParamsB}) ->
    508 				%% Just compare the quality.
    509 				QualityA > QualityB
    510 		end, Accept).
    511 
    512 %% Media ranges can be overridden by more specific media ranges or
    513 %% specific media types. If more than one media range applies to a given
    514 %% type, the most specific reference has precedence.
    515 %%
    516 %% We always choose B over A when we can't decide between the two.
    517 prioritize_mediatype({TypeA, SubTypeA, ParamsA}, {TypeB, SubTypeB, ParamsB}) ->
    518 	case TypeB of
    519 		TypeA ->
    520 			case SubTypeB of
    521 				SubTypeA -> length(ParamsA) > length(ParamsB);
    522 				<<"*">> -> true;
    523 				_Any -> false
    524 			end;
    525 		<<"*">> -> true;
    526 		_Any -> false
    527 	end.
    528 
    529 %% Ignoring the rare AcceptParams. Not sure what should be done about them.
    530 choose_media_type(Req, State, []) ->
    531 	not_acceptable(Req, State);
    532 choose_media_type(Req, State=#state{content_types_p=CTP},
    533 		[MediaType|Tail]) ->
    534 	match_media_type(Req, State, Tail, CTP, MediaType).
    535 
    536 match_media_type(Req, State, Accept, [], _MediaType) ->
    537 	choose_media_type(Req, State, Accept);
    538 match_media_type(Req, State, Accept, CTP,
    539 		MediaType = {{<<"*">>, <<"*">>, _Params_A}, _QA, _APA}) ->
    540 	match_media_type_params(Req, State, Accept, CTP, MediaType);
    541 match_media_type(Req, State, Accept,
    542 			CTP = [{{Type, SubType_P, _PP}, _Fun}|_Tail],
    543 			MediaType = {{Type, SubType_A, _PA}, _QA, _APA})
    544 		when SubType_P =:= SubType_A; SubType_A =:= <<"*">> ->
    545 	match_media_type_params(Req, State, Accept, CTP, MediaType);
    546 match_media_type(Req, State, Accept, [_Any|Tail], MediaType) ->
    547 	match_media_type(Req, State, Accept, Tail, MediaType).
    548 
    549 match_media_type_params(Req, State, Accept,
    550 		[Provided = {{TP, STP, '*'}, _Fun}|Tail],
    551 		MediaType = {{TA, _STA, Params_A0}, _QA, _APA}) ->
    552 	case lists:keytake(<<"charset">>, 1, Params_A0) of
    553 		{value, {_, Charset}, Params_A} when TA =:= <<"text">> ->
    554 			%% When we match against a wildcard, the media type is text
    555 			%% and has a charset parameter, we call charsets_provided
    556 			%% and check that the charset is provided. If the callback
    557 			%% is not exported, we accept inconditionally but ignore
    558 			%% the given charset so as to not send a wrong value back.
    559 			case call(Req, State, charsets_provided) of
    560 				no_call ->
    561 					languages_provided(Req#{media_type => {TP, STP, Params_A0}},
    562 						State#state{content_type_a=Provided});
    563 				{stop, Req2, State2} ->
    564 					terminate(Req2, State2);
    565 				{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    566 					switch_handler(Switch, Req2, State2);
    567 				{CP, Req2, State2} ->
    568 					State3 = State2#state{charsets_p=CP},
    569 					case lists:member(Charset, CP) of
    570 						false ->
    571 							match_media_type(Req2, State3, Accept, Tail, MediaType);
    572 						true ->
    573 							languages_provided(Req2#{media_type => {TP, STP, Params_A}},
    574 								State3#state{content_type_a=Provided,
    575 									charset_a=Charset})
    576 					end
    577 			end;
    578 		_ ->
    579 			languages_provided(Req#{media_type => {TP, STP, Params_A0}},
    580 				State#state{content_type_a=Provided})
    581 	end;
    582 match_media_type_params(Req, State, Accept,
    583 		[Provided = {PMT = {TP, STP, Params_P0}, Fun}|Tail],
    584 		MediaType = {{_TA, _STA, Params_A}, _QA, _APA}) ->
    585 	case lists:sort(Params_P0) =:= lists:sort(Params_A) of
    586 		true when TP =:= <<"text">> ->
    587 			%% When a charset was provided explicitly in both the charset header
    588 			%% and the media types provided and the negotiation is successful,
    589 			%% we keep the charset and don't call charsets_provided. This only
    590 			%% applies to text media types, however.
    591 			{Charset, Params_P} = case lists:keytake(<<"charset">>, 1, Params_P0) of
    592 				false -> {undefined, Params_P0};
    593 				{value, {_, Charset0}, Params_P1} -> {Charset0, Params_P1}
    594 			end,
    595 			languages_provided(Req#{media_type => {TP, STP, Params_P}},
    596 				State#state{content_type_a={{TP, STP, Params_P}, Fun},
    597 					charset_a=Charset});
    598 		true ->
    599 			languages_provided(Req#{media_type => PMT},
    600 				State#state{content_type_a=Provided});
    601 		false ->
    602 			match_media_type(Req, State, Accept, Tail, MediaType)
    603 	end.
    604 
    605 %% languages_provided should return a list of binary values indicating
    606 %% which languages are accepted by the resource.
    607 %%
    608 %% @todo I suppose we should also ask the resource if it wants to
    609 %% set a language itself or if it wants it to be automatically chosen.
    610 languages_provided(Req, State) ->
    611 	case call(Req, State, languages_provided) of
    612 		no_call ->
    613 			charsets_provided(Req, State);
    614 		{stop, Req2, State2} ->
    615 			terminate(Req2, State2);
    616 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    617 			switch_handler(Switch, Req2, State2);
    618 		{[], Req2, State2} ->
    619 			not_acceptable(Req2, State2);
    620 		{LP, Req2, State2} ->
    621 			State3 = State2#state{languages_p=LP},
    622 			case cowboy_req:parse_header(<<"accept-language">>, Req2) of
    623 				undefined ->
    624 					set_language(Req2, State3#state{language_a=hd(LP)});
    625 				AcceptLanguage ->
    626 					AcceptLanguage2 = prioritize_languages(AcceptLanguage),
    627 					choose_language(Req2, State3, AcceptLanguage2)
    628 			end
    629 	end.
    630 
    631 %% A language-range matches a language-tag if it exactly equals the tag,
    632 %% or if it exactly equals a prefix of the tag such that the first tag
    633 %% character following the prefix is "-". The special range "*", if
    634 %% present in the Accept-Language field, matches every tag not matched
    635 %% by any other range present in the Accept-Language field.
    636 %%
    637 %% @todo The last sentence probably means we should always put '*'
    638 %% at the end of the list.
    639 prioritize_languages(AcceptLanguages) ->
    640 	lists:sort(
    641 		fun ({_TagA, QualityA}, {_TagB, QualityB}) ->
    642 			QualityA > QualityB
    643 		end, AcceptLanguages).
    644 
    645 choose_language(Req, State, []) ->
    646 	not_acceptable(Req, State);
    647 choose_language(Req, State=#state{languages_p=LP}, [Language|Tail]) ->
    648 	match_language(Req, State, Tail, LP, Language).
    649 
    650 match_language(Req, State, Accept, [], _Language) ->
    651 	choose_language(Req, State, Accept);
    652 match_language(Req, State, _Accept, [Provided|_Tail], {'*', _Quality}) ->
    653 	set_language(Req, State#state{language_a=Provided});
    654 match_language(Req, State, _Accept, [Provided|_Tail], {Provided, _Quality}) ->
    655 	set_language(Req, State#state{language_a=Provided});
    656 match_language(Req, State, Accept, [Provided|Tail],
    657 		Language = {Tag, _Quality}) ->
    658 	Length = byte_size(Tag),
    659 	case Provided of
    660 		<< Tag:Length/binary, $-, _Any/bits >> ->
    661 			set_language(Req, State#state{language_a=Provided});
    662 		_Any ->
    663 			match_language(Req, State, Accept, Tail, Language)
    664 	end.
    665 
    666 set_language(Req, State=#state{language_a=Language}) ->
    667 	Req2 = cowboy_req:set_resp_header(<<"content-language">>, Language, Req),
    668 	charsets_provided(Req2#{language => Language}, State).
    669 
    670 %% charsets_provided should return a list of binary values indicating
    671 %% which charsets are accepted by the resource.
    672 %%
    673 %% A charset may have been selected while negotiating the accept header.
    674 %% There's no need to select one again.
    675 charsets_provided(Req, State=#state{charset_a=Charset})
    676 		when Charset =/= undefined ->
    677 	set_content_type(Req, State);
    678 %% If charsets_p is defined, use it instead of calling charsets_provided
    679 %% again. We also call this clause during normal execution to avoid
    680 %% duplicating code.
    681 charsets_provided(Req, State=#state{charsets_p=[]}) ->
    682 	not_acceptable(Req, State);
    683 charsets_provided(Req, State=#state{charsets_p=CP})
    684 		when CP =/= undefined ->
    685 	case cowboy_req:parse_header(<<"accept-charset">>, Req) of
    686 		undefined ->
    687 			set_content_type(Req, State#state{charset_a=hd(CP)});
    688 		AcceptCharset0 ->
    689 			AcceptCharset = prioritize_charsets(AcceptCharset0),
    690 			choose_charset(Req, State, AcceptCharset)
    691 	end;
    692 charsets_provided(Req, State) ->
    693 	case call(Req, State, charsets_provided) of
    694 		no_call ->
    695 			set_content_type(Req, State);
    696 		{stop, Req2, State2} ->
    697 			terminate(Req2, State2);
    698 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    699 			switch_handler(Switch, Req2, State2);
    700 		{CP, Req2, State2} ->
    701 			charsets_provided(Req2, State2#state{charsets_p=CP})
    702 	end.
    703 
    704 prioritize_charsets(AcceptCharsets) ->
    705 	lists:sort(
    706 		fun ({_CharsetA, QualityA}, {_CharsetB, QualityB}) ->
    707 			QualityA > QualityB
    708 		end, AcceptCharsets).
    709 
    710 choose_charset(Req, State, []) ->
    711 	not_acceptable(Req, State);
    712 %% A q-value of 0 means not acceptable.
    713 choose_charset(Req, State, [{_, 0}|Tail]) ->
    714 	choose_charset(Req, State, Tail);
    715 choose_charset(Req, State=#state{charsets_p=CP}, [Charset|Tail]) ->
    716 	match_charset(Req, State, Tail, CP, Charset).
    717 
    718 match_charset(Req, State, Accept, [], _Charset) ->
    719 	choose_charset(Req, State, Accept);
    720 match_charset(Req, State, _Accept, [Provided|_], {<<"*">>, _}) ->
    721 	set_content_type(Req, State#state{charset_a=Provided});
    722 match_charset(Req, State, _Accept, [Provided|_], {Provided, _}) ->
    723 	set_content_type(Req, State#state{charset_a=Provided});
    724 match_charset(Req, State, Accept, [_|Tail], Charset) ->
    725 	match_charset(Req, State, Accept, Tail, Charset).
    726 
    727 set_content_type(Req, State=#state{
    728 		content_type_a={{Type, SubType, Params}, _Fun},
    729 		charset_a=Charset}) ->
    730 	ParamsBin = set_content_type_build_params(Params, []),
    731 	ContentType = [Type, <<"/">>, SubType, ParamsBin],
    732 	ContentType2 = case {Type, Charset} of
    733 		{<<"text">>, Charset} when Charset =/= undefined ->
    734 			[ContentType, <<"; charset=">>, Charset];
    735 		_ ->
    736 			ContentType
    737 	end,
    738 	Req2 = cowboy_req:set_resp_header(<<"content-type">>, ContentType2, Req),
    739 	encodings_provided(Req2#{charset => Charset}, State).
    740 
    741 set_content_type_build_params('*', []) ->
    742 	<<>>;
    743 set_content_type_build_params([], []) ->
    744 	<<>>;
    745 set_content_type_build_params([], Acc) ->
    746 	lists:reverse(Acc);
    747 set_content_type_build_params([{Attr, Value}|Tail], Acc) ->
    748 	set_content_type_build_params(Tail, [[Attr, <<"=">>, Value], <<";">>|Acc]).
    749 
    750 %% @todo Match for identity as we provide nothing else for now.
    751 %% @todo Don't forget to set the Content-Encoding header when we reply a body
    752 %% and the found encoding is something other than identity.
    753 encodings_provided(Req, State) ->
    754 	ranges_provided(Req, State).
    755 
    756 not_acceptable(Req, State) ->
    757 	respond(Req, State, 406).
    758 
    759 ranges_provided(Req, State) ->
    760 	case call(Req, State, ranges_provided) of
    761 		no_call ->
    762 			variances(Req, State);
    763 		{stop, Req2, State2} ->
    764 			terminate(Req2, State2);
    765 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    766 			switch_handler(Switch, Req2, State2);
    767 		{[], Req2, State2} ->
    768 			Req3 = cowboy_req:set_resp_header(<<"accept-ranges">>, <<"none">>, Req2),
    769 			variances(Req3, State2#state{ranges_a=[]});
    770 		{RP, Req2, State2} ->
    771 			<<", ", AcceptRanges/binary>> = <<<<", ", R/binary>> || {R, _} <- RP>>,
    772 			Req3 = cowboy_req:set_resp_header(<<"accept-ranges">>, AcceptRanges, Req2),
    773 			variances(Req3, State2#state{ranges_a=RP})
    774 	end.
    775 
    776 %% variances/2 should return a list of headers that will be added
    777 %% to the Vary response header. The Accept, Accept-Language,
    778 %% Accept-Charset and Accept-Encoding headers do not need to be
    779 %% specified.
    780 %%
    781 %% @todo Do Accept-Encoding too when we handle it.
    782 %% @todo Does the order matter?
    783 variances(Req, State=#state{content_types_p=CTP,
    784 		languages_p=LP, charsets_p=CP}) ->
    785 	Variances = case CTP of
    786 		[] -> [];
    787 		[_] -> [];
    788 		[_|_] -> [<<"accept">>]
    789 	end,
    790 	Variances2 = case LP of
    791 		[] -> Variances;
    792 		[_] -> Variances;
    793 		[_|_] -> [<<"accept-language">>|Variances]
    794 	end,
    795 	Variances3 = case CP of
    796 		undefined -> Variances2;
    797 		[] -> Variances2;
    798 		[_] -> Variances2;
    799 		[_|_] -> [<<"accept-charset">>|Variances2]
    800 	end,
    801 	try variances(Req, State, Variances3) of
    802 		{Variances4, Req2, State2} ->
    803 			case [[<<", ">>, V] || V <- Variances4] of
    804 				[] ->
    805 					resource_exists(Req2, State2);
    806 				[[<<", ">>, H]|Variances5] ->
    807 					Req3 = cowboy_req:set_resp_header(
    808 						<<"vary">>, [H|Variances5], Req2),
    809 					resource_exists(Req3, State2)
    810 			end
    811 	catch Class:Reason:Stacktrace ->
    812 		error_terminate(Req, State, Class, Reason, Stacktrace)
    813 	end.
    814 
    815 variances(Req, State, Variances) ->
    816 	case unsafe_call(Req, State, variances) of
    817 		no_call ->
    818 			{Variances, Req, State};
    819 		{HandlerVariances, Req2, State2} ->
    820 			{Variances ++ HandlerVariances, Req2, State2}
    821 	end.
    822 
    823 resource_exists(Req, State) ->
    824 	expect(Req, State, resource_exists, true,
    825 		fun if_match_exists/2, fun if_match_must_not_exist/2).
    826 
    827 if_match_exists(Req, State) ->
    828 	State2 = State#state{exists=true},
    829 	case cowboy_req:parse_header(<<"if-match">>, Req) of
    830 		undefined ->
    831 			if_unmodified_since_exists(Req, State2);
    832 		'*' ->
    833 			if_unmodified_since_exists(Req, State2);
    834 		ETagsList ->
    835 			if_match(Req, State2, ETagsList)
    836 	end.
    837 
    838 if_match(Req, State, EtagsList) ->
    839 	try generate_etag(Req, State) of
    840 		%% Strong Etag comparison: weak Etag never matches.
    841 		{{weak, _}, Req2, State2} ->
    842 			precondition_failed(Req2, State2);
    843 		{Etag, Req2, State2} ->
    844 			case lists:member(Etag, EtagsList) of
    845 				true -> if_none_match_exists(Req2, State2);
    846 				%% Etag may be `undefined' which cannot be a member.
    847 				false -> precondition_failed(Req2, State2)
    848 			end
    849 	catch Class:Reason:Stacktrace ->
    850 		error_terminate(Req, State, Class, Reason, Stacktrace)
    851 	end.
    852 
    853 if_match_must_not_exist(Req, State) ->
    854 	case cowboy_req:header(<<"if-match">>, Req) of
    855 		undefined -> is_put_to_missing_resource(Req, State);
    856 		_ -> precondition_failed(Req, State)
    857 	end.
    858 
    859 if_unmodified_since_exists(Req, State) ->
    860 	try cowboy_req:parse_header(<<"if-unmodified-since">>, Req) of
    861 		undefined ->
    862 			if_none_match_exists(Req, State);
    863 		IfUnmodifiedSince ->
    864 			if_unmodified_since(Req, State, IfUnmodifiedSince)
    865 	catch _:_ ->
    866 		if_none_match_exists(Req, State)
    867 	end.
    868 
    869 %% If LastModified is the atom 'no_call', we continue.
    870 if_unmodified_since(Req, State, IfUnmodifiedSince) ->
    871 	try last_modified(Req, State) of
    872 		{LastModified, Req2, State2} ->
    873 			case LastModified > IfUnmodifiedSince of
    874 				true -> precondition_failed(Req2, State2);
    875 				false -> if_none_match_exists(Req2, State2)
    876 			end
    877 	catch Class:Reason:Stacktrace ->
    878 		error_terminate(Req, State, Class, Reason, Stacktrace)
    879 	end.
    880 
    881 if_none_match_exists(Req, State) ->
    882 	case cowboy_req:parse_header(<<"if-none-match">>, Req) of
    883 		undefined ->
    884 			if_modified_since_exists(Req, State);
    885 		'*' ->
    886 			precondition_is_head_get(Req, State);
    887 		EtagsList ->
    888 			if_none_match(Req, State, EtagsList)
    889 	end.
    890 
    891 if_none_match(Req, State, EtagsList) ->
    892 	try generate_etag(Req, State) of
    893 		{Etag, Req2, State2} ->
    894 			case Etag of
    895 				undefined ->
    896 					precondition_failed(Req2, State2);
    897 				Etag ->
    898 					case is_weak_match(Etag, EtagsList) of
    899 						true -> precondition_is_head_get(Req2, State2);
    900 						false -> method(Req2, State2)
    901 					end
    902 			end
    903 	catch Class:Reason:Stacktrace ->
    904 		error_terminate(Req, State, Class, Reason, Stacktrace)
    905 	end.
    906 
    907 %% Weak Etag comparison: only check the opaque tag.
    908 is_weak_match(_, []) ->
    909 	false;
    910 is_weak_match({_, Tag}, [{_, Tag}|_]) ->
    911 	true;
    912 is_weak_match(Etag, [_|Tail]) ->
    913 	is_weak_match(Etag, Tail).
    914 
    915 precondition_is_head_get(Req, State=#state{method=Method})
    916 		when Method =:= <<"HEAD">>; Method =:= <<"GET">> ->
    917 	not_modified(Req, State);
    918 precondition_is_head_get(Req, State) ->
    919 	precondition_failed(Req, State).
    920 
    921 if_modified_since_exists(Req, State) ->
    922 	try cowboy_req:parse_header(<<"if-modified-since">>, Req) of
    923 		undefined ->
    924 			method(Req, State);
    925 		IfModifiedSince ->
    926 			if_modified_since_now(Req, State, IfModifiedSince)
    927 	catch _:_ ->
    928 		method(Req, State)
    929 	end.
    930 
    931 if_modified_since_now(Req, State, IfModifiedSince) ->
    932 	case IfModifiedSince > erlang:universaltime() of
    933 		true -> method(Req, State);
    934 		false -> if_modified_since(Req, State, IfModifiedSince)
    935 	end.
    936 
    937 if_modified_since(Req, State, IfModifiedSince) ->
    938 	try last_modified(Req, State) of
    939 		{undefined, Req2, State2} ->
    940 			method(Req2, State2);
    941 		{LastModified, Req2, State2} ->
    942 			case LastModified > IfModifiedSince of
    943 				true -> method(Req2, State2);
    944 				false -> not_modified(Req2, State2)
    945 			end
    946 	catch Class:Reason:Stacktrace ->
    947 		error_terminate(Req, State, Class, Reason, Stacktrace)
    948 	end.
    949 
    950 not_modified(Req, State) ->
    951 	Req2 = cowboy_req:delete_resp_header(<<"content-type">>, Req),
    952 	try set_resp_etag(Req2, State) of
    953 		{Req3, State2} ->
    954 			try set_resp_expires(Req3, State2) of
    955 				{Req4, State3} ->
    956 					respond(Req4, State3, 304)
    957 			catch Class:Reason:Stacktrace ->
    958 				error_terminate(Req, State2, Class, Reason, Stacktrace)
    959 			end
    960 	catch Class:Reason:Stacktrace ->
    961 		error_terminate(Req, State, Class, Reason, Stacktrace)
    962 	end.
    963 
    964 precondition_failed(Req, State) ->
    965 	respond(Req, State, 412).
    966 
    967 is_put_to_missing_resource(Req, State=#state{method= <<"PUT">>}) ->
    968 	moved_permanently(Req, State, fun is_conflict/2);
    969 is_put_to_missing_resource(Req, State) ->
    970 	previously_existed(Req, State).
    971 
    972 %% moved_permanently/2 should return either false or {true, Location}
    973 %% with Location the full new URI of the resource.
    974 moved_permanently(Req, State, OnFalse) ->
    975 	case call(Req, State, moved_permanently) of
    976 		{{true, Location}, Req2, State2} ->
    977 			Req3 = cowboy_req:set_resp_header(
    978 				<<"location">>, Location, Req2),
    979 			respond(Req3, State2, 301);
    980 		{false, Req2, State2} ->
    981 			OnFalse(Req2, State2);
    982 		{stop, Req2, State2} ->
    983 			terminate(Req2, State2);
    984 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
    985 			switch_handler(Switch, Req2, State2);
    986 		no_call ->
    987 			OnFalse(Req, State)
    988 	end.
    989 
    990 previously_existed(Req, State) ->
    991 	expect(Req, State, previously_existed, false,
    992 		fun (R, S) -> is_post_to_missing_resource(R, S, 404) end,
    993 		fun (R, S) -> moved_permanently(R, S, fun moved_temporarily/2) end).
    994 
    995 %% moved_temporarily/2 should return either false or {true, Location}
    996 %% with Location the full new URI of the resource.
    997 moved_temporarily(Req, State) ->
    998 	case call(Req, State, moved_temporarily) of
    999 		{{true, Location}, Req2, State2} ->
   1000 			Req3 = cowboy_req:set_resp_header(
   1001 				<<"location">>, Location, Req2),
   1002 			respond(Req3, State2, 307);
   1003 		{false, Req2, State2} ->
   1004 			is_post_to_missing_resource(Req2, State2, 410);
   1005 		{stop, Req2, State2} ->
   1006 			terminate(Req2, State2);
   1007 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
   1008 			switch_handler(Switch, Req2, State2);
   1009 		no_call ->
   1010 			is_post_to_missing_resource(Req, State, 410)
   1011 	end.
   1012 
   1013 is_post_to_missing_resource(Req, State=#state{method= <<"POST">>}, OnFalse) ->
   1014 	allow_missing_post(Req, State, OnFalse);
   1015 is_post_to_missing_resource(Req, State, OnFalse) ->
   1016 	respond(Req, State, OnFalse).
   1017 
   1018 allow_missing_post(Req, State, OnFalse) ->
   1019 	expect(Req, State, allow_missing_post, true, fun accept_resource/2, OnFalse).
   1020 
   1021 method(Req, State=#state{method= <<"DELETE">>}) ->
   1022 	delete_resource(Req, State);
   1023 method(Req, State=#state{method= <<"PUT">>}) ->
   1024 	is_conflict(Req, State);
   1025 method(Req, State=#state{method=Method})
   1026 		when Method =:= <<"POST">>; Method =:= <<"PATCH">> ->
   1027 	accept_resource(Req, State);
   1028 method(Req, State=#state{method=Method})
   1029 		when Method =:= <<"GET">>; Method =:= <<"HEAD">> ->
   1030 	set_resp_body_etag(Req, State);
   1031 method(Req, State) ->
   1032 	multiple_choices(Req, State).
   1033 
   1034 %% delete_resource/2 should start deleting the resource and return.
   1035 delete_resource(Req, State) ->
   1036 	expect(Req, State, delete_resource, false, 500, fun delete_completed/2).
   1037 
   1038 %% delete_completed/2 indicates whether the resource has been deleted yet.
   1039 delete_completed(Req, State) ->
   1040 	expect(Req, State, delete_completed, true, fun has_resp_body/2, 202).
   1041 
   1042 is_conflict(Req, State) ->
   1043 	expect(Req, State, is_conflict, false, fun accept_resource/2, 409).
   1044 
   1045 %% content_types_accepted should return a list of media types and their
   1046 %% associated callback functions in the same format as content_types_provided.
   1047 %%
   1048 %% The callback will then be called and is expected to process the content
   1049 %% pushed to the resource in the request body.
   1050 %%
   1051 %% content_types_accepted SHOULD return a different list
   1052 %% for each HTTP method.
   1053 accept_resource(Req, State) ->
   1054 	case call(Req, State, content_types_accepted) of
   1055 		no_call ->
   1056 			respond(Req, State, 415);
   1057 		{stop, Req2, State2} ->
   1058 			terminate(Req2, State2);
   1059 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
   1060 			switch_handler(Switch, Req2, State2);
   1061 		{CTA, Req2, State2} ->
   1062 			CTA2 = [normalize_content_types(P) || P <- CTA],
   1063 			try cowboy_req:parse_header(<<"content-type">>, Req2) of
   1064 				%% We do not match against the boundary parameter for multipart.
   1065 				{Type = <<"multipart">>, SubType, Params} ->
   1066 					ContentType = {Type, SubType, lists:keydelete(<<"boundary">>, 1, Params)},
   1067 					choose_content_type(Req2, State2, ContentType, CTA2);
   1068 				ContentType ->
   1069 					choose_content_type(Req2, State2, ContentType, CTA2)
   1070 			catch _:_ ->
   1071 				respond(Req2, State2, 415)
   1072 			end
   1073 	end.
   1074 
   1075 %% The special content type '*' will always match. It can be used as a
   1076 %% catch-all content type for accepting any kind of request content.
   1077 %% Note that because it will always match, it should be the last of the
   1078 %% list of content types, otherwise it'll shadow the ones following.
   1079 choose_content_type(Req, State, _ContentType, []) ->
   1080 	respond(Req, State, 415);
   1081 choose_content_type(Req, State, ContentType, [{Accepted, Fun}|_Tail])
   1082 		when Accepted =:= '*'; Accepted =:= ContentType ->
   1083 	process_content_type(Req, State, Fun);
   1084 %% The special parameter '*' will always match any kind of content type
   1085 %% parameters.
   1086 %% Note that because it will always match, it should be the last of the
   1087 %% list for specific content type, otherwise it'll shadow the ones following.
   1088 choose_content_type(Req, State, {Type, SubType, Param},
   1089 		[{{Type, SubType, AcceptedParam}, Fun}|_Tail])
   1090 		when AcceptedParam =:= '*'; AcceptedParam =:= Param ->
   1091 	process_content_type(Req, State, Fun);
   1092 choose_content_type(Req, State, ContentType, [_Any|Tail]) ->
   1093 	choose_content_type(Req, State, ContentType, Tail).
   1094 
   1095 process_content_type(Req, State=#state{method=Method, exists=Exists}, Fun) ->
   1096 	try case call(Req, State, Fun) of
   1097 		{stop, Req2, State2} ->
   1098 			terminate(Req2, State2);
   1099 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
   1100 			switch_handler(Switch, Req2, State2);
   1101 		{true, Req2, State2} when Exists ->
   1102 			next(Req2, State2, fun has_resp_body/2);
   1103 		{true, Req2, State2} ->
   1104 			next(Req2, State2, fun maybe_created/2);
   1105 		{false, Req2, State2} ->
   1106 			respond(Req2, State2, 400);
   1107 		{{created, ResURL}, Req2, State2} when Method =:= <<"POST">> ->
   1108 			Req3 = cowboy_req:set_resp_header(
   1109 				<<"location">>, ResURL, Req2),
   1110 			respond(Req3, State2, 201);
   1111 		{{see_other, ResURL}, Req2, State2} when Method =:= <<"POST">> ->
   1112 			Req3 = cowboy_req:set_resp_header(
   1113 				<<"location">>, ResURL, Req2),
   1114 			respond(Req3, State2, 303);
   1115 		{{true, ResURL}, Req2, State2} when Method =:= <<"POST">> ->
   1116 			Req3 = cowboy_req:set_resp_header(
   1117 				<<"location">>, ResURL, Req2),
   1118 			if
   1119 				Exists -> respond(Req3, State2, 303);
   1120 				true -> respond(Req3, State2, 201)
   1121 			end
   1122 	end catch Class:Reason = {case_clause, no_call}:Stacktrace ->
   1123 		error_terminate(Req, State, Class, Reason, Stacktrace)
   1124 	end.
   1125 
   1126 %% If PUT was used then the resource has been created at the current URL.
   1127 %% Otherwise, if a location header has been set then the resource has been
   1128 %% created at a new URL. If not, send a 200 or 204 as expected from a
   1129 %% POST or PATCH request.
   1130 maybe_created(Req, State=#state{method= <<"PUT">>}) ->
   1131 	respond(Req, State, 201);
   1132 maybe_created(Req, State) ->
   1133 	case cowboy_req:has_resp_header(<<"location">>, Req) of
   1134 		true -> respond(Req, State, 201);
   1135 		false -> has_resp_body(Req, State)
   1136 	end.
   1137 
   1138 has_resp_body(Req, State) ->
   1139 	case cowboy_req:has_resp_body(Req) of
   1140 		true -> multiple_choices(Req, State);
   1141 		false -> respond(Req, State, 204)
   1142 	end.
   1143 
   1144 %% Set the Etag header if any for the response provided.
   1145 set_resp_body_etag(Req, State) ->
   1146 	try set_resp_etag(Req, State) of
   1147 		{Req2, State2} ->
   1148 			set_resp_body_last_modified(Req2, State2)
   1149 	catch Class:Reason:Stacktrace ->
   1150 		error_terminate(Req, State, Class, Reason, Stacktrace)
   1151 	end.
   1152 
   1153 %% Set the Last-Modified header if any for the response provided.
   1154 set_resp_body_last_modified(Req, State) ->
   1155 	try last_modified(Req, State) of
   1156 		{LastModified, Req2, State2} ->
   1157 			case LastModified of
   1158 				LastModified when is_atom(LastModified) ->
   1159 					set_resp_body_expires(Req2, State2);
   1160 				LastModified ->
   1161 					LastModifiedBin = cowboy_clock:rfc1123(LastModified),
   1162 					Req3 = cowboy_req:set_resp_header(
   1163 						<<"last-modified">>, LastModifiedBin, Req2),
   1164 					set_resp_body_expires(Req3, State2)
   1165 			end
   1166 	catch Class:Reason:Stacktrace ->
   1167 		error_terminate(Req, State, Class, Reason, Stacktrace)
   1168 	end.
   1169 
   1170 %% Set the Expires header if any for the response provided.
   1171 set_resp_body_expires(Req, State) ->
   1172 	try set_resp_expires(Req, State) of
   1173 		{Req2, State2} ->
   1174 			if_range(Req2, State2)
   1175 	catch Class:Reason:Stacktrace ->
   1176 		error_terminate(Req, State, Class, Reason, Stacktrace)
   1177 	end.
   1178 
   1179 %% When both the if-range and range headers are set, we perform
   1180 %% a strong comparison. If it fails, we send a full response.
   1181 if_range(Req=#{headers := #{<<"if-range">> := _, <<"range">> := _}},
   1182 		State=#state{etag=Etag}) ->
   1183 	try cowboy_req:parse_header(<<"if-range">>, Req) of
   1184 		%% Strong etag comparison is an exact match with the generate_etag result.
   1185 		Etag={strong, _} ->
   1186 			range(Req, State);
   1187 		%% We cannot do a strong date comparison because we have
   1188 		%% no way of knowing whether the representation changed
   1189 		%% twice during the second covered by the presented
   1190 		%% validator. (RFC7232 2.2.2)
   1191 		_ ->
   1192 			set_resp_body(Req, State)
   1193 	catch _:_ ->
   1194 		set_resp_body(Req, State)
   1195 	end;
   1196 if_range(Req, State) ->
   1197 	range(Req, State).
   1198 
   1199 range(Req, State=#state{ranges_a=[]}) ->
   1200 	set_resp_body(Req, State);
   1201 range(Req, State) ->
   1202 	try cowboy_req:parse_header(<<"range">>, Req) of
   1203 		undefined ->
   1204 			set_resp_body(Req, State);
   1205 		%% @todo Maybe change parse_header to return <<"bytes">> in 3.0.
   1206 		{bytes, BytesRange} ->
   1207 			choose_range(Req, State, {<<"bytes">>, BytesRange});
   1208 		Range ->
   1209 			choose_range(Req, State, Range)
   1210 	catch _:_ ->
   1211 		%% We send a 416 response back when we can't parse the
   1212 		%% range header at all. I'm not sure this is the right
   1213 		%% way to go but at least this can help clients identify
   1214 		%% what went wrong when their range requests never work.
   1215 		range_not_satisfiable(Req, State, undefined)
   1216 	end.
   1217 
   1218 choose_range(Req, State=#state{ranges_a=RangesAccepted}, Range={RangeUnit, _}) ->
   1219 	case lists:keyfind(RangeUnit, 1, RangesAccepted) of
   1220 		{_, Callback} ->
   1221 			%% We pass the selected range onward in the Req.
   1222 			range_satisfiable(Req#{range => Range}, State, Callback);
   1223 		false ->
   1224 			set_resp_body(Req, State)
   1225 	end.
   1226 
   1227 range_satisfiable(Req, State, Callback) ->
   1228 	case call(Req, State, range_satisfiable) of
   1229 		no_call ->
   1230 			set_ranged_body(Req, State, Callback);
   1231 		{stop, Req2, State2} ->
   1232 			terminate(Req2, State2);
   1233 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
   1234 			switch_handler(Switch, Req2, State2);
   1235 		{true, Req2, State2} ->
   1236 			set_ranged_body(Req2, State2, Callback);
   1237 		{false, Req2, State2} ->
   1238 			range_not_satisfiable(Req2, State2, undefined);
   1239 		{{false, Int}, Req2, State2} when is_integer(Int) ->
   1240 			range_not_satisfiable(Req2, State2, [<<"*/">>, integer_to_binary(Int)]);
   1241 		{{false, Iodata}, Req2, State2} when is_binary(Iodata); is_list(Iodata) ->
   1242 			range_not_satisfiable(Req2, State2, Iodata)
   1243 	end.
   1244 
   1245 %% When the callback selected is 'auto' and the range unit
   1246 %% is bytes, we call the normal provide callback and split
   1247 %% the content automatically.
   1248 set_ranged_body(Req=#{range := {<<"bytes">>, _}}, State, auto) ->
   1249 	set_ranged_body_auto(Req, State);
   1250 set_ranged_body(Req, State, Callback) ->
   1251 	set_ranged_body_callback(Req, State, Callback).
   1252 
   1253 set_ranged_body_auto(Req, State=#state{handler=Handler, content_type_a={_, Callback}}) ->
   1254 	try case call(Req, State, Callback) of
   1255 		{stop, Req2, State2} ->
   1256 			terminate(Req2, State2);
   1257 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
   1258 			switch_handler(Switch, Req2, State2);
   1259 		{Body, Req2, State2} ->
   1260 			maybe_set_ranged_body_auto(Req2, State2, Body)
   1261 	end catch Class:{case_clause, no_call}:Stacktrace ->
   1262 		error_terminate(Req, State, Class, {error, {missing_callback, {Handler, Callback, 2}},
   1263 			'A callback specified in content_types_provided/2 is not exported.'},
   1264 			Stacktrace)
   1265 	end.
   1266 
   1267 maybe_set_ranged_body_auto(Req=#{range := {_, Ranges}}, State, Body) ->
   1268 	Size = case Body of
   1269 		{sendfile, _, Bytes, _} -> Bytes;
   1270 		_ -> iolist_size(Body)
   1271 	end,
   1272 	Checks = [case Range of
   1273 		{From, infinity} -> From < Size;
   1274 		{From, To} -> (From < Size) andalso (From =< To) andalso (To =< Size);
   1275 		Neg -> (Neg =/= 0) andalso (-Neg < Size)
   1276 	end || Range <- Ranges],
   1277 	case lists:usort(Checks) of
   1278 		[true] -> set_ranged_body_auto(Req, State, Body);
   1279 		_ -> range_not_satisfiable(Req, State, [<<"*/">>, integer_to_binary(Size)])
   1280 	end.
   1281 
   1282 %% We might also want to have some checks about range order,
   1283 %% number of ranges, and perhaps also join ranges that are
   1284 %% too close into one contiguous range. Some of these can
   1285 %% be done before calling the ProvideCallback.
   1286 
   1287 set_ranged_body_auto(Req=#{range := {_, Ranges}}, State, Body) ->
   1288 	Parts = [ranged_partition(Range, Body) || Range <- Ranges],
   1289 	case Parts of
   1290 		[OnePart] -> set_one_ranged_body(Req, State, OnePart);
   1291 		_ when is_tuple(Body) -> send_multipart_ranged_body(Req, State, Parts);
   1292 		_ -> set_multipart_ranged_body(Req, State, Parts)
   1293 	end.
   1294 
   1295 ranged_partition(Range, {sendfile, Offset0, Bytes0, Path}) ->
   1296 	{From, To, Offset, Bytes} = case Range of
   1297 		{From0, infinity} -> {From0, Bytes0 - 1, Offset0 + From0, Bytes0 - From0};
   1298 		{From0, To0} -> {From0, To0, Offset0 + From0, 1 + To0 - From0};
   1299 		Neg -> {Bytes0 + Neg, Bytes0 - 1, Offset0 + Bytes0 + Neg, -Neg}
   1300 	end,
   1301 	{{From, To, Bytes0}, {sendfile, Offset, Bytes, Path}};
   1302 ranged_partition(Range, Data0) ->
   1303 	Total = iolist_size(Data0),
   1304 	{From, To, Data} = case Range of
   1305 		{From0, infinity} ->
   1306 			{_, Data1} = cow_iolists:split(From0, Data0),
   1307 			{From0, Total - 1, Data1};
   1308 		{From0, To0} ->
   1309 			{_, Data1} = cow_iolists:split(From0, Data0),
   1310 			{Data2, _} = cow_iolists:split(To0 - From0 + 1, Data1),
   1311 			{From0, To0, Data2};
   1312 		Neg ->
   1313 			{_, Data1} = cow_iolists:split(Total + Neg, Data0),
   1314 			{Total + Neg, Total - 1, Data1}
   1315 	end,
   1316 	{{From, To, Total}, Data}.
   1317 
   1318 -ifdef(TEST).
   1319 ranged_partition_test_() ->
   1320 	Tests = [
   1321 		%% Sendfile with open-ended range.
   1322 		{{0, infinity}, {sendfile, 0, 12, "t"}, {{0, 11, 12}, {sendfile, 0, 12, "t"}}},
   1323 		{{6, infinity}, {sendfile, 0, 12, "t"}, {{6, 11, 12}, {sendfile, 6, 6, "t"}}},
   1324 		{{11, infinity}, {sendfile, 0, 12, "t"}, {{11, 11, 12}, {sendfile, 11, 1, "t"}}},
   1325 		%% Sendfile with open-ended range. Sendfile tuple has an offset originally.
   1326 		{{0, infinity}, {sendfile, 3, 12, "t"}, {{0, 11, 12}, {sendfile, 3, 12, "t"}}},
   1327 		{{6, infinity}, {sendfile, 3, 12, "t"}, {{6, 11, 12}, {sendfile, 9, 6, "t"}}},
   1328 		{{11, infinity}, {sendfile, 3, 12, "t"}, {{11, 11, 12}, {sendfile, 14, 1, "t"}}},
   1329 		%% Sendfile with a specific range.
   1330 		{{0, 11}, {sendfile, 0, 12, "t"}, {{0, 11, 12}, {sendfile, 0, 12, "t"}}},
   1331 		{{6, 11}, {sendfile, 0, 12, "t"}, {{6, 11, 12}, {sendfile, 6, 6, "t"}}},
   1332 		{{11, 11}, {sendfile, 0, 12, "t"}, {{11, 11, 12}, {sendfile, 11, 1, "t"}}},
   1333 		{{1, 10}, {sendfile, 0, 12, "t"}, {{1, 10, 12}, {sendfile, 1, 10, "t"}}},
   1334 		%% Sendfile with a specific range. Sendfile tuple has an offset originally.
   1335 		{{0, 11}, {sendfile, 3, 12, "t"}, {{0, 11, 12}, {sendfile, 3, 12, "t"}}},
   1336 		{{6, 11}, {sendfile, 3, 12, "t"}, {{6, 11, 12}, {sendfile, 9, 6, "t"}}},
   1337 		{{11, 11}, {sendfile, 3, 12, "t"}, {{11, 11, 12}, {sendfile, 14, 1, "t"}}},
   1338 		{{1, 10}, {sendfile, 3, 12, "t"}, {{1, 10, 12}, {sendfile, 4, 10, "t"}}},
   1339 		%% Sendfile with negative range.
   1340 		{-12, {sendfile, 0, 12, "t"}, {{0, 11, 12}, {sendfile, 0, 12, "t"}}},
   1341 		{-6, {sendfile, 0, 12, "t"}, {{6, 11, 12}, {sendfile, 6, 6, "t"}}},
   1342 		{-1, {sendfile, 0, 12, "t"}, {{11, 11, 12}, {sendfile, 11, 1, "t"}}},
   1343 		%% Sendfile with negative range. Sendfile tuple has an offset originally.
   1344 		{-12, {sendfile, 3, 12, "t"}, {{0, 11, 12}, {sendfile, 3, 12, "t"}}},
   1345 		{-6, {sendfile, 3, 12, "t"}, {{6, 11, 12}, {sendfile, 9, 6, "t"}}},
   1346 		{-1, {sendfile, 3, 12, "t"}, {{11, 11, 12}, {sendfile, 14, 1, "t"}}},
   1347 		%% Iodata with open-ended range.
   1348 		{{0, infinity}, <<"Hello world!">>, {{0, 11, 12}, <<"Hello world!">>}},
   1349 		{{6, infinity}, <<"Hello world!">>, {{6, 11, 12}, <<"world!">>}},
   1350 		{{11, infinity}, <<"Hello world!">>, {{11, 11, 12}, <<"!">>}},
   1351 		%% Iodata with a specific range. The resulting data is
   1352 		%% wrapped in a list because of how cow_iolists:split/2 works.
   1353 		{{0, 11}, <<"Hello world!">>, {{0, 11, 12}, [<<"Hello world!">>]}},
   1354 		{{6, 11}, <<"Hello world!">>, {{6, 11, 12}, [<<"world!">>]}},
   1355 		{{11, 11}, <<"Hello world!">>, {{11, 11, 12}, [<<"!">>]}},
   1356 		{{1, 10}, <<"Hello world!">>, {{1, 10, 12}, [<<"ello world">>]}},
   1357 		%% Iodata with negative range.
   1358 		{-12, <<"Hello world!">>, {{0, 11, 12}, <<"Hello world!">>}},
   1359 		{-6, <<"Hello world!">>, {{6, 11, 12}, <<"world!">>}},
   1360 		{-1, <<"Hello world!">>, {{11, 11, 12}, <<"!">>}}
   1361 	],
   1362 	[{iolist_to_binary(io_lib:format("range ~p data ~p", [VR, VD])),
   1363 		fun() -> R = ranged_partition(VR, VD) end} || {VR, VD, R} <- Tests].
   1364 -endif.
   1365 
   1366 set_ranged_body_callback(Req, State=#state{handler=Handler}, Callback) ->
   1367 	try case call(Req, State, Callback) of
   1368 		{stop, Req2, State2} ->
   1369 			terminate(Req2, State2);
   1370 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
   1371 			switch_handler(Switch, Req2, State2);
   1372 		%% When we receive a single range, we send it directly.
   1373 		{[OneRange], Req2, State2} ->
   1374 			set_one_ranged_body(Req2, State2, OneRange);
   1375 		%% When we receive multiple ranges we have to send them as multipart/byteranges.
   1376 		%% This also applies to non-bytes units. (RFC7233 A) If users don't want to use
   1377 		%% this for non-bytes units they can always return a single range with a binary
   1378 		%% content-range information.
   1379 		{Ranges, Req2, State2} when length(Ranges) > 1 ->
   1380 			%% We have to check whether there are sendfile tuples in the
   1381 			%% ranges to be sent. If there are we must use stream_reply.
   1382 			HasSendfile = [] =/= [true || {_, {sendfile, _, _, _}} <- Ranges],
   1383 			case HasSendfile of
   1384 				true -> send_multipart_ranged_body(Req2, State2, Ranges);
   1385 				false -> set_multipart_ranged_body(Req2, State2, Ranges)
   1386 			end
   1387 	end catch Class:{case_clause, no_call}:Stacktrace ->
   1388 		error_terminate(Req, State, Class, {error, {missing_callback, {Handler, Callback, 2}},
   1389 			'A callback specified in ranges_provided/2 is not exported.'},
   1390 			Stacktrace)
   1391 	end.
   1392 
   1393 set_one_ranged_body(Req0, State, OneRange) ->
   1394 	{ContentRange, Body} = prepare_range(Req0, OneRange),
   1395 	Req1 = cowboy_req:set_resp_header(<<"content-range">>, ContentRange, Req0),
   1396 	Req = cowboy_req:set_resp_body(Body, Req1),
   1397 	respond(Req, State, 206).
   1398 
   1399 set_multipart_ranged_body(Req, State, [FirstRange|MoreRanges]) ->
   1400 	Boundary = cow_multipart:boundary(),
   1401 	ContentType = cowboy_req:resp_header(<<"content-type">>, Req),
   1402 	{FirstContentRange, FirstPartBody} = prepare_range(Req, FirstRange),
   1403 	FirstPartHead = cow_multipart:first_part(Boundary, [
   1404 		{<<"content-type">>, ContentType},
   1405 		{<<"content-range">>, FirstContentRange}
   1406 	]),
   1407 	MoreParts = [begin
   1408 		{NextContentRange, NextPartBody} = prepare_range(Req, NextRange),
   1409 		NextPartHead = cow_multipart:part(Boundary, [
   1410 			{<<"content-type">>, ContentType},
   1411 			{<<"content-range">>, NextContentRange}
   1412 		]),
   1413 		[NextPartHead, NextPartBody]
   1414 	end || NextRange <- MoreRanges],
   1415 	Body = [FirstPartHead, FirstPartBody, MoreParts, cow_multipart:close(Boundary)],
   1416 	Req2 = cowboy_req:set_resp_header(<<"content-type">>,
   1417 		[<<"multipart/byteranges; boundary=">>, Boundary], Req),
   1418 	Req3 = cowboy_req:set_resp_body(Body, Req2),
   1419 	respond(Req3, State, 206).
   1420 
   1421 %% Similar to set_multipart_ranged_body except we have to stream
   1422 %% the data because the parts contain sendfile tuples.
   1423 send_multipart_ranged_body(Req, State, [FirstRange|MoreRanges]) ->
   1424 	Boundary = cow_multipart:boundary(),
   1425 	ContentType = cowboy_req:resp_header(<<"content-type">>, Req),
   1426 	Req2 = cowboy_req:set_resp_header(<<"content-type">>,
   1427 		[<<"multipart/byteranges; boundary=">>, Boundary], Req),
   1428 	Req3 = cowboy_req:stream_reply(206, Req2),
   1429 	{FirstContentRange, FirstPartBody} = prepare_range(Req, FirstRange),
   1430 	FirstPartHead = cow_multipart:first_part(Boundary, [
   1431 		{<<"content-type">>, ContentType},
   1432 		{<<"content-range">>, FirstContentRange}
   1433 	]),
   1434 	cowboy_req:stream_body(FirstPartHead, nofin, Req3),
   1435 	cowboy_req:stream_body(FirstPartBody, nofin, Req3),
   1436 	_ = [begin
   1437 		{NextContentRange, NextPartBody} = prepare_range(Req, NextRange),
   1438 		NextPartHead = cow_multipart:part(Boundary, [
   1439 			{<<"content-type">>, ContentType},
   1440 			{<<"content-range">>, NextContentRange}
   1441 		]),
   1442 		cowboy_req:stream_body(NextPartHead, nofin, Req3),
   1443 		cowboy_req:stream_body(NextPartBody, nofin, Req3),
   1444 		[NextPartHead, NextPartBody]
   1445 	end || NextRange <- MoreRanges],
   1446 	cowboy_req:stream_body(cow_multipart:close(Boundary), fin, Req3),
   1447 	terminate(Req3, State).
   1448 
   1449 prepare_range(#{range := {RangeUnit, _}}, {{From, To, Total0}, Body}) ->
   1450 	Total = case Total0 of
   1451 		'*' -> <<"*">>;
   1452 		_ -> integer_to_binary(Total0)
   1453 	end,
   1454 	ContentRange = [RangeUnit, $\s, integer_to_binary(From),
   1455 		$-, integer_to_binary(To), $/, Total],
   1456 	{ContentRange, Body};
   1457 prepare_range(#{range := {RangeUnit, _}}, {RangeData, Body}) ->
   1458 	{[RangeUnit, $\s, RangeData], Body}.
   1459 
   1460 %% We send the content-range header when we can on error.
   1461 range_not_satisfiable(Req, State, undefined) ->
   1462 	respond(Req, State, 416);
   1463 range_not_satisfiable(Req0=#{range := {RangeUnit, _}}, State, RangeData) ->
   1464 	Req = cowboy_req:set_resp_header(<<"content-range">>,
   1465 		[RangeUnit, $\s, RangeData], Req0),
   1466 	respond(Req, State, 416).
   1467 
   1468 %% Set the response headers and call the callback found using
   1469 %% content_types_provided/2 to obtain the request body and add
   1470 %% it to the response.
   1471 set_resp_body(Req, State=#state{handler=Handler, content_type_a={_, Callback}}) ->
   1472 	try case call(Req, State, Callback) of
   1473 		{stop, Req2, State2} ->
   1474 			terminate(Req2, State2);
   1475 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
   1476 			switch_handler(Switch, Req2, State2);
   1477 		{Body, Req2, State2} ->
   1478 			Req3 = cowboy_req:set_resp_body(Body, Req2),
   1479 			multiple_choices(Req3, State2)
   1480 	end catch Class:{case_clause, no_call}:Stacktrace ->
   1481 		error_terminate(Req, State, Class, {error, {missing_callback, {Handler, Callback, 2}},
   1482 			'A callback specified in content_types_provided/2 is not exported.'},
   1483 			Stacktrace)
   1484 	end.
   1485 
   1486 multiple_choices(Req, State) ->
   1487 	expect(Req, State, multiple_choices, false, 200, 300).
   1488 
   1489 %% Response utility functions.
   1490 
   1491 set_resp_etag(Req, State) ->
   1492 	{Etag, Req2, State2} = generate_etag(Req, State),
   1493 	case Etag of
   1494 		undefined ->
   1495 			{Req2, State2};
   1496 		Etag ->
   1497 			Req3 = cowboy_req:set_resp_header(
   1498 				<<"etag">>, encode_etag(Etag), Req2),
   1499 			{Req3, State2}
   1500 	end.
   1501 
   1502 -spec encode_etag({strong | weak, binary()}) -> iolist().
   1503 encode_etag({strong, Etag}) -> [$",Etag,$"];
   1504 encode_etag({weak, Etag}) -> ["W/\"",Etag,$"].
   1505 
   1506 set_resp_expires(Req, State) ->
   1507 	{Expires, Req2, State2} = expires(Req, State),
   1508 	case Expires of
   1509 		Expires when is_atom(Expires) ->
   1510 			{Req2, State2};
   1511 		Expires when is_binary(Expires) ->
   1512 			Req3 = cowboy_req:set_resp_header(
   1513 				<<"expires">>, Expires, Req2),
   1514 			{Req3, State2};
   1515 		Expires ->
   1516 			ExpiresBin = cowboy_clock:rfc1123(Expires),
   1517 			Req3 = cowboy_req:set_resp_header(
   1518 				<<"expires">>, ExpiresBin, Req2),
   1519 			{Req3, State2}
   1520 	end.
   1521 
   1522 %% Info retrieval. No logic.
   1523 
   1524 generate_etag(Req, State=#state{etag=no_call}) ->
   1525 	{undefined, Req, State};
   1526 generate_etag(Req, State=#state{etag=undefined}) ->
   1527 	case unsafe_call(Req, State, generate_etag) of
   1528 		no_call ->
   1529 			{undefined, Req, State#state{etag=no_call}};
   1530 		{Etag, Req2, State2} when is_binary(Etag) ->
   1531 			Etag2 = cow_http_hd:parse_etag(Etag),
   1532 			{Etag2, Req2, State2#state{etag=Etag2}};
   1533 		{Etag, Req2, State2} ->
   1534 			{Etag, Req2, State2#state{etag=Etag}}
   1535 	end;
   1536 generate_etag(Req, State=#state{etag=Etag}) ->
   1537 	{Etag, Req, State}.
   1538 
   1539 last_modified(Req, State=#state{last_modified=no_call}) ->
   1540 	{undefined, Req, State};
   1541 last_modified(Req, State=#state{last_modified=undefined}) ->
   1542 	case unsafe_call(Req, State, last_modified) of
   1543 		no_call ->
   1544 			{undefined, Req, State#state{last_modified=no_call}};
   1545 		{LastModified, Req2, State2} ->
   1546 			{LastModified, Req2, State2#state{last_modified=LastModified}}
   1547 	end;
   1548 last_modified(Req, State=#state{last_modified=LastModified}) ->
   1549 	{LastModified, Req, State}.
   1550 
   1551 expires(Req, State=#state{expires=no_call}) ->
   1552 	{undefined, Req, State};
   1553 expires(Req, State=#state{expires=undefined}) ->
   1554 	case unsafe_call(Req, State, expires) of
   1555 		no_call ->
   1556 			{undefined, Req, State#state{expires=no_call}};
   1557 		{Expires, Req2, State2} ->
   1558 			{Expires, Req2, State2#state{expires=Expires}}
   1559 	end;
   1560 expires(Req, State=#state{expires=Expires}) ->
   1561 	{Expires, Req, State}.
   1562 
   1563 %% REST primitives.
   1564 
   1565 expect(Req, State, Callback, Expected, OnTrue, OnFalse) ->
   1566 	case call(Req, State, Callback) of
   1567 		no_call ->
   1568 			next(Req, State, OnTrue);
   1569 		{stop, Req2, State2} ->
   1570 			terminate(Req2, State2);
   1571 		{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
   1572 			switch_handler(Switch, Req2, State2);
   1573 		{Expected, Req2, State2} ->
   1574 			next(Req2, State2, OnTrue);
   1575 		{_Unexpected, Req2, State2} ->
   1576 			next(Req2, State2, OnFalse)
   1577 	end.
   1578 
   1579 call(Req0, State=#state{handler=Handler,
   1580 		handler_state=HandlerState0}, Callback) ->
   1581 	case erlang:function_exported(Handler, Callback, 2) of
   1582 		true ->
   1583 			try Handler:Callback(Req0, HandlerState0) of
   1584 				no_call ->
   1585 					no_call;
   1586 				{Result, Req, HandlerState} ->
   1587 					{Result, Req, State#state{handler_state=HandlerState}}
   1588 			catch Class:Reason:Stacktrace ->
   1589 				error_terminate(Req0, State, Class, Reason, Stacktrace)
   1590 			end;
   1591 		false ->
   1592 			no_call
   1593 	end.
   1594 
   1595 unsafe_call(Req0, State=#state{handler=Handler,
   1596 		handler_state=HandlerState0}, Callback) ->
   1597 	case erlang:function_exported(Handler, Callback, 2) of
   1598 		false ->
   1599 			no_call;
   1600 		true ->
   1601 			case Handler:Callback(Req0, HandlerState0) of
   1602 				no_call ->
   1603 					no_call;
   1604 				{Result, Req, HandlerState} ->
   1605 					{Result, Req, State#state{handler_state=HandlerState}}
   1606 			end
   1607 	end.
   1608 
   1609 next(Req, State, Next) when is_function(Next) ->
   1610 	Next(Req, State);
   1611 next(Req, State, StatusCode) when is_integer(StatusCode) ->
   1612 	respond(Req, State, StatusCode).
   1613 
   1614 respond(Req0, State, StatusCode) ->
   1615 	%% We remove the content-type header when there is no body,
   1616 	%% except when the status code is 200 because it might have
   1617 	%% been intended (for example sending an empty file).
   1618 	Req = case cowboy_req:has_resp_body(Req0) of
   1619 		true when StatusCode =:= 200 -> Req0;
   1620 		true -> Req0;
   1621 		false -> cowboy_req:delete_resp_header(<<"content-type">>, Req0)
   1622 	end,
   1623 	terminate(cowboy_req:reply(StatusCode, Req), State).
   1624 
   1625 switch_handler({switch_handler, Mod}, Req, #state{handler_state=HandlerState}) ->
   1626 	{Mod, Req, HandlerState};
   1627 switch_handler({switch_handler, Mod, Opts}, Req, #state{handler_state=HandlerState}) ->
   1628 	{Mod, Req, HandlerState, Opts}.
   1629 
   1630 -spec error_terminate(cowboy_req:req(), #state{}, atom(), any(), any()) -> no_return().
   1631 error_terminate(Req, #state{handler=Handler, handler_state=HandlerState}, Class, Reason, Stacktrace) ->
   1632 	cowboy_handler:terminate({crash, Class, Reason}, Req, HandlerState, Handler),
   1633 	erlang:raise(Class, Reason, Stacktrace).
   1634 
   1635 terminate(Req, #state{handler=Handler, handler_state=HandlerState}) ->
   1636 	Result = cowboy_handler:terminate(normal, Req, HandlerState, Handler),
   1637 	{ok, Req, Result}.