Skip to content

Commit

Permalink
[upstream] support path in the upstream url
Browse files Browse the repository at this point in the history
Route traffic to that path + current url.
  • Loading branch information
mikz committed Sep 26, 2018
1 parent fa4772a commit fe6faad
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 18 deletions.
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
--- 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]

0 comments on commit fe6faad

Please sign in to comment.