Comparison

plugins/mod_http.lua @ 12443:17d87fb2312a 0.12

mod_http: Reintroduce support for disabling or limiting CORS (fixes #1730) This is far better than pre-0.12, because we now have a universal way to configure and enable/disable CORS on a per-module basis.
author Matthew Wild <mwild1@gmail.com>
date Mon, 28 Mar 2022 14:40:21 +0100
parent 12269:a19d435dee90
child 12444:b33558969b3e
comparison
equal deleted inserted replaced
12441:dc6263625069 12443:17d87fb2312a
29 29
30 server.set_option("body_size_limit", module:get_option_number("http_max_content_size")); 30 server.set_option("body_size_limit", module:get_option_number("http_max_content_size"));
31 server.set_option("buffer_size_limit", module:get_option_number("http_max_buffer_size")); 31 server.set_option("buffer_size_limit", module:get_option_number("http_max_buffer_size"));
32 32
33 -- CORS settings 33 -- CORS settings
34 local cors_overrides = module:get_option("http_cors_override", {});
34 local opt_methods = module:get_option_set("access_control_allow_methods", { "GET", "OPTIONS" }); 35 local opt_methods = module:get_option_set("access_control_allow_methods", { "GET", "OPTIONS" });
35 local opt_headers = module:get_option_set("access_control_allow_headers", { "Content-Type" }); 36 local opt_headers = module:get_option_set("access_control_allow_headers", { "Content-Type" });
37 local opt_origins = module:get_option_set("access_control_allow_origins");
36 local opt_credentials = module:get_option_boolean("access_control_allow_credentials", false); 38 local opt_credentials = module:get_option_boolean("access_control_allow_credentials", false);
37 local opt_max_age = module:get_option_number("access_control_max_age", 2 * 60 * 60); 39 local opt_max_age = module:get_option_number("access_control_max_age", 2 * 60 * 60);
38 40
39 local function get_http_event(host, app_path, key) 41 local function get_http_event(host, app_path, key)
40 local method, path = key:match("^(%S+)%s+(.+)$"); 42 local method, path = key:match("^(%S+)%s+(.+)$");
107 module:log("warn", "No http ports enabled, can't generate an external URL"); 109 module:log("warn", "No http ports enabled, can't generate an external URL");
108 end 110 end
109 return "http://disabled.invalid/"; 111 return "http://disabled.invalid/";
110 end 112 end
111 113
112 local function apply_cors_headers(response, methods, headers, max_age, allow_credentials, origin) 114 local function apply_cors_headers(response, methods, headers, max_age, allow_credentials, allowed_origins, origin)
115 if allowed_origins and not allowed_origins[origin] then
116 return;
117 end
113 response.headers.access_control_allow_methods = tostring(methods); 118 response.headers.access_control_allow_methods = tostring(methods);
114 response.headers.access_control_allow_headers = tostring(headers); 119 response.headers.access_control_allow_headers = tostring(headers);
115 response.headers.access_control_max_age = tostring(max_age) 120 response.headers.access_control_max_age = tostring(max_age)
116 response.headers.access_control_allow_origin = origin or "*"; 121 response.headers.access_control_allow_origin = origin or "*";
117 if allow_credentials then 122 if allow_credentials then
139 local app_handlers = apps[app_name]; 144 local app_handlers = apps[app_name];
140 145
141 local app_methods = opt_methods; 146 local app_methods = opt_methods;
142 local app_headers = opt_headers; 147 local app_headers = opt_headers;
143 local app_credentials = opt_credentials; 148 local app_credentials = opt_credentials;
149 local app_origins;
150 if opt_origins and not (opt_origins:empty() or opt_origins:contains("*")) then
151 opt_origins = opt_origins._items;
152 end
144 153
145 local function cors_handler(event_data) 154 local function cors_handler(event_data)
146 local request, response = event_data.request, event_data.response; 155 local request, response = event_data.request, event_data.response;
147 apply_cors_headers(response, app_methods, app_headers, opt_max_age, app_credentials, request.headers.origin); 156 apply_cors_headers(response, app_methods, app_headers, opt_max_age, app_credentials, app_origins, request.headers.origin);
148 end 157 end
149 158
150 local function options_handler(event_data) 159 local function options_handler(event_data)
151 cors_handler(event_data); 160 cors_handler(event_data);
152 return ""; 161 return "";
153 end 162 end
154 163
155 if event.item.cors then 164 local cors = cors_overrides[app_name] or event.item.cors;
156 local cors = event.item.cors; 165 if cors then
157 if cors.credentials ~= nil then 166 if cors.enabled ~= false then
158 app_credentials = cors.credentials; 167 if cors.credentials ~= nil then
159 end 168 app_credentials = cors.credentials;
160 if cors.headers then 169 end
161 for header, enable in pairs(cors.headers) do 170 if cors.headers then
162 if enable and not app_headers:contains(header) then 171 for header, enable in pairs(cors.headers) do
163 app_headers = app_headers + set.new { header }; 172 if enable and not app_headers:contains(header) then
164 elseif not enable and app_headers:contains(header) then 173 app_headers = app_headers + set.new { header };
165 app_headers = app_headers - set.new { header }; 174 elseif not enable and app_headers:contains(header) then
175 app_headers = app_headers - set.new { header };
176 end
177 end
178 end
179 if cors.origins then
180 if cors.origins == "*" or cors.origins[1] == "*" then
181 app_origins = nil;
182 else
183 app_origins = set.new(cors.origins)._items;
166 end 184 end
167 end 185 end
168 end 186 end
169 end 187 end
170 188