diff --git a/src/api-umbrella/proxy/middleware/api_matcher.lua b/src/api-umbrella/proxy/middleware/api_matcher.lua index 2a001c53c..623efccef 100644 --- a/src/api-umbrella/proxy/middleware/api_matcher.lua +++ b/src/api-umbrella/proxy/middleware/api_matcher.lua @@ -3,7 +3,6 @@ local stringx = require "pl.stringx" local utils = require "api-umbrella.proxy.utils" local append_array = utils.append_array -local gsub = string.gsub local set_uri = utils.set_uri local startswith = stringx.startswith @@ -50,8 +49,10 @@ return function(active_config) if api and url_match then -- Rewrite the URL prefix path. - local new_path = gsub(request_path, url_match["_frontend_prefix_matcher"], url_match["backend_prefix"], 1) - if new_path ~= request_path then + local new_path, _, new_path_err = ngx.re.sub(request_path, url_match["_frontend_prefix_regex"], url_match["backend_prefix"], "jo") + if new_path_err then + ngx.log(ngx.ERR, "regex error: ", new_path_err) + elseif new_path ~= request_path then set_uri(new_path) end diff --git a/src/api-umbrella/proxy/middleware/rewrite_response.lua b/src/api-umbrella/proxy/middleware/rewrite_response.lua index d615214a7..2dfd8e3b9 100644 --- a/src/api-umbrella/proxy/middleware/rewrite_response.lua +++ b/src/api-umbrella/proxy/middleware/rewrite_response.lua @@ -3,7 +3,6 @@ local url = require "socket.url" local utils = require "api-umbrella.proxy.utils" local append_args = utils.append_args -local gsub = string.gsub local startswith = stringx.startswith local url_build = url.build local url_parse = url.parse @@ -126,14 +125,30 @@ local function rewrite_redirects() changed = true end - if host_matches or relative then - if matched_api and matched_api["url_matches"] then - for _, url_match in ipairs(matched_api["url_matches"]) do - if startswith(parsed["path"], url_match["backend_prefix"]) then - parsed["path"] = gsub(parsed["path"], url_match["_backend_prefix_matcher"], url_match["frontend_prefix"], 1) - changed = true - break - end + -- If the redirect being returned possibly contains paths for the underlying + -- backend URL, then rewrite the path. + if (host_matches or relative) and matched_api then + -- If the redirect path begins with the backend prefix, then consider it + -- for rewriting. + local url_match = ngx.ctx.matched_api_url_match + if url_match and startswith(parsed["path"], url_match["backend_prefix"]) then + -- As long as the patah matches the backend prefix, mark as changed, so + -- the api key is appended (regardless of whether we actually replaced + -- the path). + changed = true + + -- Don't rewrite the path if the frontend prefix contains the backend + -- prefix and the redirect path already contains the frontend prefix. + -- + -- This helps ensure that if the API backend is already returning + -- public/frontend URLs, we don't try to rewrite these again. - + local rewrite_path = true + if url_match["_frontend_prefix_contains_backend_prefix"] and startswith(parsed["path"], url_match["frontend_prefix"]) then + rewrite_path = false + end + + if rewrite_path then + parsed["path"] = ngx.re.sub(parsed["path"], url_match["_backend_prefix_regex"], url_match["frontend_prefix"], "jo") end end end diff --git a/src/api-umbrella/proxy/models/active_config.lua b/src/api-umbrella/proxy/models/active_config.lua index e0780c1f8..b4c0baa98 100644 --- a/src/api-umbrella/proxy/models/active_config.lua +++ b/src/api-umbrella/proxy/models/active_config.lua @@ -9,11 +9,11 @@ local random_token = require "api-umbrella.utils.random_token" local resolve_backend_dns = require "api-umbrella.proxy.jobs.resolve_backend_dns" local tablex = require "pl.tablex" local utils = require "api-umbrella.proxy.utils" +local startswith = require("pl.stringx").startswith local append_array = utils.append_array local cache_computed_settings = utils.cache_computed_settings local deepcopy = tablex.deepcopy -local escape = plutils.escape local set_packed = utils.set_packed local size = tablex.size local split = plutils.split @@ -55,8 +55,18 @@ local function cache_computed_api(api) if api["url_matches"] then for _, url_match in ipairs(api["url_matches"]) do - url_match["_frontend_prefix_matcher"] = "^" .. escape(url_match["frontend_prefix"]) - url_match["_backend_prefix_matcher"] = "^" .. escape(url_match["backend_prefix"]) + url_match["_frontend_prefix_regex"] = "^" .. escape_regex(url_match["frontend_prefix"]) + url_match["_backend_prefix_regex"] = "^" .. escape_regex(url_match["backend_prefix"]) + + url_match["_frontend_prefix_contains_backend_prefix"] = false + if startswith(url_match["frontend_prefix"], url_match["backend_prefix"]) then + url_match["_frontend_prefix_contains_backend_prefix"] = true + end + + url_match["_backend_prefix_contains_frontend_prefix"] = false + if startswith(url_match["backend_prefix"], url_match["frontend_prefix"]) then + url_match["_backend_prefix_contains_frontend_prefix"] = true + end end end diff --git a/templates/etc/test-env/nginx/apis.conf.mustache b/templates/etc/test-env/nginx/apis.conf.mustache index 156ac69ec..2ba18dc7c 100644 --- a/templates/etc/test-env/nginx/apis.conf.mustache +++ b/templates/etc/test-env/nginx/apis.conf.mustache @@ -92,7 +92,7 @@ server { echo -n "Hello World"; } - location = /redirect { + location /redirect { rewrite_by_lua_block { ngx.redirect(ngx.unescape_uri(ngx.var.arg_to or "/hello")) } diff --git a/test/proxy/response_rewriting/test_redirects.rb b/test/proxy/response_rewriting/test_redirects.rb index 54e8159df..7538c1caf 100644 --- a/test/proxy/response_rewriting/test_redirects.rb +++ b/test/proxy/response_rewriting/test_redirects.rb @@ -10,82 +10,295 @@ def setup once_per_class_setup do prepend_api_backends([ { - :frontend_host => "frontend.foo", + :frontend_host => unique_test_class_hostname, :backend_host => "example.com", :servers => [{ :host => "127.0.0.1", :port => 9444 }], - :url_matches => [{ :frontend_prefix => "/#{unique_test_class_id}/front/end/path", :backend_prefix => "/backend-prefix" }], + :url_matches => [ + { + # Add url matches that match the backend (since / will match + # everything), but don't match the frontend prefix, to ensure + # these don't get used during rewriting. + :frontend_prefix => "/unused-matcher-with-root-backend-prefix", + :backend_prefix => "/", + }, + { + :frontend_prefix => "/frontend-prefix-routes-to-path", + :backend_prefix => "/backend-prefix", + }, + { + :frontend_prefix => "/frontend-prefix-routes-to-root/", + :backend_prefix => "/", + }, + { + :frontend_prefix => "/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/", + :backend_prefix => "/redirect/frontend-prefix-contains-backend-prefix/", + }, + { + :frontend_prefix => "/redirect/backend-prefix-contains-frontend-prefix/", + :backend_prefix => "/redirect/backend-prefix-contains-frontend-prefix/backend-piece/", + }, + { + :frontend_prefix => "/backend-prefix/redirect", + :backend_prefix => "/backend-prefix/redirect", + }, + { + :frontend_prefix => "/", + :backend_prefix => "/backend-prefix/", + }, + { + :frontend_prefix => "/unused-matcher-with-root-backend-prefix-last", + :backend_prefix => "/", + }, + ], }, ]) end end - def test_relative_leaves_unknown_path - response = make_redirect_request("/somewhere") - assert_equal("/somewhere", response.headers["location"]) + def test_relative_unknown_path + assert_redirects("/somewhere", { + :frontend_prefix_routes_to_path => "/somewhere", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/somewhere?api_key=#{api_key}", + :frontend_root_routes_to_path => "/somewhere", + :frontend_prefix_equals_backend_prefix => "/somewhere", + :frontend_prefix_contains_backend_prefix => "/somewhere", + :backend_prefix_contains_frontend_prefix => "/somewhere", + }) end - def test_relative_rewrites_frontend_prefix - response = make_redirect_request("/backend-prefix/more/here") - assert_equal("/#{unique_test_class_id}/front/end/path/more/here?api_key=#{api_key}", response.headers["location"]) + def test_relative_frontend_prefix_routes_to_root + assert_redirects("/frontend-prefix-routes-to-root/foo", { + :frontend_prefix_routes_to_path => "/frontend-prefix-routes-to-root/foo", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/foo?api_key=#{api_key}", + :frontend_root_routes_to_path => "/frontend-prefix-routes-to-root/foo", + :frontend_prefix_equals_backend_prefix => "/frontend-prefix-routes-to-root/foo", + :frontend_prefix_contains_backend_prefix => "/frontend-prefix-routes-to-root/foo", + :backend_prefix_contains_frontend_prefix => "/frontend-prefix-routes-to-root/foo", + }) end - def test_absolute_leaves_unknown_domain - response = make_redirect_request("http://other_url.com/hello") - assert_equal("http://other_url.com/hello", response.headers["location"]) + def test_relative_frontend_prefix_routes_to_root_incomplete_path + assert_redirects("/frontend-prefix-routes-to-roo", { + :frontend_prefix_routes_to_path => "/frontend-prefix-routes-to-roo", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/frontend-prefix-routes-to-roo?api_key=#{api_key}", + :frontend_root_routes_to_path => "/frontend-prefix-routes-to-roo", + :frontend_prefix_equals_backend_prefix => "/frontend-prefix-routes-to-roo", + :frontend_prefix_contains_backend_prefix => "/frontend-prefix-routes-to-roo", + :backend_prefix_contains_frontend_prefix => "/frontend-prefix-routes-to-roo", + }) end - def test_absolute_rewrites_backend_domain - response = make_redirect_request("http://example.com/hello") - assert_equal("http://frontend.foo:9080/hello?api_key=#{api_key}", response.headers["location"]) + def test_relative_frontend_prefix_routes_to_path + assert_redirects("/frontend-prefix-routes-to-path", { + :frontend_prefix_routes_to_path => "/frontend-prefix-routes-to-path", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/frontend-prefix-routes-to-path?api_key=#{api_key}", + :frontend_root_routes_to_path => "/frontend-prefix-routes-to-path", + :frontend_prefix_equals_backend_prefix => "/frontend-prefix-routes-to-path", + :frontend_prefix_contains_backend_prefix => "/frontend-prefix-routes-to-path", + :backend_prefix_contains_frontend_prefix => "/frontend-prefix-routes-to-path", + }) end - def test_absolute_rewrites_backend_domain_https - response = make_redirect_request("https://example.com/hello") - assert_equal("https://frontend.foo:9081/hello?api_key=#{api_key}", response.headers["location"]) + def test_relative_frontend_prefix_contains_backend_prefix_partial + assert_redirects("/redirect/frontend-prefix-contains-backend-prefix/", { + :frontend_prefix_routes_to_path => "/redirect/frontend-prefix-contains-backend-prefix/", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/redirect/frontend-prefix-contains-backend-prefix/?api_key=#{api_key}", + :frontend_root_routes_to_path => "/redirect/frontend-prefix-contains-backend-prefix/", + :frontend_prefix_equals_backend_prefix => "/redirect/frontend-prefix-contains-backend-prefix/", + :frontend_prefix_contains_backend_prefix => "/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/?api_key=#{api_key}", + :backend_prefix_contains_frontend_prefix => "/redirect/frontend-prefix-contains-backend-prefix/", + }) + end + + def test_relative_frontend_prefix_contains_backend_prefix_complete + assert_redirects("/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/", { + :frontend_prefix_routes_to_path => "/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/?api_key=#{api_key}", + :frontend_root_routes_to_path => "/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/", + :frontend_prefix_equals_backend_prefix => "/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/", + :frontend_prefix_contains_backend_prefix => "/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/?api_key=#{api_key}", + :backend_prefix_contains_frontend_prefix => "/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/", + }) + end + + def test_relative_backend_prefix_contains_frontend_prefix_partial + assert_redirects("/redirect/backend-prefix-contains-frontend-prefix/", { + :frontend_prefix_routes_to_path => "/redirect/backend-prefix-contains-frontend-prefix/", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/redirect/backend-prefix-contains-frontend-prefix/?api_key=#{api_key}", + :frontend_root_routes_to_path => "/redirect/backend-prefix-contains-frontend-prefix/", + :frontend_prefix_equals_backend_prefix => "/redirect/backend-prefix-contains-frontend-prefix/", + :frontend_prefix_contains_backend_prefix => "/redirect/backend-prefix-contains-frontend-prefix/", + :backend_prefix_contains_frontend_prefix => "/redirect/backend-prefix-contains-frontend-prefix/", + }) + end + + def test_relative_backend_prefix_contains_frontend_prefix_complete + assert_redirects("/redirect/backend-prefix-contains-frontend-prefix/backend-piece/", { + :frontend_prefix_routes_to_path => "/redirect/backend-prefix-contains-frontend-prefix/backend-piece/", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/redirect/backend-prefix-contains-frontend-prefix/backend-piece/?api_key=#{api_key}", + :frontend_root_routes_to_path => "/redirect/backend-prefix-contains-frontend-prefix/backend-piece/", + :frontend_prefix_equals_backend_prefix => "/redirect/backend-prefix-contains-frontend-prefix/backend-piece/", + :frontend_prefix_contains_backend_prefix => "/redirect/backend-prefix-contains-frontend-prefix/backend-piece/", + :backend_prefix_contains_frontend_prefix => "/redirect/backend-prefix-contains-frontend-prefix/?api_key=#{api_key}", + }) + end + + def test_relative_frontend_prefix_equals_backend_prefix + assert_redirects("/backend-prefix/more/here", { + :frontend_prefix_routes_to_path => "/frontend-prefix-routes-to-path/more/here?api_key=#{api_key}", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/backend-prefix/more/here?api_key=#{api_key}", + :frontend_root_routes_to_path => "/more/here?api_key=#{api_key}", + :frontend_prefix_equals_backend_prefix => "/backend-prefix/more/here", + :frontend_prefix_contains_backend_prefix => "/backend-prefix/more/here", + :backend_prefix_contains_frontend_prefix => "/backend-prefix/more/here", + }) + end + + def test_relative_frontend_prefix_equals_backend_prefix_incomplete + assert_redirects("/backend-prefi", { + :frontend_prefix_routes_to_path => "/backend-prefi", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/backend-prefi?api_key=#{api_key}", + :frontend_root_routes_to_path => "/backend-prefi", + :frontend_prefix_equals_backend_prefix => "/backend-prefi", + :frontend_prefix_contains_backend_prefix => "/backend-prefi", + :backend_prefix_contains_frontend_prefix => "/backend-prefi", + }) + end + + def test_absolute_unknown_host + assert_redirects("http://other_url.com/hello", { + :frontend_prefix_routes_to_path => "http://other_url.com/hello", + :frontend_prefix_routes_to_root => "http://other_url.com/hello", + :frontend_root_routes_to_path => "http://other_url.com/hello", + :frontend_prefix_equals_backend_prefix => "http://other_url.com/hello", + :frontend_prefix_contains_backend_prefix => "http://other_url.com/hello", + :backend_prefix_contains_frontend_prefix => "http://other_url.com/hello", + }) + end + + def test_absolute_matching_host + assert_redirects("http://example.com/hello", { + :frontend_prefix_routes_to_path => "http://#{unique_test_class_hostname}:9080/hello?api_key=#{api_key}", + :frontend_prefix_routes_to_root => "http://#{unique_test_class_hostname}:9080/frontend-prefix-routes-to-root/hello?api_key=#{api_key}", + :frontend_root_routes_to_path => "http://#{unique_test_class_hostname}:9080/hello?api_key=#{api_key}", + :frontend_prefix_equals_backend_prefix => "http://#{unique_test_class_hostname}:9080/hello?api_key=#{api_key}", + :frontend_prefix_contains_backend_prefix => "http://#{unique_test_class_hostname}:9080/hello?api_key=#{api_key}", + :backend_prefix_contains_frontend_prefix => "http://#{unique_test_class_hostname}:9080/hello?api_key=#{api_key}", + }) + end + + def test_absolute_matching_host_https + assert_redirects("https://example.com/hello", { + :frontend_prefix_routes_to_path => "https://#{unique_test_class_hostname}:9081/hello?api_key=#{api_key}", + :frontend_prefix_routes_to_root => "https://#{unique_test_class_hostname}:9081/frontend-prefix-routes-to-root/hello?api_key=#{api_key}", + :frontend_root_routes_to_path => "https://#{unique_test_class_hostname}:9081/hello?api_key=#{api_key}", + :frontend_prefix_equals_backend_prefix => "https://#{unique_test_class_hostname}:9081/hello?api_key=#{api_key}", + :frontend_prefix_contains_backend_prefix => "https://#{unique_test_class_hostname}:9081/hello?api_key=#{api_key}", + :backend_prefix_contains_frontend_prefix => "https://#{unique_test_class_hostname}:9081/hello?api_key=#{api_key}", + }) end def test_absolute_requires_full_domain_match - response = make_redirect_request("http://eeexample.com/hello") - assert_equal("http://eeexample.com/hello", response.headers["location"]) + assert_redirects("http://eeexample.com/hello", { + :frontend_prefix_routes_to_path => "http://eeexample.com/hello", + :frontend_prefix_routes_to_root => "http://eeexample.com/hello", + :frontend_root_routes_to_path => "http://eeexample.com/hello", + :frontend_prefix_equals_backend_prefix => "http://eeexample.com/hello", + :frontend_prefix_contains_backend_prefix => "http://eeexample.com/hello", + :backend_prefix_contains_frontend_prefix => "http://eeexample.com/hello", + }) end def test_absolute_rewrites_frontend_prefix_path - response = make_redirect_request("http://example.com/backend-prefix/") - assert_equal("http://frontend.foo:9080/#{unique_test_class_id}/front/end/path/?api_key=#{api_key}", response.headers["location"]) + assert_redirects("http://example.com/backend-prefix/", { + :frontend_prefix_routes_to_path => "http://#{unique_test_class_hostname}:9080/frontend-prefix-routes-to-path/?api_key=#{api_key}", + :frontend_prefix_routes_to_root => "http://#{unique_test_class_hostname}:9080/frontend-prefix-routes-to-root/backend-prefix/?api_key=#{api_key}", + :frontend_root_routes_to_path => "http://#{unique_test_class_hostname}:9080/?api_key=#{api_key}", + :frontend_prefix_equals_backend_prefix => "http://#{unique_test_class_hostname}:9080/backend-prefix/?api_key=#{api_key}", + :frontend_prefix_contains_backend_prefix => "http://#{unique_test_class_hostname}:9080/backend-prefix/?api_key=#{api_key}", + :backend_prefix_contains_frontend_prefix => "http://#{unique_test_class_hostname}:9080/backend-prefix/?api_key=#{api_key}", + }) end def test_relative_unknown_path_leaves_query_params - response = make_redirect_request("/somewhere?param=example.com") - assert_equal("/somewhere?param=example.com", response.headers["location"]) + assert_redirects("/somewhere?param=example.com", { + :frontend_prefix_routes_to_path => "/somewhere?param=example.com", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/somewhere?param=example.com&api_key=#{api_key}", + :frontend_root_routes_to_path => "/somewhere?param=example.com", + :frontend_prefix_equals_backend_prefix => "/somewhere?param=example.com", + :frontend_prefix_contains_backend_prefix => "/somewhere?param=example.com", + :backend_prefix_contains_frontend_prefix => "/somewhere?param=example.com", + }) end def test_relative_rewrite_keeps_query_params - response = make_redirect_request("/backend-prefix/more/here?some=param&and=another") - assert_equal("/#{unique_test_class_id}/front/end/path/more/here?some=param&and=another&api_key=#{api_key}", response.headers["location"]) + assert_redirects("/backend-prefix/more/here?some=param&and=another", { + :frontend_prefix_routes_to_path => "/frontend-prefix-routes-to-path/more/here?some=param&and=another&api_key=#{api_key}", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/backend-prefix/more/here?some=param&and=another&api_key=#{api_key}", + :frontend_root_routes_to_path => "/more/here?some=param&and=another&api_key=#{api_key}", + :frontend_prefix_equals_backend_prefix => "/backend-prefix/more/here?some=param&and=another", + :frontend_prefix_contains_backend_prefix => "/backend-prefix/more/here?some=param&and=another", + :backend_prefix_contains_frontend_prefix => "/backend-prefix/more/here?some=param&and=another", + }) end def test_absolute_rewrite_keeps_query_params - response = make_redirect_request("http://example.com/?some=param&and=another") - assert_equal("http://frontend.foo:9080/?some=param&and=another&api_key=#{api_key}", response.headers["location"]) + assert_redirects("http://example.com/?some=param&and=another", { + :frontend_prefix_routes_to_path => "http://#{unique_test_class_hostname}:9080/?some=param&and=another&api_key=#{api_key}", + :frontend_prefix_routes_to_root => "http://#{unique_test_class_hostname}:9080/frontend-prefix-routes-to-root/?some=param&and=another&api_key=#{api_key}", + :frontend_root_routes_to_path => "http://#{unique_test_class_hostname}:9080/?some=param&and=another&api_key=#{api_key}", + :frontend_prefix_equals_backend_prefix => "http://#{unique_test_class_hostname}:9080/?some=param&and=another&api_key=#{api_key}", + :frontend_prefix_contains_backend_prefix => "http://#{unique_test_class_hostname}:9080/?some=param&and=another&api_key=#{api_key}", + :backend_prefix_contains_frontend_prefix => "http://#{unique_test_class_hostname}:9080/?some=param&and=another&api_key=#{api_key}", + }) end def test_leaves_empty_redirect - response = make_redirect_request("") - assert_equal("", response.headers["location"]) + assert_redirects("", { + :frontend_prefix_routes_to_path => "", + :frontend_prefix_routes_to_root => "", + :frontend_root_routes_to_path => "", + :frontend_prefix_equals_backend_prefix => "", + :frontend_prefix_contains_backend_prefix => "", + :backend_prefix_contains_frontend_prefix => "", + }) end private def make_redirect_request(redirect_to) - response = Typhoeus.get("http://127.0.0.1:9080/#{unique_test_class_id}/front/end/path/redirect", http_options.deep_merge({ - :headers => { - "Host" => "frontend.foo", - }, - :params => { - :to => redirect_to, - }, - })) - assert_response_code(302, response) - response + responses = {} + + { + :frontend_prefix_routes_to_path => "/frontend-prefix-routes-to-path/redirect", + :frontend_prefix_routes_to_root => "/frontend-prefix-routes-to-root/redirect", + :frontend_root_routes_to_path => "/redirect", + :frontend_prefix_equals_backend_prefix => "/backend-prefix/redirect", + :frontend_prefix_contains_backend_prefix => "/redirect/frontend-prefix-contains-backend-prefix/frontend-piece/", + :backend_prefix_contains_frontend_prefix => "/redirect/backend-prefix-contains-frontend-prefix/", + }.each do |key, path| + response = Typhoeus.get("http://127.0.0.1:9080#{path}", http_options.deep_merge({ + :headers => { + "Host" => unique_test_class_hostname, + }, + :params => { + :to => redirect_to, + }, + })) + assert_response_code(302, response) + responses[key] = response + end + + responses + end + + def assert_redirects(redirect_to, expected_redirects) + responses = make_redirect_request(redirect_to) + actual_redirects = {} + responses.each do |key, response| + actual_redirects[key] = response.headers["Location"] + end + + assert_equal(expected_redirects, actual_redirects) end end diff --git a/test/support/api_umbrella_test_helpers/common_asserts.rb b/test/support/api_umbrella_test_helpers/common_asserts.rb index 329c3ed7a..cff6d4fea 100644 --- a/test/support/api_umbrella_test_helpers/common_asserts.rb +++ b/test/support/api_umbrella_test_helpers/common_asserts.rb @@ -16,6 +16,7 @@ def assert_response_code(expected_code, response) redirect_time: #{response.redirect_time} effective_url: #{response.effective_url} primary_ip: #{response.primary_ip} + response_headers: #{response.headers.inspect} response_body: #{response.body} EOS end diff --git a/test/support/api_umbrella_test_helpers/setup.rb b/test/support/api_umbrella_test_helpers/setup.rb index 33d80de6c..c4c2b0c25 100644 --- a/test/support/api_umbrella_test_helpers/setup.rb +++ b/test/support/api_umbrella_test_helpers/setup.rb @@ -8,6 +8,7 @@ module Setup include ApiUmbrellaTestHelpers::CommonAsserts + @@incrementing_unique_number = 0 @@incrementing_unique_ip_addr = IPAddr.new("127.0.0.1") @@current_override_config = {} mattr_reader :api_user @@ -22,8 +23,11 @@ module Setup mattr_accessor(:config_mutex) { Mutex.new } mattr_accessor(:config_set_mutex) { Mutex.new } mattr_accessor(:config_publish_mutex) { Mutex.new } + mattr_accessor(:increment_mutex) { Mutex.new } included do + mattr_accessor :unique_test_class_id_value + mattr_accessor :unique_test_class_hostname_value mattr_accessor :class_setup_complete mattr_accessor(:class_setup_mutex) { Mutex.new } end @@ -271,41 +275,59 @@ def override_config_reset(reload_flag) override_config_set({}, reload_flag) end - def unique_test_class_id - @unique_test_class_id ||= self.class.name.gsub(/[^\w]+/, "-") + def to_unique_id(name) + name.gsub(/[^\w]+/, "-") end - def unique_test_id - @unique_test_id ||= self.location.gsub(/[^\w]+/, "-") + def to_unique_hostname(name) + # Replace all non alpha-numeric chars (namely underscores that might be + # in the ID) with dashes (since underscores aren't valid for hostnames). + hostname = name.downcase.gsub(/[^a-z0-9]+/, "-") + + # Truncate the hostname so the label will fit in unbound's 63 char limit. + hostname = hostname[-56..-1] || hostname + + # Strip first char if it happens to be a dash. + hostname.gsub!(/^-/, "") + + # Since we've truncated the test ID, it's possible it's no longer unique, + # so append a unique number to the end (ensuring that it will fit within + # the 63 char limit). + unique_number = next_unique_number + assert_operator(unique_number, :<=, 999999) + hostname = "#{hostname}-#{unique_number.to_s.rjust(6, "0")}" + + "#{hostname}.test" end - def unique_test_hostname - unless @unique_test_hostname - # Replace all non alpha-numeric chars (namely underscores that might be - # in the ID) with dashes (since underscores aren't valid for - # hostnames). - hostname = unique_test_id.downcase.gsub(/[^a-z0-9]+/, "-") + def unique_test_class_id + self.unique_test_class_id_value ||= to_unique_id(self.class.name) + end - # Truncate the hostname so the label will fit in unbound's 63 char - # limit. - hostname = hostname[-56..-1] || hostname + def unique_test_class_hostname + self.unique_test_class_hostname_value ||= to_unique_hostname(unique_test_class_id) + end - # Strip first char if it happens to be a dash. - hostname.gsub!(/^-/, "") + def unique_test_id + @unique_test_id ||= to_unique_id(self.location) + end - # Since we've truncated the test ID, it's possible it's no longer - # unique, so append some random chars (but still, fitting within the 63 - # char limit). - hostname = "#{hostname}-#{SecureRandom.hex(3)}" + def unique_test_hostname + @unique_test_hostname ||= to_unique_hostname(unique_test_id) + end - @unique_test_hostname = "#{hostname}.test" + def next_unique_number + self.increment_mutex.synchronize do + @@incrementing_unique_number += 1 + @@incrementing_unique_number end - @unique_test_hostname end def next_unique_ip_addr - @@incrementing_unique_ip_addr = @@incrementing_unique_ip_addr.succ - @@incrementing_unique_ip_addr.to_s + self.increment_mutex.synchronize do + @@incrementing_unique_ip_addr = @@incrementing_unique_ip_addr.succ + @@incrementing_unique_ip_addr.to_s + end end def unique_test_ip_addr