Skip to content
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

Merged
merged 11 commits into from
Mar 22, 2021

Conversation

batman-ezio
Copy link
Contributor

@batman-ezio batman-ezio commented Mar 16, 2021

What this PR does / why we need it:

Fix #3763

Pre-submission checklist:

  • [ x] Did you explain what problem does this PR solve? Or what new features have been added?
  • [ x] Have you added corresponding test cases?
  • [ x] Have you modified the corresponding document?
  • Is this PR backward compatible? If it is not backward compatible, please discuss on the mailing list first

apisix/plugins/cors.lua Outdated Show resolved Hide resolved
apisix/plugins/cors.lua Outdated Show resolved Hide resolved
apisix/plugins/cors.lua Show resolved Hide resolved
apisix/plugins/cors.lua Outdated Show resolved Hide resolved
@tokers
Copy link
Contributor

tokers commented Mar 17, 2021

@batman-ezio Corresponding test cases are required to verify these changes.

@@ -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 |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"which origin is"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

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
Copy link
Member

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.

Copy link
Contributor Author

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

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")
Copy link
Member

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure


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
Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. thanks.

end

local function process_with_allow_origins_by_regex(conf, ctx)
local allow_origins_by_regex = conf.allow_origins_by_regex or {}
Copy link
Member

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.

Copy link
Contributor Author

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)
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test cases added

@@ -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
Copy link
Member

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.

Copy link
Contributor Author

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

Copy link
Member

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.

@batman-ezio batman-ezio requested a review from tokers March 19, 2021 07:47
@juzhiyuan
Copy link
Member

ping @tokers to review.

@spacewander spacewander merged commit bb95f7a into apache:master Mar 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: add "allow_origins_by_regex" to cors plugin
5 participants