Skip to content

Commit

Permalink
feat(core) add ability to inject X-Kong-Upstream-Status header
Browse files Browse the repository at this point in the history
X-Kong-Upstream-Status header returns the status
code returned by the upstream API.
This header is disabled by default and can be enabled
by adding it to `headers` config property in kong.conf.
  • Loading branch information
hbagdi committed Apr 28, 2018
1 parent da4e36b commit 41df399
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 0 deletions.
1 change: 1 addition & 0 deletions kong/conf_loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ local header_key_to_name = {
[string.lower(headers.SERVER)] = headers.SERVER,
[string.lower(headers.PROXY_LATENCY)] = headers.PROXY_LATENCY,
[string.lower(headers.UPSTREAM_LATENCY)] = headers.UPSTREAM_LATENCY,
[string.lower(headers.UPSTREAM_STATUS)] = headers.UPSTREAM_STATUS,
}

local PREFIX_PATHS = {
Expand Down
1 change: 1 addition & 0 deletions kong/constants.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ return {
HOST_OVERRIDE = "X-Host-Override",
PROXY_LATENCY = "X-Kong-Proxy-Latency",
UPSTREAM_LATENCY = "X-Kong-Upstream-Latency",
UPSTREAM_STATUS = "X-Kong-Upstream-Status",
CONSUMER_ID = "X-Consumer-ID",
CONSUMER_CUSTOM_ID = "X-Consumer-Custom-ID",
CONSUMER_USERNAME = "X-Consumer-Username",
Expand Down
8 changes: 8 additions & 0 deletions kong/runloop/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -687,12 +687,20 @@ return {
},
header_filter = {
before = function(ctx)
local var = ngx.var
local header = ngx.header

if ctx.KONG_PROXIED then
local now = get_now()
-- time spent waiting for a response from upstream
ctx.KONG_WAITING_TIME = now - ctx.KONG_ACCESS_ENDED_AT
ctx.KONG_HEADER_FILTER_STARTED_AT = now
end

local upstream_header = constants.HEADERS.UPSTREAM_STATUS
if singletons.configuration.headers[upstream_header] then
header[upstream_header] = string.match(var.upstream_status, "(%S+)$")
end
end,
after = function(ctx)
local header = ngx.header
Expand Down
142 changes: 142 additions & 0 deletions spec/02-integration/05-proxy/14-upstream-status-header_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
local helpers = require "spec.helpers"
local constants = require "kong.constants"

describe(constants.HEADERS.UPSTREAM_STATUS .. " header", function()
local client

setup(function()
local bp = helpers.get_db_utils()
assert(helpers.dao:run_migrations())

local service = bp.services:insert {
host = helpers.mock_upstream_host,
port = helpers.mock_upstream_port,
protocol = helpers.mock_upstream_protocol,
}
assert(service)

local route1 = bp.routes:insert {
protocols = { "http" },
service = service,
paths = { "/foo" },
}
assert(route1)

local route2 = bp.routes:insert {
protocols = { "http" },
service = service,
paths = { "/bar" },
}
assert(route2)

bp.plugins:insert({
name = "dummy",
route_id = route2.id,
config = {
resp_code = 500,
}
})
end)


describe("should be same as upstream status code", function()
setup(function()
assert(helpers.start_kong {
headers = "server_tokens,latency_tokens,x-kong-upstream-status",
custom_plugins = "dummy",
nginx_conf = "spec/fixtures/custom_nginx.template",
})
client = helpers.proxy_client()
end)

teardown(function()
if client then
client:close()
end
helpers.stop_kong(nil, nil, true)
end)

it("when no plugin changes status code", function()
local res = assert(client:send {
method = "GET",
path = "/foo",
headers = {
host = helpers.mock_upstream_host,
}
})
assert.res_status(200, res)
assert.equal('200', res.headers[constants.HEADERS.UPSTREAM_STATUS])
end)

it("when a plugin changes status code", function()
local res = assert(client:send {
method = "GET",
host = helpers.mock_upstream_host,
path = "/bar",
headers = {
["Host"] = helpers.mock_upstream_host,
}
})
assert.res_status(500, res)
assert.equal('200', res.headers[constants.HEADERS.UPSTREAM_STATUS])
end)
end)

describe("is not injected with default configuration", function()
setup(function()
assert(helpers.start_kong{
nginx_conf = "spec/fixtures/custom_nginx.template",
})
end)

teardown(function()
if client then
client:close()
end
helpers.stop_kong(nil, nil, true)
end)

it("", function()
local client = helpers.proxy_client()
local res = assert(client:send {
method = "GET",
path = "/foo",
headers = {
host = helpers.mock_upstream_host,
}
})
assert.res_status(200, res)
assert.is_nil(res.headers[constants.HEADERS.UPSTREAM_STATUS])
end)
end)

describe("is injected with configuration [headers=X-Kong-Upstream-Status]", function()

setup(function()
assert(helpers.start_kong{
nginx_conf = "spec/fixtures/custom_nginx.template",
headers="X-Kong-Upstream-Status",
})
end)

teardown(function()
if client then
client:close()
end
helpers.stop_kong(nil, nil, true)
end)

it("", function()
local client = helpers.proxy_client()
local res = assert(client:send {
method = "GET",
path = "/foo",
headers = {
host = helpers.mock_upstream_host,
}
})
assert.res_status(200, res)
assert('200', res.headers[constants.HEADERS.UPSTREAM_STATUS])
end)
end)
end)
4 changes: 4 additions & 0 deletions spec/fixtures/custom_plugins/kong/plugins/dummy/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ function DummyHandler:header_filter(conf)

ngx.header["Dummy-Plugin"] = conf.resp_header_value

if conf.resp_code then
ngx.status = conf.resp_code
end

if conf.append_body then
ngx.header["Content-Length"] = nil
end
Expand Down
1 change: 1 addition & 0 deletions spec/fixtures/custom_plugins/kong/plugins/dummy/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ return {
fields = {
resp_header_value = { type = "string", default = "1" },
append_body = { type = "string" },
resp_code = { type = "number" },
}
}

0 comments on commit 41df399

Please sign in to comment.