From 761e07f2097fcde8b325df94f1965a9c9237252f Mon Sep 17 00:00:00 2001 From: Daniel White Date: Sat, 2 Nov 2013 20:57:29 +1100 Subject: [PATCH 1/2] Determine test policy options by inspecting query parameters The goal of this change is to make the policy module for tests simpler, and improve the ease of understanding and changing tests by embedding the options in each test case. --- test/cors_SUITE.erl | 136 +++++++++++++++++++-------- test/cors_SUITE_data/cors_policy.erl | 43 ++++++--- 2 files changed, 125 insertions(+), 54 deletions(-) diff --git a/test/cors_SUITE.erl b/test/cors_SUITE.erl index 3f3301b..2986d75 100644 --- a/test/cors_SUITE.erl +++ b/test/cors_SUITE.erl @@ -90,17 +90,40 @@ end_per_group(Name, _) -> %% Helpers -build_url(Path, Config) -> +build_url(Path, Options, Config) -> Port = ?config(port, Config), - iolist_to_binary([<<"http://localhost:">>, integer_to_list(Port), Path]). + Params = build_params(Options), + iolist_to_binary([<<"http://localhost:">>, integer_to_list(Port), Path, Params]). -request(Method, Headers, Config) -> +build_params(Options) -> + case lists:map(fun build_param/1, Options) of + [] -> + []; + [["&" | First] | Rest] -> + ["?", First, Rest] + end. + +build_param({Name, Value}) -> + ["&", atom_to_list(Name), "=", format_option(Value)]. + +format_option(Bin) when is_binary(Bin) -> + cowboy_http:urlencode(Bin); +format_option(Bool) when is_boolean(Bool) -> + io_lib:fwrite("~p", [Bool]); +format_option(List) when is_list(List) -> + IoList = lists:map(fun(X) -> [",", X] end, List), + <<",", Bin/binary>> = iolist_to_binary(IoList), + cowboy_http:urlencode(Bin). + +request(Method, Headers, Options, Config) -> {ok, Client} = cowboy_client:init([]), - {ok, Client2} = cowboy_client:request(Method, build_url(<<"/">>, Config), Headers, Client), + Url = build_url(<<"/">>, Options, Config), + ct:pal("Sending request to ~p", [Url]), + {ok, Client2} = cowboy_client:request(Method, Url, Headers, Client), cowboy_client:response(Client2). -preflight(Headers, Config) -> - request(<<"OPTIONS">>, Headers, Config). +request(Method, Headers, Config) -> + request(Method, Headers, [], Config). %% Tests @@ -113,44 +136,57 @@ standard_no_origin_options(Config) -> false = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers). standard_get(Config) -> - Origin = <<"http://banned.example.com">>, + Origin = <<"http://example.com">>, {ok, 204, Headers, _} = request(<<"GET">>, [{<<"Origin">>, Origin}], Config), false = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers). standard_options(Config) -> - Origin = <<"http://banned.example.com">>, + Origin = <<"http://example.com">>, {ok, 204, Headers, _} = request(<<"OPTIONS">>, [{<<"Origin">>, Origin}], Config), false = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers). simple_allowed_get(Config) -> - Origin = <<"http://allowed.example.com">>, + Origin = <<"http://example.com">>, {ok, 204, Headers, _} = - request(<<"GET">>, [{<<"Origin">>, Origin}], Config), + request(<<"GET">>, + [{<<"Origin">>, Origin}], + [{allowed_origins, [<<"http://example.org">>, Origin]}, + {allowed_methods, [<<"PUT">>, <<"GET">>]}], + Config), {_, Origin} = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers), - {_, <<"x-exposed">>} = lists:keyfind(<<"access-control-expose-headers">>, 1, Headers), false = lists:keyfind(<<"access-control-allow-credentials">>, 1, Headers). simple_allowed_credentials_get(Config) -> - Origin = <<"http://credentials.example.com">>, + Origin = <<"http://example.com">>, {ok, 204, Headers, _} = - request(<<"GET">>, [{<<"Origin">>, Origin}], Config), + request(<<"GET">>, + [{<<"Origin">>, Origin}], + [{allowed_origins, Origin}, + {allow_credentials, true}], + Config), {_, Origin} = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers), - {_, <<"x-exposed">>} = lists:keyfind(<<"access-control-expose-headers">>, 1, Headers), {_, <<"true">>} = lists:keyfind(<<"access-control-allow-credentials">>, 1, Headers). actual_options(Config) -> %% OPTIONS request without Access-Control-Request-Method is not a pre-flight request. - Origin = <<"http://allowed.example.com">>, + Origin = <<"http://example.com">>, {ok, 204, Headers, _} = - preflight([{<<"Origin">>, Origin}], Config), + request(<<"OPTIONS">>, + [{<<"Origin">>, Origin}], + [{allowed_origins, Origin}], + Config), {_, Origin} = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers), %% Ensure OPTIONS request was handled. {_, <<"exposed">>} = lists:keyfind(<<"x-exposed">>, 1, Headers). preflight_method(Config) -> - Origin = <<"http://allowed.example.com">>, + Origin = <<"http://example.com">>, {ok, 200, Headers, _} = - preflight([{<<"Origin">>, Origin}, {<<"Access-Control-Request-Method">>, <<"DELETE">>}], Config), + request(<<"OPTIONS">>, + [{<<"Origin">>, Origin}, + {<<"Access-Control-Request-Method">>, <<"DELETE">>}], + [{allowed_origins, Origin}], + Config), false = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers), false = lists:keyfind(<<"access-control-allow-methods">>, 1, Headers), false = lists:keyfind(<<"access-control-allow-credentials">>, 1, Headers), @@ -159,9 +195,14 @@ preflight_method(Config) -> false = lists:keyfind(<<"x-exposed">>, 1, Headers). preflight_allowed_method(Config) -> - Origin = <<"http://allowed.example.com">>, + Origin = <<"http://example.com">>, {ok, 200, Headers, _} = - preflight([{<<"Origin">>, Origin}, {<<"Access-Control-Request-Method">>, <<"PUT">>}], Config), + request(<<"OPTIONS">>, + [{<<"Origin">>, Origin}, + {<<"Access-Control-Request-Method">>, <<"PUT">>}], + [{allowed_origins, Origin}, + {allowed_methods, [<<"GET">>, <<"PUT">>]}], + Config), {_, Origin} = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers), {_, <<"PUT">>} = lists:keyfind(<<"access-control-allow-methods">>, 1, Headers), false = lists:keyfind(<<"access-control-allow-credentials">>, 1, Headers), @@ -170,9 +211,15 @@ preflight_allowed_method(Config) -> false = lists:keyfind(<<"x-exposed">>, 1, Headers). preflight_credentials(Config) -> - Origin = <<"http://credentials.example.com">>, + Origin = <<"http://example.com">>, {ok, 200, Headers, _} = - preflight([{<<"Origin">>, Origin}, {<<"Access-Control-Request-Method">>, <<"PUT">>}], Config), + request(<<"OPTIONS">>, + [{<<"Origin">>, Origin}, + {<<"Access-Control-Request-Method">>, <<"PUT">>}], + [{allowed_origins, Origin}, + {allowed_methods, <<"PUT">>}, + {allow_credentials, true}], + Config), {_, Origin} = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers), {_, <<"PUT">>} = lists:keyfind(<<"access-control-allow-methods">>, 1, Headers), {_, <<"true">>} = lists:keyfind(<<"access-control-allow-credentials">>, 1, Headers), @@ -181,13 +228,16 @@ preflight_credentials(Config) -> false = lists:keyfind(<<"x-exposed">>, 1, Headers). preflight_header(Config) -> - Origin = <<"http://allowed.example.com">>, + Origin = <<"http://example.com">>, {ok, 200, Headers, _} = - preflight([ - {<<"Origin">>, Origin}, - {<<"Access-Control-Request-Method">>, <<"PUT">>}, - {<<"Access-Control-Request-Headers">>, <<"X-Custom">>} - ], Config), + request(<<"OPTIONS">>, + [{<<"Origin">>, Origin}, + {<<"Access-Control-Request-Method">>, <<"PUT">>}, + {<<"Access-Control-Request-Headers">>, <<"X-Custom">>}], + [{allowed_origins, Origin}, + {allowed_methods, <<"PUT">>}, + {allowed_headers, [<<"x-unused">>, <<"x-also-unused">>]}], + Config), false = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers), false = lists:keyfind(<<"access-control-allow-methods">>, 1, Headers), false = lists:keyfind(<<"access-control-allow-headers">>, 1, Headers), @@ -197,13 +247,16 @@ preflight_header(Config) -> false = lists:keyfind(<<"x-exposed">>, 1, Headers). preflight_allowed_header(Config) -> - Origin = <<"http://allowed.example.com">>, + Origin = <<"http://example.com">>, {ok, 200, Headers, _} = - preflight([ - {<<"Origin">>, Origin}, - {<<"Access-Control-Request-Method">>, <<"PUT">>}, - {<<"Access-Control-Request-Headers">>, <<"X-Requested">>} - ], Config), + request(<<"OPTIONS">>, + [{<<"Origin">>, Origin}, + {<<"Access-Control-Request-Method">>, <<"PUT">>}, + {<<"Access-Control-Request-Headers">>, <<"X-Requested">>}], + [{allowed_origins, Origin}, + {allowed_methods, <<"PUT">>}, + {allowed_headers, [<<"x-allowed">>, <<"x-requested">>]}], + Config), {_, Origin} = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers), {_, <<"PUT">>} = lists:keyfind(<<"access-control-allow-methods">>, 1, Headers), {_, <<"X-Requested">>} = lists:keyfind(<<"access-control-allow-headers">>, 1, Headers), @@ -214,13 +267,16 @@ preflight_allowed_header(Config) -> %% Test for Webkit browsers requesting 'Origin' header. preflight_allowed_header_webkit(Config) -> - Origin = <<"http://allowed.example.com">>, + Origin = <<"http://example.com">>, {ok, 200, Headers, _} = - preflight([ - {<<"Origin">>, Origin}, - {<<"Access-Control-Request-Method">>, <<"PUT">>}, - {<<"Access-Control-Request-Headers">>, <<"origin, x-requested">>} - ], Config), + request(<<"OPTIONS">>, + [{<<"Origin">>, Origin}, + {<<"Access-Control-Request-Method">>, <<"PUT">>}, + {<<"Access-Control-Request-Headers">>, <<"origin, x-requested">>}], + [{allowed_origins, Origin}, + {allowed_methods, <<"PUT">>}, + {allowed_headers, [<<"x-allowed">>, <<"x-requested">>]}], + Config), {_, Origin} = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers), {_, <<"PUT">>} = lists:keyfind(<<"access-control-allow-methods">>, 1, Headers), {_, <<"origin, x-requested">>} = lists:keyfind(<<"access-control-allow-headers">>, 1, Headers), diff --git a/test/cors_SUITE_data/cors_policy.erl b/test/cors_SUITE_data/cors_policy.erl index 183a7c9..00ee3a2 100644 --- a/test/cors_SUITE_data/cors_policy.erl +++ b/test/cors_SUITE_data/cors_policy.erl @@ -12,25 +12,40 @@ policy_init(Req) -> {ok, Req, undefined_state}. allowed_origins(Req, State) -> - Allowed = [ - <<"http://allowed.example.com">>, - <<"http://credentials.example.com">> - ], - {Allowed, Req, State}. + {Allowed, Req1} = parse_list(<<"allowed_origins">>, Req), + {Allowed, Req1, State}. allow_credentials(Req, State) -> - case cowboy_req:header(<<"origin">>, Req) of - {<<"http://credentials.example.com">>, Req1} -> - {true, Req1, State}; - {_, Req1} -> - {false, Req1, State} - end. + {IsAllowed, Req1} = parse_boolean(<<"allow_credentials">>, Req, false), + {IsAllowed, Req1, State}. exposed_headers(Req, State) -> - {[<<"x-exposed">>], Req, State}. + {Exposed, Req1} = parse_list(<<"exposed_headers">>, Req), + {Exposed, Req1, State}. allowed_headers(Req, State) -> - {[<<"x-requested">>], Req, State}. + {Allowed, Req1} = parse_list(<<"allowed_headers">>, Req), + {Allowed, Req1, State}. allowed_methods(Req, State) -> - {[<<"GET">>, <<"POST">>, <<"PUT">>], Req, State}. + {Allowed, Req1} = parse_list(<<"allowed_methods">>, Req), + {Allowed, Req1, State}. + +parse_list(Name, Req) -> + case cowboy_req:qs_val(Name, Req) of + {undefined, Req1} -> + {[], Req1}; + {Bin, Req1} -> + List = binary:split(Bin, <<",">>, [global]), + {List, Req1} + end. + +parse_boolean(Name, Req, Default) -> + case cowboy_req:qs_val(Name, Req) of + {undefined, Req1} -> + {Default, Req1}; + {<<"true">>, Req1} -> + {true, Req1}; + {<<"false">>, Req1} -> + {false, Req1} + end. From f5c10b46245ecd27777da47ab5fcc8eff678ed3a Mon Sep 17 00:00:00 2001 From: Daniel White Date: Sat, 2 Nov 2013 23:27:56 +1100 Subject: [PATCH 2/2] Add unused test case to suite It appears this test was written, but never executed as part of the suite. --- test/cors_SUITE.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/cors_SUITE.erl b/test/cors_SUITE.erl index 2986d75..22e0128 100644 --- a/test/cors_SUITE.erl +++ b/test/cors_SUITE.erl @@ -50,6 +50,7 @@ groups() -> preflight_method, preflight_allowed_method, preflight_credentials, + preflight_header, preflight_allowed_header, preflight_allowed_header_webkit ]}