Add CORS support

Two new options: cors_allow_origins and cors_max_age.

* cors_allow_origins: list of origins allowed, for example
  ["http://rabbitmq.com", "http://pivotal.com"];
  or ["*"] to allow everything.

* cors_max_age: time in seconds that clients may cache
  preflight requests. It defaults to 30 minutes.
This commit is contained in:
Loïc Hoguin 2016-04-04 16:20:54 +02:00
parent f15b26a961
commit 1ae44f86a2
42 changed files with 375 additions and 18 deletions

View File

@ -0,0 +1,88 @@
%% The contents of this file are subject to the Mozilla Public License
%% Version 1.1 (the "License"); you may not use this file except in
%% compliance with the License. You may obtain a copy of the License at
%% http://www.mozilla.org/MPL/
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
%% License for the specific language governing rights and limitations
%% under the License.
%%
%% The Original Code is RabbitMQ Management Plugin.
%%
%% The Initial Developer of the Original Code is GoPivotal, Inc.
%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
%%
%% Useful documentation about CORS:
%% * https://tools.ietf.org/html/rfc6454
%% * https://www.w3.org/TR/cors/
%% * https://staticapps.org/articles/cross-domain-requests-with-cors/
-module(rabbit_mgmt_cors).
-export([set_headers/2]).
%% We don't set access-control-max-age because we currently have
%% no way to know which headers apply to the whole resource. We
%% only know for the next request.
set_headers(ReqData, Module) ->
ReqData1 = case wrq:get_resp_header("vary", ReqData) of
undefined -> wrq:set_resp_header("vary", "origin", ReqData);
VaryValue -> wrq:set_resp_header("vary", VaryValue ++ ", origin", ReqData)
end,
case match_origin(ReqData1) of
false ->
ReqData1;
Origin ->
ReqData2 = case wrq:method(ReqData1) of
'OPTIONS' -> handle_options(ReqData1, Module);
_ -> ReqData1
end,
wrq:set_resp_headers([
{"access-control-allow-origin", Origin},
{"access-control-allow-credentials", "true"}
], ReqData2)
end.
%% Set max-age from configuration (default: 30 minutes).
%% Set allow-methods from what is defined in Module:allowed_methods/2.
%% Set allow-headers to the same as the request (accept all headers).
handle_options(ReqData, Module) ->
MaxAge = application:get_env(rabbitmq_management, cors_max_age, 1800),
{Methods, _, _} = Module:allowed_methods(undefined, undefined),
AllowMethods = string:join([atom_to_list(M) || M <- Methods], ", "),
ReqHeaders = wrq:get_req_header("access-control-request-headers", ReqData),
MaxAgeHd = case MaxAge of
undefined -> [];
_ -> {"access-control-max-age", integer_to_list(MaxAge)}
end,
MaybeAllowHeaders = case ReqHeaders of
undefined -> [];
_ -> [{"access-control-allow-headers", ReqHeaders}]
end,
wrq:set_resp_headers([MaxAgeHd,
{"access-control-allow-methods", AllowMethods}
|MaybeAllowHeaders], ReqData).
%% If the origin header is missing or "null", we disable CORS.
%% Otherwise, we only enable it if the origin is found in the
%% cors_allow_origins configuration variable, or if "*" is (it
%% allows all origins).
match_origin(ReqData) ->
case wrq:get_req_header("origin", ReqData) of
undefined -> false;
"null" -> false;
Origin ->
AllowedOrigins = application:get_env(rabbitmq_management,
cors_allow_origins, []),
case lists:member(Origin, AllowedOrigins) of
true ->
Origin;
false ->
%% Maybe the configuration explicitly allows "*".
case lists:member("*", AllowedOrigins) of
true -> Origin;
false -> false
end
end
end.

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_aliveness_test).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-export([resource_exists/2]).
@ -30,6 +31,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -20,6 +20,7 @@
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, delete_resource/2,
args_hash/1]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -29,6 +30,9 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -40,7 +44,7 @@ content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'DELETE'], ReqData, Context}.
{['HEAD', 'GET', 'DELETE', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
Binding = binding(ReqData),

View File

@ -20,6 +20,7 @@
-export([allowed_methods/2, post_is_create/2, create_path/2]).
-export([content_types_accepted/2, accept_content/2, resource_exists/2]).
-export([basic/1, augmented/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -31,6 +32,9 @@
init([Mode]) ->
{ok, {Mode, #context{}}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -49,8 +53,8 @@ content_types_accepted(ReqData, Context) ->
allowed_methods(ReqData, {Mode, Context}) ->
{case Mode of
source_destination -> ['HEAD', 'GET', 'POST'];
_ -> ['HEAD', 'GET']
source_destination -> ['HEAD', 'GET', 'POST', 'OPTIONS'];
_ -> ['HEAD', 'GET', 'OPTIONS']
end, ReqData, {Mode, Context}}.
post_is_create(ReqData, Context) ->

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_channel).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-export([resource_exists/2]).
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -18,6 +18,7 @@
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2,
augmented/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2]).
@ -30,6 +31,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -20,6 +20,7 @@
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2,
augmented/2, resource_exists/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2]).
@ -32,6 +33,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -19,6 +19,7 @@
-export([init/1, resource_exists/2, to_json/2,
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, accept_content/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,6 +29,9 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -39,7 +43,7 @@ content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'PUT'], ReqData, Context}.
{['HEAD', 'GET', 'PUT', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
{true, ReqData, Context}.

View File

@ -18,6 +18,7 @@
-export([init/1, resource_exists/2, to_json/2, content_types_provided/2,
is_authorized/2, allowed_methods/2, delete_resource/2, conn/1]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,6 +29,9 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -36,7 +40,7 @@ encodings_provided(ReqData, Context) ->
{"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'DELETE'], ReqData, Context}.
{['HEAD', 'GET', 'DELETE', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
case conn(ReqData) of

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_connection_channels).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-export([resource_exists/2]).
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -18,6 +18,7 @@
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2,
augmented/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2]).
@ -30,6 +31,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -20,6 +20,7 @@
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2,
augmented/2, resource_exists/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2]).
@ -32,6 +33,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -17,6 +17,7 @@
-export([init/1, to_json/2, content_types_provided/2, resource_exists/2,
is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2]).
@ -29,6 +30,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -19,6 +19,7 @@
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([content_types_accepted/2, allowed_methods/2, accept_json/2]).
-export([post_is_create/2, create_path/2, accept_multipart/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-export([apply_defs/3]).
@ -32,6 +33,9 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -44,7 +48,7 @@ content_types_accepted(ReqData, Context) ->
{"multipart/form-data", accept_multipart}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'POST'], ReqData, Context}.
{['HEAD', 'GET', 'POST', 'OPTIONS'], ReqData, Context}.
post_is_create(ReqData, Context) ->
{true, ReqData, Context}.

View File

@ -20,6 +20,7 @@
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, accept_content/2,
delete_resource/2, exchange/1, exchange/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -29,6 +30,9 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -40,7 +44,7 @@ content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'PUT', 'DELETE'], ReqData, Context}.
{['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
{case exchange(ReqData) of

View File

@ -18,6 +18,7 @@
-export([init/1, resource_exists/2, post_is_create/2, is_authorized/2,
allowed_methods/2, content_types_provided/2, process_post/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -27,8 +28,11 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['POST'], ReqData, Context}.
{['POST', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -18,6 +18,7 @@
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2,
resource_exists/2, basic/1, augmented/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_extensions).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -26,6 +27,12 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -16,6 +16,7 @@
-module(rabbit_mgmt_wm_healthchecks).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-export([resource_exists/2]).
@ -26,6 +27,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_node).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-export([resource_exists/2]).
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_nodes).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([all_nodes/1, all_nodes_raw/0]).
-export([encodings_provided/2]).
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_overview).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2, pget/3]).
@ -29,6 +30,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -20,6 +20,7 @@
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, accept_content/2,
delete_resource/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2]).
@ -32,6 +33,9 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -43,7 +47,7 @@ content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'PUT', 'DELETE'], ReqData, Context}.
{['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
{case parameter(ReqData) of

View File

@ -18,6 +18,7 @@
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2,
resource_exists/2, basic/1]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -20,6 +20,7 @@
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, accept_content/2,
delete_resource/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -29,6 +30,9 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -40,7 +44,7 @@ content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'PUT', 'DELETE'], ReqData, Context}.
{['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
{case perms(ReqData) of

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_permissions).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([permissions/0]).
-export([encodings_provided/2]).
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -18,6 +18,7 @@
-export([init/1, to_json/2, content_types_provided/2, resource_exists/2,
is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -18,6 +18,7 @@
-export([init/1, to_json/2, content_types_provided/2, resource_exists/2,
is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -18,6 +18,7 @@
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2,
resource_exists/2, basic/1]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -20,6 +20,7 @@
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, accept_content/2,
delete_resource/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2]).
@ -32,6 +33,9 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -43,7 +47,7 @@ content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'PUT', 'DELETE'], ReqData, Context}.
{['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
{case policy(ReqData) of

View File

@ -20,6 +20,7 @@
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, accept_content/2,
delete_resource/2, queue/1, queue/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -29,6 +30,9 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -40,7 +44,7 @@ content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'PUT', 'DELETE'], ReqData, Context}.
{['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
{case queue(ReqData) of

View File

@ -18,6 +18,7 @@
-export([init/1, resource_exists/2, post_is_create/2, is_authorized/2,
allowed_methods/2, process_post/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,8 +29,11 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['POST'], ReqData, Context}.
{['POST', 'OPTIONS'], ReqData, Context}.
encodings_provided(ReqData, Context) ->
{[{"identity", fun(X) -> X end},

View File

@ -18,6 +18,7 @@
-export([init/1, resource_exists/2, post_is_create/2, is_authorized/2,
allowed_methods/2, process_post/2, content_types_provided/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,8 +29,11 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['POST'], ReqData, Context}.
{['POST', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -18,6 +18,7 @@
-export([init/1, resource_exists/2, is_authorized/2, allowed_methods/2,
delete_resource/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -27,8 +28,11 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['DELETE'], ReqData, Context}.
{['DELETE', 'OPTIONS'], ReqData, Context}.
encodings_provided(ReqData, Context) ->
{[{"identity", fun(X) -> X end},

View File

@ -18,6 +18,7 @@
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2,
resource_exists/2, basic/1, augmented/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -20,6 +20,7 @@
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, accept_content/2,
delete_resource/2, user/1, put_user/1, put_user/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2]).
@ -31,6 +32,9 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -42,7 +46,7 @@ content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'PUT', 'DELETE'], ReqData, Context}.
{['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
{case user(ReqData) of

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_users).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-export([users/0]).
@ -30,6 +31,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -20,6 +20,7 @@
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, accept_content/2,
delete_resource/2, id/1, put_vhost/2]).
-export([finish_request/2]).
-export([encodings_provided/2]).
-import(rabbit_misc, [pget/2]).
@ -31,6 +32,9 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
@ -42,7 +46,7 @@ content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'PUT', 'DELETE'], ReqData, Context}.
{['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}.
resource_exists(ReqData, Context) ->
{rabbit_vhost:exists(id(ReqData)), ReqData, Context}.

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_vhosts).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-export([basic/0, augmented/2]).
@ -28,6 +29,12 @@
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -17,6 +17,7 @@
-module(rabbit_mgmt_wm_whoami).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
-export([finish_request/2, allowed_methods/2]).
-export([encodings_provided/2]).
-include("rabbit_mgmt.hrl").
@ -26,6 +27,12 @@
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
finish_request(ReqData, Context) ->
{ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'OPTIONS'], ReqData, Context}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.

View File

@ -12,7 +12,9 @@
%% List of {MaxAgeInSeconds, SampleEveryNSeconds}
[{global, [{605, 5}, {3660, 60}, {29400, 600}, {86400, 1800}]},
{basic, [{605, 5}, {3600, 60}]},
{detailed, [{10, 5}]}]}
{detailed, [{10, 5}]}]},
{cors_allow_origins, []},
{cors_max_age, 1800}
]},
{applications, [kernel, stdlib, rabbit, xmerl, rabbitmq_web_dispatch,
amqp_client, rabbitmq_management_agent]}]}.

View File

@ -23,6 +23,48 @@
-import(rabbit_mgmt_test_util, [assert_list/2, assert_item/2, test_item/2]).
-import(rabbit_misc, [pget/2]).
cors_test() ->
%% With CORS disabled. No header should be received.
{ok, {_, HdNoCORS, _}} = req(get, "/overview", [auth_header("guest", "guest")]),
false = lists:keymember("access-control-allow-origin", 1, HdNoCORS),
%% The Vary header should include "Origin" regardless of CORS configuration.
{_, "Accept-Encoding, origin"} = lists:keyfind("vary", 1, HdNoCORS),
%% Enable CORS.
application:set_env(rabbitmq_management, cors_allow_origins, ["http://rabbitmq.com"]),
%% We should only receive allow-origin and allow-credentials from GET.
{ok, {_, HdGetCORS, _}} = req(get, "/overview",
[{"origin", "http://rabbitmq.com"}, auth_header("guest", "guest")]),
true = lists:keymember("access-control-allow-origin", 1, HdGetCORS),
true = lists:keymember("access-control-allow-credentials", 1, HdGetCORS),
false = lists:keymember("access-control-expose-headers", 1, HdGetCORS),
false = lists:keymember("access-control-max-age", 1, HdGetCORS),
false = lists:keymember("access-control-allow-methods", 1, HdGetCORS),
false = lists:keymember("access-control-allow-headers", 1, HdGetCORS),
%% We should receive allow-origin, allow-credentials and allow-methods from OPTIONS.
{ok, {_, HdOptionsCORS, _}} = req(options, "/overview",
[{"origin", "http://rabbitmq.com"}, auth_header("guest", "guest")]),
true = lists:keymember("access-control-allow-origin", 1, HdOptionsCORS),
true = lists:keymember("access-control-allow-credentials", 1, HdOptionsCORS),
false = lists:keymember("access-control-expose-headers", 1, HdOptionsCORS),
true = lists:keymember("access-control-max-age", 1, HdOptionsCORS),
true = lists:keymember("access-control-allow-methods", 1, HdOptionsCORS),
false = lists:keymember("access-control-allow-headers", 1, HdOptionsCORS),
%% We should receive allow-headers when request-headers is sent.
{ok, {_, HdAllowHeadersCORS, _}} = req(options, "/overview",
[{"origin", "http://rabbitmq.com"},
auth_header("guest", "guest"),
{"access-control-request-headers", "x-piggy-bank"}]),
{_, "x-piggy-bank"} = lists:keyfind("access-control-allow-headers", 1, HdAllowHeadersCORS),
%% Disable preflight request caching.
application:set_env(rabbitmq_management, cors_max_age, undefined),
%% We shouldn't receive max-age anymore.
{ok, {_, HdNoMaxAgeCORS, _}} = req(options, "/overview",
[{"origin", "http://rabbitmq.com"}, auth_header("guest", "guest")]),
false = lists:keymember("access-control-max-age", 1, HdNoMaxAgeCORS),
%% Disable CORS again.
application:set_env(rabbitmq_management, cors_allow_origins, []),
ok.
overview_test() ->
%% Rather crude, but this req doesn't say much and at least this means it
%% didn't blow up.