diff options
-rw-r--r-- | examples/basic_auth/README.md | 5 | ||||
-rw-r--r-- | examples/basic_auth/src/basic_auth_app.erl | 6 | ||||
-rw-r--r-- | src/cowboy_http.erl | 37 | ||||
-rw-r--r-- | src/cowboy_rest.erl | 19 | ||||
-rw-r--r-- | test/http_SUITE.erl | 15 | ||||
-rw-r--r-- | test/rest_created_path_resource.erl | 35 |
6 files changed, 92 insertions, 25 deletions
diff --git a/examples/basic_auth/README.md b/examples/basic_auth/README.md index 74662cd..38ae9a2 100644 --- a/examples/basic_auth/README.md +++ b/examples/basic_auth/README.md @@ -1,5 +1,5 @@ -Cowboy Basic Authorization Rest Hello World. -============================================ +Cowboy Basic Authorization Rest Hello World +=========================================== To compile this example you need rebar in your PATH. @@ -41,4 +41,3 @@ content-type: text/plain Hello, Alladin! ``` - diff --git a/examples/basic_auth/src/basic_auth_app.erl b/examples/basic_auth/src/basic_auth_app.erl index c60a574..24c766e 100644 --- a/examples/basic_auth/src/basic_auth_app.erl +++ b/examples/basic_auth/src/basic_auth_app.erl @@ -11,11 +11,11 @@ %% API. start(_Type, _Args) -> - Dispatch = [ + Dispatch = cowboy_router:compile([ {'_', [ - {[], toppage_handler, []} + {"/", toppage_handler, []} ]} - ], + ]), {ok, _} = cowboy:start_http(http, 100, [{port, 8080}], [ {env, [{dispatch, Dispatch}]} ]), diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl index 67d3f70..a78e090 100644 --- a/src/cowboy_http.erl +++ b/src/cowboy_http.erl @@ -802,6 +802,23 @@ qvalue(<< C, Rest/binary >>, Fun, Q, M) qvalue(Data, Fun, Q, _M) -> Fun(Data, Q). +%% @doc Parse authorization value according rfc 2617. +%% Only Basic authorization is supported so far. +-spec authorization(binary(), binary()) -> {binary(), any()} | {error, badarg}. +authorization(UserPass, Type = <<"basic">>) -> + cowboy_http:whitespace(UserPass, + fun(D) -> + authorization_basic_userid(base64:mime_decode(D), + fun(Rest, Userid) -> + authorization_basic_password(Rest, + fun(Password) -> + {Type, {Userid, Password}} + end) + end) + end); +authorization(String, Type) -> + {Type, String}. + %% @doc Parse user credentials. -spec authorization_basic_userid(binary(), fun()) -> any(). authorization_basic_userid(Data, Fun) -> @@ -831,23 +848,6 @@ authorization_basic_password(<<>>, Fun, Acc) -> authorization_basic_password(<<C, Rest/binary>>, Fun, Acc) -> authorization_basic_password(Rest, Fun, <<Acc/binary, C>>). -%% @doc Parse authorization value according rfc 2617. -%% Only Basic authorization is supported so far. --spec authorization(binary(), binary()) -> {binary(), any()} | {error, badarg}. -authorization(UserPass, Type = <<"basic">>) -> - cowboy_http:whitespace(UserPass, - fun(D) -> - authorization_basic_userid(base64:mime_decode(D), - fun(Rest, Userid) -> - authorization_basic_password(Rest, - fun(Password) -> - {Type, {Userid, Password}} - end) - end) - end); -authorization(String, Type) -> - {Type, String}. - %% Decoding. %% @doc Decode a stream of chunks. @@ -1350,7 +1350,6 @@ http_authorization_test_() -> authorization(<<"_[]@#$%^&*()-AA==">>, <<"basic">>)), ?_assertEqual({error, badarg}, authorization(<<"dXNlcjpwYXNzCA==">>, <<"basic">>)) %% user:pass\010 - ]. - + ]. -endif. 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}. + + |