From 9ba9c888b71b6385a553d23b36b9272fdf3bc4b8 Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Mon, 23 Mar 2020 09:57:02 +0800 Subject: [PATCH 01/13] feat: add cors plugin --- conf/config.yaml | 1 + lua/apisix/plugins/cors.lua | 132 +++++++++++ t/plugin/cors.t | 424 ++++++++++++++++++++++++++++++++++++ 3 files changed, 557 insertions(+) create mode 100644 lua/apisix/plugins/cors.lua create mode 100644 t/plugin/cors.t diff --git a/conf/config.yaml b/conf/config.yaml index 65f79da91151..2d3d852efef5 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -143,6 +143,7 @@ plugins: # plugin list - proxy-cache - tcp-logger - proxy-mirror + - cors stream_plugins: - mqtt-proxy diff --git a/lua/apisix/plugins/cors.lua b/lua/apisix/plugins/cors.lua new file mode 100644 index 000000000000..2b7ee3b47125 --- /dev/null +++ b/lua/apisix/plugins/cors.lua @@ -0,0 +1,132 @@ +-- +-- 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. +-- +local core = require("apisix.core") +local ngx = ngx +local plugin_name = "cors" + + +local schema = { + type = "object", + properties = { + allow_origins = { + description = "you can use '*' to allow all origins when no credentials and '**' to allow forcefully(it will bring some security risks, be carefully), multiple method use ',' to split. default: *.", + type = "string" + }, + allow_methods = { + description = "you can use '*' to allow all method when no credentials and '**' to allow forcefully(it will bring some security risks, be carefully), multiple method use ',' to split. default: *.", + type = "string" + }, + allow_headers = { + description = "you can use '*' to allow all header when no credentials, multiple header use ',' to split. default: *.", + type = "string" + }, + expose_headers = { + description = "you can use '*' to expose all header when no credentials, multiple header use ',' to split. default: *.", + type = "string" + }, + max_age = { + description = "maximum number of seconds the results can be cached.-1 mean no cached, max value is depend on browser, more detail plz check MDN. default: 5.", + type = "integer" + }, + allow_credential = { + type = "boolean" + }, + } +} + + +local _M = { + version = 1.0, + -- we should set cors plugin at first to handle preflight request + priority = 20000, + type = 'auth', + name = plugin_name, + schema = schema, +} + + +function _M.check_schema(conf) + local ok, err = core.schema.check(schema, conf) + if not ok then + return false, err + end + + if not conf.allow_origins then + conf.allow_origins = "*" + end + + if not conf.allow_methods then + conf.allow_methods = "*" + end + + if not conf.allow_headers then + conf.allow_headers = "*" + end + + + if not conf.expose_headers then + conf.expose_headers = "*" + end + + if not conf.max_age then + conf.max_age = 5 + end + + if not conf.allow_credential then + conf.allow_credential = false + end + + return true +end + +function _M.header_filter(conf, ctx) + if conf.allow_origins == "**" then + conf.allow_origins = ngx.var.http_origin or '*' + end + if string.find(conf.allow_origins, ",") then + local finded = false + for origin in string.gmatch(conf.allow_origins, "([^,]+)") do + if origin == ngx.var.http_origin then + conf.allow_origins = origin + finded = true + break + end + end + if not finded then + return + end + end + + if conf.allow_methods == "**" then + conf.allow_methods = "GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS,CONNECT,TRACE" + end + + ngx.header["Access-Control-Allow-Origin"] = conf.allow_origins + ngx.header["Access-Control-Allow-Methods"] = conf.allow_methods + ngx.header["Access-Control-Allow-Headers"] = conf.allow_headers + ngx.header["Access-Control-Expose-Headers"] = conf.expose_headers + ngx.header["Access-Control-Max-Age"] = conf.max_age + if conf.allow_credential then + ngx.header["Access-Control-Allow-Credentials"] = true + end + + if ctx.var.request_method == "OPTIONS" then + return 200 + end +end + +return _M diff --git a/t/plugin/cors.t b/t/plugin/cors.t new file mode 100644 index 000000000000..a21bbcf9a2a0 --- /dev/null +++ b/t/plugin/cors.t @@ -0,0 +1,424 @@ +# +# 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. +# +BEGIN { + if ($ENV{TEST_NGINX_CHECK_LEAK}) { + $SkipReason = "unavailable for the hup tests"; + + } else { + $ENV{TEST_NGINX_USE_HUP} = 1; + undef $ENV{TEST_NGINX_USE_STAP}; + } +} + +use t::APISIX 'no_plan'; + +repeat_each(1); +no_long_string(); +no_shuffle(); +no_root_location(); +run_tests; + +__DATA__ + +=== TEST 1: sanity +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.cors") + local ok, err = plugin.check_schema({ + allow_origins = '', + allow_methods = '', + allow_headers = '', + expose_headers = '', + max_age = 600, + allow_credential = true + }) + if not ok then + ngx.say(err) + end + + ngx.say("done") + } + } +--- request +GET /t +--- response_body +done +--- no_error_log +[error] + + + +=== TEST 2: wrong value of key +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.cors") + local ok, err = plugin.check_schema({ + allow_origins = '', + allow_methods = '', + allow_headers = '', + expose_headers = '', + max_age = '600', + allow_credential = true + }) + if not ok then + ngx.say(err) + end + + ngx.say("done") + + } + } +--- request +GET /t +--- response_body +property "max_age" validation failed: wrong type: expected integer, got string +done +--- no_error_log +[error] + + + +=== TEST 3: add plugin +--- 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": { + } + }, + "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 +--- no_error_log +[error] + + + +=== TEST 4: update plugin +--- 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": "**", + "allow_headers": "*", + "expose_headers": "*", + "madx_age": 5, + "allow_credential": true + } + }, + "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 +--- no_error_log +[error] + + + +=== TEST 5: disable plugin +--- 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": { + }, + "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 +--- no_error_log +[error] + + + +=== TEST 6: set route(default) +--- 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, + [[{ + "methods": ["GET"], + "plugins": { + "cors": { + } + }, + "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 +--- no_error_log +[error] + + + +=== TEST 7: cors default +--- request +GET /hello HTTP/1.1 +--- response_body +hello world +--- response_headers +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: * +Access-Control-Allow-Headers: * +Access-Control-Expose-Headers: * +Access-Control-Max-Age: 5 +Access-Control-Allow-Credentials: +--- no_error_log +[error] + +=== TEST 8: set route(spcific) +--- 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,http://sub2.domain.com", + "allow_methods": "GET,POST", + "allow_headers": "headr1,headr2", + "expose_headers": "ex-headr1,ex-headr2", + "max_age": 50, + "allow_credential": true + } + }, + "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 +--- no_error_log +[error] + +=== TEST 9: cors spcific +--- request +GET /hello HTTP/1.1 +--- more_headers +Origin: http://sub2.domain.com +--- response_body +hello world +--- response_headers +Access-Control-Allow-Origin: http://sub2.domain.com +Access-Control-Allow-Methods: GET,POST +Access-Control-Allow-Headers: headr1,headr2 +Access-Control-Expose-Headers: ex-headr1,ex-headr2 +Access-Control-Max-Age: 50 +Access-Control-Allow-Credentials: true +--- no_error_log +[error] + +=== TEST 10: cors spcific no match orgin +--- request +GET /hello HTTP/1.1 +--- more_headers +Origin: http://sub3.domain.com +--- response_body +hello world +--- 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: +--- no_error_log +[error] + +=== TEST 11: set route(force wildcard) +--- 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": "**", + "allow_headers": "*", + "expose_headers": "*" + } + }, + "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 +--- no_error_log +[error] + +=== TEST 12: cors force wildcard +--- request +GET /hello HTTP/1.1 +--- more_headers +Origin: https://sub.domain.com +ExternalHeader1: val +ExternalHeader2: val +ExternalHeader3: val +--- response_body +hello world +--- response_headers +Access-Control-Allow-Origin: https://sub.domain.com +Access-Control-Allow-Methods: GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS,CONNECT,TRACE +Access-Control-Allow-Headers: * +Access-Control-Expose-Headers: * +Access-Control-Max-Age: 5 +Access-Control-Allow-Credentials: +--- no_error_log +[error] + +=== TEST 13: cors force wildcard no origin +--- request +GET /hello HTTP/1.1 +--- more_headers +ExternalHeader1: val +ExternalHeader2: val +ExternalHeader3: val +--- response_body +hello world +--- response_headers +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS,CONNECT,TRACE +Access-Control-Allow-Headers: * +Access-Control-Expose-Headers: * +Access-Control-Max-Age: 5 +Access-Control-Allow-Credentials: +--- no_error_log +[error] + +=== TEST 14: options return directly +--- request +OPTIONS /hello HTTP/1.1 +--- response_body + +--- no_error_log +[error] From d369b9cbc90d54a526951a95b1f15561ec38e6a9 Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Mon, 23 Mar 2020 10:01:34 +0800 Subject: [PATCH 02/13] fix: remove unnecessary code --- t/plugin/cors.t | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/t/plugin/cors.t b/t/plugin/cors.t index a21bbcf9a2a0..a2473741c9a6 100644 --- a/t/plugin/cors.t +++ b/t/plugin/cors.t @@ -14,16 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -BEGIN { - if ($ENV{TEST_NGINX_CHECK_LEAK}) { - $SkipReason = "unavailable for the hup tests"; - - } else { - $ENV{TEST_NGINX_USE_HUP} = 1; - undef $ENV{TEST_NGINX_USE_STAP}; - } -} - use t::APISIX 'no_plan'; repeat_each(1); From f6aa92f329468c106e3cd1cdd4062b744fdbf6af Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Mon, 23 Mar 2020 13:18:40 +0800 Subject: [PATCH 03/13] fix: lint error and admin api unit test --- lua/apisix/plugins/cors.lua | 11 ++++++----- t/admin/plugins.t | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lua/apisix/plugins/cors.lua b/lua/apisix/plugins/cors.lua index 2b7ee3b47125..fb270bdf0b3a 100644 --- a/lua/apisix/plugins/cors.lua +++ b/lua/apisix/plugins/cors.lua @@ -14,10 +14,11 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- -local core = require("apisix.core") -local ngx = ngx +local core = require("apisix.core") +local ngx = ngx local plugin_name = "cors" - +local str_find = string.find +local str_gmatch = string.gmatch local schema = { type = "object", @@ -97,9 +98,9 @@ function _M.header_filter(conf, ctx) if conf.allow_origins == "**" then conf.allow_origins = ngx.var.http_origin or '*' end - if string.find(conf.allow_origins, ",") then + if str_find(conf.allow_origins, ",") then local finded = false - for origin in string.gmatch(conf.allow_origins, "([^,]+)") do + for origin in str_gmatch(conf.allow_origins, "([^,]+)") do if origin == ngx.var.http_origin then conf.allow_origins = origin finded = true diff --git a/t/admin/plugins.t b/t/admin/plugins.t index b8771c711328..86447940253c 100644 --- a/t/admin/plugins.t +++ b/t/admin/plugins.t @@ -30,7 +30,7 @@ __DATA__ --- request GET /apisix/admin/plugins/list --- response_body_like eval -qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite","fault-injection","udp-logger","wolf-rbac","proxy-cache","tcp-logger","proxy-mirror"\]/ +qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite","fault-injection","udp-logger","wolf-rbac","proxy-cache","tcp-logger","proxy-mirror","cors"\]/ --- no_error_log [error] From 3450b65a5e2b86d56435cf6d5b1793a935752ba0 Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Mon, 23 Mar 2020 14:17:46 +0800 Subject: [PATCH 04/13] fix: lint error when line lengeth exceeding 100 --- lua/apisix/plugins/cors.lua | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lua/apisix/plugins/cors.lua b/lua/apisix/plugins/cors.lua index fb270bdf0b3a..0399ec69aa52 100644 --- a/lua/apisix/plugins/cors.lua +++ b/lua/apisix/plugins/cors.lua @@ -24,23 +24,31 @@ local schema = { type = "object", properties = { allow_origins = { - description = "you can use '*' to allow all origins when no credentials and '**' to allow forcefully(it will bring some security risks, be carefully), multiple method use ',' to split. default: *.", + description = "you can use '*' to allow all origins when no credentials and '**', ".. + "to allow forcefully(it will bring some security risks, be carefully), ".. + "multiple origin use ',' to split. default: *.", type = "string" }, allow_methods = { - description = "you can use '*' to allow all method when no credentials and '**' to allow forcefully(it will bring some security risks, be carefully), multiple method use ',' to split. default: *.", + description = "you can use '*' to allow all methods when no credentials and '**', ".. + "to allow forcefully(it will bring some security risks, be carefully), ".. + "multiple method use ',' to split. default: *.", type = "string" }, allow_headers = { - description = "you can use '*' to allow all header when no credentials, multiple header use ',' to split. default: *.", + description = "you can use '*' to allow all header when no credentials, ".. + "multiple header use ',' to split. default: *.", type = "string" }, expose_headers = { - description = "you can use '*' to expose all header when no credentials, multiple header use ',' to split. default: *.", + description = "you can use '*' to expose all header when no credentials, ".. + "multiple header use ',' to split. default: *.", type = "string" }, max_age = { - description = "maximum number of seconds the results can be cached.-1 mean no cached, max value is depend on browser, more detail plz check MDN. default: 5.", + description = "maximum number of seconds the results can be cached.".. + "-1 mean no cached,the max value is depend on browser,".. + "more detail plz check MDN. default: 5.", type = "integer" }, allow_credential = { From 3fa711857f832991af86613518671086b54e83e7 Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Mon, 23 Mar 2020 14:36:11 +0800 Subject: [PATCH 05/13] fix: lint error --- lua/apisix/plugins/cors.lua | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lua/apisix/plugins/cors.lua b/lua/apisix/plugins/cors.lua index 0399ec69aa52..b38d9ee67243 100644 --- a/lua/apisix/plugins/cors.lua +++ b/lua/apisix/plugins/cors.lua @@ -57,7 +57,6 @@ local schema = { } } - local _M = { version = 1.0, -- we should set cors plugin at first to handle preflight request @@ -67,7 +66,6 @@ local _M = { schema = schema, } - function _M.check_schema(conf) local ok, err = core.schema.check(schema, conf) if not ok then @@ -86,7 +84,6 @@ function _M.check_schema(conf) conf.allow_headers = "*" end - if not conf.expose_headers then conf.expose_headers = "*" end @@ -97,7 +94,7 @@ function _M.check_schema(conf) if not conf.allow_credential then conf.allow_credential = false - end + end return true end @@ -123,7 +120,7 @@ function _M.header_filter(conf, ctx) if conf.allow_methods == "**" then conf.allow_methods = "GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS,CONNECT,TRACE" end - + ngx.header["Access-Control-Allow-Origin"] = conf.allow_origins ngx.header["Access-Control-Allow-Methods"] = conf.allow_methods ngx.header["Access-Control-Allow-Headers"] = conf.allow_headers From 0f1051abe59c02b71dc7468ba8a2896536feb199 Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Mon, 23 Mar 2020 15:15:50 +0800 Subject: [PATCH 06/13] fix: change cors priority and debug unit test --- lua/apisix/plugins/cors.lua | 5 ++--- t/debug/debug-mode.t | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/apisix/plugins/cors.lua b/lua/apisix/plugins/cors.lua index b38d9ee67243..91a749f82166 100644 --- a/lua/apisix/plugins/cors.lua +++ b/lua/apisix/plugins/cors.lua @@ -58,9 +58,8 @@ local schema = { } local _M = { - version = 1.0, - -- we should set cors plugin at first to handle preflight request - priority = 20000, + version = 0.1, + priority = 4000, type = 'auth', name = plugin_name, schema = schema, diff --git a/t/debug/debug-mode.t b/t/debug/debug-mode.t index d5a6c1d1035a..5627a19fcd74 100644 --- a/t/debug/debug-mode.t +++ b/t/debug/debug-mode.t @@ -57,6 +57,7 @@ qr/loaded plugin and sort by priority: [-\d]+ name: [\w-]+/ --- grep_error_log_out loaded plugin and sort by priority: 11000 name: fault-injection loaded plugin and sort by priority: 10000 name: serverless-pre-function +loaded plugin and sort by priority: 4000 name: cors loaded plugin and sort by priority: 3000 name: ip-restriction loaded plugin and sort by priority: 2599 name: openid-connect loaded plugin and sort by priority: 2555 name: wolf-rbac From 3da47379934084585a4d258b3e71bc981b0c74f4 Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Mon, 23 Mar 2020 15:59:53 +0800 Subject: [PATCH 07/13] fix: optimze description --- lua/apisix/plugins/cors.lua | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/lua/apisix/plugins/cors.lua b/lua/apisix/plugins/cors.lua index 91a749f82166..fd9fa0738911 100644 --- a/lua/apisix/plugins/cors.lua +++ b/lua/apisix/plugins/cors.lua @@ -24,31 +24,36 @@ local schema = { type = "object", properties = { allow_origins = { - description = "you can use '*' to allow all origins when no credentials and '**', ".. - "to allow forcefully(it will bring some security risks, be carefully), ".. - "multiple origin use ',' to split. default: *.", + description = + "you can use '*' to allow all origins when no credentials,".. + "'**' to allow forcefully(it will bring some security risks, be carefully),".. + "multiple origin use ',' to split. default: *.", type = "string" }, allow_methods = { - description = "you can use '*' to allow all methods when no credentials and '**', ".. - "to allow forcefully(it will bring some security risks, be carefully), ".. - "multiple method use ',' to split. default: *.", + description = + "you can use '*' to allow all methods when no credentials and '**',".. + "'**' to allow forcefully(it will bring some security risks, be carefully),".. + "multiple method use ',' to split. default: *.", type = "string" }, allow_headers = { - description = "you can use '*' to allow all header when no credentials, ".. - "multiple header use ',' to split. default: *.", + description = + "you can use '*' to allow all header when no credentials,".. + "multiple header use ',' to split. default: *.", type = "string" }, expose_headers = { - description = "you can use '*' to expose all header when no credentials, ".. - "multiple header use ',' to split. default: *.", + description = + "you can use '*' to expose all header when no credentials,".. + "multiple header use ',' to split. default: *.", type = "string" }, max_age = { - description = "maximum number of seconds the results can be cached.".. - "-1 mean no cached,the max value is depend on browser,".. - "more detail plz check MDN. default: 5.", + description = + "maximum number of seconds the results can be cached.".. + "-1 mean no cached,the max value is depend on browser,".. + "more detail plz check MDN. default: 5.", type = "integer" }, allow_credential = { From eba991f15264c8b1e8513645d14677f73474adcb Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Sat, 28 Mar 2020 11:36:05 +0800 Subject: [PATCH 08/13] refator: fix reviews --- lua/apisix/plugins/cors.lua | 80 +++++++++++++++++-------------------- t/plugin/cors.t | 14 +++++++ 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/lua/apisix/plugins/cors.lua b/lua/apisix/plugins/cors.lua index fd9fa0738911..208fa71aa1c2 100644 --- a/lua/apisix/plugins/cors.lua +++ b/lua/apisix/plugins/cors.lua @@ -18,46 +18,52 @@ local core = require("apisix.core") local ngx = ngx local plugin_name = "cors" local str_find = string.find -local str_gmatch = string.gmatch +local re_gmatch = ngx.re.gmatch local schema = { type = "object", properties = { allow_origins = { description = - "you can use '*' to allow all origins when no credentials,".. - "'**' to allow forcefully(it will bring some security risks, be carefully),".. + "you can use '*' to allow all origins when no credentials," .. + "'**' to allow forcefully(it will bring some security risks, be carefully)," .. "multiple origin use ',' to split. default: *.", - type = "string" + type = "string", + default = "*" }, allow_methods = { description = - "you can use '*' to allow all methods when no credentials and '**',".. - "'**' to allow forcefully(it will bring some security risks, be carefully),".. + "you can use '*' to allow all methods when no credentials and '**'," .. + "'**' to allow forcefully(it will bring some security risks, be carefully)," .. "multiple method use ',' to split. default: *.", - type = "string" + type = "string", + default = "*" }, allow_headers = { description = - "you can use '*' to allow all header when no credentials,".. + "you can use '*' to allow all header when no credentials," .. "multiple header use ',' to split. default: *.", - type = "string" + type = "string", + default = "*" }, expose_headers = { description = - "you can use '*' to expose all header when no credentials,".. + "you can use '*' to expose all header when no credentials," .. "multiple header use ',' to split. default: *.", - type = "string" + type = "string", + default = "*" }, max_age = { description = - "maximum number of seconds the results can be cached.".. - "-1 mean no cached,the max value is depend on browser,".. + "maximum number of seconds the results can be cached." .. + "-1 mean no cached,the max value is depend on browser," .. "more detail plz check MDN. default: 5.", - type = "integer" + type = "integer", + default = 5 }, allow_credential = { - type = "boolean" + type = "boolean", + default = false }, } } @@ -76,30 +82,6 @@ function _M.check_schema(conf) return false, err end - if not conf.allow_origins then - conf.allow_origins = "*" - end - - if not conf.allow_methods then - conf.allow_methods = "*" - end - - if not conf.allow_headers then - conf.allow_headers = "*" - end - - if not conf.expose_headers then - conf.expose_headers = "*" - end - - if not conf.max_age then - conf.max_age = 5 - end - - if not conf.allow_credential then - conf.allow_credential = false - end - return true end @@ -107,11 +89,23 @@ function _M.header_filter(conf, ctx) if conf.allow_origins == "**" then conf.allow_origins = ngx.var.http_origin or '*' end - if str_find(conf.allow_origins, ",") then + if str_find(conf.allow_origins, ",", 1, true) then local finded = false - for origin in str_gmatch(conf.allow_origins, "([^,]+)") do - if origin == ngx.var.http_origin then - conf.allow_origins = origin + local iterator, err = re_gmatch(conf.allow_origins, "([^,]+)", "jiox") + if not iterator then + return 500, {message = "match origins failed", error = err} + end + while true do + local origin, err = iterator() + if err then + return 500, {message = "iterate origins failed", error = err} + end + if not origin then + break + end + + if origin[0] == ngx.var.http_origin then + conf.allow_origins = origin[0] finded = true break end diff --git a/t/plugin/cors.t b/t/plugin/cors.t index a2473741c9a6..eed58fb136e1 100644 --- a/t/plugin/cors.t +++ b/t/plugin/cors.t @@ -252,6 +252,8 @@ Access-Control-Allow-Credentials: --- no_error_log [error] + + === TEST 8: set route(spcific) --- config location /t { @@ -293,6 +295,8 @@ passed --- no_error_log [error] + + === TEST 9: cors spcific --- request GET /hello HTTP/1.1 @@ -310,6 +314,8 @@ Access-Control-Allow-Credentials: true --- no_error_log [error] + + === TEST 10: cors spcific no match orgin --- request GET /hello HTTP/1.1 @@ -327,6 +333,8 @@ Access-Control-Allow-Credentials: --- no_error_log [error] + + === TEST 11: set route(force wildcard) --- config location /t { @@ -366,6 +374,8 @@ passed --- no_error_log [error] + + === TEST 12: cors force wildcard --- request GET /hello HTTP/1.1 @@ -386,6 +396,8 @@ Access-Control-Allow-Credentials: --- no_error_log [error] + + === TEST 13: cors force wildcard no origin --- request GET /hello HTTP/1.1 @@ -405,6 +417,8 @@ Access-Control-Allow-Credentials: --- no_error_log [error] + + === TEST 14: options return directly --- request OPTIONS /hello HTTP/1.1 From 954bb1c37cb70a2804f34af51a90430e8bcbc656 Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Sat, 28 Mar 2020 16:54:18 +0800 Subject: [PATCH 09/13] feat: append docs --- doc/plugins/cors-cn.md | 92 ++++++++++++++++++++++++++++++++++++++++++ doc/plugins/cors.md | 91 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 doc/plugins/cors-cn.md create mode 100644 doc/plugins/cors.md diff --git a/doc/plugins/cors-cn.md b/doc/plugins/cors-cn.md new file mode 100644 index 000000000000..7d70a22a7e39 --- /dev/null +++ b/doc/plugins/cors-cn.md @@ -0,0 +1,92 @@ + + +# [English](cors.md) + +# 目录 + +- [**简介**](#简介) +- [**属性**](#属性) +- [**如何启用**](#如何启用) +- [**测试插件**](#测试插件) +- [**禁用插件**](#禁用插件) + +## 简介 + +`cors` 插件可以让你轻易地为服务端启用 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) 的返回头。 + +## 属性 + +- `allow_origins`: `可选`.允许跨域访问的Origin, 格式如:`scheme`://`host`:`port`, 比如: https://somehost.com:8081. 多个值使用 `,` 分割, `allow_credential` 为 `false` 时可以使用 `*` 来表示所有 Origin均允许通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有Origin都通过,但请注意这样存在安全隐患。默认值为 `*`。 +- `allow_methods`: `可选`.允许跨域访问的Method, 比如: `GET`, `POST`等。多个值使用 `,` 分割, `allow_credential` 为 `false` 时可以使用 `*` 来表示所有 Origin均允许通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Method 都通过,但请注意这样存在安全隐患。默认值为 `*`。 +- `allow_headers`: `可选`.允许跨域访问时请求方携带哪些非 CORS规范 以外的 Header, 多个值使用 `,` 分割。默认值为 `*`。 +- `expose_headers`: `可选`.允许跨域访问时响应方携带哪些非 CORS规范 以外的 Header, 多个值使用 `,` 分割。默认值为 `*`。 +- `max_age`: `可选`.浏览器缓存CORS结果的最大时间, 单位为秒, 在这个时间范围内浏览器会复用上一次的检查结果, `-1` 表示不缓存。请注意各个浏览器允许的的最大时间不用, 详情请参考 [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#Directives). 默认值为 `5`。 +- `allow_credential`: 是否允许跨域访问的请求方携带凭据(如 Cookie 等), 默认值为: `false`。 + +## 如何启用 +创建 `Route` 或 `Service` 对象,并配置 `cors` 插件。 +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/hello", + "plugins": { + "cors": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:8080": 1 + } + } +}' +``` + +## 测试插件 +请求下接口, 发现接口已经返回了`CORS`相关的header, 代表插件生效 +```shell +curl http://127.0.0.1:9080/hello -v +... +< Server: APISIX web server +< Access-Control-Allow-Origin: * +< Access-Control-Allow-Methods: * +< Access-Control-Allow-Headers: * +< Access-Control-Expose-Headers: * +< Access-Control-Max-Age: 5 +... +``` + +## 禁用插件 + +从配置中移除`cors`插件即可。 +```shell +$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/hello", + "plugins": {}, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:8080": 1 + } + } +}' +``` diff --git a/doc/plugins/cors.md b/doc/plugins/cors.md new file mode 100644 index 000000000000..42647db0d360 --- /dev/null +++ b/doc/plugins/cors.md @@ -0,0 +1,91 @@ + + +# [Chinese](cors-cn.md) + +# Summary + +- [**Description**](#Description) +- [**Attributes**](#Attributes) +- [**How To Enable**](#how-to-Enable) +- [**Test Plugin**](#test-plugin) +- [**Disable Plugin**](#disable-plugin) + +## Description + +`cors` plugin can help you enable [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) easily. + +## Attributes + +- `allow_origins`: `optional`.Which Origins is allowed to enable CORS, format as:`scheme`://`host`:`port`, for example: https://somehost.com:8081. Multiple origin use `,` to split. When `allow_credential` is `false`, you can use `*` to indicate allow all any origin. you alse can allow all any origins forcefully using `**` even already enable `allow_credential`, but it will bring some securiy risks. Default value: `*`. +- `allow_methods`: `optional`.Which Method is allowed to enable CORS, such as: `GET`, `POST` etc. Multiple method use `,` to split. When `allow_credential` is `false`, you can use `*` to indicate allow all any method. You alse can allow all any method forcefully using `**` even already enable `allow_credential`, but it will bring some securiy risks. Default value: `*`. +- `allow_headers`: `optional`.Which headers are allowed to set in requst when access cross-origin resource. Multiple value use `,` to split. Default value: `*`. +- `expose_headers`: `optional`.Which headers are allowed to set in response when access cross-origin resource. Multiple value use `,` to split. Default value: `*`. +- `max_age`: `optional`.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.Default value: `5`. +- `allow_credential`: Enable request include credentia (such as Cookie etc.), Default avlue: `false`. + +## How To Enable +Create a `Route` or `Service` object and configure `cors` plugin. +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/hello", + "plugins": { + "cors": {} + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:8080": 1 + } + } +}' +``` + +## Test Plugin +curl to server, you will find the headers about `CORS` is be returned, it means plugin is working fine. +```shell +curl http://127.0.0.1:9080/hello -v +... +< Server: APISIX web server +< Access-Control-Allow-Origin: * +< Access-Control-Allow-Methods: * +< Access-Control-Allow-Headers: * +< Access-Control-Expose-Headers: * +< Access-Control-Max-Age: 5 +... +``` + +## Disable Plugin +Remove plugin from configuraion. +```shell +$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/hello", + "plugins": {}, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:8080": 1 + } + } +}' +``` From 8bbc29d42aff9e464046f14e60d940bf415a5d7d Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Sat, 28 Mar 2020 17:15:58 +0800 Subject: [PATCH 10/13] doc: append link to main document --- doc/README.md | 1 + doc/README_CN.md | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/README.md b/doc/README.md index ad83c5b06182..40da08e2423a 100644 --- a/doc/README.md +++ b/doc/README.md @@ -63,6 +63,7 @@ Plugins * [udp-logger](plugins/udp-logger.md): Log requests to UDP servers. * [proxy-mirror](plugins/proxy-mirror.md): Provides the ability to mirror client requests. * [kafka-logger](plugins/kafka-logger.md): Log requests to External Kafka servers. +* [cors](plugins/cors.md): Enbale cors for you api. Deploy to the Cloud ======= diff --git a/doc/README_CN.md b/doc/README_CN.md index f063486f5450..bf3141400251 100644 --- a/doc/README_CN.md +++ b/doc/README_CN.md @@ -64,3 +64,4 @@ Reference document * [udp-logger](plugins/udp-logger.md): 将请求记录到UDP服务器 * [tcp-logger](plugins/tcp-logger.md): 将请求记录到TCP服务器 * [kafka-logger](plugins/kafka-logger-cn.md): 将请求记录到外部Kafka服务器。 +* [cors](plugins/cors-cn.md): 为你的API启用CORS. From 054988b8daa4770acb7e5801c7b71185110fad9d Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Sat, 28 Mar 2020 18:23:16 +0800 Subject: [PATCH 11/13] doc: add ref to features --- README.md | 1 + README_CN.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 4ccbf88fba6d..1d6bc1d13070 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ A/B testing, canary release, blue-green deployment, limit rate, defense against - [Limit-count](doc/plugins/limit-count.md) - [Limit-concurrency](doc/plugins/limit-conn.md) - Anti-ReDoS(Regular expression Denial of Service): Built-in policies to Anti ReDoS without configuration. + - [CORS](doc/plugins/cors.md) - **OPS friendly** - OpenTracing: [support Apache Skywalking and Zipkin](doc/plugins/zipkin.md) diff --git a/README_CN.md b/README_CN.md index 1f85fbb651e5..1296f26a0159 100644 --- a/README_CN.md +++ b/README_CN.md @@ -90,6 +90,7 @@ A/B 测试、金丝雀发布(灰度发布)、蓝绿部署、限流限速、抵 - [限制请求数](doc/plugins/limit-count-cn.md) - [限制并发](doc/plugins/limit-conn-cn.md) - 防御 ReDoS(正则表达式拒绝服务):内置策略,无需配置即可抵御 ReDoS。 + - [CORS](doc/plugins/cors-cn.md) - **运维友好** - OpenTracing 可观测性: [支持 Apache Skywalking 和 Zipkin](doc/plugins/zipkin-cn.md)。 From 79e4421f88d30894e2099c1f6f53665593ad088c Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Sat, 28 Mar 2020 18:39:13 +0800 Subject: [PATCH 12/13] doc: optimize document's format. --- doc/plugins/cors-cn.md | 25 +++++++++++++------------ doc/plugins/cors.md | 18 +++++++++++------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/doc/plugins/cors-cn.md b/doc/plugins/cors-cn.md index 7d70a22a7e39..2591b70d4ae8 100644 --- a/doc/plugins/cors-cn.md +++ b/doc/plugins/cors-cn.md @@ -3,15 +3,15 @@ # 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 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 +# 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. +# 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. # @@ -33,19 +33,20 @@ ## 属性 -- `allow_origins`: `可选`.允许跨域访问的Origin, 格式如:`scheme`://`host`:`port`, 比如: https://somehost.com:8081. 多个值使用 `,` 分割, `allow_credential` 为 `false` 时可以使用 `*` 来表示所有 Origin均允许通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有Origin都通过,但请注意这样存在安全隐患。默认值为 `*`。 -- `allow_methods`: `可选`.允许跨域访问的Method, 比如: `GET`, `POST`等。多个值使用 `,` 分割, `allow_credential` 为 `false` 时可以使用 `*` 来表示所有 Origin均允许通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Method 都通过,但请注意这样存在安全隐患。默认值为 `*`。 -- `allow_headers`: `可选`.允许跨域访问时请求方携带哪些非 CORS规范 以外的 Header, 多个值使用 `,` 分割。默认值为 `*`。 -- `expose_headers`: `可选`.允许跨域访问时响应方携带哪些非 CORS规范 以外的 Header, 多个值使用 `,` 分割。默认值为 `*`。 -- `max_age`: `可选`.浏览器缓存CORS结果的最大时间, 单位为秒, 在这个时间范围内浏览器会复用上一次的检查结果, `-1` 表示不缓存。请注意各个浏览器允许的的最大时间不用, 详情请参考 [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#Directives). 默认值为 `5`。 -- `allow_credential`: 是否允许跨域访问的请求方携带凭据(如 Cookie 等), 默认值为: `false`。 +- `allow_origins`: `可选`,允许跨域访问的 Origin,格式如:`scheme`://`host`:`port`,比如: https://somehost.com:8081。多个值使用 `,` 分割,`allow_credential` 为 `false` 时可以使用 `*` 来表示所有 Origin 均允许通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Origin 都通过,但请注意这样存在安全隐患。默认值为 `*`。 +- `allow_methods`: `可选`,允许跨域访问的 Method,比如: `GET`,`POST`等。多个值使用 `,` 分割,`allow_credential` 为 `false` 时可以使用 `*` 来表示所有 Origin 均允许通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Method 都通过,但请注意这样存在安全隐患。默认值为 `*`。 +- `allow_headers`: `可选`,允许跨域访问时请求方携带哪些非 `CORS规范` 以外的 Header, 多个值使用 `,` 分割。默认值为 `*`。 +- `expose_headers`: `可选`,允许跨域访问时响应方携带哪些非 `CORS规范` 以外的 Header, 多个值使用 `,` 分割。默认值为 `*`。 +- `max_age`: `可选`,浏览器缓存 CORS 结果的最大时间,单位为秒,在这个时间范围内浏览器会复用上一次的检查结果,`-1` 表示不缓存。请注意各个浏览器允许的的最大时间不用,详情请参考 [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#Directives). 默认值为 `5`。 +- `allow_credential`: 是否允许跨域访问的请求方携带凭据(如 Cookie 等),默认值为: `false`。 ## 如何启用 + 创建 `Route` 或 `Service` 对象,并配置 `cors` 插件。 + ```shell curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { - "methods": ["GET"], "uri": "/hello", "plugins": { "cors": {} @@ -60,7 +61,8 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 ``` ## 测试插件 -请求下接口, 发现接口已经返回了`CORS`相关的header, 代表插件生效 + +请求下接口,发现接口已经返回了`CORS`相关的header,代表插件生效 ```shell curl http://127.0.0.1:9080/hello -v ... @@ -79,7 +81,6 @@ curl http://127.0.0.1:9080/hello -v ```shell $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { - "methods": ["GET"], "uri": "/hello", "plugins": {}, "upstream": { diff --git a/doc/plugins/cors.md b/doc/plugins/cors.md index 42647db0d360..6e6114ee215c 100644 --- a/doc/plugins/cors.md +++ b/doc/plugins/cors.md @@ -33,19 +33,20 @@ ## Attributes -- `allow_origins`: `optional`.Which Origins is allowed to enable CORS, format as:`scheme`://`host`:`port`, for example: https://somehost.com:8081. Multiple origin use `,` to split. When `allow_credential` is `false`, you can use `*` to indicate allow all any origin. you alse can allow all any origins forcefully using `**` even already enable `allow_credential`, but it will bring some securiy risks. Default value: `*`. -- `allow_methods`: `optional`.Which Method is allowed to enable CORS, such as: `GET`, `POST` etc. Multiple method use `,` to split. When `allow_credential` is `false`, you can use `*` to indicate allow all any method. You alse can allow all any method forcefully using `**` even already enable `allow_credential`, but it will bring some securiy risks. Default value: `*`. -- `allow_headers`: `optional`.Which headers are allowed to set in requst when access cross-origin resource. Multiple value use `,` to split. Default value: `*`. -- `expose_headers`: `optional`.Which headers are allowed to set in response when access cross-origin resource. Multiple value use `,` to split. Default value: `*`. -- `max_age`: `optional`.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.Default value: `5`. +- `allow_origins`: `optional`, Which Origins is allowed to enable CORS, format as:`scheme`://`host`:`port`, for example: https://somehost.com:8081. Multiple origin use `,` to split. When `allow_credential` is `false`, you can use `*` to indicate allow all any origin. you alse can allow all any origins forcefully using `**` even already enable `allow_credential`, but it will bring some securiy risks. Default value: `*`. +- `allow_methods`: `optional`, Which Method is allowed to enable CORS, such as: `GET`, `POST` etc. Multiple method use `,` to split. When `allow_credential` is `false`, you can use `*` to indicate allow all any method. You alse can allow all any method forcefully using `**` even already enable `allow_credential`, but it will bring some securiy risks. Default value: `*`. +- `allow_headers`: `optional`, Which headers are allowed to set in requst when access cross-origin resource. Multiple value use `,` to split. Default value: `*`. +- `expose_headers`: `optional`, Which headers are allowed to set in response when access cross-origin resource. Multiple value use `,` to split. Default value: `*`. +- `max_age`: `optional`, 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.Default value: `5`. - `allow_credential`: Enable request include credentia (such as Cookie etc.), Default avlue: `false`. ## How To Enable + Create a `Route` or `Service` object and configure `cors` plugin. + ```shell curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { - "methods": ["GET"], "uri": "/hello", "plugins": { "cors": {} @@ -60,7 +61,9 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 ``` ## Test Plugin + curl to server, you will find the headers about `CORS` is be returned, it means plugin is working fine. + ```shell curl http://127.0.0.1:9080/hello -v ... @@ -74,11 +77,12 @@ curl http://127.0.0.1:9080/hello -v ``` ## Disable Plugin + Remove plugin from configuraion. + ```shell $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { - "methods": ["GET"], "uri": "/hello", "plugins": {}, "upstream": { From b7fcb3920e55169b7ba8d863ae1ba6dcead4d1a1 Mon Sep 17 00:00:00 2001 From: ShiningRush <277040271@qq.com> Date: Sat, 28 Mar 2020 22:21:15 +0800 Subject: [PATCH 13/13] doc: fix chinese comma in license header --- doc/plugins/cors-cn.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/plugins/cors-cn.md b/doc/plugins/cors-cn.md index 2591b70d4ae8..413dc95acc85 100644 --- a/doc/plugins/cors-cn.md +++ b/doc/plugins/cors-cn.md @@ -3,15 +3,15 @@ # 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 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 +# 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. +# 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. #