%% 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-2017 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]). set_headers(ReqData, Module) -> %% Send vary: origin by default if nothing else was set. ReqData1 = cowboy_req:set_resp_header(<<"vary">>, <<"origin">>, ReqData), case match_origin(ReqData1) of false -> ReqData1; Origin -> ReqData2 = case cowboy_req:method(ReqData1) of <<"OPTIONS">> -> handle_options(ReqData1, Module); _ -> ReqData1 end, ReqData3 = cowboy_req:set_resp_header(<<"access-control-allow-origin">>, Origin, ReqData2), cowboy_req:set_resp_header(<<"access-control-allow-credentials">>, "true", ReqData3) 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(ReqData0, Module) -> MaxAge = application:get_env(rabbitmq_management, cors_max_age, 1800), Methods = case erlang:function_exported(Module, allowed_methods, 2) of false -> [<<"HEAD">>, <<"GET">>, <<"OPTIONS">>]; true -> element(1, Module:allowed_methods(undefined, undefined)) end, AllowMethods = string:join([binary_to_list(M) || M <- Methods], ", "), ReqHeaders = cowboy_req:header(<<"access-control-request-headers">>, ReqData0), ReqData1 = case MaxAge of undefined -> ReqData0; _ -> cowboy_req:set_resp_header(<<"access-control-max-age">>, integer_to_list(MaxAge), ReqData0) end, ReqData2 = case ReqHeaders of undefined -> ReqData1; _ -> cowboy_req:set_resp_header(<<"access-control-allow-headers">>, ReqHeaders, ReqData0) end, cowboy_req:set_resp_header(<<"access-control-allow-methods">>, AllowMethods, ReqData2). %% 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 cowboy_req:header(<<"origin">>, ReqData) of undefined -> false; <<"null">> -> false; Origin -> AllowedOrigins = application:get_env(rabbitmq_management, cors_allow_origins, []), case lists:member(binary_to_list(Origin), AllowedOrigins) of true -> Origin; false -> %% Maybe the configuration explicitly allows "*". case lists:member("*", AllowedOrigins) of true -> Origin; false -> false end end end.