From 8a798014e980d596e631cf5f24957ee15f9a1ac4 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Tue, 23 Oct 2012 14:37:46 -0500 Subject: allow POST rest handling to specify path after accepting content --- src/cowboy_rest.erl | 19 +++++++++++++++++++ test/http_SUITE.erl | 15 +++++++++++++++ test/rest_created_path_resource.erl | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 test/rest_created_path_resource.erl diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl index fb7f2e1..8967b1d 100644 --- a/src/cowboy_rest.erl +++ b/src/cowboy_rest.erl @@ -670,6 +670,8 @@ post_is_create(Req, State) -> %% (including the leading /). create_path(Req, State) -> case call(Req, State, create_path) of + no_call -> + put_resource(Req, State, fun created_path/2); {halt, Req2, HandlerState} -> terminate(Req2, State#state{handler_state=HandlerState}); {Path, Req2, HandlerState} -> @@ -681,6 +683,23 @@ create_path(Req, State) -> State2, 303) end. +%% Called after content_types_accepted is called for POST methods +%% when create_path did not exist. Expects the full path to +%% be returned and MUST exist in the case that create_path +%% does not. +created_path(Req, State) -> + case call(Req, State, created_path) of + {halt, Req2, HandlerState} -> + terminate(Req2, State#state{handler_state=HandlerState}); + {Path, Req2, HandlerState} -> + {HostURL, Req3} = cowboy_req:host_url(Req2), + State2 = State#state{handler_state=HandlerState}, + Req4 = cowboy_req:set_resp_header( + <<"Location">>, << HostURL/binary, Path/binary >>, Req3), + respond(cowboy_req:set_meta(put_path, Path, Req4), + State2, 303) + end. + %% process_post should return true when the POST body could be processed %% and false when it hasn't, in which case a 500 error is sent. process_post(Req, State) -> diff --git a/test/http_SUITE.erl b/test/http_SUITE.erl index 492863f..0b35cf3 100644 --- a/test/http_SUITE.erl +++ b/test/http_SUITE.erl @@ -50,6 +50,7 @@ -export([onresponse_reply/1]). -export([pipeline/1]). -export([rest_bad_accept/1]). +-export([rest_created_path/1]). -export([rest_expires/1]). -export([rest_keepalive/1]). -export([rest_keepalive_post/1]). @@ -112,6 +113,7 @@ groups() -> nc_zero, pipeline, rest_bad_accept, + rest_created_path, rest_expires, rest_keepalive, rest_keepalive_post, @@ -334,6 +336,7 @@ init_dispatch(Config) -> {"/missing_put_callbacks", rest_missing_callbacks, []}, {"/nodelete", rest_nodelete_resource, []}, {"/patch", rest_patch_resource, []}, + {"/created_path", rest_created_path_resource, []}, {"/resetags", rest_resource_etags, []}, {"/rest_expires", rest_expires, []}, {"/loop_timeout", http_handler_loop_timeout, []}, @@ -763,6 +766,18 @@ rest_bad_accept(Config) -> Client), {ok, 400, _, _} = cowboy_client:response(Client2). +rest_created_path(Config) -> + Headers = [{<<"content-type">>, <<"text/plain">>}], + Body = <<"Whatever">>, + Client = ?config(client, Config), + URL = build_url("/created_path", Config), + {ok, Client2} = cowboy_client:request(<<"POST">>, URL, Headers, + Body, Client), + {ok, 303, ResHeaders, _} = cowboy_client:response(Client2), + {<<"location">>, _Location} = + lists:keyfind(<<"location">>, 1, ResHeaders), + ok. + rest_expires(Config) -> Client = ?config(client, Config), {ok, Client2} = cowboy_client:request(<<"GET">>, diff --git a/test/rest_created_path_resource.erl b/test/rest_created_path_resource.erl new file mode 100644 index 0000000..5ad8cfc --- /dev/null +++ b/test/rest_created_path_resource.erl @@ -0,0 +1,35 @@ +-module(rest_created_path_resource). +-export([init/3]). +-export([allowed_methods/2]). +-export([content_types_provided/2]). +-export([get_text_plain/2]). +-export([post_is_create/2]). +-export([content_types_accepted/2]). +-export([post_text_plain/2]). +-export([created_path/2]). + +init(_Transport, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +allowed_methods(Req, State) -> +{[<<"HEAD">>, <<"GET">>, <<"POST">>], Req, State}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}. + +get_text_plain(Req, State) -> + {<<"This is REST!">>, Req, State}. + +post_is_create(Req, State) -> + {true, Req, State}. + +content_types_accepted(Req, State) -> + {[{{<<"text">>, <<"plain">>, []}, post_text_plain}], Req, State}. + +post_text_plain(Req, State) -> + {true, Req, State}. + +created_path(Req, State) -> + {<<"/created">>, Req, State}. + + -- cgit v1.2.3