From f04232e2a5a8939b8cd5e6cc59c923c6ad1b2197 Mon Sep 17 00:00:00 2001 From: thefosk Date: Tue, 26 Apr 2016 16:56:09 -0700 Subject: [PATCH] Closing #1150 --- kong/constants.lua | 4 +- kong/core/resolver.lua | 2 + spec/integration/05-proxy/resolver_spec.lua | 57 +++++++++++++++++---- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/kong/constants.lua b/kong/constants.lua index c8b6fd0f75a..35e0f5d15ea 100644 --- a/kong/constants.lua +++ b/kong/constants.lua @@ -26,7 +26,9 @@ return { CREDENTIAL_USERNAME = "X-Credential-Username", RATELIMIT_LIMIT = "X-RateLimit-Limit", RATELIMIT_REMAINING = "X-RateLimit-Remaining", - CONSUMER_GROUPS = "X-Consumer-Groups" + CONSUMER_GROUPS = "X-Consumer-Groups", + FORWARDED_HOST = "X-Forwarded-Host", + FORWARDED_PREFIX = "X-Forwarded-Prefix" }, RATELIMIT = { PERIODS = { diff --git a/kong/core/resolver.lua b/kong/core/resolver.lua index 92b7721fdea..8630c73c213 100644 --- a/kong/core/resolver.lua +++ b/kong/core/resolver.lua @@ -207,6 +207,7 @@ local function find_api(uri, headers) api, matched_host, hosts_list = _M.find_api_by_request_host(headers, apis_dics) -- If it was found by Host, return if api then + ngx.req.set_header(constants.HEADERS.FORWARDED_HOST, matched_host) return nil, api, matched_host, hosts_list end @@ -240,6 +241,7 @@ function _M.execute(request_uri, request_headers) -- If API was retrieved by request_path and the request_path needs to be stripped if strip_request_path_pattern and api.strip_request_path then uri = _M.strip_request_path(uri, strip_request_path_pattern, url_has_path(upstream_url)) + ngx.req.set_header(constants.HEADERS.FORWARDED_PREFIX, api.request_path) end upstream_url = upstream_url..uri diff --git a/spec/integration/05-proxy/resolver_spec.lua b/spec/integration/05-proxy/resolver_spec.lua index be281818f48..29ffb99d7be 100644 --- a/spec/integration/05-proxy/resolver_spec.lua +++ b/spec/integration/05-proxy/resolver_spec.lua @@ -44,7 +44,8 @@ describe("Resolver", function() {name = "tests-trailing-slash-path3", request_path = "/test-trailing-slash3", strip_request_path = true, upstream_url = "http://www.mockbin.org"}, {name = "tests-trailing-slash-path4", request_path = "/test-trailing-slash4", strip_request_path = true, upstream_url = "http://www.mockbin.org/"}, {name = "tests-deep-path", request_path = "/hello/world", strip_request_path = true, upstream_url = "http://mockbin.com"}, - {name = "tests-deep-path-two", request_path = "/hello/world/wot", strip_request_path = true, upstream_url = "http://httpbin.org"} + {name = "tests-deep-path-two", request_path = "/hello/world/wot", strip_request_path = true, upstream_url = "http://httpbin.org"}, + {name = "tests-request_path-resolver2", upstream_url = "http://mockbin.com", request_path = "/headers"} }, plugin = { {name = "key-auth", config = {key_names = {"apikey"} }, __api = 2} @@ -63,8 +64,10 @@ describe("Resolver", function() local response, status, headers = http_client.get(spec_helper.STUB_GET_URL, nil, {host = "foo.com"}) assert.equal(404, status) assert.equal('{"request_path":"\\/request","message":"API not found with these values","request_host":["foo.com"]}\n', response) - assert.falsy(headers[constants.HEADERS.PROXY_LATENCY]) - assert.falsy(headers[constants.HEADERS.UPSTREAM_LATENCY]) + assert.falsy(headers[constants.HEADERS.PROXY_LATENCY:lower()]) + assert.falsy(headers[constants.HEADERS.UPSTREAM_LATENCY:lower()]) + assert.falsy(headers[constants.HEADERS.FORWARDED_HOST:lower()]) + assert.falsy(headers[constants.HEADERS.FORWARDED_PREFIX:lower()]) end) end) @@ -114,8 +117,12 @@ describe("Resolver", function() describe("Existing API", function() describe("By Host", function() it("should proxy when the API is in Kong", function() - local _, status = http_client.get(STUB_GET_URL, nil, {host = "mockbin.com"}) + local response, status = http_client.get(STUB_GET_URL, nil, {host = "mockbin.com"}) assert.equal(200, status) + + local body = cjson.decode(response) + assert.equal("mockbin.com", body.headers[constants.HEADERS.FORWARDED_HOST:lower()]) + assert.falsy(body.headers[constants.HEADERS.FORWARDED_PREFIX:lower()]) end) it("should proxy when the Host header is not trimmed", function() local _, status = http_client.get(STUB_GET_URL, nil, {host = " mockbin.com "}) @@ -126,8 +133,12 @@ describe("Resolver", function() assert.equal(200, status) end) it("should proxy when the Host header contains a port", function() - local _, status = http_client.get(STUB_GET_URL, nil, {host = "mockbin.com:80"}) + local response, status = http_client.get(STUB_GET_URL, nil, {host = "mockbin.com:80"}) assert.equal(200, status) + + local body = cjson.decode(response) + assert.equal("mockbin.com", body.headers[constants.HEADERS.FORWARDED_HOST:lower()]) + assert.falsy(body.headers[constants.HEADERS.FORWARDED_PREFIX:lower()]) end) describe("with wildcard subdomain", function() it("should proxy when the request_host is a wildcard subdomain", function() @@ -150,6 +161,25 @@ describe("Resolver", function() local _, status = http_client.get(spec_helper.PROXY_URL.."/mockbin") assert.equal(200, status) + + + local response, status = http_client.get(spec_helper.PROXY_URL.."/mockbin/request") + assert.equal(200, status) + + local body = cjson.decode(response) + assert.equal("/mockbin", body.headers[constants.HEADERS.FORWARDED_PREFIX:lower()]) + assert.falsy(body.headers[constants.HEADERS.FORWARDED_HOST:lower()]) + + -- There should be no X-Forwarded-Prefix if no prefix is being stripped + local response, status = http_client.get(spec_helper.PROXY_URL.."/headers") + assert.equal(200, status) + local body = cjson.decode(response) + assert.falsy(body.headers[constants.HEADERS.FORWARDED_HOST:lower()]) + for _, v in ipairs(body.headers) do + if v.name == constants.HEADERS.FORWARDED_PREFIX:lower() then + error(constants.HEADERS.FORWARDED_PREFIX.." should not be set") + end + end end) it("should not proxy when the request_path does not match the start of the request_uri", function() local response, status = http_client.get(spec_helper.PROXY_URL.."/somerequest_path/status/200") @@ -161,6 +191,13 @@ describe("Resolver", function() it("should proxy when the request_path has a deep level", function() local _, status = http_client.get(spec_helper.PROXY_URL.."/deep/request_path/status/200") assert.equal(200, status) + + local response, status = http_client.get(spec_helper.PROXY_URL.."/deep/request_path/request") + assert.equal(200, status) + + local body = cjson.decode(response) + assert.equal("/deep/request_path", body.headers[constants.HEADERS.FORWARDED_PREFIX:lower()]) + assert.falsy(body.headers[constants.HEADERS.FORWARDED_HOST:lower()]) end) it("should not care about querystring parameters", function() local _, status = http_client.get(spec_helper.PROXY_URL.."/mockbin?foo=bar") @@ -277,27 +314,27 @@ describe("Resolver", function() it("should leave percent-encoded values in URI untouched", function() local response, status = http_client.get(spec_helper.STUB_GET_URL.."/hello%2Fworld", {}, {host = "mockbin-uri.com"}) assert.equal(200, status) - assert.equal("http://mockbin.org/request/hello%2fworld", cjson.decode(response).url) + assert.equal("http://mockbin-uri.com/request/hello%2fworld", cjson.decode(response).url) end) it("should leave untouched percent-encoded values in querystring", function() local response, status = http_client.get(spec_helper.STUB_GET_URL, {foo = "abc%7Cdef%2c%20world"}, {host = "mockbin-uri.com"}) assert.equal(200, status) - assert.equal("http://mockbin.org/request?foo=abc%7cdef%2c%20world", cjson.decode(response).url) + assert.equal("http://mockbin-uri.com/request?foo=abc%7cdef%2c%20world", cjson.decode(response).url) end) it("should leave untouched percent-encoded keys in querystring", function() local response, status = http_client.get(spec_helper.STUB_GET_URL, {["hello%20world"] = "foo"}, {host = "mockbin-uri.com"}) assert.equal(200, status) - assert.equal("http://mockbin.org/request?hello%20world=foo", cjson.decode(response).url) + assert.equal("http://mockbin-uri.com/request?hello%20world=foo", cjson.decode(response).url) end) it("should percent-encoded keys in querystring", function() local response, status = http_client.get(spec_helper.STUB_GET_URL, {["hello world"] = "foo"}, {host = "mockbin-uri.com"}) assert.equal(200, status) - assert.equal("http://mockbin.org/request?hello%20world=foo", cjson.decode(response).url) + assert.equal("http://mockbin-uri.com/request?hello%20world=foo", cjson.decode(response).url) end) it("should percent-encoded keys in querystring", function() local response, status = http_client.get(spec_helper.STUB_GET_URL, {foo = "abc|def, world"}, {host = "mockbin-uri.com"}) assert.equal(200, status) - assert.equal("http://mockbin.org/request?foo=abc%7cdef%2c%20world", cjson.decode(response).url) + assert.equal("http://mockbin-uri.com/request?foo=abc%7cdef%2c%20world", cjson.decode(response).url) end) end) end)