Skip to content

Commit 7127ec2

Browse files
committed
Merge pull request #7 from danielwhite/fix-exposed-headers
Use a single header for Access-Control-Expose-Headers
2 parents 428293d + 09c1a24 commit 7127ec2

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

src/cowboy_cors.erl

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ exposed_headers(Req, State) ->
139139

140140
set_exposed_headers(Req, []) ->
141141
Req;
142-
set_exposed_headers(Req, [Header|Tail]) ->
143-
Req1 = cowboy_req:set_resp_header(<<"access-control-expose-headers">>, Header, Req),
144-
set_exposed_headers(Req1, Tail).
142+
set_exposed_headers(Req, Headers) ->
143+
Bin = header_list(Headers),
144+
cowboy_req:set_resp_header(<<"access-control-expose-headers">>, Bin, Req).
145145

146146
%% allow_credentials/1 should return true or false.
147147
allow_credentials(Req, State) ->
@@ -195,3 +195,12 @@ terminate(Req, #state{env = Env}) ->
195195
-spec error_terminate(cowboy_req:req(), #state{}) -> no_return().
196196
error_terminate(_Req, _State) ->
197197
erlang:throw({?MODULE, error}).
198+
199+
%% create a comma-separated list for a header value
200+
header_list(Values) ->
201+
header_list(Values, <<>>).
202+
203+
header_list([Value], Acc) ->
204+
<<Acc/binary, Value/binary>>;
205+
header_list([Value | Rest], Acc) ->
206+
header_list(Rest, <<Acc/binary, Value/binary, ",">>).

test/cors_SUITE.erl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
-export([standard_options/1]).
1818
-export([simple_allowed_get/1]).
1919
-export([simple_allowed_credentials_get/1]).
20+
-export([simple_exposed_headers/1]).
2021
-export([actual_options/1]).
2122
-export([preflight_method/1]).
2223
-export([preflight_allowed_method/1]).
@@ -46,6 +47,7 @@ groups() ->
4647
standard_options,
4748
simple_allowed_get,
4849
simple_allowed_credentials_get,
50+
simple_exposed_headers,
4951
actual_options,
5052
preflight_method,
5153
preflight_allowed_method,
@@ -168,6 +170,21 @@ simple_allowed_credentials_get(Config) ->
168170
{_, Origin} = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers),
169171
{_, <<"true">>} = lists:keyfind(<<"access-control-allow-credentials">>, 1, Headers).
170172

173+
simple_exposed_headers(Config) ->
174+
Origin = <<"http://example.com">>,
175+
Exposed = [<<"x-first">>, <<"x-second">>],
176+
{ok, 204, Headers, _} =
177+
request(<<"GET">>,
178+
[{<<"Origin">>, Origin}],
179+
[{allowed_origins, Origin},
180+
{allowed_methods, <<"GET">>},
181+
{exposed_headers, Exposed}],
182+
Config),
183+
{_, Origin} = lists:keyfind(<<"access-control-allow-origin">>, 1, Headers),
184+
{_, ExposedList} = lists:keyfind(<<"access-control-expose-headers">>, 1, Headers),
185+
Exposed = cowboy_http:nonempty_list(ExposedList, fun cowboy_http:token/2),
186+
false = lists:keyfind(<<"access-control-allow-credentials">>, 1, Headers).
187+
171188
actual_options(Config) ->
172189
%% OPTIONS request without Access-Control-Request-Method is not a pre-flight request.
173190
Origin = <<"http://example.com">>,

0 commit comments

Comments
 (0)