From 08d771773cdefd8d34716ed407792cda5625c620 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Sat, 3 Feb 2024 00:21:57 +0100 Subject: [PATCH 1/9] THREESCALE-10582 http client timeouts --- gateway/src/apicast/http_proxy.lua | 6 ++++-- gateway/src/apicast/upstream.lua | 1 + gateway/src/resty/http/proxy.lua | 4 +++- gateway/src/resty/resolver/http.lua | 8 +++++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/gateway/src/apicast/http_proxy.lua b/gateway/src/apicast/http_proxy.lua index ef90584d1..b42259c5c 100644 --- a/gateway/src/apicast/http_proxy.lua +++ b/gateway/src/apicast/http_proxy.lua @@ -146,7 +146,8 @@ local function forward_https_request(proxy_uri, uri, proxy_opts) path = format('%s%s%s', ngx.var.uri, ngx.var.is_args, ngx.var.query_string or ''), body = body, proxy_uri = proxy_uri, - proxy_auth = opts.proxy_auth + proxy_auth = opts.proxy_auth, + upstream_connection_opts = opts.upstream_connection_opts } local httpc, err = http_proxy.new(request, opts.skip_https_connect) @@ -226,7 +227,8 @@ function _M.request(upstream, proxy_uri) local proxy_opts = { proxy_auth = proxy_auth, skip_https_connect = upstream.skip_https_connect, - request_unbuffered = upstream.request_unbuffered + request_unbuffered = upstream.request_unbuffered, + upstream_connection_opts = upstream.upstream_connection_opts } forward_https_request(proxy_uri, uri, proxy_opts) diff --git a/gateway/src/apicast/upstream.lua b/gateway/src/apicast/upstream.lua index 8900f33ac..0feb3420b 100644 --- a/gateway/src/apicast/upstream.lua +++ b/gateway/src/apicast/upstream.lua @@ -232,6 +232,7 @@ function _M:call(context) end self.request_unbuffered = context.request_unbuffered + self.upstream_connection_opts = context.upstream_connection_opts http_proxy.request(self, proxy_uri) else local err = self:rewrite_request() diff --git a/gateway/src/resty/http/proxy.lua b/gateway/src/resty/http/proxy.lua index b236aba04..8b5dc859d 100644 --- a/gateway/src/resty/http/proxy.lua +++ b/gateway/src/resty/http/proxy.lua @@ -132,7 +132,9 @@ local function find_proxy_url(request) end local function connect(request, skip_https_connect) - local httpc = http.new() + request = request or { } + local opts = { timeouts = request.upstream_connection_opts } + local httpc = http.new(opts) local proxy_uri = find_proxy_url(request) request.ssl_verify = request.options and request.options.ssl and request.options.ssl.verify diff --git a/gateway/src/resty/resolver/http.lua b/gateway/src/resty/resolver/http.lua index 4af497855..06e832b7f 100644 --- a/gateway/src/resty/resolver/http.lua +++ b/gateway/src/resty/resolver/http.lua @@ -8,9 +8,15 @@ local _M = setmetatable({}, { __index = resty_http }) local mt = { __index = _M } -function _M.new() +function _M.new(opts) + opts = opts or { } local http = resty_http:new() + local timeouts = opts.timeouts + if timeouts then + http:set_timeouts(timeouts.connect_timeout, timeouts.send_timeout, timeouts.read_timeout) + end + http.resolver = resty_resolver:instance() http.balancer = round_robin.new() From a1f600852f7ff5500271cfb731e4684943588b38 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Sat, 3 Feb 2024 00:37:52 +0100 Subject: [PATCH 2/9] small refactor - skip_https_connect as request attribute - http_proxy not used attribute http_backend removed --- gateway/src/apicast/http_proxy.lua | 6 +++--- gateway/src/resty/http/proxy.lua | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gateway/src/apicast/http_proxy.lua b/gateway/src/apicast/http_proxy.lua index b42259c5c..df55d6258 100644 --- a/gateway/src/apicast/http_proxy.lua +++ b/gateway/src/apicast/http_proxy.lua @@ -27,7 +27,6 @@ local DEFAULT_CHUNKSIZE = 32 * 1024 function _M.reset() _M.resolver = resty_resolver - _M.http_backend = require('resty.http_ng.backend.resty') _M.dns_resolution = 'apicast' -- can be set to 'proxy' to let proxy do the name resolution return _M @@ -147,10 +146,11 @@ local function forward_https_request(proxy_uri, uri, proxy_opts) body = body, proxy_uri = proxy_uri, proxy_auth = opts.proxy_auth, - upstream_connection_opts = opts.upstream_connection_opts + upstream_connection_opts = opts.upstream_connection_opts, + skip_https_connect = opts.skip_https_connect } - local httpc, err = http_proxy.new(request, opts.skip_https_connect) + local httpc, err = http_proxy.new(request) if not httpc then ngx.log(ngx.ERR, 'could not connect to proxy: ', proxy_uri, ' err: ', err) diff --git a/gateway/src/resty/http/proxy.lua b/gateway/src/resty/http/proxy.lua index 8b5dc859d..3b0b1d0f3 100644 --- a/gateway/src/resty/http/proxy.lua +++ b/gateway/src/resty/http/proxy.lua @@ -77,11 +77,12 @@ local function _connect_proxy_https(httpc, request, host, port) return httpc end -local function connect_proxy(httpc, request, skip_https_connect) +local function connect_proxy(httpc, request) -- target server requires hostname not IP and DNS resolution is left to the proxy itself as specified in the RFC #7231 -- https://httpwg.org/specs/rfc7231.html#CONNECT local uri = request.uri local proxy_uri = request.proxy + local skip_https_connect = request.skip_https_connect if proxy_uri.scheme ~= 'http' then return nil, 'proxy connection supports only http' @@ -131,7 +132,7 @@ local function find_proxy_url(request) return request.proxy_uri or _M.find(uri) end -local function connect(request, skip_https_connect) +local function connect(request) request = request or { } local opts = { timeouts = request.upstream_connection_opts } local httpc = http.new(opts) @@ -141,7 +142,7 @@ local function connect(request, skip_https_connect) request.proxy = proxy_uri if proxy_uri then - return connect_proxy(httpc, request, skip_https_connect) + return connect_proxy(httpc, request) else return connect_direct(httpc, request) end From 2e15fe28ba27f4767f997b6081e83f5830229b61 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Sun, 4 Feb 2024 19:05:10 +0100 Subject: [PATCH 3/9] THREESCALE-10582 e2e tests --- gateway/src/resty/balancer.lua | 2 + gateway/src/resty/resolver/http.lua | 10 ++- t/apicast-policy-http-proxy.t | 4 +- t/apicast-policy-upstream-connection.t | 87 ++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 4 deletions(-) diff --git a/gateway/src/resty/balancer.lua b/gateway/src/resty/balancer.lua index 7f7af2e22..831140beb 100644 --- a/gateway/src/resty/balancer.lua +++ b/gateway/src/resty/balancer.lua @@ -146,6 +146,8 @@ function _M:set_timeouts(connect_timeout, send_timeout, read_timeout) -- If one of the values is nil, the default applies: -- https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md#set_timeouts + ngx.log(ngx.DEBUG, 'setting timeouts (secs), connect_timeout: ', connect_timeout, + ' send_timeout: ', send_timeout, ' read_timeout: ', read_timeout) return ngx_balancer.set_timeouts(connect_timeout, send_timeout, read_timeout) end diff --git a/gateway/src/resty/resolver/http.lua b/gateway/src/resty/resolver/http.lua index 06e832b7f..b58c62d45 100644 --- a/gateway/src/resty/resolver/http.lua +++ b/gateway/src/resty/resolver/http.lua @@ -14,7 +14,15 @@ function _M.new(opts) local timeouts = opts.timeouts if timeouts then - http:set_timeouts(timeouts.connect_timeout, timeouts.send_timeout, timeouts.read_timeout) + ngx.log(ngx.DEBUG, 'setting timeouts (secs), connect_timeout: ', timeouts.connect_timeout, + ' send_timeout: ', timeouts.send_timeout, ' read_timeout: ', timeouts.read_timeout) + -- lua-resty-http uses nginx API for lua sockets + -- in milliseconds + -- https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#tcpsocksettimeouts + local connect_timeout = timeouts.connect_timeout and timeouts.connect_timeout * 1000 + local send_timeout = timeouts.send_timeout and timeouts.send_timeout * 1000 + local read_timeout = timeouts.read_timeout and timeouts.read_timeout * 1000 + http:set_timeouts(connect_timeout, send_timeout, read_timeout) end http.resolver = resty_resolver:instance() diff --git a/t/apicast-policy-http-proxy.t b/t/apicast-policy-http-proxy.t index 5655a5fd2..199657190 100644 --- a/t/apicast-policy-http-proxy.t +++ b/t/apicast-policy-http-proxy.t @@ -202,10 +202,8 @@ ETag: foobar --- error_code: 200 --- error_log env proxy request: CONNECT test-upstream.lvh.me:$TEST_NGINX_RANDOM_PORT HTTP/1.1 ---- user_files fixture=tls.pl eval ---- error_log env using proxy: $TEST_NGINX_HTTPS_PROXY - +--- user_files fixture=tls.pl eval === TEST 4: using HTTP proxy with Basic Auth --- configuration diff --git a/t/apicast-policy-upstream-connection.t b/t/apicast-policy-upstream-connection.t index 21a36aadb..767e32ce2 100644 --- a/t/apicast-policy-upstream-connection.t +++ b/t/apicast-policy-upstream-connection.t @@ -1,6 +1,8 @@ use lib 't'; use Test::APIcast::Blackbox 'no_plan'; +require("http_proxy.pl"); + run_tests(); __DATA__ @@ -59,3 +61,88 @@ GET / --- error_log upstream timed out --- error_code: + +=== TEST 2: Set timeouts using HTTPS proxy for backend +In this test we set some timeouts to 1s. To force a read timeout, the upstream +returns part of the response, then waits 3s (more than the timeout defined), +and after that, it returns the rest of the response. Backend is configured with https_proxy +This test uses the "ignore_response" section, because we know that the response +is not going to be complete and that makes the Test::Nginx framework raise an +error. With "ignore_response" that error is ignored. +--- configuration random_port env +{ + "services": [ + { + "backend_version": 1, + "proxy": { + "api_backend": "https://test-upstream.lvh.me:$TEST_NGINX_RANDOM_PORT", + "proxy_rules": [ + { "pattern": "/test", "http_method": "GET", "metric_system_name": "hits", "delta": 2 } + ], + "policy_chain": [ + { + "name": "apicast.policy.upstream_connection", + "configuration": { + "connect_timeout": 1, + "send_timeout": 1, + "read_timeout": 1 + } + }, + { + "name": "apicast.policy.http_proxy", + "configuration": { + "https_proxy": "$TEST_NGINX_HTTPS_PROXY" + } + }, + { + "name": "apicast.policy.apicast" + } + ] + } + } + ] +} +--- backend + location /transactions/authrep.xml { + content_by_lua_block { + ngx.exit(ngx.OK) + } + } +--- upstream env +server_name test-upstream.lvh.me; +listen $TEST_NGINX_RANDOM_PORT ssl; + +ssl_certificate $TEST_NGINX_SERVER_ROOT/html/server.crt; +ssl_certificate_key $TEST_NGINX_SERVER_ROOT/html/server.key; + +location /test { + content_by_lua_block { + ngx.say("first part") + ngx.flush(true) + ngx.sleep(3) + ngx.say("yay, second part") + } + + access_by_lua_block { + assert = require('luassert') + assert.equal('https', ngx.var.scheme) + assert.equal('$TEST_NGINX_RANDOM_PORT', ngx.var.server_port) + assert.equal('test-upstream.lvh.me', ngx.var.ssl_server_name) + + local host = ngx.req.get_headers()["Host"] + local result = string.match(host, "^test%-upstream%.lvh%.me:") + assert.equals(result, "test-upstream.lvh.me:") + } +} +--- request +GET /test?user_key=test3 +--- ignore_response +--- more_headers +User-Agent: Test::APIcast::Blackbox +ETag: foobar +--- error_code: +--- error_log env +proxy request: CONNECT test-upstream.lvh.me:$TEST_NGINX_RANDOM_PORT HTTP/1.1 +using proxy: $TEST_NGINX_HTTPS_PROXY +proxy_response(): timeout +--- user_files fixture=tls.pl eval From d28613388b7d451da66ec98ad6d861b75632359a Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Mon, 5 Feb 2024 11:43:35 +0100 Subject: [PATCH 4/9] CHANGELOG update --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 268f23a07..75f1b8cef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Docker compose up instead of docker compose run [PR #1442](https://github.com/3scale/APIcast/pull/1442) +- Fix integration of upstream connection policy with camel policy [THREESCALE-10582](https://issues.redhat.com/browse/THREESCALE-10582) [PR #1443](https://github.com/3scale/APIcast/pull/1443) + ### Added - Detect number of CPU shares when running on Cgroups V2 [PR #1410](https://github.com/3scale/apicast/pull/1410) [THREESCALE-10167](https://issues.redhat.com/browse/THREESCALE-10167) From 24992d0c09c92b99141f95a4df793bc8bfaa0c69 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Mon, 5 Feb 2024 18:17:16 +0100 Subject: [PATCH 5/9] spec/http_proxy_spec.lua: very basic unittest --- spec/http_proxy_spec.lua | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 spec/http_proxy_spec.lua diff --git a/spec/http_proxy_spec.lua b/spec/http_proxy_spec.lua new file mode 100644 index 000000000..a4c5b677f --- /dev/null +++ b/spec/http_proxy_spec.lua @@ -0,0 +1,52 @@ + +describe('http_proxy', function() + describe('.request', function() + local function stub_ngx_request() + ngx.var = { } + + stub(ngx, 'exit') + stub(ngx.req, 'get_headers', function() return { } end) + stub(ngx.req, 'get_method', function() return 'GET' end) + end + + local function stub_resty_http_proxy() + local httpc = { + } + + local response = {} + stub(httpc, 'request', function() return response end) + stub(httpc, 'proxy_response') + stub(httpc, 'set_keepalive') + + local resty_http_proxy = require 'resty.http.proxy' + stub(resty_http_proxy, 'new', function() return httpc end) + end + + before_each(function() + stub_ngx_request() + stub_resty_http_proxy() + end) + + describe('on https backend', function() + local upstream = { + uri = { + scheme = 'https' + }, + request_unbuffered = false, + skip_https_connect = false + } + local proxy_uri = { + } + + before_each(function() + stub(upstream, 'rewrite_request') + end) + + it('terminates phase', function() + local http_proxy = require('apicast.http_proxy') + http_proxy.request(upstream, proxy_uri) + assert.spy(ngx.exit).was_called_with(ngx.OK) + end) + end) + end) +end) From a7dec6d7a499beab41916ecd38a43c4c455c067a Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Tue, 6 Feb 2024 09:45:45 +0100 Subject: [PATCH 6/9] CHANGELOG fix --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75f1b8cef..781eae3b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Docker compose up instead of docker compose run [PR #1442](https://github.com/3scale/APIcast/pull/1442) -- Fix integration of upstream connection policy with camel policy [THREESCALE-10582](https://issues.redhat.com/browse/THREESCALE-10582) [PR #1443](https://github.com/3scale/APIcast/pull/1443) +- Fix integration of upstream connection policy with camel policy [PR #1443](https://github.com/3scale/APIcast/pull/1443) [THREESCALE-10582](https://issues.redhat.com/browse/THREESCALE-10582) ### Added From b705c0f2b7666e3c824b6787b699ad85669a3aeb Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Tue, 6 Feb 2024 10:30:48 +0100 Subject: [PATCH 7/9] timeouts in src/resty/http/proxy.lua --- gateway/src/resty/http/proxy.lua | 17 ++++++++++-- gateway/src/resty/resolver/http.lua | 16 +---------- spec/resty/http/proxy_spec.lua | 37 ++++++++++++++++++++------ t/apicast-policy-camel.t | 2 +- t/apicast-policy-upstream-connection.t | 2 -- 5 files changed, 46 insertions(+), 28 deletions(-) diff --git a/gateway/src/resty/http/proxy.lua b/gateway/src/resty/http/proxy.lua index 3b0b1d0f3..eccdcd4c4 100644 --- a/gateway/src/resty/http/proxy.lua +++ b/gateway/src/resty/http/proxy.lua @@ -134,8 +134,21 @@ end local function connect(request) request = request or { } - local opts = { timeouts = request.upstream_connection_opts } - local httpc = http.new(opts) + local httpc = http.new() + + if request.upstream_connection_opts then + local con_opts = request.upstream_connection_opts + ngx.log(ngx.DEBUG, 'setting timeouts (secs), connect_timeout: ', con_opts.connect_timeout, + ' send_timeout: ', con_opts.send_timeout, ' read_timeout: ', con_opts.read_timeout) + -- lua-resty-http uses nginx API for lua sockets + -- in milliseconds + -- https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#tcpsocksettimeouts + local connect_timeout = con_opts.connect_timeout and con_opts.connect_timeout * 1000 + local send_timeout = con_opts.send_timeout and con_opts.send_timeout * 1000 + local read_timeout = con_opts.read_timeout and con_opts.read_timeout * 1000 + httpc:set_timeouts(connect_timeout, send_timeout, read_timeout) + end + local proxy_uri = find_proxy_url(request) request.ssl_verify = request.options and request.options.ssl and request.options.ssl.verify diff --git a/gateway/src/resty/resolver/http.lua b/gateway/src/resty/resolver/http.lua index b58c62d45..4af497855 100644 --- a/gateway/src/resty/resolver/http.lua +++ b/gateway/src/resty/resolver/http.lua @@ -8,23 +8,9 @@ local _M = setmetatable({}, { __index = resty_http }) local mt = { __index = _M } -function _M.new(opts) - opts = opts or { } +function _M.new() local http = resty_http:new() - local timeouts = opts.timeouts - if timeouts then - ngx.log(ngx.DEBUG, 'setting timeouts (secs), connect_timeout: ', timeouts.connect_timeout, - ' send_timeout: ', timeouts.send_timeout, ' read_timeout: ', timeouts.read_timeout) - -- lua-resty-http uses nginx API for lua sockets - -- in milliseconds - -- https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#tcpsocksettimeouts - local connect_timeout = timeouts.connect_timeout and timeouts.connect_timeout * 1000 - local send_timeout = timeouts.send_timeout and timeouts.send_timeout * 1000 - local read_timeout = timeouts.read_timeout and timeouts.read_timeout * 1000 - http:set_timeouts(connect_timeout, send_timeout, read_timeout) - end - http.resolver = resty_resolver:instance() http.balancer = round_robin.new() diff --git a/spec/resty/http/proxy_spec.lua b/spec/resty/http/proxy_spec.lua index fef47fdf0..0967ac9bf 100644 --- a/spec/resty/http/proxy_spec.lua +++ b/spec/resty/http/proxy_spec.lua @@ -47,16 +47,37 @@ describe('resty.http.proxy', function() end) context('.new', function() - it('connects to the #http_proxy', function() - _M:reset({ http_proxy = 'http://127.0.0.1:1984' }) + before_each(function() + _M:reset({ http_proxy = 'http://127.0.0.1:1984' }) + end) - local request = { url = 'http://upstream:8091/request', method = 'GET' } - local proxy = assert(_M.new(request)) + it('connects to the #http_proxy', function() + local request = { url = 'http://upstream:8091/request', method = 'GET' } + local proxy = assert(_M.new(request)) - local res = assert(proxy:request(request)) + local res = assert(proxy:request(request)) - assert.same(200, res.status) - assert.match('GET http://upstream:8091/request HTTP/1.1', res:read_body()) - end) + assert.same(200, res.status) + assert.match('GET http://upstream:8091/request HTTP/1.1', res:read_body()) + end) + + it('connects to the #http_proxy with timeouts', function() + local request = { + url = 'http://upstream:8091/request', + method = 'GET', + upstream_connection_opts = { + connect_timeout = 1, + send_timeout = 1, + read_timeout = 1 + } + } + + local proxy = assert(_M.new(request)) + + local res = assert(proxy:request(request)) + + assert.same(200, res.status) + assert.match('GET http://upstream:8091/request HTTP/1.1', res:read_body()) + end) end) end) diff --git a/t/apicast-policy-camel.t b/t/apicast-policy-camel.t index 6577e6391..37c41834c 100644 --- a/t/apicast-policy-camel.t +++ b/t/apicast-policy-camel.t @@ -19,7 +19,7 @@ run_tests(); __DATA__ -=== TEST 1: API backend connection uses http proxy +=== TEST 1: API backend connection uses http proxy --- configuration { "services": [ diff --git a/t/apicast-policy-upstream-connection.t b/t/apicast-policy-upstream-connection.t index 767e32ce2..701f7ba6f 100644 --- a/t/apicast-policy-upstream-connection.t +++ b/t/apicast-policy-upstream-connection.t @@ -60,7 +60,6 @@ GET / --- ignore_response --- error_log upstream timed out ---- error_code: === TEST 2: Set timeouts using HTTPS proxy for backend In this test we set some timeouts to 1s. To force a read timeout, the upstream @@ -140,7 +139,6 @@ GET /test?user_key=test3 --- more_headers User-Agent: Test::APIcast::Blackbox ETag: foobar ---- error_code: --- error_log env proxy request: CONNECT test-upstream.lvh.me:$TEST_NGINX_RANDOM_PORT HTTP/1.1 using proxy: $TEST_NGINX_HTTPS_PROXY From afc70d20372e2b2305845e6568b32fcdd3415b54 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Tue, 6 Feb 2024 11:51:44 +0100 Subject: [PATCH 8/9] e2e test: upstream connection policy with HTTPS_PROXY env var --- t/apicast-policy-upstream-connection.t | 81 ++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/t/apicast-policy-upstream-connection.t b/t/apicast-policy-upstream-connection.t index 701f7ba6f..2f3bea86a 100644 --- a/t/apicast-policy-upstream-connection.t +++ b/t/apicast-policy-upstream-connection.t @@ -144,3 +144,84 @@ proxy request: CONNECT test-upstream.lvh.me:$TEST_NGINX_RANDOM_PORT HTTP/1.1 using proxy: $TEST_NGINX_HTTPS_PROXY proxy_response(): timeout --- user_files fixture=tls.pl eval + +=== TEST 3: Set timeouts using HTTPS proxy for backend using HTTPS_PROXY env var +In this test we set some timeouts to 1s. To force a read timeout, the upstream +returns part of the response, then waits 3s (more than the timeout defined), +and after that, it returns the rest of the response. Backend is configured with https_proxy +This test uses the "ignore_response" section, because we know that the response +is not going to be complete and that makes the Test::Nginx framework raise an +error. With "ignore_response" that error is ignored. +--- env eval +( + "https_proxy" => $ENV{TEST_NGINX_HTTPS_PROXY}, +) +--- configuration random_port env +{ + "services": [ + { + "backend_version": 1, + "proxy": { + "api_backend": "https://test-upstream.lvh.me:$TEST_NGINX_RANDOM_PORT", + "proxy_rules": [ + { "pattern": "/test", "http_method": "GET", "metric_system_name": "hits", "delta": 1 } + ], + "policy_chain": [ + { + "name": "apicast.policy.upstream_connection", + "configuration": { + "connect_timeout": 1, + "send_timeout": 1, + "read_timeout": 1 + } + }, + { + "name": "apicast.policy.apicast" + } + ] + } + } + ] +} +--- backend + location /transactions/authrep.xml { + content_by_lua_block { + ngx.exit(ngx.OK) + } + } +--- upstream env +server_name test-upstream.lvh.me; +listen $TEST_NGINX_RANDOM_PORT ssl; +ssl_certificate $TEST_NGINX_SERVER_ROOT/html/server.crt; +ssl_certificate_key $TEST_NGINX_SERVER_ROOT/html/server.key; + +location /test { + content_by_lua_block { + ngx.say("first part") + ngx.flush(true) + ngx.sleep(3) + ngx.say("yay, second part") + } + + access_by_lua_block { + assert = require('luassert') + assert.equal('https', ngx.var.scheme) + assert.equal('$TEST_NGINX_RANDOM_PORT', ngx.var.server_port) + assert.equal('test-upstream.lvh.me', ngx.var.ssl_server_name) + + local host = ngx.req.get_headers()["Host"] + local result = string.match(host, "^test%-upstream%.lvh%.me:") + assert.equals(result, "test-upstream.lvh.me:") + } +} + +--- request +GET /test?user_key=test3 +--- more_headers +User-Agent: Test::APIcast::Blackbox +ETag: foobar +--- error_log env +proxy request: CONNECT test-upstream.lvh.me:$TEST_NGINX_RANDOM_PORT HTTP/1.1 +using proxy: $TEST_NGINX_HTTPS_PROXY +proxy_response(): timeout +--- user_files fixture=tls.pl eval From f34affbf4f842ce2fd8a49a574aa35e1d3f0e4d9 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Tue, 6 Feb 2024 13:54:08 +0100 Subject: [PATCH 9/9] e2e test: upstream connection policy with HTTPS_PROXY camel proxy --- t/apicast-policy-upstream-connection.t | 83 ++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/t/apicast-policy-upstream-connection.t b/t/apicast-policy-upstream-connection.t index 2f3bea86a..1a7aa404e 100644 --- a/t/apicast-policy-upstream-connection.t +++ b/t/apicast-policy-upstream-connection.t @@ -225,3 +225,86 @@ proxy request: CONNECT test-upstream.lvh.me:$TEST_NGINX_RANDOM_PORT HTTP/1.1 using proxy: $TEST_NGINX_HTTPS_PROXY proxy_response(): timeout --- user_files fixture=tls.pl eval + +=== TEST 4: Set timeouts using HTTPS Camel proxy for backend +In this test we set some timeouts to 1s. To force a read timeout, the upstream +returns part of the response, then waits 3s (more than the timeout defined), +and after that, it returns the rest of the response. Backend is configured with https_proxy +This test uses the "ignore_response" section, because we know that the response +is not going to be complete and that makes the Test::Nginx framework raise an +error. With "ignore_response" that error is ignored. +--- configuration random_port env +{ + "services": [ + { + "backend_version": 1, + "proxy": { + "api_backend": "https://test-upstream.lvh.me:$TEST_NGINX_RANDOM_PORT", + "proxy_rules": [ + { "pattern": "/test", "http_method": "GET", "metric_system_name": "hits", "delta": 2 } + ], + "policy_chain": [ + { + "name": "apicast.policy.upstream_connection", + "configuration": { + "connect_timeout": 1, + "send_timeout": 1, + "read_timeout": 1 + } + }, + { + "name": "apicast.policy.camel", + "configuration": { + "https_proxy": "$TEST_NGINX_HTTPS_PROXY" + } + }, + { + "name": "apicast.policy.apicast" + } + ] + } + } + ] +} +--- backend + location /transactions/authrep.xml { + content_by_lua_block { + ngx.exit(ngx.OK) + } + } +--- upstream env +server_name test-upstream.lvh.me; +listen $TEST_NGINX_RANDOM_PORT ssl; + +ssl_certificate $TEST_NGINX_SERVER_ROOT/html/server.crt; +ssl_certificate_key $TEST_NGINX_SERVER_ROOT/html/server.key; + +location /test { + content_by_lua_block { + ngx.say("first part") + ngx.flush(true) + ngx.sleep(3) + ngx.say("yay, second part") + } + + access_by_lua_block { + assert = require('luassert') + assert.equal('https', ngx.var.scheme) + assert.equal('$TEST_NGINX_RANDOM_PORT', ngx.var.server_port) + assert.equal('test-upstream.lvh.me', ngx.var.ssl_server_name) + + local host = ngx.req.get_headers()["Host"] + local result = string.match(host, "^test%-upstream%.lvh%.me:") + assert.equals(result, "test-upstream.lvh.me:") + } +} +--- request +GET /test?user_key=test3 +--- ignore_response +--- more_headers +User-Agent: Test::APIcast::Blackbox +ETag: foobar +--- error_log env +using proxy: $TEST_NGINX_HTTPS_PROXY +err: timeout +--- user_files fixture=tls.pl eval