Skip to content

Commit

Permalink
tests(proxy) rewrite preserve_hosts suite
Browse files Browse the repository at this point in the history
* tests(fixtures) udpate custom Nginx template

Updated to use the latest Kong 0.10.0 Nginx template configuration.

* tests(helpers) introduce 'nginx_conf' option

`helpers.start_kong()` now receives an `nginx_conf` option, similar to
the CLI's `--nginx-conf`, which makes the test instance start with a
custom Nginx template configuration.

* tests(proxy) rewrite 'preserve_host' suite

We'd rather not depend on any third-party service for testing such a
behavior since `preserve_host` typically creates invalid HTTP requests
to upstream services.

Here we introduce custom Nginx locations that allow us to mimic (and
improve) httpbin.org behavior locally. The long term goal is to
transition all of the tests relying on httpbin.org to such local code,
so this is a step forwards, regardless of the testing framework or Nginx
configuration handling we might have in the future.
  • Loading branch information
thibaultcha authored Mar 22, 2017
1 parent 209176a commit 5d86d09
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 55 deletions.
105 changes: 60 additions & 45 deletions spec/02-integration/05-proxy/01-router_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -241,73 +241,88 @@ describe("Router", function()
{
name = "api-1",
preserve_host = true,
upstream_url = "http://httpbin.org",
upstream_url = "http://localhost:9999/headers-inspect",
hosts = "preserved.com",
},
{
name = "api-2",
preserve_host = false,
upstream_url = "http://httpbin.org",
upstream_url = "http://localhost:9999/headers-inspect",
hosts = "discarded.com",
}
},
}

assert(helpers.start_kong())
assert(helpers.start_kong {
nginx_conf = "spec/fixtures/custom_nginx.template",
})
end)

teardown(function()
helpers.stop_kong()
end)

