From 25053ce869af29a114f075d3097755007fa51a4b Mon Sep 17 00:00:00 2001 From: thefosk Date: Mon, 3 Aug 2015 13:57:01 -0700 Subject: [PATCH] Adding "preserve_host" flag to APIs, closes #444 --- .../cassandra/2015-08-21-813213_0.5.0.lua | 17 ++++++++++++++ kong.yml | 4 +++- kong/dao/schemas/apis.lua | 3 ++- kong/resolver/access.lua | 8 +++++-- spec/integration/proxy/api_resolver_spec.lua | 23 ++++++++++++++++++- 5 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 database/migrations/cassandra/2015-08-21-813213_0.5.0.lua diff --git a/database/migrations/cassandra/2015-08-21-813213_0.5.0.lua b/database/migrations/cassandra/2015-08-21-813213_0.5.0.lua new file mode 100644 index 000000000000..c30544821c72 --- /dev/null +++ b/database/migrations/cassandra/2015-08-21-813213_0.5.0.lua @@ -0,0 +1,17 @@ +local Migration = { + name = "2015-08-21-813213_0.5.0", + + up = function(options) + return [[ + ALTER TABLE apis ADD preserve_host boolean; + ]] + end, + + down = function(options) + return [[ + ALTER TABLE apis DROP preserve_host; + ]] + end +} + +return Migration diff --git a/kong.yml b/kong.yml index 91b5c5b423ee..ab0f38ba1063 100644 --- a/kong.yml +++ b/kong.yml @@ -138,7 +138,8 @@ nginx: | location / { default_type 'text/plain'; - # This property will be used later by proxy_pass + # These properties will be used later by proxy_pass + set $backend_host nil; set $backend_url nil; # Authenticate the user and load the API info @@ -148,6 +149,7 @@ nginx: | proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $backend_host; proxy_pass $backend_url; proxy_pass_header Server; diff --git a/kong/dao/schemas/apis.lua b/kong/dao/schemas/apis.lua index 67c66a1990b9..e86f2704511a 100644 --- a/kong/dao/schemas/apis.lua +++ b/kong/dao/schemas/apis.lua @@ -83,6 +83,7 @@ return { regex = "([a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*)" }, path = { type = "string", unique = true, func = check_path }, strip_path = { type = "boolean" }, - target_url = { type = "string", required = true, func = validate_target_url } + target_url = { type = "string", required = true, func = validate_target_url }, + preserve_host = { type = "boolean" } } } diff --git a/kong/resolver/access.lua b/kong/resolver/access.lua index 8345de0eefe0..47724931d45b 100644 --- a/kong/resolver/access.lua +++ b/kong/resolver/access.lua @@ -176,8 +176,12 @@ function _M.execute(conf) -- Setting the backend URL for the proxy_pass directive ngx.var.backend_url = get_backend_url(api)..request_uri - ngx.req.set_header("Host", get_host_from_url(ngx.var.backend_url)) - + if api.preserve_host then + ngx.var.backend_host = ngx.req.get_headers()["host"] + else + ngx.var.backend_host = get_host_from_url(ngx.var.backend_url) + end + ngx.ctx.api = api end diff --git a/spec/integration/proxy/api_resolver_spec.lua b/spec/integration/proxy/api_resolver_spec.lua index cb0546b27ece..8f3ffc8d84ef 100644 --- a/spec/integration/proxy/api_resolver_spec.lua +++ b/spec/integration/proxy/api_resolver_spec.lua @@ -9,6 +9,7 @@ local http_client = require "kong.tools.http_client" local STUB_GET_URL = spec_helper.STUB_GET_URL local STUB_GET_SSL_URL = spec_helper.STUB_GET_SSL_URL +local PROXY_URL = spec_helper.PROXY_URL -- Parses an SSL certificate returned by LuaSec local function parse_cert(cert) @@ -32,7 +33,9 @@ describe("Resolver", function() {name = "tests stripped path resolver with pattern characters", target_url = "http://mockbin.com", path = "/mockbin-with-pattern/", strip_path = true}, {name = "tests deep path resolver", target_url = "http://mockbin.com", path = "/deep/path/", strip_path = true}, {name = "tests wildcard subdomain", target_url = "http://mockbin.com/status/200", public_dns = "*.wildcard.com"}, - {name = "tests wildcard subdomain 2", target_url = "http://mockbin.com/status/201", public_dns = "wildcard.*"} + {name = "tests wildcard subdomain 2", target_url = "http://mockbin.com/status/201", public_dns = "wildcard.*"}, + {name = "tests preserve host", public_dns = "httpbin-nopreserve.com", target_url = "http://httpbin.org"}, + {name = "tests preserve host 2", public_dns = "httpbin-preserve.com", target_url = "http://httpbin.org", preserve_host = true} }, plugin_configuration = { { name = "keyauth", value = {key_names = {"apikey"} }, __api = 2 } @@ -192,4 +195,22 @@ describe("Resolver", function() end) end) + + describe("Preseve Host", function() + + it("should not preserve the host (default behavior)", function() + local response, status = http_client.get(PROXY_URL.."/get", nil, { host = "httpbin-nopreserve.com"}) + assert.equal(200, status) + local parsed_response = cjson.decode(response) + assert.equal("httpbin.org", parsed_response.headers["Host"]) + end) + + it("should preserve the host (default behavior)", function() + local response, status = http_client.get(PROXY_URL.."/get", nil, { host = "httpbin-preserve.com"}) + assert.equal(200, status) + local parsed_response = cjson.decode(response) + assert.equal("httpbin-preserve.com", parsed_response.headers["Host"]) + end) + + end) end)