diff --git a/kong/init.lua b/kong/init.lua index db055f3c960..b01970b2b2d 100644 --- a/kong/init.lua +++ b/kong/init.lua @@ -769,6 +769,9 @@ function Kong.handle_error() kong_resty_ctx.apply_ref() local ctx = ngx.ctx + + ctx.KONG_UNEXPECTED = true + if not ctx.plugins_for_request then for _ in plugins_iterator(ctx, loaded_plugins, configured_plugins, true) do -- just build list of plugins diff --git a/kong/pdk/response.lua b/kong/pdk/response.lua index 8c2813c69eb..7e77c3c73da 100644 --- a/kong/pdk/response.lua +++ b/kong/pdk/response.lua @@ -72,7 +72,7 @@ local function new(self, major_version) -- Returns the HTTP status code currently set for the downstream response (as -- a Lua number). -- - -- If the request was proxied (as per `kong.service.get_source()`), the + -- If the request was proxied (as per `kong.response.get_source()`), the -- return value will be that of the response from the Service (identical to -- `kong.service.response.get_status()`). -- @@ -233,11 +233,17 @@ local function new(self, major_version) function _RESPONSE.get_source() check_phase(header_body_log) - if ngx.ctx.KONG_PROXIED then + local ctx = ngx.ctx + + if ctx.KONG_UNEXPECTED then + return "error" + end + + if ctx.KONG_PROXIED then return "service" end - if ngx.ctx.KONG_EXITED then + if ctx.KONG_EXITED then return "exit" end diff --git a/kong/pdk/service/response.lua b/kong/pdk/service/response.lua index 7625408f713..54851e71e37 100644 --- a/kong/pdk/service/response.lua +++ b/kong/pdk/service/response.lua @@ -58,7 +58,7 @@ local function new(pdk, major_version) -- @function kong.service.response.get_status -- @phases `header_filter`, `body_filter`, `log` -- @treturn number|nil the status code from the response from the Service, or `nil` - -- if the request was not proxied (i.e. `kong.service.get_source()` returned + -- if the request was not proxied (i.e. `kong.response.get_source()` returned -- anything other than `"service"`. -- @usage -- kong.log.inspect(kong.service.response.get_status()) -- 418 diff --git a/kong/plugins/acl/acls.lua b/kong/plugins/acl/acls.lua index 0548ec6d90a..1a863af5662 100644 --- a/kong/plugins/acl/acls.lua +++ b/kong/plugins/acl/acls.lua @@ -16,13 +16,13 @@ local invalidate_cache = function(self, entity) end local cache_key = self:cache_key(consumer.id) - return singletons.cache:invalidate(cache_key) end local _ACLs = {} + function _ACLs:post_crud_event(operation, entity) local _, err, err_t = invalidate_cache(self, entity) if err then diff --git a/kong/plugins/acl/handler.lua b/kong/plugins/acl/handler.lua index 1feae7fd1cb..f27dbda16ef 100644 --- a/kong/plugins/acl/handler.lua +++ b/kong/plugins/acl/handler.lua @@ -22,7 +22,7 @@ local ACLHandler = BasePlugin:extend() ACLHandler.PRIORITY = 950 -ACLHandler.VERSION = "0.2.0" +ACLHandler.VERSION = "1.0.0" function ACLHandler:new() @@ -85,7 +85,7 @@ function ACLHandler:access(conf) return kong.response.exit(403, { message = "You cannot consume this service" }) end - if not conf.hide_groups_header then + if not conf.hide_groups_header and to_be_blocked then kong.service.request.set_header(constants.HEADERS.CONSUMER_GROUPS, to_be_blocked) end diff --git a/kong/plugins/basic-auth/access.lua b/kong/plugins/basic-auth/access.lua index ec293a65ab2..2e90c972e65 100644 --- a/kong/plugins/basic-auth/access.lua +++ b/kong/plugins/basic-auth/access.lua @@ -116,18 +116,41 @@ local function load_consumer_into_memory(consumer_id, anonymous) end local function set_consumer(consumer, credential) - kong.service.request.set_header(constants.HEADERS.CONSUMER_ID, consumer.id) - kong.service.request.set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) - kong.service.request.set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + local set_header = kong.service.request.set_header + local clear_header = kong.service.request.clear_header + + if consumer and consumer.id then + set_header(constants.HEADERS.CONSUMER_ID, consumer.id) + else + clear_header(constants.HEADERS.CONSUMER_ID) + end + + if consumer and consumer.custom_id then + set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) + else + clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID) + end + + if consumer and consumer.username then + set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + else + clear_header(constants.HEADERS.CONSUMER_USERNAME) + end kong.client.authenticate(consumer, credential) if credential then - kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) - kong.service.request.clear_header(constants.HEADERS.ANONYMOUS) + if credential.username then + set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) + else + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) + end + + clear_header(constants.HEADERS.ANONYMOUS) else - kong.service.request.set_header(constants.HEADERS.ANONYMOUS, true) + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) + set_header(constants.HEADERS.ANONYMOUS, true) end end diff --git a/kong/plugins/basic-auth/handler.lua b/kong/plugins/basic-auth/handler.lua index 5cb77318a5e..f997df7af2b 100644 --- a/kong/plugins/basic-auth/handler.lua +++ b/kong/plugins/basic-auth/handler.lua @@ -18,7 +18,7 @@ end BasicAuthHandler.PRIORITY = 1001 -BasicAuthHandler.VERSION = "0.2.0" +BasicAuthHandler.VERSION = "1.0.0" return BasicAuthHandler diff --git a/kong/plugins/correlation-id/handler.lua b/kong/plugins/correlation-id/handler.lua index 240a5dba720..6cb1a1e5fcc 100644 --- a/kong/plugins/correlation-id/handler.lua +++ b/kong/plugins/correlation-id/handler.lua @@ -44,7 +44,7 @@ local CorrelationIdHandler = BasePlugin:extend() CorrelationIdHandler.PRIORITY = 1 -CorrelationIdHandler.VERSION = "0.2.0" +CorrelationIdHandler.VERSION = "1.0.0" function CorrelationIdHandler:new() @@ -63,16 +63,18 @@ function CorrelationIdHandler:access(conf) CorrelationIdHandler.super.access(self) -- Set header for upstream - local header_value = kong.request.get_header(conf.header_name) - if not header_value then + local correlation_id = kong.request.get_header(conf.header_name) + if not correlation_id then -- Generate the header value - header_value = generators[conf.generator]() - kong.service.request.set_header(conf.header_name, header_value) + correlation_id = generators[conf.generator]() + if correlation_id then + kong.service.request.set_header(conf.header_name, correlation_id) + end end if conf.echo_downstream then -- For later use, to echo it back downstream - kong.ctx.plugin.correlationid_header_value = header_value + kong.ctx.plugin.correlation_id = correlation_id end end @@ -80,10 +82,13 @@ end function CorrelationIdHandler:header_filter(conf) CorrelationIdHandler.super.header_filter(self) - local header_value = kong.ctx.plugin.correlationid_header_value + if not conf.echo_downstream then + return + end - if conf.echo_downstream and header_value then - kong.response.set_header(conf.header_name, header_value) + local correlation_id = kong.ctx.plugin.correlation_id + if correlation_id then + kong.response.set_header(conf.header_name, correlation_id) end end diff --git a/kong/plugins/cors/handler.lua b/kong/plugins/cors/handler.lua index 532c3add1db..6b0de7094b6 100644 --- a/kong/plugins/cors/handler.lua +++ b/kong/plugins/cors/handler.lua @@ -1,10 +1,11 @@ local BasePlugin = require "kong.plugins.base_plugin" -local re_find = ngx.re.find -local concat = table.concat -local tostring = tostring -local ipairs = ipairs +local kong = kong +local re_find = ngx.re.find +local concat = table.concat +local tostring = tostring +local ipairs = ipairs local NO_CONTENT = 204 @@ -14,7 +15,7 @@ local CorsHandler = BasePlugin:extend() CorsHandler.PRIORITY = 2000 -CorsHandler.VERSION = "0.1.0" +CorsHandler.VERSION = "1.0.0" local function configure_origin(conf) @@ -75,7 +76,7 @@ local function configure_credentials(conf, allow_all) end if not allow_all then - set_header("Access-Control-Allow-Credentials", "true") + set_header("Access-Control-Allow-Credentials", true) return end @@ -84,7 +85,7 @@ local function configure_credentials(conf, allow_all) local req_origin = kong.request.get_header("origin") if req_origin then set_header("Access-Control-Allow-Origin", req_origin) - set_header("Access-Control-Allow-Credentials", "true") + set_header("Access-Control-Allow-Credentials", true) set_header("Vary", "Origin") end end @@ -116,7 +117,7 @@ function CorsHandler:access(conf) local set_header = kong.response.set_header - if conf.headers then + if conf.headers and #conf.headers > 0 then set_header("Access-Control-Allow-Headers", concat(conf.headers, ",")) else @@ -150,7 +151,7 @@ function CorsHandler:header_filter(conf) local allow_all = configure_origin(conf) configure_credentials(conf, allow_all) - if conf.exposed_headers then + if conf.exposed_headers and #conf.exposed_headers > 0 then kong.response.set_header("Access-Control-Expose-Headers", concat(conf.exposed_headers, ",")) end diff --git a/kong/plugins/hmac-auth/access.lua b/kong/plugins/hmac-auth/access.lua index 9122d0168c5..e6cf83b1ef6 100644 --- a/kong/plugins/hmac-auth/access.lua +++ b/kong/plugins/hmac-auth/access.lua @@ -247,18 +247,41 @@ end local function set_consumer(consumer, credential) - kong.service.request.set_header(constants.HEADERS.CONSUMER_ID, consumer.id) - kong.service.request.set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) - kong.service.request.set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + local set_header = kong.service.request.set_header + local clear_header = kong.service.request.clear_header + + if consumer and consumer.id then + set_header(constants.HEADERS.CONSUMER_ID, consumer.id) + else + clear_header(constants.HEADERS.CONSUMER_ID) + end + + if consumer and consumer.custom_id then + set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) + else + clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID) + end + + if consumer and consumer.username then + set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + else + clear_header(constants.HEADERS.CONSUMER_USERNAME) + end kong.client.authenticate(consumer, credential) if credential then - kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) - kong.service.request.clear_header(constants.HEADERS.ANONYMOUS) + if credential.username then + set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) + else + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) + end + + clear_header(constants.HEADERS.ANONYMOUS) else - kong.service.request.set_header(constants.HEADERS.ANONYMOUS, true) + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) + set_header(constants.HEADERS.ANONYMOUS, true) end end diff --git a/kong/plugins/hmac-auth/handler.lua b/kong/plugins/hmac-auth/handler.lua index 67abc3fea65..92f7ca20d22 100644 --- a/kong/plugins/hmac-auth/handler.lua +++ b/kong/plugins/hmac-auth/handler.lua @@ -18,7 +18,7 @@ end HMACAuthHandler.PRIORITY = 1000 -HMACAuthHandler.VERSION = "0.2.0" +HMACAuthHandler.VERSION = "1.0.0" return HMACAuthHandler diff --git a/kong/plugins/jwt/handler.lua b/kong/plugins/jwt/handler.lua index 19531805d0a..370a1065b72 100644 --- a/kong/plugins/jwt/handler.lua +++ b/kong/plugins/jwt/handler.lua @@ -15,7 +15,7 @@ local JwtHandler = BasePlugin:extend() JwtHandler.PRIORITY = 1005 -JwtHandler.VERSION = "0.2.0" +JwtHandler.VERSION = "1.0.0" --- Retrieve a JWT in a request. @@ -87,9 +87,26 @@ end local function set_consumer(consumer, credential, token) - kong.service.request.set_header(constants.HEADERS.CONSUMER_ID, consumer.id) - kong.service.request.set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) - kong.service.request.set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + local set_header = kong.service.request.set_header + local clear_header = kong.service.request.clear_header + + if consumer and consumer.id then + set_header(constants.HEADERS.CONSUMER_ID, consumer.id) + else + clear_header(constants.HEADERS.CONSUMER_ID) + end + + if consumer and consumer.custom_id then + set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) + else + clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID) + end + + if consumer and consumer.username then + set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + else + clear_header(constants.HEADERS.CONSUMER_USERNAME) + end kong.client.authenticate(consumer, credential) @@ -98,15 +115,16 @@ local function set_consumer(consumer, credential, token) ngx.ctx.authenticated_jwt_token = token -- backward compatibilty only if credential.username then - kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) + set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) else - kong.service.request.clear_header(constants.HEADERS.CREDENTIAL_USERNAME) + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) end - kong.service.request.clear_header(constants.HEADERS.ANONYMOUS) + clear_header(constants.HEADERS.ANONYMOUS) else - kong.service.request.set_header(constants.HEADERS.ANONYMOUS, true) + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) + set_header(constants.HEADERS.ANONYMOUS, true) end end diff --git a/kong/plugins/key-auth/handler.lua b/kong/plugins/key-auth/handler.lua index 096be88ca03..8024a208dfb 100644 --- a/kong/plugins/key-auth/handler.lua +++ b/kong/plugins/key-auth/handler.lua @@ -1,14 +1,19 @@ local constants = require "kong.constants" local BasePlugin = require "kong.plugins.base_plugin" + +local kong = kong local type = type + local _realm = 'Key realm="' .. _KONG._NAME .. '"' + local KeyAuthHandler = BasePlugin:extend() + KeyAuthHandler.PRIORITY = 1003 -KeyAuthHandler.VERSION = "0.2.0" +KeyAuthHandler.VERSION = "1.0.0" function KeyAuthHandler:new() @@ -38,26 +43,44 @@ local function load_consumer(consumer_id, anonymous) return result end + local function set_consumer(consumer, credential) - local const = constants.HEADERS + local set_header = kong.service.request.set_header + local clear_header = kong.service.request.clear_header - local new_headers = { - [const.CONSUMER_ID] = consumer.id, - [const.CONSUMER_CUSTOM_ID] = tostring(consumer.custom_id), - [const.CONSUMER_USERNAME] = consumer.username, - } + if consumer and consumer.id then + set_header(constants.HEADERS.CONSUMER_ID, consumer.id) + else + clear_header(constants.HEADERS.CONSUMER_ID) + end + + if consumer and consumer.custom_id then + set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) + else + clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID) + end + + if consumer and consumer.username then + set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + else + clear_header(constants.HEADERS.CONSUMER_USERNAME) + end kong.client.authenticate(consumer, credential) if credential then - new_headers[const.CREDENTIAL_USERNAME] = credential.username - kong.service.request.clear_header(const.ANONYMOUS) -- in case of auth plugins concatenation + if credential.username then + set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) + else + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) + end + + clear_header(constants.HEADERS.ANONYMOUS) else - new_headers[const.ANONYMOUS] = true + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) + set_header(constants.HEADERS.ANONYMOUS, true) end - - kong.service.request.set_headers(new_headers) end diff --git a/kong/plugins/ldap-auth/access.lua b/kong/plugins/ldap-auth/access.lua index 3c2c6be44c3..ac11ceb08b2 100644 --- a/kong/plugins/ldap-auth/access.lua +++ b/kong/plugins/ldap-auth/access.lua @@ -151,26 +151,45 @@ end local function set_consumer(consumer, credential) kong.client.authenticate(consumer, credential) + local set_header = kong.service.request.set_header + local clear_header = kong.service.request.clear_header + if consumer then -- this can only be the Anonymous user in this case - kong.service.request.set_header(constants.HEADERS.CONSUMER_ID, consumer.id) - kong.service.request.set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) - kong.service.request.set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) - kong.service.request.set_header(constants.HEADERS.ANONYMOUS, true) + if consumer.id then + set_header(constants.HEADERS.CONSUMER_ID, consumer.id) + else + clear_header(constants.HEADERS.CONSUMER_ID) + end + + if consumer.custom_id then + set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) + else + clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID) + end + + if consumer.username then + set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + else + clear_header(constants.HEADERS.CONSUMER_USERNAME) + end + + set_header(constants.HEADERS.ANONYMOUS, true) return end - if credential then - -- here we have been authenticated by ldap - kong.service.request.set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) + if credential and credential.username then + set_header(constants.HEADERS.CREDENTIAL_USERNAME, credential.username) + else + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) end -- in case of auth plugins concatenation, remove remnants of anonymous - kong.service.request.clear_header(constants.HEADERS.ANONYMOUS) - kong.service.request.clear_header(constants.HEADERS.CONSUMER_ID) - kong.service.request.clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID) - kong.service.request.clear_header(constants.HEADERS.CONSUMER_USERNAME) + clear_header(constants.HEADERS.ANONYMOUS) + clear_header(constants.HEADERS.CONSUMER_ID) + clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID) + clear_header(constants.HEADERS.CONSUMER_USERNAME) end diff --git a/kong/plugins/ldap-auth/handler.lua b/kong/plugins/ldap-auth/handler.lua index e6c588e281f..0d7eadc4672 100644 --- a/kong/plugins/ldap-auth/handler.lua +++ b/kong/plugins/ldap-auth/handler.lua @@ -17,7 +17,7 @@ end LdapAuthHandler.PRIORITY = 1002 -LdapAuthHandler.VERSION = "0.2.0" +LdapAuthHandler.VERSION = "1.0.0" return LdapAuthHandler diff --git a/kong/plugins/oauth2/access.lua b/kong/plugins/oauth2/access.lua index 379a9f17063..b6ca18457a9 100644 --- a/kong/plugins/oauth2/access.lua +++ b/kong/plugins/oauth2/access.lua @@ -4,11 +4,12 @@ local constants = require "kong.constants" local timestamp = require "kong.tools.timestamp" -local string_find = string.find - - +local kong = kong +local next = next +local type = type local split = utils.split local strip = utils.strip +local string_find = string.find local check_https = utils.check_https local encode_args = utils.encode_args local random_string = utils.random_string @@ -22,6 +23,7 @@ local ngx_decode_base64 = ngx.decode_base64 local _M = {} + local EMPTY = {} local RESPONSE_TYPE = "response_type" local STATE = "state" @@ -557,20 +559,48 @@ local function load_consumer_into_memory(consumer_id, anonymous) end local function set_consumer(consumer, credential, token) - local clear_header = kong.service.request.clear_header local set_header = kong.service.request.set_header + local clear_header = kong.service.request.clear_header + + if consumer and consumer.id then + set_header(constants.HEADERS.CONSUMER_ID, consumer.id) + else + clear_header(constants.HEADERS.CONSUMER_ID) + end - set_header(constants.HEADERS.CONSUMER_ID, consumer.id) - set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) - set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + if consumer and consumer.custom_id then + set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id) + else + clear_header(constants.HEADERS.CONSUMER_CUSTOM_ID) + end + + if consumer and consumer.username then + set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username) + else + clear_header(constants.HEADERS.CONSUMER_USERNAME) + end kong.client.authenticate(consumer, credential) + if credential then - set_header("x-authenticated-scope", token.scope) - set_header("x-authenticated-userid", token.authenticated_userid) + if token.scope then + set_header("x-authenticated-scope", token.scope) + else + clear_header("x-authenticated-scope") + end + + if token.authenticated_userid then + set_header("x-authenticated-userid", token.authenticated_userid) + else + clear_header("x-authenticated-userid") + end + clear_header(constants.HEADERS.ANONYMOUS) -- in case of auth plugins concatenation + else set_header(constants.HEADERS.ANONYMOUS, true) + clear_header("x-authenticated-scope") + clear_header("x-authenticated-userid") end end diff --git a/kong/plugins/oauth2/handler.lua b/kong/plugins/oauth2/handler.lua index d725dd287d1..4843284b138 100644 --- a/kong/plugins/oauth2/handler.lua +++ b/kong/plugins/oauth2/handler.lua @@ -13,6 +13,6 @@ function OAuthHandler:access(conf) end OAuthHandler.PRIORITY = 1004 -OAuthHandler.VERSION = "0.1.0" +OAuthHandler.VERSION = "1.0.0" return OAuthHandler diff --git a/spec/03-plugins/12-correlation-id/01-access_spec.lua b/spec/03-plugins/12-correlation-id/01-access_spec.lua index 2078f30c343..83c4c6bc77e 100644 --- a/spec/03-plugins/12-correlation-id/01-access_spec.lua +++ b/spec/03-plugins/12-correlation-id/01-access_spec.lua @@ -12,7 +12,7 @@ for _, strategy in helpers.each_strategy() do local proxy_client lazy_setup(function() - local bp = helpers.get_db_utils(strategy) + local bp = helpers.get_db_utils(strategy, nil, { "error-generator-post" }) local route1 = bp.routes:insert { hosts = { "correlation1.com" }, @@ -34,6 +34,20 @@ for _, strategy in helpers.each_strategy() do hosts = { "correlation5.com" }, } + local mock_service = bp.services:insert { + host = "127.0.0.2", + port = 26865, + } + + local route6 = bp.routes:insert { + hosts = { "correlation-timeout.com" }, + service = mock_service, + } + + local route7 = bp.routes:insert { + hosts = { "correlation-error.com" }, + } + bp.plugins:insert { name = "correlation-id", route = { id = route1.id }, @@ -82,6 +96,32 @@ for _, strategy in helpers.each_strategy() do }, } + bp.plugins:insert { + name = "correlation-id", + route = { id = route6.id }, + config = { + generator = "uuid", + echo_downstream = true, + }, + } + + bp.plugins:insert { + name = "correlation-id", + route = { id = route7.id }, + config = { + generator = "uuid", + echo_downstream = true, + }, + } + + bp.plugins:insert { + name = "error-generator-post", + route = { id = route7.id }, + config = { + access = true, + }, + } + assert(helpers.start_kong({ database = strategy, nginx_conf = "spec/fixtures/custom_nginx.template", @@ -210,6 +250,28 @@ for _, strategy in helpers.each_strategy() do assert.matches(UUID_PATTERN, upstream_id) assert.equal(upstream_id, downstream_id) end) + it("echo_downstream sends uuid back to client even when upstream timeouts", function() + local res = assert(proxy_client:send { + method = "GET", + path = "/request", + headers = { + ["Host"] = "correlation-timeout.com" + } + }) + assert.res_status(502, res) + assert.matches(UUID_PATTERN, res.headers["kong-request-id"]) + end) + it("echo_downstream sends uuid back to client even there is a runtime error", function() + local res = assert(proxy_client:send { + method = "GET", + path = "/request", + headers = { + ["Host"] = "correlation-error.com" + } + }) + assert.res_status(500, res) + assert.matches(UUID_PATTERN, res.headers["kong-request-id"]) + end) it("echo_downstream does not send uuid back to client if not asked", function() local res = assert(proxy_client:send { method = "GET", diff --git a/spec/03-plugins/14-cors/01-access_spec.lua b/spec/03-plugins/14-cors/01-access_spec.lua index 81eb661da0f..50e8e01cf65 100644 --- a/spec/03-plugins/14-cors/01-access_spec.lua +++ b/spec/03-plugins/14-cors/01-access_spec.lua @@ -6,7 +6,7 @@ for _, strategy in helpers.each_strategy() do local proxy_client lazy_setup(function() - local bp = helpers.get_db_utils(strategy) + local bp = helpers.get_db_utils(strategy, nil, { "error-generator-post" }) local route1 = bp.routes:insert({ hosts = { "cors1.com" }, @@ -44,15 +44,29 @@ for _, strategy in helpers.each_strategy() do hosts = { "cors9.com" }, }) + local mock_service = bp.services:insert { + host = "127.0.0.2", + port = 26865, + } + + local route10 = bp.routes:insert { + hosts = { "cors-timeout.com" }, + service = mock_service, + } + + local route11 = bp.routes:insert { + hosts = { "cors-error.com" }, + } + bp.plugins:insert { - name = "cors", + name = "cors", route = { id = route1.id }, } bp.plugins:insert { - name = "cors", + name = "cors", route = { id = route2.id }, - config = { + config = { origins = { "example.com" }, methods = { "GET" }, headers = { "origin", "type", "accepts" }, @@ -63,9 +77,9 @@ for _, strategy in helpers.each_strategy() do } bp.plugins:insert { - name = "cors", + name = "cors", route = { id = route3.id }, - config = { + config = { origins = { "example.com" }, methods = { "GET" }, headers = { "origin", "type", "accepts" }, @@ -76,28 +90,28 @@ for _, strategy in helpers.each_strategy() do } bp.plugins:insert { - name = "cors", + name = "cors", route = { id = route4.id }, } bp.plugins:insert { - name = "key-auth", + name = "key-auth", route = { id = route4.id } } bp.plugins:insert { - name = "cors", + name = "cors", route = { id = route5.id }, - config = { + config = { origins = { "*" }, credentials = true } } bp.plugins:insert { - name = "cors", + name = "cors", route = { id = route6.id }, - config = { + config = { origins = { "example.com", "example.org" }, methods = { "GET" }, headers = { "origin", "type", "accepts" }, @@ -108,30 +122,64 @@ for _, strategy in helpers.each_strategy() do } bp.plugins:insert { - name = "cors", + name = "cors", route = { id = route7.id }, - config = { + config = { origins = { "*" }, credentials = false } } bp.plugins:insert { - name = "cors", + name = "cors", route = { id = route8.id }, - config = { + config = { origins = {}, } } bp.plugins:insert { - name = "cors", + name = "cors", route = { id = route9.id }, - config = { + config = { origins = { [[.*\.?example(?:-foo)?.com]] }, } } + bp.plugins:insert { + name = "cors", + route = { id = route10.id }, + config = { + origins = { "example.com" }, + methods = { "GET" }, + headers = { "origin", "type", "accepts" }, + exposed_headers = { "x-auth-token" }, + max_age = 10, + preflight_continue = true + } + } + + bp.plugins:insert { + name = "cors", + route = { id = route11.id }, + config = { + origins = { "example.com" }, + methods = { "GET" }, + headers = { "origin", "type", "accepts" }, + exposed_headers = { "x-auth-token" }, + max_age = 10, + preflight_continue = true + } + } + + bp.plugins:insert { + name = "error-generator-post", + route = { id = route11.id }, + config = { + access = true, + }, + } + assert(helpers.start_kong({ database = strategy, nginx_conf = "spec/fixtures/custom_nginx.template", @@ -282,6 +330,40 @@ for _, strategy in helpers.each_strategy() do assert.is_nil(res.headers["Access-Control-Max-Age"]) end) + it("works even when upstream timeouts", function() + local res = assert(proxy_client:send { + method = "GET", + headers = { + ["Host"] = "cors-timeout.com" + } + }) + assert.res_status(502, res) + assert.equal("example.com", res.headers["Access-Control-Allow-Origin"]) + assert.equal("x-auth-token", res.headers["Access-Control-Expose-Headers"]) + assert.equal("Origin", res.headers["Vary"]) + assert.is_nil(res.headers["Access-Control-Allow-Credentials"]) + assert.is_nil(res.headers["Access-Control-Allow-Methods"]) + assert.is_nil(res.headers["Access-Control-Allow-Headers"]) + assert.is_nil(res.headers["Access-Control-Max-Age"]) + end) + + it("works even when a runtime error occurs", function() + local res = assert(proxy_client:send { + method = "GET", + headers = { + ["Host"] = "cors-error.com" + } + }) + assert.res_status(500, res) + assert.equal("example.com", res.headers["Access-Control-Allow-Origin"]) + assert.equal("x-auth-token", res.headers["Access-Control-Expose-Headers"]) + assert.equal("Origin", res.headers["Vary"]) + assert.is_nil(res.headers["Access-Control-Allow-Credentials"]) + assert.is_nil(res.headers["Access-Control-Allow-Methods"]) + assert.is_nil(res.headers["Access-Control-Allow-Headers"]) + assert.is_nil(res.headers["Access-Control-Max-Age"]) + end) + it("works with 404 responses", function() local res = assert(proxy_client:send { method = "GET", diff --git a/spec/fixtures/custom_plugins/kong/plugins/error-generator-post/handler.lua b/spec/fixtures/custom_plugins/kong/plugins/error-generator-post/handler.lua new file mode 100644 index 00000000000..ebb7e31bf3d --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/error-generator-post/handler.lua @@ -0,0 +1,77 @@ +local BasePlugin = require "kong.plugins.base_plugin" + + +local error = error + + +local ErrorGeneratorPostHandler = BasePlugin:extend() + + +ErrorGeneratorPostHandler.PRIORITY = -math.huge + + +function ErrorGeneratorPostHandler:new() + ErrorGeneratorPostHandler.super.new(self, "logger") +end + + +function ErrorGeneratorPostHandler:init_worker() + ErrorGeneratorPostHandler.super.init_worker(self) +end + + +function ErrorGeneratorPostHandler:certificate(conf) + ErrorGeneratorPostHandler.super.certificate(self) + + if conf.certificate then + error("[error-generator-post] certificate") + end +end + + +function ErrorGeneratorPostHandler:rewrite(conf) + ErrorGeneratorPostHandler.super.rewrite(self) + + if conf.rewrite then + error("[error-generator-post] rewrite") + end +end + + +function ErrorGeneratorPostHandler:access(conf) + ErrorGeneratorPostHandler.super.access(self) + + if conf.access then + error("[error-generator-post] access") + end +end + + +function ErrorGeneratorPostHandler:header_filter(conf) + ErrorGeneratorPostHandler.super.header_filter(self) + + if conf.header_filter then + error("[error-generator-post] header_filter") + end +end + + +function ErrorGeneratorPostHandler:body_filter(conf) + ErrorGeneratorPostHandler.super.body_filter(self) + + if conf.header_filter then + error("[error-generator-post] body_filter") + end +end + + +function ErrorGeneratorPostHandler:log(conf) + ErrorGeneratorPostHandler.super.log(self) + + if conf.log then + error("[error-generator] body_filter") + end +end + + +return ErrorGeneratorPostHandler diff --git a/spec/fixtures/custom_plugins/kong/plugins/error-generator-post/schema.lua b/spec/fixtures/custom_plugins/kong/plugins/error-generator-post/schema.lua new file mode 100644 index 00000000000..b4b88bbb434 --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/error-generator-post/schema.lua @@ -0,0 +1,10 @@ +return { + fields = { + certificate = { type = "boolean", required = false, default = false }, + rewrite = { type = "boolean", required = false, default = false }, + access = { type = "boolean", required = false, default = false }, + header_filter = { type = "boolean", required = false, default = false }, + body_filter = { type = "boolean", required = false, default = false }, + log = { type = "boolean", required = false, default = false }, + } +} diff --git a/spec/fixtures/custom_plugins/kong/plugins/error-generator-pre/handler.lua b/spec/fixtures/custom_plugins/kong/plugins/error-generator-pre/handler.lua new file mode 100644 index 00000000000..b9fef7d1813 --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/error-generator-pre/handler.lua @@ -0,0 +1,77 @@ +local BasePlugin = require "kong.plugins.base_plugin" + + +local error = error + + +local ErrorGeneratorPreHandler = BasePlugin:extend() + + +ErrorGeneratorPreHandler.PRIORITY = math.huge + + +function ErrorGeneratorPreHandler:new() + ErrorGeneratorPreHandler.super.new(self, "logger") +end + + +function ErrorGeneratorPreHandler:init_worker() + ErrorGeneratorPreHandler.super.init_worker(self) +end + + +function ErrorGeneratorPreHandler:certificate(conf) + ErrorGeneratorPreHandler.super.certificate(self) + + if conf.certificate then + error("[error-generator-pre] certificate") + end +end + + +function ErrorGeneratorPreHandler:rewrite(conf) + ErrorGeneratorPreHandler.super.rewrite(self) + + if conf.rewrite then + error("[error-generator-pre] rewrite") + end +end + + +function ErrorGeneratorPreHandler:access(conf) + ErrorGeneratorPreHandler.super.access(self) + + if conf.access then + error("[error-generator-pre] access") + end +end + + +function ErrorGeneratorPreHandler:header_filter(conf) + ErrorGeneratorPreHandler.super.header_filter(self) + + if conf.header_filter then + error("[error-generator-pre] header_filter") + end +end + + +function ErrorGeneratorPreHandler:body_filter(conf) + ErrorGeneratorPreHandler.super.body_filter(self) + + if conf.header_filter then + error("[error-generator-pre] body_filter") + end +end + + +function ErrorGeneratorPreHandler:log(conf) + ErrorGeneratorPreHandler.super.log(self) + + if conf.log then + error("[error-generator] body_filter") + end +end + + +return ErrorGeneratorPreHandler diff --git a/spec/fixtures/custom_plugins/kong/plugins/error-generator-pre/schema.lua b/spec/fixtures/custom_plugins/kong/plugins/error-generator-pre/schema.lua new file mode 100644 index 00000000000..b4b88bbb434 --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/error-generator-pre/schema.lua @@ -0,0 +1,10 @@ +return { + fields = { + certificate = { type = "boolean", required = false, default = false }, + rewrite = { type = "boolean", required = false, default = false }, + access = { type = "boolean", required = false, default = false }, + header_filter = { type = "boolean", required = false, default = false }, + body_filter = { type = "boolean", required = false, default = false }, + log = { type = "boolean", required = false, default = false }, + } +} diff --git a/spec/helpers.lua b/spec/helpers.lua index 599cf349534..beea799d133 100644 --- a/spec/helpers.lua +++ b/spec/helpers.lua @@ -1128,7 +1128,7 @@ local function kong_exec(cmd, env, pl_returns, env_vars) env.lua_package_path = env.lua_package_path .. ";" .. conf.lua_package_path if not env.plugins then - env.plugins = "bundled,dummy,cache,rewriter,error-handler-log" + env.plugins = "bundled,dummy,cache,rewriter,error-handler-log,error-generator-pre,error-generator-post" end -- build Kong environment variables diff --git a/t/01-pdk/08-response/12-get_source.t b/t/01-pdk/08-response/12-get_source.t index ea7c417a748..5bc542119dc 100644 --- a/t/01-pdk/08-response/12-get_source.t +++ b/t/01-pdk/08-response/12-get_source.t @@ -2,7 +2,7 @@ use warnings FATAL => 'all'; use Test::Nginx::Socket::Lua; use t::Util; -plan tests => repeat_each() * (blocks() * 3); +plan tests => repeat_each() * (blocks() * 3) - 3; run_tests(); @@ -75,3 +75,98 @@ GET /t X-Source: exit --- no_error_log [error] + + + +=== TEST 4: response.get_source() returns "error" when upstream timeouts +--- config + location = /t { + proxy_pass http://localhost:58252; + + header_filter_by_lua_block { + if ngx.status == 502 then + ngx.ctx.KONG_UNEXPECTED = true + end + + ngx.header.content_length = nil + } + + body_filter_by_lua_block { + local PDK = require "kong.pdk" + local pdk = PDK.new() + + ngx.arg[1] = "content source: " .. pdk.response.get_source() + ngx.arg[2] = true + } + } +--- request +GET /t +--- error_code: 502 +--- response_body chop +content source: error + + + +=== TEST 5: response.get_source() returns "error" when upstream timeouts even with KONG_PROXIED = true +--- config + location = /t { + access_by_lua_block { + ngx.ctx.KONG_PROXIED = true + } + + proxy_pass http://localhost:58252; + + header_filter_by_lua_block { + if ngx.status == 502 then + ngx.ctx.KONG_UNEXPECTED = true + end + + ngx.header.content_length = nil + } + + body_filter_by_lua_block { + local PDK = require "kong.pdk" + local pdk = PDK.new() + + ngx.arg[1] = "content source: " .. pdk.response.get_source() + ngx.arg[2] = true + } + } +--- request +GET /t +--- error_code: 502 +--- response_body chop +content source: error + + + +=== TEST 6: response.get_source() returns "error" when upstream timeouts even with KONG_EXITED = true +--- config + location = /t { + access_by_lua_block { + ngx.ctx.KONG_EXITED = true + } + + proxy_pass http://localhost:58252; + + header_filter_by_lua_block { + if ngx.status == 502 then + ngx.ctx.KONG_UNEXPECTED = true + end + + ngx.header.content_length = nil + } + + body_filter_by_lua_block { + local PDK = require "kong.pdk" + local pdk = PDK.new() + + ngx.arg[1] = "content source: " .. pdk.response.get_source() + ngx.arg[2] = true + } + } +--- request +GET /t +--- error_code: 502 +--- response_body chop +content source: error