This is an automated email from the ASF dual-hosted git repository.
monkeydluffy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new b40264f44 feat(cors): support for the Timing-Allow-Origin header
(#9365)
b40264f44 is described below
commit b40264f44e6d3d2d895e3ff981d251102e5d95a1
Author: skimdz86 <[email protected]>
AuthorDate: Tue Dec 5 18:05:33 2023 +0100
feat(cors): support for the Timing-Allow-Origin header (#9365)
---
apisix/plugins/cors.lua | 102 ++++++-
docs/en/latest/plugins/cors.md | 20 ++
t/plugin/cors4.t | 641 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 748 insertions(+), 15 deletions(-)
diff --git a/apisix/plugins/cors.lua b/apisix/plugins/cors.lua
index f4a59ce5e..94f54683e 100644
--- a/apisix/plugins/cors.lua
+++ b/apisix/plugins/cors.lua
@@ -25,6 +25,8 @@ local re_find = ngx.re.find
local ipairs = ipairs
local origins_pattern = [[^(\*|\*\*|null|\w+://[^,]+(,\w+://[^,]+)*)$]]
+local TYPE_ACCESS_CONTROL_ALLOW_ORIGIN = "ACAO"
+local TYPE_TIMING_ALLOW_ORIGIN = "TAO"
local lrucache = core.lrucache.new({
type = "plugin",
@@ -119,6 +121,28 @@ local schema = {
minItems = 1,
uniqueItems = true,
},
+ timing_allow_origins = {
+ description =
+ "you can use '*' to allow all origins which can view timing
information " ..
+ "when no credentials," ..
+ "'**' to allow forcefully (it will bring some security risks,
be careful)," ..
+ "multiple origin use ',' to split. default: nil",
+ type = "string",
+ pattern = origins_pattern
+ },
+ timing_allow_origins_by_regex = {
+ type = "array",
+ description =
+ "you can use regex to allow specific origins which can view
timing information," ..
+ "for example use [.*\\.test.com] to allow a.test.com and
b.test.com",
+ items = {
+ type = "string",
+ minLength = 1,
+ maxLength = 4096,
+ },
+ minItems = 1,
+ uniqueItems = true,
+ },
}
}
@@ -166,7 +190,8 @@ function _M.check_schema(conf, schema_type)
end
if conf.allow_credential then
if conf.allow_origins == "*" or conf.allow_methods == "*" or
- conf.allow_headers == "*" or conf.expose_headers == "*" then
+ conf.allow_headers == "*" or conf.expose_headers == "*" or
+ conf.timing_allow_origins == "*" then
return false, "you can not set '*' for other option when
'allow_credential' is true"
end
end
@@ -179,6 +204,15 @@ function _M.check_schema(conf, schema_type)
end
end
+ if conf.timing_allow_origins_by_regex then
+ for i, re_rule in ipairs(conf.timing_allow_origins_by_regex) do
+ local ok, err = re_compile(re_rule, "j")
+ if not ok then
+ return false, err
+ end
+ end
+ end
+
return true
end
@@ -204,7 +238,14 @@ local function set_cors_headers(conf, ctx)
end
end
-local function process_with_allow_origins(allow_origins, ctx, req_origin,
+local function set_timing_headers(conf, ctx)
+ if ctx.timing_allow_origin then
+ core.response.set_header("Timing-Allow-Origin",
ctx.timing_allow_origin)
+ end
+end
+
+
+local function process_with_allow_origins(allow_origin_type, allow_origins,
ctx, req_origin,
cache_key, cache_version)
if allow_origins == "**" then
allow_origins = req_origin or '*'
@@ -217,7 +258,7 @@ local function process_with_allow_origins(allow_origins,
ctx, req_origin,
)
else
multiple_origin, err = core.lrucache.plugin_ctx(
- lrucache, ctx, nil, create_multiple_origin_cache, allow_origins
+ lrucache, ctx, allow_origin_type,
create_multiple_origin_cache, allow_origins
)
end
@@ -236,18 +277,23 @@ local function process_with_allow_origins(allow_origins,
ctx, req_origin,
return allow_origins
end
-local function process_with_allow_origins_by_regex(conf, ctx, req_origin)
- if not conf.allow_origins_by_regex_rules_concat then
+local function process_with_allow_origins_by_regex(allow_origin_type,
+ allow_origins_by_regex,
conf, ctx, req_origin)
+
+ local allow_origins_by_regex_rules_concat_conf_key =
+ "allow_origins_by_regex_rules_concat_" .. allow_origin_type
+
+ if not conf[allow_origins_by_regex_rules_concat_conf_key] then
local allow_origins_by_regex_rules = {}
- for i, re_rule in ipairs(conf.allow_origins_by_regex) do
+ for i, re_rule in ipairs(allow_origins_by_regex) do
allow_origins_by_regex_rules[i] = re_rule
end
- conf.allow_origins_by_regex_rules_concat = core.table.concat(
+ conf[allow_origins_by_regex_rules_concat_conf_key] = core.table.concat(
allow_origins_by_regex_rules, "|")
end
- -- core.log.warn("regex: ", conf.allow_origins_by_regex_rules_concat, "\n
")
- local matched = re_find(req_origin,
conf.allow_origins_by_regex_rules_concat, "jo")
+ -- core.log.warn("regex: ",
conf[allow_origins_by_regex_rules_concat_conf_key], "\n ")
+ local matched = re_find(req_origin,
conf[allow_origins_by_regex_rules_concat_conf_key], "jo")
if matched then
return req_origin
end
@@ -258,7 +304,9 @@ local function match_origins(req_origin, allow_origins)
return req_origin == allow_origins or allow_origins == '*'
end
-local function
process_with_allow_origins_by_metadata(allow_origins_by_metadata, ctx,
req_origin)
+local function process_with_allow_origins_by_metadata(allow_origin_type,
allow_origins_by_metadata,
+ ctx, req_origin)
+
if allow_origins_by_metadata == nil then
return
end
@@ -268,8 +316,10 @@ local function
process_with_allow_origins_by_metadata(allow_origins_by_metadata,
local allow_origins_map = metadata.value.allow_origins
for _, key in ipairs(allow_origins_by_metadata) do
local allow_origins_conf = allow_origins_map[key]
- local allow_origins =
process_with_allow_origins(allow_origins_conf, ctx, req_origin,
- plugin_name .. "#" .. key, metadata.modifiedIndex)
+ local allow_origins = process_with_allow_origins(
+ allow_origin_type, allow_origins_conf, ctx, req_origin,
+ plugin_name .. "#" .. key, metadata.modifiedIndex
+ )
if match_origins(req_origin, allow_origins) then
return req_origin
end
@@ -292,13 +342,18 @@ function _M.header_filter(conf, ctx)
-- If allow_origins_by_regex is not nil, should be matched to it only
local allow_origins
if conf.allow_origins_by_regex == nil then
- allow_origins = process_with_allow_origins(conf.allow_origins, ctx,
req_origin)
+ allow_origins = process_with_allow_origins(
+ TYPE_ACCESS_CONTROL_ALLOW_ORIGIN, conf.allow_origins, ctx,
req_origin
+ )
else
- allow_origins = process_with_allow_origins_by_regex(conf, ctx,
req_origin)
+ allow_origins = process_with_allow_origins_by_regex(
+ TYPE_ACCESS_CONTROL_ALLOW_ORIGIN, conf.allow_origins_by_regex,
+ conf, ctx, req_origin
+ )
end
if not match_origins(req_origin, allow_origins) then
allow_origins = process_with_allow_origins_by_metadata(
- conf.allow_origins_by_metadata, ctx, req_origin
+ TYPE_ACCESS_CONTROL_ALLOW_ORIGIN, conf.allow_origins_by_metadata,
ctx, req_origin
)
end
if conf.allow_origins ~= "*" then
@@ -308,6 +363,23 @@ function _M.header_filter(conf, ctx)
ctx.cors_allow_origins = allow_origins
set_cors_headers(conf, ctx)
end
+
+ local timing_allow_origins
+ if conf.timing_allow_origins_by_regex == nil and conf.timing_allow_origins
then
+ timing_allow_origins = process_with_allow_origins(
+ TYPE_TIMING_ALLOW_ORIGIN, conf.timing_allow_origins, ctx,
req_origin
+ )
+ elseif conf.timing_allow_origins_by_regex then
+ timing_allow_origins = process_with_allow_origins_by_regex(
+ TYPE_TIMING_ALLOW_ORIGIN, conf.timing_allow_origins_by_regex,
+ conf, ctx, req_origin
+ )
+ end
+ if timing_allow_origins and match_origins(req_origin,
timing_allow_origins) then
+ ctx.timing_allow_origin = timing_allow_origins
+ set_timing_headers(conf, ctx)
+ end
+
end
return _M
diff --git a/docs/en/latest/plugins/cors.md b/docs/en/latest/plugins/cors.md
index dad827965..cf8d28064 100644
--- a/docs/en/latest/plugins/cors.md
+++ b/docs/en/latest/plugins/cors.md
@@ -32,6 +32,8 @@ The `cors` Plugins lets you enable
[CORS](https://developer.mozilla.org/en-US/do
## Attributes
+### CORS attributes
+
| Name | Type | Required | Default | Description
|
|---------------------------|---------|----------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| allow_origins | string | False | "*" | Origins to allow
CORS. Use the `scheme://host:port` format. For example,
`https://somedomain.com:8081`. If you have multiple origins, use a `,` to list
them. If `allow_credential` is set to `false`, you can enable CORS for all
origins by using `*`. If `allow_credential` is set to `true`, you can
forcefully allow CORS on all origins by using `**` but it will pose some
security issues. |
@@ -50,6 +52,24 @@ The `cors` Plugins lets you enable
[CORS](https://developer.mozilla.org/en-US/do
:::
+### Resource Timing attributes
+
+| Name | Type | Required | Default | Description
|
+|---------------------------|---------|----------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| timing_allow_origins | string | False | nil | Origin to
allow to access the resource timing information. See
[Timing-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin).
Use the `scheme://host:port` format. For example,
`https://somedomain.com:8081`. If you have multiple origins, use a `,` to list
them. |
+| timing_allow_origins_by_regex | array | False | nil | Regex to
match with origin for enabling access to the resource timing information. For
example, `[".*\.test.com"]` can match all subdomain of `test.com`. When set to
specified range, only domains in this range will be allowed, no matter what
`timing_allow_origins` is. |
+
+:::note
+
+The Timing-Allow-Origin header is defined in the Resource Timing API, but it
is related to the CORS concept.
+
+Suppose you have 2 domains, `domain-A.com` and `domain-B.com`.
+You are on a page on `domain-A.com`, you have an XHR call to a resource on
`domain-B.com` and you need its timing information.
+You can allow the browser to show this timing information only if you have
cross-origin permissions on `domain-B.com`.
+So, you have to set the CORS headers first, then access the `domain-B.com`
URL, and if you set
[Timing-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin),
the browser will show the requested timing information.
+
+:::
+
## Metadata
| Name | Type | Required | Description
|
diff --git a/t/plugin/cors4.t b/t/plugin/cors4.t
new file mode 100644
index 000000000..c1a9947ad
--- /dev/null
+++ b/t/plugin/cors4.t
@@ -0,0 +1,641 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+no_shuffle();
+log_level("info");
+
+add_block_preprocessor(sub {
+ my ($block) = @_;
+
+ if (!$block->request) {
+ $block->set_value("request", "GET /t");
+ }
+
+ if (!$block->no_error_log && !$block->error_log) {
+ $block->set_value("no_error_log", "[error]\n[alert]");
+ }
+});
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: validate timing_allow_origins
+--- config
+ location /t {
+ content_by_lua_block {
+ local plugin = require("apisix.plugins.cors")
+ local function validate(val)
+ local conf = {}
+ conf.timing_allow_origins = val
+ return plugin.check_schema(conf)
+ end
+
+ local good = {
+ "*",
+ "**",
+ "null",
+ "http://y.com.uk",
+ "https://x.com",
+ "https://x.com,http://y.com.uk",
+ "https://x.com,http://y.com.uk,http://c.tv",
+ "https://x.com,http://y.com.uk:12000,http://c.tv",
+ }
+ for _, g in ipairs(good) do
+ local ok, err = validate(g)
+ if not ok then
+ ngx.say("failed to validate ", g, ", ", err)
+ end
+ end
+
+ local bad = {
+ "",
+ "*a",
+ "*,http://y.com",
+ "nulll",
+ "http//y.com.uk",
+ "x.com",
+ "https://x.com,y.com.uk",
+ "https://x.com,*,https://y.com.uk",
+ "https://x.com,http://y.com.uk,http:c.tv",
+ }
+ for _, b in ipairs(bad) do
+ local ok, err = validate(b)
+ if ok then
+ ngx.say("failed to reject ", b)
+ end
+ end
+
+ ngx.say("done")
+ }
+ }
+--- response_body
+done
+
+
+
+=== TEST 2: set route ( allow_origins default, timing_allow_origins specified )
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "cors": {
+ "allow_origins": "*",
+ "allow_methods": "GET,POST",
+ "allow_headers": "request-h",
+ "expose_headers": "expose-h",
+ "max_age": 10,
+ "timing_allow_origins": "http://sub.domain.com"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 3: origin matching
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://sub.domain.com
+--- response_headers
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin: http://sub.domain.com
+
+
+
+=== TEST 4: origin not matching timing_allow_origins
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://other.domain.com
+--- response_headers
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin:
+
+
+
+=== TEST 5: set route ( allow_origins same as timing_allow_origins )
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "cors": {
+ "allow_origins": "http://sub.domain.com",
+ "allow_methods": "GET,POST",
+ "allow_headers": "request-h",
+ "expose_headers": "expose-h",
+ "max_age": 10,
+ "timing_allow_origins": "http://sub.domain.com"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 6: origin matching
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://sub.domain.com
+--- response_headers
+Access-Control-Allow-Origin: http://sub.domain.com
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin: http://sub.domain.com
+
+
+
+=== TEST 7: origin not matching
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://other.domain.com
+--- response_headers
+Access-Control-Allow-Origin:
+Access-Control-Allow-Methods:
+Access-Control-Allow-Headers:
+Access-Control-Expose-Headers:
+Access-Control-Max-Age:
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin:
+
+
+
+=== TEST 8: set route ( allow_origins differs from timing_allow_origins )
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "cors": {
+ "allow_origins": "http://one.domain.com",
+ "allow_methods": "GET,POST",
+ "allow_headers": "request-h",
+ "expose_headers": "expose-h",
+ "max_age": 10,
+ "timing_allow_origins": "http://another.domain.com"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 9: origin matching allow_origins
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://one.domain.com
+--- response_headers
+Access-Control-Allow-Origin: http://one.domain.com
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin:
+
+
+
+=== TEST 10: origin matching timing_allow_origins
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://another.domain.com
+--- response_headers
+Access-Control-Allow-Origin:
+Access-Control-Allow-Methods:
+Access-Control-Allow-Headers:
+Access-Control-Expose-Headers:
+Access-Control-Max-Age:
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin: http://another.domain.com
+
+
+
+=== TEST 11: origin not matching
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://notexistent.domain.com
+--- response_headers
+Access-Control-Allow-Origin:
+Access-Control-Allow-Methods:
+Access-Control-Allow-Headers:
+Access-Control-Expose-Headers:
+Access-Control-Max-Age:
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin:
+
+
+
+=== TEST 12: set route ( allow_origins superset of timing_allow_origins )
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "cors": {
+ "allow_origins":
"http://one.domain.com,http://two.domain.com",
+ "allow_methods": "GET,POST",
+ "allow_headers": "request-h",
+ "expose_headers": "expose-h",
+ "max_age": 10,
+ "timing_allow_origins": "http://one.domain.com"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 13: origin matching allow_origins and timing_allow_origins
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://one.domain.com
+--- response_headers
+Access-Control-Allow-Origin: http://one.domain.com
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin: http://one.domain.com
+
+
+
+=== TEST 14: origin matching only allow_origins
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://two.domain.com
+--- response_headers
+Access-Control-Allow-Origin: http://two.domain.com
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin:
+
+
+
+=== TEST 15: origin not matching
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://notexistent.domain.com
+--- response_headers
+Access-Control-Allow-Origin:
+Access-Control-Allow-Methods:
+Access-Control-Allow-Headers:
+Access-Control-Expose-Headers:
+Access-Control-Max-Age:
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin:
+
+
+
+=== TEST 16: set route ( allow_origins and timing_allow_origins are two
different sets with intersection )
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "cors": {
+ "allow_origins":
"http://one.domain.com,http://two.domain.com",
+ "allow_methods": "GET,POST",
+ "allow_headers": "request-h",
+ "expose_headers": "expose-h",
+ "max_age": 10,
+ "timing_allow_origins":
"http://one.domain.com,http://three.domain.com"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 17: origin matching allow_origins and timing_allow_origins
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://one.domain.com
+--- response_headers
+Access-Control-Allow-Origin: http://one.domain.com
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin: http://one.domain.com
+
+
+
+=== TEST 18: origin matching only allow_origins
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://two.domain.com
+--- response_headers
+Access-Control-Allow-Origin: http://two.domain.com
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin:
+
+
+
+=== TEST 19: origin matching only timing_allow_origins
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://three.domain.com
+--- response_headers
+Access-Control-Allow-Origin:
+Access-Control-Allow-Methods:
+Access-Control-Allow-Headers:
+Access-Control-Expose-Headers:
+Access-Control-Max-Age:
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin: http://three.domain.com
+
+
+
+=== TEST 20: origin not matching
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://notexistent.domain.com
+--- response_headers
+Access-Control-Allow-Origin:
+Access-Control-Allow-Methods:
+Access-Control-Allow-Headers:
+Access-Control-Expose-Headers:
+Access-Control-Max-Age:
+Access-Control-Allow-Credentials:
+Timing-Allow-Origin:
+
+
+
+=== TEST 21: set route ( allow_origins and timing_allow_origins specified with
regex )
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "cors": {
+ "allow_origins_by_regex":
["http://.*?\\.domain\\.com"],
+ "allow_methods": "GET,POST",
+ "allow_headers": "request-h",
+ "expose_headers": "expose-h",
+ "max_age": 10,
+ "timing_allow_origins_by_regex":
["http://.*?\\.domain\\.com"]
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 22: regex specified match
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://sub.domain.com
+--- response_headers
+Access-Control-Allow-Origin: http://sub.domain.com
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Timing-Allow-Origin: http://sub.domain.com
+
+
+
+=== TEST 23: regex no match
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://other.newdomain.com
+--- response_headers
+Access-Control-Allow-Origin:
+Access-Control-Allow-Methods:
+Access-Control-Allow-Headers:
+Access-Control-Expose-Headers:
+Access-Control-Max-Age:
+Timing-Allow-Origin:
+
+
+
+=== TEST 24: set route ( allow_origins and timing_allow_origins specified with
different regex )
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "cors": {
+ "allow_origins_by_regex":
["http://.*?\\.domain\\.com"],
+ "allow_methods": "GET,POST",
+ "allow_headers": "request-h",
+ "expose_headers": "expose-h",
+ "max_age": 10,
+ "timing_allow_origins_by_regex":
["http://test.*?\\.domain\\.com"],
+ "timing_allow_origins":
"http://nonexistent.newdomain.com"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 25: regex specified match, test priority of regex over list of origins
+--- request
+GET /hello HTTP/1.1
+--- more_headers
+Origin: http://testurl.domain.com
+--- response_headers
+Access-Control-Allow-Origin: http://testurl.domain.com
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Allow-Headers: request-h
+Access-Control-Expose-Headers: expose-h
+Access-Control-Max-Age: 10
+Timing-Allow-Origin: http://testurl.domain.com