diff options
Diffstat (limited to 'src/cowboy_http_rest.erl')
-rw-r--r-- | src/cowboy_http_rest.erl | 113 |
1 files changed, 73 insertions, 40 deletions
diff --git a/src/cowboy_http_rest.erl b/src/cowboy_http_rest.erl index 35f82e3..e6cc6ff 100644 --- a/src/cowboy_http_rest.erl +++ b/src/cowboy_http_rest.erl @@ -53,7 +53,8 @@ %% You do not need to call this function manually. To upgrade to the REST %% protocol, you simply need to return <em>{upgrade, protocol, {@module}}</em> %% in your <em>cowboy_http_handler:init/3</em> handler function. --spec upgrade(pid(), module(), any(), #http_req{}) -> {ok, #http_req{}}. +-spec upgrade(pid(), module(), any(), #http_req{}) + -> {ok, #http_req{}} | close. upgrade(_ListenerPid, Handler, Opts, Req) -> try case erlang:function_exported(Handler, rest_init, 2) of @@ -73,7 +74,7 @@ upgrade(_ListenerPid, Handler, Opts, Req) -> "** Request was ~p~n** Stacktrace: ~p~n~n", [Handler, Class, Reason, Opts, Req, erlang:get_stacktrace()]), {ok, _Req2} = cowboy_http_req:reply(500, Req), - ok + close end. service_available(Req, State) -> @@ -88,8 +89,10 @@ known_methods(Req=#http_req{method=Method}, State) -> next(Req, State, fun uri_too_long/2); no_call -> next(Req, State, 501); - {List, Req2, HandlerState2} -> - State2 = State#state{handler_state=HandlerState2}, + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); + {List, Req2, HandlerState} -> + State2 = State#state{handler_state=HandlerState}, case lists:member(Method, List) of true -> next(Req2, State2, fun uri_too_long/2); false -> next(Req2, State2, 501) @@ -106,8 +109,10 @@ allowed_methods(Req=#http_req{method=Method}, State) -> next(Req, State, fun malformed_request/2); no_call -> method_not_allowed(Req, State, ['GET', 'HEAD']); - {List, Req2, HandlerState2} -> - State2 = State#state{handler_state=HandlerState2}, + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); + {List, Req2, HandlerState} -> + State2 = State#state{handler_state=HandlerState}, case lists:member(Method, List) of true -> next(Req2, State2, fun malformed_request/2); false -> method_not_allowed(Req2, State2, List) @@ -137,12 +142,14 @@ is_authorized(Req, State) -> case call(Req, State, is_authorized) of no_call -> forbidden(Req, State); - {true, Req2, HandlerState2} -> - forbidden(Req2, State#state{handler_state=HandlerState2}); - {{false, AuthHead}, Req2, HandlerState2} -> + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); + {true, Req2, HandlerState} -> + forbidden(Req2, State#state{handler_state=HandlerState}); + {{false, AuthHead}, Req2, HandlerState} -> {ok, Req3} = cowboy_http_req:set_resp_header( <<"Www-Authenticate">>, AuthHead, Req2), - respond(Req3, State#state{handler_state=HandlerState2}, 401) + respond(Req3, State#state{handler_state=HandlerState}, 401) end. forbidden(Req, State) -> @@ -162,8 +169,12 @@ valid_entity_length(Req, State) -> %% If you need to add additional headers to the response at this point, %% you should do it directly in the options/2 call using set_resp_headers. options(Req=#http_req{method='OPTIONS'}, State) -> - {ok, Req2, HandlerState2} = call(Req, State, options), - respond(Req2, State#state{handler_state=HandlerState2}, 200); + case call(Req, State, options) of + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); + {ok, Req2, HandlerState} -> + respond(Req2, State#state{handler_state=HandlerState}, 200) + end; options(Req, State) -> content_types_provided(Req, State). @@ -186,6 +197,8 @@ content_types_provided(Req=#http_req{meta=Meta}, State) -> case call(Req, State, content_types_provided) of no_call -> not_acceptable(Req, State); + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); {[], Req2, HandlerState} -> not_acceptable(Req2, State#state{handler_state=HandlerState}); {CTP, Req2, HandlerState} -> @@ -280,10 +293,12 @@ languages_provided(Req, State) -> case call(Req, State, languages_provided) of no_call -> charsets_provided(Req, State); - {[], Req2, HandlerState2} -> - not_acceptable(Req2, State#state{handler_state=HandlerState2}); - {LP, Req2, HandlerState2} -> - State2 = State#state{handler_state=HandlerState2, languages_p=LP}, + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); + {[], Req2, HandlerState} -> + not_acceptable(Req2, State#state{handler_state=HandlerState}); + {LP, Req2, HandlerState} -> + State2 = State#state{handler_state=HandlerState, languages_p=LP}, {AcceptLanguage, Req3} = cowboy_http_req:parse_header('Accept-Language', Req2), case AcceptLanguage of @@ -341,10 +356,12 @@ charsets_provided(Req, State) -> case call(Req, State, charsets_provided) of no_call -> set_content_type(Req, State); - {[], Req2, HandlerState2} -> - not_acceptable(Req2, State#state{handler_state=HandlerState2}); - {CP, Req2, HandlerState2} -> - State2 = State#state{handler_state=HandlerState2, charsets_p=CP}, + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); + {[], Req2, HandlerState} -> + not_acceptable(Req2, State#state{handler_state=HandlerState}); + {CP, Req2, HandlerState} -> + State2 = State#state{handler_state=HandlerState, charsets_p=CP}, {AcceptCharset, Req3} = cowboy_http_req:parse_header('Accept-Charset', Req2), case AcceptCharset of @@ -579,12 +596,14 @@ is_put_to_missing_resource(Req, State) -> %% with Location the full new URI of the resource. moved_permanently(Req, State, OnFalse) -> case call(Req, State, moved_permanently) of - {{true, Location}, Req2, HandlerState2} -> + {{true, Location}, Req2, HandlerState} -> {ok, Req3} = cowboy_http_req:set_resp_header( <<"Location">>, Location, Req2), - respond(Req3, State#state{handler_state=HandlerState2}, 301); - {false, Req2, HandlerState2} -> - OnFalse(Req2, State#state{handler_state=HandlerState2}); + respond(Req3, State#state{handler_state=HandlerState}, 301); + {false, Req2, HandlerState} -> + OnFalse(Req2, State#state{handler_state=HandlerState}); + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); no_call -> OnFalse(Req, State) end. @@ -598,12 +617,14 @@ previously_existed(Req, State) -> %% with Location the full new URI of the resource. moved_temporarily(Req, State) -> case call(Req, State, moved_temporarily) of - {{true, Location}, Req2, HandlerState2} -> + {{true, Location}, Req2, HandlerState} -> {ok, Req3} = cowboy_http_req:set_resp_header( <<"Location">>, Location, Req2), - respond(Req3, State#state{handler_state=HandlerState2}, 307); - {false, Req2, HandlerState2} -> - is_post_to_missing_resource(Req2, State#state{handler_state=HandlerState2}, 410); + respond(Req3, State#state{handler_state=HandlerState}, 307); + {false, Req2, HandlerState} -> + is_post_to_missing_resource(Req2, State#state{handler_state=HandlerState}, 410); + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); no_call -> is_post_to_missing_resource(Req, State, 410) end. @@ -642,6 +663,8 @@ post_is_create(Req, State) -> %% (including the leading /). create_path(Req=#http_req{meta=Meta}, State) -> case call(Req, State, create_path) of + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); {Path, Req2, HandlerState} -> Location = create_path_location(Req2, Path), State2 = State#state{handler_state=HandlerState}, @@ -672,6 +695,8 @@ create_path_location_port(_, Port) -> %% and false when it hasn't, in which case a 500 error is sent. process_post(Req, State) -> case call(Req, State, process_post) of + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); {true, Req2, HandlerState} -> State2 = State#state{handler_state=HandlerState}, next(Req2, State2, 201); @@ -699,8 +724,10 @@ put_resource(Req, State, OnTrue) -> case call(Req, State, content_types_accepted) of no_call -> respond(Req, State, 415); - {CTA, Req2, HandlerState2} -> - State2 = State#state{handler_state=HandlerState2}, + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); + {CTA, Req2, HandlerState} -> + State2 = State#state{handler_state=HandlerState}, {ContentType, Req3} = cowboy_http_req:parse_header('Content-Type', Req2), choose_content_type(Req3, State2, OnTrue, ContentType, CTA) @@ -711,6 +738,8 @@ choose_content_type(Req, State, _OnTrue, _ContentType, []) -> choose_content_type(Req, State, OnTrue, ContentType, [{Accepted, Fun}|_Tail]) when ContentType =:= Accepted -> case call(Req, State, Fun) of + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); {true, Req2, HandlerState} -> State2 = State#state{handler_state=HandlerState}, next(Req2, State2, OnTrue); @@ -754,6 +783,8 @@ set_resp_body(Req=#http_req{method=Method}, end, {Req5, State4} = set_resp_expires(Req4, State3), case call(Req5, State4, Fun) of + {halt, Req6, HandlerState} -> + terminate(Req6, State4#state{handler_state=HandlerState}); {Body, Req6, HandlerState} -> State5 = State4#state{handler_state=HandlerState}, {ok, Req7} = case Body of @@ -803,8 +834,8 @@ generate_etag(Req, State=#state{etag=undefined}) -> case call(Req, State, generate_etag) of no_call -> {undefined, Req, State#state{etag=no_call}}; - {Etag, Req2, HandlerState2} -> - {Etag, Req2, State#state{handler_state=HandlerState2, etag=Etag}} + {Etag, Req2, HandlerState} -> + {Etag, Req2, State#state{handler_state=HandlerState, etag=Etag}} end; generate_etag(Req, State=#state{etag=Etag}) -> {Etag, Req, State}. @@ -815,8 +846,8 @@ last_modified(Req, State=#state{last_modified=undefined}) -> case call(Req, State, last_modified) of no_call -> {undefined, Req, State#state{last_modified=no_call}}; - {LastModified, Req2, HandlerState2} -> - {LastModified, Req2, State#state{handler_state=HandlerState2, + {LastModified, Req2, HandlerState} -> + {LastModified, Req2, State#state{handler_state=HandlerState, last_modified=LastModified}} end; last_modified(Req, State=#state{last_modified=LastModified}) -> @@ -828,8 +859,8 @@ expires(Req, State=#state{expires=undefined}) -> case call(Req, State, expires) of no_call -> {undefined, Req, State#state{expires=no_call}}; - {Expires, Req2, HandlerState2} -> - {Expires, Req2, State#state{handler_state=HandlerState2, + {Expires, Req2, HandlerState} -> + {Expires, Req2, State#state{handler_state=HandlerState, expires=Expires}} end; expires(Req, State=#state{expires=Expires}) -> @@ -841,10 +872,12 @@ expect(Req, State, Callback, Expected, OnTrue, OnFalse) -> case call(Req, State, Callback) of no_call -> next(Req, State, OnTrue); - {Expected, Req2, HandlerState2} -> - next(Req2, State#state{handler_state=HandlerState2}, OnTrue); - {_Unexpected, Req2, HandlerState2} -> - next(Req2, State#state{handler_state=HandlerState2}, OnFalse) + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); + {Expected, Req2, HandlerState} -> + next(Req2, State#state{handler_state=HandlerState}, OnTrue); + {_Unexpected, Req2, HandlerState} -> + next(Req2, State#state{handler_state=HandlerState}, OnFalse) end. call(Req, #state{handler=Handler, handler_state=HandlerState}, Fun) -> |