it("preserves downstream host if enabled", function()
local res = assert(client:send {
method = "GET",
path = "/get",
headers = { ["Host"] = "preserved.com" },
})
describe(" = false (default)", function()
it("uses hostname from upstream_url", function()
local res = assert(client:send {
method = "GET",
path = "/get",
headers = { ["Host"] = "discarded.com" },
})

assert.res_status(200, res)
local json = cjson.decode((res:read_body()))
assert.equal("preserved.com", json.headers.Host)
end)
local body = assert.res_status(200, res)
local json = cjson.decode(body)
assert.matches("localhost", json.host, nil, true) -- not testing :port
end)

pending("preserves downstream host+port if enabled", function()
-- pending because httpbin.org seems to not return the exact header
-- but a parsed one, with the port stripped.
local res = assert(client:send {
method = "GET",
path = "/get",
headers = { ["Host"] = "preserved.com:80" },
})
it("uses port value from upstream_url if not default", function()
local res = assert(client:send {
method = "GET",
path = "/get",
headers = { ["Host"] = "discarded.com" },
})

assert.res_status(200, res)
local json = cjson.decode((res:read_body()))
assert.equal("preserved.com:80", json.headers.Host)
local body = assert.res_status(200, res)
local json = cjson.decode(body)
assert.matches(":9999", json.host, nil, true) -- not testing hostname
end)
end)

pending("preserves downstream host+non_default_port if enabled", function()
-- pending because httpbin.org seems to not return the exact header
-- but a parsed one, with the port stripped.
local res = assert(client:send {
method = "GET",
path = "/get",
headers = { ["Host"] = "preserved.com:123" },
})
describe(" = true", function()
it("forwards request Host", function()
local res = assert(client:send {
method = "GET",
path = "/",
headers = { ["Host"] = "preserved.com" },
})

assert.res_status(200, res)
local json = cjson.decode((res:read_body()))
assert.equal("preserved.com:123", json.headers.Host)
end)
local body = assert.res_status(200, res)
local json = cjson.decode(body)
assert.equal("preserved.com", json.host)
end)

it("discards downstream host if disabled", function()
local res = assert(client:send {
method = "GET",
path = "/get",
headers = { ["Host"] = "discarded.com" },
})
it("forwards request Host:Port even if port is default", function()
local res = assert(client:send {
method = "GET",
path = "/get",
headers = { ["Host"] = "preserved.com:80" },
})

local body = assert.res_status(200, res)
local json = cjson.decode(body)
assert.equal("preserved.com:80", json.host)
end)

assert.response(res).has.status(200)
assert.equal("httpbin.org", assert.request(res).has.header("Host"))
it("forwards request Host:Port if port isn't default", function()
local res = assert(client:send {
method = "GET",
path = "/get",
headers = { ["Host"] = "preserved.com:123" },
})

local body = assert.res_status(200, res)
local json = cjson.decode(body)
assert.equal("preserved.com:123", json.host)
end)
end)
end)

Expand Down
83 changes: 74 additions & 9 deletions spec/fixtures/custom_nginx.template
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,23 @@ http {
charset UTF-8;

error_log logs/error.log ${{LOG_LEVEL}};
access_log logs/access.log;

> if anonymous_reports then
${{SYSLOG_REPORTS}}
> end

> if nginx_optimizations then
>-- send_timeout 60s; # default value
>-- keepalive_timeout 75s; # default value
>-- client_body_timeout 60s; # default value
>-- client_header_timeout 60s; # default value
>-- tcp_nopush on; # disabled until benchmarked
>-- proxy_buffer_size 128k; # disabled until benchmarked
>-- proxy_buffers 4 256k; # disabled until benchmarked
>-- proxy_busy_buffers_size 256k; # disabled until benchmarked
>-- reset_timedout_connection on; # disabled until benchmarked
> end

client_max_body_size 0;
proxy_ssl_server_name on;
underscores_in_headers on;
Expand All @@ -29,18 +40,22 @@ http {
lua_package_path '${{LUA_PACKAGE_PATH}};;';
lua_package_cpath '${{LUA_PACKAGE_CPATH}};;';
lua_code_cache ${{LUA_CODE_CACHE}};
lua_socket_pool_size ${{LUA_SOCKET_POOL_SIZE}};
lua_max_running_timers 4096;
lua_max_pending_timers 16384;
lua_shared_dict kong 4m;
lua_shared_dict cache ${{MEM_CACHE_SIZE}};
lua_shared_dict cassandra 1m;
lua_shared_dict cassandra_prepared 5m;
lua_shared_dict cache_locks 100k;
lua_shared_dict process_events 1m;
lua_shared_dict cassandra 5m;
lua_socket_log_errors off;
> if lua_ssl_trusted_certificate then
lua_ssl_trusted_certificate '${{lua_ssl_trusted_certificate}}';
lua_ssl_trusted_certificate '${{LUA_SSL_TRUSTED_CERTIFICATE}}';
lua_ssl_verify_depth ${{LUA_SSL_VERIFY_DEPTH}};
> end

init_by_lua_block {
require 'resty.core'
kong = require 'kong'
kong.init()
}
Expand All @@ -49,35 +64,62 @@ http {
kong.init_worker()
}

proxy_next_upstream_tries 999;

upstream kong_upstream {
server 0.0.0.1;
balancer_by_lua_block {
kong.balancer()
}
keepalive ${{UPSTREAM_KEEPALIVE}};
}

map $http_upgrade $upstream_connection {
default keep-alive;
websocket upgrade;
}

map $http_upgrade $upstream_upgrade {
default '';
websocket websocket;
}

server {
server_name kong;
listen ${{PROXY_LISTEN}};
error_page 500 502 503 504 /50x;
error_page 404 408 411 412 413 414 417 /kong_error_handler;
error_page 500 502 503 504 /kong_error_handler;

access_log logs/access.log;

> if ssl then
listen ${{PROXY_LISTEN_SSL}} ssl;
ssl_certificate ${{SSL_CERT}};
ssl_certificate_key ${{SSL_CERT_KEY}};
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_certificate_by_lua_block {
kong.ssl_certificate()
}
> end

location / {
set $upstream_host nil;
set $upstream_url nil;
set $upstream_scheme nil;

access_by_lua_block {
kong.access()
}

proxy_http_version 1.1;
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 $upstream_host;
proxy_set_header Upgrade $upstream_upgrade;
proxy_set_header Connection $upstream_connection;

proxy_pass_header Server;
proxy_pass $upstream_url;
proxy_pass $upstream_scheme://kong_upstream;

header_filter_by_lua_block {
kong.header_filter()
Expand All @@ -92,7 +134,7 @@ http {
}
}

location = /50x {
location = /kong_error_handler {
internal;
content_by_lua_block {
require('kong.core.error_handlers')(ngx)
Expand All @@ -104,13 +146,23 @@ http {
server_name kong_admin;
listen ${{ADMIN_LISTEN}};

access_log logs/admin_access.log;

client_max_body_size 10m;
client_body_buffer_size 10m;

> if admin_ssl then
listen ${{ADMIN_LISTEN_SSL}} ssl;
ssl_certificate ${{ADMIN_SSL_CERT}};
ssl_certificate_key ${{ADMIN_SSL_CERT_KEY}};
ssl_protocols TLSv1.1 TLSv1.2;
> end

location / {
default_type application/json;
content_by_lua_block {
ngx.header['Access-Control-Allow-Origin'] = '*'
ngx.header['Access-Control-Allow-Credentials'] = 'false'
if ngx.req.get_method() == 'OPTIONS' then
ngx.header['Access-Control-Allow-Methods'] = 'GET,HEAD,PUT,PATCH,POST,DELETE'
ngx.header['Access-Control-Allow-Headers'] = 'Content-Type'
Expand Down Expand Up @@ -139,5 +191,18 @@ http {
location /custom_server_path {
return 200;
}

location /headers-inspect {
content_by_lua_block {
local cjson = require "cjson"

local headers = ngx.req.get_headers()
local json = cjson.encode(headers)

ngx.status = 200
ngx.say(json)
ngx.exit(200)
}
}
}
}
7 changes: 6 additions & 1 deletion spec/helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,12 @@ return {
local ok, err = prepare_prefix(env.prefix)
if not ok then return nil, err end

return kong_exec("start --conf "..TEST_CONF_PATH, env)
local nginx_conf = ""
if env.nginx_conf then
nginx_conf = " --nginx-conf " .. env.nginx_conf
end

return kong_exec("start --conf " .. TEST_CONF_PATH .. nginx_conf, env)
end,
stop_kong = function(prefix, preserve_prefix)
prefix = prefix or conf.prefix
Expand Down

0 comments on commit 5d86d09

Please sign in to comment.