Fix Access-Control-Allow-Headers header; Fix case when cors is not set (#315)
* Fix Access-Control-Allow-Headers header; Fix case when cors is not set
* Add tests for handling cors headers
diff --git a/scripts/lua/cors.lua b/scripts/lua/cors.lua
index ea11579..8c0b1f5 100644
--- a/scripts/lua/cors.lua
+++ b/scripts/lua/cors.lua
@@ -25,21 +25,28 @@
if resourceConfig.cors ~= nil then
ngx.var.cors_origins = resourceConfig.cors.origin
ngx.var.cors_methods = resourceConfig.cors.methods
+ -- preflight options call
if resourceConfig.cors.origin ~= 'false' and ngx.req.get_method() == 'OPTIONS' then
+ -- 'Access-Control-Allow-Headers' response header is required for preflight requests that have 'Access-Control-Request-Headers' headers
+ local accessControlRequestHeaders = ngx.req.get_headers()['Access-Control-Request-Headers']
+ if accessControlRequestHeaders ~= nil then
+ ngx.header['Access-Control-Allow-Headers'] = accessControlRequestHeaders
+ end
request.success(200)
end
end
end
function _M.replaceHeaders()
- if ngx.var.cors_origins ~= nil then
+ if ngx.var.cors_origins ~= nil and ngx.var.cors_origins ~= '' then
if ngx.var.cors_origins == 'false' then
ngx.header['Access-Control-Allow-Origin'] = nil
ngx.header['Access-Control-Allow-Methods'] = nil
+ ngx.header['Access-Control-Allow-Headers'] = nil
+ ngx.header['Access-Control-Allow-Credentials'] = nil
else
ngx.header['Access-Control-Allow-Origin'] = ngx.var.cors_origins == 'true' and (ngx.var.http_origin or '*') or ngx.var.cors_origins
ngx.header['Access-Control-Allow-Methods'] = ngx.var.cors_methods or 'GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS'
- ngx.header['Access-Control-Allow-Headers'] = ngx.req.get_headers()['Access-Control-Request-Headers']
ngx.header['Access-Control-Allow-Credentials'] = 'true'
end
end
diff --git a/tests/fakengx.lua b/tests/fakengx.lua
index ed8ddfd..7a0ec1e 100644
--- a/tests/fakengx.lua
+++ b/tests/fakengx.lua
@@ -310,6 +310,7 @@
ngx.thread = {}
ngx.location = {}
ngx.shared = {}
+ ngx.header = {}
-- Create shared dict API
setmetatable(ngx.shared, {
@@ -474,7 +475,11 @@
end
function ngx.req.get_headers()
- return {}
+ return ngx.header
+ end
+
+ function ngx.req.get_method()
+ return
end
-- http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp
diff --git a/tests/scripts/lua/cors.lua b/tests/scripts/lua/cors.lua
new file mode 100644
index 0000000..565440c
--- /dev/null
+++ b/tests/scripts/lua/cors.lua
@@ -0,0 +1,98 @@
+--
+-- 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 fakengx = require 'fakengx'
+local cors = require 'cors'
+local redis = require 'lib/redis'
+local cjson = require 'cjson'
+
+
+describe('Testing cors headers', function()
+ before_each(function()
+ _G.ngx = fakengx.new()
+ ngx.var.cors_origins = ''
+ ngx.var.cors_methods = ''
+ operations = {
+ GET = {
+ backendUrl = 'https://example.com',
+ backendMethod = 'GET'
+ }
+ }
+ _G.resourceObj = cjson.decode(redis.generateResourceObj(operations, nil, nil, nil))
+ end)
+
+ it('Access-Control headers should be present for preflight options call if cors is enabled', function()
+ -- mock options call
+ ngx.req.get_method = function()
+ return 'OPTIONS'
+ end
+
+ ngx.header['Access-Control-Request-Headers'] = 'test-header'
+
+ resourceObj.cors = {
+ origin = 'true',
+ methods = 'GET, POST, PUT'
+ }
+ cors.processCall(resourceObj)
+ cors.replaceHeaders()
+
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Origin'], '*')
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Methods'], 'GET, POST, PUT')
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Credentials'], 'true')
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Headers'], 'test-header')
+ end)
+
+ it('Access-Control headers should be present with cors enabled', function()
+ resourceObj.cors = {
+ origin = 'true',
+ }
+ cors.processCall(resourceObj)
+ cors.replaceHeaders()
+
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Origin'], '*')
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Methods'], 'GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS')
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Credentials'], 'true')
+ end)
+
+ it('Access-Control headers should not be present with cors disabled', function()
+ resourceObj.cors = {
+ origin = 'false'
+ }
+ cors.processCall(resourceObj)
+ cors.replaceHeaders()
+
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Origin'], nil)
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Methods'], nil)
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Headers'], nil)
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Credentials'], nil)
+ end)
+
+ it('Should pass through Access-Control headers if cors is not defined', function()
+ ngx.header['Access-Control-Allow-Origin'] = 'https://foo.bar'
+ ngx.header['Access-Control-Allow-Headers'] = 'Content-Type'
+
+ resourceObj.cors = nil
+
+ cors.processCall(resourceObj)
+ cors.replaceHeaders()
+
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Origin'], 'https://foo.bar')
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Headers'], 'Content-Type')
+ assert.are.same(ngx.req.get_headers()['Access-Control-Allow-Methods'], nil)
+ end)
+
+end)