From ff90d5273b3368bb570c9ee7b96d3ff1120d780f Mon Sep 17 00:00:00 2001 From: Alan Richardson Date: Fri, 17 Jul 2026 09:29:03 +0100 Subject: [PATCH] Prefer configured HTTPS Swagger server for same host --- .../thingifier/swaggerizer/Swaggerizer.java | 71 ++++++++++++++++++- .../SwaggerizerServerPreferenceTest.java | 39 ++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 thingifier/src/test/java/uk/co/compendiumdev/thingifier/swaggerizer/SwaggerizerServerPreferenceTest.java diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/swaggerizer/Swaggerizer.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/swaggerizer/Swaggerizer.java index 6c552f02..ea7a6247 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/swaggerizer/Swaggerizer.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/swaggerizer/Swaggerizer.java @@ -11,6 +11,7 @@ import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.servers.Server; +import java.net.URI; import java.util.ArrayList; import java.util.List; import uk.co.compendiumdev.thingifier.Thingifier; @@ -541,7 +542,8 @@ private void preferServer(final OpenAPI api, final String preferredServerUrl) { return; } - final String preferredUrl = preferredServerUrl.trim(); + final String preferredUrl = + configuredHttpsUrlForSameHost(preferredServerUrl.trim(), api.getServers()); final List existingServers = api.getServers(); final List reorderedServers = new ArrayList<>(); Server preferredServer = null; @@ -563,6 +565,73 @@ private void preferServer(final OpenAPI api, final String preferredServerUrl) { api.setServers(reorderedServers); } + private String configuredHttpsUrlForSameHost( + final String preferredUrl, final List configuredServers) { + final URI preferredUri = uriFrom(preferredUrl); + if (preferredUri == null || !"http".equalsIgnoreCase(preferredUri.getScheme())) { + return preferredUrl; + } + + if (configuredServers == null) { + return preferredUrl; + } + + for (Server server : configuredServers) { + if (server.getUrl() == null) { + continue; + } + + final String configuredUrl = server.getUrl().trim(); + final URI configuredUri = uriFrom(configuredUrl); + if (configuredUri == null || !"https".equalsIgnoreCase(configuredUri.getScheme())) { + continue; + } + + if (sameHostAndPort(preferredUri, configuredUri)) { + return configuredUrl; + } + } + + return preferredUrl; + } + + private boolean sameHostAndPort(final URI preferredUri, final URI configuredUri) { + if (!sameHost(preferredUri, configuredUri)) { + return false; + } + if (preferredUri.getPort() == -1 && configuredUri.getPort() == -1) { + return true; + } + return effectivePort(preferredUri) == effectivePort(configuredUri); + } + + private boolean sameHost(final URI preferredUri, final URI configuredUri) { + return preferredUri.getHost() != null + && configuredUri.getHost() != null + && preferredUri.getHost().equalsIgnoreCase(configuredUri.getHost()); + } + + private int effectivePort(final URI uri) { + if (uri.getPort() != -1) { + return uri.getPort(); + } + if ("https".equalsIgnoreCase(uri.getScheme())) { + return 443; + } + if ("http".equalsIgnoreCase(uri.getScheme())) { + return 80; + } + return -1; + } + + private URI uriFrom(final String url) { + try { + return URI.create(url); + } catch (IllegalArgumentException e) { + return null; + } + } + private boolean sameServerUrl(final String preferredUrl, final String configuredUrl) { if (configuredUrl == null) { return false; diff --git a/thingifier/src/test/java/uk/co/compendiumdev/thingifier/swaggerizer/SwaggerizerServerPreferenceTest.java b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/swaggerizer/SwaggerizerServerPreferenceTest.java new file mode 100644 index 00000000..055208ac --- /dev/null +++ b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/swaggerizer/SwaggerizerServerPreferenceTest.java @@ -0,0 +1,39 @@ +package uk.co.compendiumdev.thingifier.swaggerizer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn; + +class SwaggerizerServerPreferenceTest { + + @Test + void keepsLocalhostFirstWhenCurrentRequestIsLocalhost() { + final String json = + new Swaggerizer(apiDefn()).asJsonWithPreferredServer("http://localhost:4567"); + + Assertions.assertTrue( + json.indexOf("\"url\" : \"http://localhost:4567\"") + < json.indexOf("\"url\" : \"https://apichallenges.eviltester.com\"")); + Assertions.assertFalse(json.contains("\"description\" : \"current request\"")); + } + + @Test + void prefersConfiguredHttpsServerForSameHostWhenCurrentRequestIsHttp() { + final String json = + new Swaggerizer(apiDefn()) + .asJsonWithPreferredServer("http://apichallenges.eviltester.com"); + + Assertions.assertTrue( + json.indexOf("\"url\" : \"https://apichallenges.eviltester.com\"") + < json.indexOf("\"url\" : \"http://localhost:4567\"")); + Assertions.assertFalse(json.contains("\"url\" : \"http://apichallenges.eviltester.com\"")); + Assertions.assertFalse(json.contains("\"description\" : \"current request\"")); + } + + private ThingifierApiDocumentationDefn apiDefn() { + final ThingifierApiDocumentationDefn apiDefn = new ThingifierApiDocumentationDefn(); + apiDefn.addServer("https://apichallenges.eviltester.com", "cloud hosted version"); + apiDefn.addServer("http://localhost:4567", "local execution"); + return apiDefn; + } +}