-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add allow_origins_by_regex to cors plugin #3839
feat: add allow_origins_by_regex to cors plugin #3839
Conversation
@batman-ezio Corresponding test cases are required to verify these changes. |
docs/en/latest/plugins/cors.md
Outdated
@@ -43,6 +43,7 @@ title: cors | |||
| expose_headers | string | optional | "*" | | Which headers are allowed to set in response when access cross-origin resource. Multiple value use `,` to split. | | |||
| max_age | integer | optional | 5 | | Maximum number of seconds the results can be cached.. Within this time range, the browser will reuse the last check result. `-1` means no cache. Please note that the maximum value is depended on browser, please refer to [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#Directives) for details. | | |||
| allow_credential | boolean | optional | false | | Enable request include credential (such as Cookie etc.). According to CORS specification, if you set this option to `true`, you can not use '*' for other options. | | |||
| allow_origins_by_regex | array | optional | nil | | Use regex expressions to match which origins is allowed to enable CORS, for example, [".*\.test.com"] can use to match all subdomain of test.com | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"which origin is"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
apisix/plugins/cors.lua
Outdated
if allow_methods == "**" then | ||
allow_methods = "GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS,CONNECT,TRACE" | ||
end | ||
|
||
core.response.set_header("Access-Control-Allow-Origin", ctx.cors_allow_origins) | ||
if ctx.cors_allow_origins ~= "*" then | ||
if ctx.cors_allow_origins ~= "*" or next(allow_origins_by_regex) ~= nil then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the origin is matched by regex, it should not be *
as this is only available in allow_origins
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function set_cors_headers can call not only matched by regex,.
if it matched by allow_origins = '**'
then it will go here and needs to add Vary
Origin header
apisix/plugins/cors.lua
Outdated
function _M.header_filter(conf, ctx) | ||
local allow_origins = conf.allow_origins | ||
local function process_with_allow_origins(conf, ctx) | ||
local allow_origins = conf.allow_origins or {} | ||
local req_origin = core.request.header(ctx, "Origin") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we pass req_origin as an argument to avoid getting it repeatedly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
apisix/plugins/cors.lua
Outdated
|
||
local function process_with_allow_origins_by_regex(conf, ctx) | ||
local allow_origins_by_regex = conf.allow_origins_by_regex or {} | ||
if next(allow_origins_by_regex) == nil then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to check if the configuration is empty in the schema, like
apisix/apisix/plugins/ip-restriction.lua
Line 37 in c3e03bb
minItems = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. thanks.
apisix/plugins/cors.lua
Outdated
end | ||
|
||
local function process_with_allow_origins_by_regex(conf, ctx) | ||
local allow_origins_by_regex = conf.allow_origins_by_regex or {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need to create a temporary {}
if conf.allow_origins_by_regex is nil.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
t/plugin/cors.t
Outdated
|
||
|
||
|
||
=== TEST 30: set route (regex specified not match) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This configuration is a copy of TEST 28? We don't need it.
BTW, we need a test with two regexes configured so that we can test the regex concat.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test cases added
apisix/plugins/cors.lua
Outdated
@@ -133,7 +157,7 @@ local function set_cors_headers(conf, ctx) | |||
end | |||
|
|||
core.response.set_header("Access-Control-Allow-Origin", ctx.cors_allow_origins) | |||
if ctx.cors_allow_origins ~= "*" then | |||
if ctx.cors_allow_origins ~= "*" or conf.allow_origins_by_regex ~= nil then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't understand why we need or conf.allow_origins_by_regex ~= nil
.
If allow_origins_by_regex
is given but not matched, it can't go into this function.
If allow_origins_by_regex
is given but matched, the cors_allow_origins
can't be *
as *
is just a mark used in allow_origins
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if allow_origins_by_regex is matched, the cors_allow_origins will be the matched domain. not *
for example. it we use [".*.test.com"]
and the request is from a.test.com
then the cors_allow_origins will set to a.test.com
. not *
conf.allow_origins_by_regex ~= nil
means we use regex to match many domains.
the Vary must set as Origin
f a request may contain a Access-Control-Allow-Origin with different values, then the CDN should always respond with Vary: Origin,
check
https://stackoverflow.com/questions/25329405/why-isnt-vary-origin-response-set-on-a-cors-miss
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
if allow_origins_by_regex is matched, the cors_allow_origins will be the matched domain. not *
So ctx.cors_allow_origins ~= "*"
will be true.
Therefore there is no need to add an additional condition.
ping @tokers to review. |
What this PR does / why we need it:
Fix #3763
Pre-submission checklist: