Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[upstream] support path in the upstream url #905

Merged
merged 1 commit into from
Sep 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added

- Prometheus metrics for the 3scale batching policy [PR #902](https://github.com/3scale/apicast/pull/902)
- Support for path in the upstream URL [PR #905](https://github.com/3scale/apicast/pull/905)

## [3.3.0-cr1] - 2018-09-14

Expand Down
2 changes: 1 addition & 1 deletion gateway/src/apicast/http_proxy.lua
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ local function absolute_url(uri)
uri.scheme,
host,
port,
uri.path or ngx.var.uri or ''
uri.path or ''
)
end

Expand Down
17 changes: 16 additions & 1 deletion gateway/src/apicast/upstream.lua
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,21 @@ function _M:port()
return self.uri.port or resty_url.default_port(self.uri.scheme)
end

local root_uri = {
['/'] = true,
[''] = true,
}

local function prefix_path(prefix)
local uri = ngx.var.uri or ''

if root_uri[uri] then return prefix end

uri = resty_url.join(prefix, uri)

return uri
end

--- Rewrite request Host header to what is provided in the argument or in the URL.
function _M:rewrite_request()
local uri = self.uri
Expand All @@ -126,7 +141,7 @@ function _M:rewrite_request()
ngx.req.set_header('Host', self.host or uri.host)

if uri.path then
ngx.req.set_uri(uri.path)
ngx.req.set_uri(prefix_path(uri.path))
end

if uri.query then
Expand Down
1 change: 1 addition & 0 deletions gateway/src/resty/http_ng/backend/ngx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ function backend.resolver()
ngx.req.set_header(name, headers[name])
end

ngx.req.set_uri('/') -- reset the original PROXY_LOCATION path
ngx.var.connection_header = headers.connection
ngx.var.host_header = headers.host
ngx.var.options = headers['3scale-options']
Expand Down
32 changes: 32 additions & 0 deletions spec/upstream_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,38 @@ describe('Upstream', function()
assert.spy(ngx.req.set_uri).was_called_with('/test-path')
end)

for url, path in pairs({
['http://example.com'] = '/',
['http://example.com/path'] = '/path',
['http://example.com/path/'] = '/path/',
['http://example.com/path/foo'] = '/path/foo',
['http://example.com/path/foo/'] = '/path/foo/',
['http://example.com/path?test=value/'] = '/path',
}) do
it(('/ uses path %s for upstream %s'):format(path, url), function()
ngx.var.uri = '/'
local upstream = Upstream.new(url)
upstream:rewrite_request()
assert.same(path, ngx.var.uri)
end)
end

for url, path in pairs({
['http://example.com'] = '/test',
['http://example.com/path'] = '/path/test',
['http://example.com/path/'] = '/path/test',
['http://example.com/path/foo'] = '/path/foo/test',
['http://example.com/path/foo/'] = '/path/foo/test',
['http://example.com/path?test=value/'] = '/path/test',
}) do
it(('/test uses path %s for upstream %s'):format(path, url), function()
ngx.var.uri = '/test'
local upstream = Upstream.new(url)
upstream:rewrite_request()
assert.same(path, ngx.var.uri)
end)
end

it('sets request query params to the upstream query params', function()
assert(Upstream.new('http://example.com/?query=param')):rewrite_request()

Expand Down
34 changes: 34 additions & 0 deletions t/apicast-blackbox.t
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,37 @@ location /transactions/authrep.xml {
--- no_error_log
[error]
--- user_files fixture=tls.pl eval



=== TEST 4: api backend gets the request on its subpath
The request url is concatenated with the api backend url.
--- configuration
{
"services": [
{
"id": 42,
"backend_version": 1,
"proxy": {
"api_backend": "http://test:$TEST_NGINX_SERVER_PORT/foo",
"proxy_rules": [
{ "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 2 }
]
}
}
]
}
--- backend
location /transactions/authrep.xml {
echo 'ok';
}
--- upstream
location / {
echo 'path: $uri';
}
--- request
GET /bar?user_key=value
--- response_body
path: /foo/bar
--- no_error_log
[error]
8 changes: 4 additions & 4 deletions t/apicast-caching.t
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Two services can exist together and are split by their hostname.
backend_authentication_type = 'service_token',
backend_authentication_value = 'service-one',
proxy = {
api_backend = "http://127.0.0.1:$TEST_NGINX_SERVER_PORT/api-backend/one/",
api_backend = "http://127.0.0.1:$TEST_NGINX_SERVER_PORT/api-backend/foo/",
hosts = { 'one' },
proxy_rules = {
{ pattern = '/', http_method = 'GET', metric_system_name = 'hits', delta = 1 }
Expand All @@ -89,7 +89,7 @@ Two services can exist together and are split by their hostname.
backend_authentication_type = 'service_token',
backend_authentication_value = 'service-two',
proxy = {
api_backend = "http://127.0.0.1:$TEST_NGINX_SERVER_PORT/api-backend/two/",
api_backend = "http://127.0.0.1:$TEST_NGINX_SERVER_PORT/api-backend/bar/",
hosts = { 'two' },
proxy_rules = {
{ pattern = '/', http_method = 'GET', metric_system_name = 'hits', delta = 2 }
Expand Down Expand Up @@ -135,8 +135,8 @@ Two services can exist together and are split by their hostname.
--- request
GET /t
--- response_body
yay, api backend: /one/
yay, api backend: /two/
yay, api backend: /foo/one
yay, api backend: /bar/two
--- error_code: 200
--- no_error_log
[error]
Expand Down
8 changes: 4 additions & 4 deletions t/apicast-path-routing.t
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ env APICAST_PATH_ROUTING;
id = 42,
backend_version = 1,
proxy = {
api_backend = "http://127.0.0.1:$TEST_NGINX_SERVER_PORT/api-backend/one/",
api_backend = "http://127.0.0.1:$TEST_NGINX_SERVER_PORT/api-backend/foo/",
hosts = { 'same' },
backend_authentication_type = 'service_token',
backend_authentication_value = 'service-one',
Expand All @@ -35,7 +35,7 @@ env APICAST_PATH_ROUTING;
id = 21,
backend_version = 2,
proxy = {
api_backend = "http://127.0.0.1:$TEST_NGINX_SERVER_PORT/api-backend/two/",
api_backend = "http://127.0.0.1:$TEST_NGINX_SERVER_PORT/api-backend/bar/",
hosts = { 'same' },
backend_authentication_type = 'service_token',
backend_authentication_value = 'service-two',
Expand Down Expand Up @@ -71,8 +71,8 @@ env APICAST_PATH_ROUTING;
--- request
GET /t
--- response_body
yay, api backend: /one/
yay, api backend: /two/
yay, api backend: /foo/one
yay, api backend: /bar/two
--- error_code: 200
--- grep_error_log eval: qr/apicast cache (?:hit|miss|write) key: [^,\s]+/
--- grep_error_log_out
Expand Down
8 changes: 2 additions & 6 deletions t/apicast-policy-upstream.t
Original file line number Diff line number Diff line change
Expand Up @@ -215,16 +215,12 @@ yay, api backend
}
--- upstream
location /path_in_the_rule {
content_by_lua_block {
require('luassert').are.equal('GET /path_in_the_rule?user_key=uk&a_param=a_value HTTP/1.1',
ngx.var.request)
ngx.say('yay, api backend');
}
echo $request;
}
--- request
GET /some_path?user_key=uk&a_param=a_value
--- response_body
yay, api backend
GET /path_in_the_rule/some_path?user_key=uk&a_param=a_value HTTP/1.1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically this is a breaking change as it used to be GET /path_in_the_rule.

But I was thinking that the upstream policy needs some improvements anyway. For example, stripping the path that it matched from the URL etc. So we can make general improvements to that policy and make it configurable how it operates on URI paths.

--- error_code: 200
--- no_error_log
[error]
Expand Down
79 changes: 77 additions & 2 deletions t/http-proxy.t
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ apicast cache write key: 42:value:usage%5Bhits%5D=2, ttl: nil, context: ngx.time
{
"backend_version": 1,
"proxy": {
"api_backend": "http://test:$TEST_NGINX_SERVER_PORT/",
"api_backend": "http://test:$TEST_NGINX_SERVER_PORT",
"proxy_rules": [
{ "pattern": "/test", "http_method": "GET", "metric_system_name": "hits", "delta": 2 }
]
Expand Down Expand Up @@ -420,7 +420,7 @@ proxy request: GET http://127.0.0.1:$TEST_NGINX_SERVER_PORT/test?user_key=value
{
"backend_version": 1,
"proxy": {
"api_backend": "https://test:$TEST_NGINX_RANDOM_PORT/",
"api_backend": "https://test:$TEST_NGINX_RANDOM_PORT",
"proxy_rules": [
{ "pattern": "/test", "http_method": "GET", "metric_system_name": "hits", "delta": 2 }
]
Expand Down Expand Up @@ -685,3 +685,78 @@ proxy request: CONNECT 127.0.0.1:$TEST_NGINX_RANDOM_PORT HTTP/1.1
--- no_error_log
[error]
--- user_files fixture=tls.pl eval
=== TEST 14: upstream API connection uses proxy and correctly routes to a path.
--- env eval
("http_proxy" => $ENV{TEST_NGINX_HTTP_PROXY})
--- configuration
{
"services": [
{
"backend_version": 1,
"proxy": {
"api_backend": "http://test:$TEST_NGINX_SERVER_PORT/foo",
"proxy_rules": [
{ "pattern": "/test", "http_method": "GET", "metric_system_name": "hits", "delta": 2 }
]
}
}
]
}
--- backend
location /transactions/authrep.xml {
content_by_lua_block {
ngx.exit(ngx.OK)
}
}
--- upstream
location / {
echo $request;
}
--- request
GET /test?user_key=value
--- response_body
GET /foo/test?user_key=value HTTP/1.1
--- error_code: 200
--- error_log env
proxy request: GET http://127.0.0.1:$TEST_NGINX_SERVER_PORT/foo/test?user_key=value HTTP/1.1
--- no_error_log
[error]
=== TEST 15: Upstream Policy connection uses proxy and correctly routes to a path.
--- env eval
("http_proxy" => $ENV{TEST_NGINX_HTTP_PROXY})
--- configuration
{
"services": [
{
"proxy": {
"policy_chain": [
{ "name": "apicast.policy.upstream",
"configuration":
{
"rules": [ { "regex": "/test", "url": "http://test/foo" } ]
}
}
]
}
}
]
}
--- upstream
location / {
echo $request;
}
--- request
GET /test?user_key=value
--- response_body
GET /foo/test?user_key=value HTTP/1.1
--- error_code: 200
--- error_log env
proxy request: GET http://127.0.0.1:$TEST_NGINX_SERVER_PORT/foo/test?user_key=value HTTP/1.1
--- no_error_log
[error]