-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2203 from Mashape/feat/cors-multiple-origins
feat(cors) allow for multiple origins
- Loading branch information
Showing
7 changed files
with
212 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,88 +1,141 @@ | ||
local BasePlugin = require "kong.plugins.base_plugin" | ||
local responses = require "kong.tools.responses" | ||
local responses = require "kong.tools.responses" | ||
|
||
|
||
local req_get_method = ngx.req.get_method | ||
local re_find = ngx.re.find | ||
local concat = table.concat | ||
local tostring = tostring | ||
local ipairs = ipairs | ||
|
||
|
||
local CorsHandler = BasePlugin:extend() | ||
|
||
|
||
CorsHandler.PRIORITY = 2000 | ||
|
||
local OPTIONS = "OPTIONS" | ||
|
||
local function configure_origin(ngx, conf) | ||
if conf.origin == nil then | ||
if not conf.origins then | ||
ngx.header["Access-Control-Allow-Origin"] = "*" | ||
else | ||
ngx.header["Access-Control-Allow-Origin"] = conf.origin | ||
ngx.header["Vary"] = "Origin" | ||
ngx.ctx.cors_allow_all = true | ||
return | ||
end | ||
|
||
if #conf.origins == 1 then | ||
if conf.origins[1] == "*" then | ||
ngx.ctx.cors_allow_all = true | ||
|
||
else | ||
ngx.header["Vary"] = "Origin" | ||
end | ||
|
||
ngx.header["Access-Control-Allow-Origin"] = conf.origins[1] | ||
return | ||
end | ||
|
||
local req_origin = ngx.var.http_origin | ||
if req_origin then | ||
for _, domain in ipairs(conf.origins) do | ||
local from, _, err = re_find(req_origin, | ||
[[\Q]] .. domain .. [[\E$]], | ||
"jo") | ||
if err then | ||
ngx.log(ngx.ERR, "[cors] could not search for domain: ", err) | ||
end | ||
|
||
if from then | ||
ngx.header["Access-Control-Allow-Origin"] = req_origin | ||
ngx.header["Vary"] = "Origin" | ||
return | ||
end | ||
end | ||
end | ||
end | ||
|
||
|
||
local function configure_credentials(ngx, conf) | ||
if conf.origin == nil or conf.origin == "*" then | ||
if ngx.ctx.cors_allow_all then | ||
ngx.header["Access-Control-Allow-Credentials"] = "false" | ||
|
||
elseif conf.credentials then | ||
ngx.header["Access-Control-Allow-Credentials"] = "true" | ||
end | ||
end | ||
|
||
local function configure_headers(ngx, conf, headers) | ||
if conf.headers == nil then | ||
ngx.header["Access-Control-Allow-Headers"] = headers["access-control-request-headers"] or "" | ||
|
||
local function configure_headers(ngx, conf) | ||
if not conf.headers then | ||
ngx.header["Access-Control-Allow-Headers"] = ngx.var["http_access_control_request_headers"] or "" | ||
|
||
else | ||
ngx.header["Access-Control-Allow-Headers"] = table.concat(conf.headers, ",") | ||
ngx.header["Access-Control-Allow-Headers"] = concat(conf.headers, ",") | ||
end | ||
end | ||
|
||
|
||
local function configure_exposed_headers(ngx, conf) | ||
if conf.exposed_headers ~= nil then | ||
ngx.header["Access-Control-Expose-Headers"] = table.concat(conf.exposed_headers, ",") | ||
if conf.exposed_headers then | ||
ngx.header["Access-Control-Expose-Headers"] = concat(conf.exposed_headers, ",") | ||
end | ||
end | ||
|
||
|
||
local function configure_methods(ngx, conf) | ||
if conf.methods == nil then | ||
if not conf.methods then | ||
ngx.header["Access-Control-Allow-Methods"] = "GET,HEAD,PUT,PATCH,POST,DELETE" | ||
|
||
else | ||
ngx.header["Access-Control-Allow-Methods"] = table.concat(conf.methods, ",") | ||
ngx.header["Access-Control-Allow-Methods"] = concat(conf.methods, ",") | ||
end | ||
end | ||
|
||
|
||
local function configure_max_age(ngx, conf) | ||
if conf.max_age ~= nil then | ||
if conf.max_age then | ||
ngx.header["Access-Control-Max-Age"] = tostring(conf.max_age) | ||
end | ||
end | ||
|
||
|
||
function CorsHandler:new() | ||
CorsHandler.super.new(self, "cors") | ||
end | ||
|
||
|
||
function CorsHandler:access(conf) | ||
CorsHandler.super.access(self) | ||
if ngx.req.get_method() == OPTIONS then | ||
CorsHandler.super.access(self) | ||
|
||
if req_get_method() == "OPTIONS" then | ||
if not conf.preflight_continue then | ||
configure_origin(ngx, conf) | ||
configure_credentials(ngx, conf) | ||
configure_headers(ngx, conf, ngx.req.get_headers()) | ||
configure_headers(ngx, conf) | ||
configure_methods(ngx, conf) | ||
configure_max_age(ngx, conf) | ||
ngx.ctx.skip_response_headers = true -- Don't add response headers because we already added them all | ||
return responses.send_HTTP_NO_CONTENT() | ||
else | ||
-- Don't add any response header because we are delegating the preflight to the upstream API (conf.preflight_continue=true) | ||
|
||
-- Don't add response headers because we already added them all | ||
ngx.ctx.skip_response_headers = true | ||
|
||
return responses.send_HTTP_NO_CONTENT() | ||
end | ||
|
||
-- Don't add any response header because we are delegating the preflight to | ||
-- the upstream API (conf.preflight_continue=true) | ||
ngx.ctx.skip_response_headers = true | ||
end | ||
end | ||
|
||
|
||
function CorsHandler:header_filter(conf) | ||
CorsHandler.super.header_filter(self) | ||
|
||
if not ngx.ctx.skip_response_headers then | ||
configure_origin(ngx, conf) | ||
configure_credentials(ngx, conf) | ||
configure_exposed_headers(ngx, conf) | ||
end | ||
end | ||
|
||
return CorsHandler | ||
|
||
return CorsHandler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
return { | ||
{ | ||
name = "2017-03-14_multiple_orgins", | ||
up = function(db, _, dao) | ||
local cjson = require "cjson" | ||
|
||
local rows, err = db:query([[ | ||
SELECT * FROM plugins WHERE name = 'cors' ALLOW FILTERING | ||
]]) | ||
if err then | ||
return err | ||
end | ||
|
||
for _, row in ipairs(rows) do | ||
local config = cjson.decode(row.config) | ||
|
||
config.origins = { config.origin } | ||
config.origin = nil | ||
|
||
local _, err = db:query(string.format([[ | ||
UPDATE plugins SET config = '%s' WHERE name = 'cors' AND id = %s | ||
]], cjson.encode(config), row.id)) | ||
if err then | ||
return err | ||
end | ||
end | ||
end, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
return { | ||
{ | ||
name = "2017-03-14_multiple_orgins", | ||
up = function(db) | ||
local cjson = require "cjson" | ||
|
||
local rows, err = db:query([[ | ||
SELECT * FROM plugins WHERE name = 'cors' | ||
]]) | ||
if err then | ||
return err | ||
end | ||
|
||
for _, row in ipairs(rows) do | ||
row.config.origins = { row.config.origin } | ||
row.config.origin = nil | ||
|
||
local _, err = db:query(string.format([[ | ||
UPDATE plugins SET config = '%s' WHERE id = '%s' | ||
]], cjson.encode(row.config), row.id)) | ||
if err then | ||
return err | ||
end | ||
end | ||
end, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,12 @@ | ||
return { | ||
no_consumer = true, | ||
fields = { | ||
origin = { type = "string" }, | ||
origins = { type = "array" }, | ||
headers = { type = "array" }, | ||
exposed_headers = { type = "array" }, | ||
methods = { type = "array", enum = { "HEAD", "GET", "POST", "PUT", "PATCH", "DELETE" } }, | ||
max_age = { type = "number" }, | ||
credentials = { type = "boolean", default = false }, | ||
preflight_continue = { type = "boolean", default = false } | ||
} | ||
} | ||
} |
Oops, something went wrong.