Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Server> existingServers = api.getServers();
final List<Server> reorderedServers = new ArrayList<>();
Server preferredServer = null;
Expand All @@ -563,6 +565,73 @@ private void preferServer(final OpenAPI api, final String preferredServerUrl) {
api.setServers(reorderedServers);
}

private String configuredHttpsUrlForSameHost(
final String preferredUrl, final List<Server> 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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat explicit HTTP default ports as the same external host

When the reverse proxy supplies an origin such as http://apichallenges.eviltester.com:80 while the configured server is https://apichallenges.eviltester.com, this comparison returns false (80 != 443). preferServer then adds the HTTP current-request server instead of reusing the HTTPS server, recreating the browser-breaking mixed-content URL this change is intended to avoid. The no-port variant succeeds through the preceding special case, so default-port spelling alone changes the result.

Useful? React with 👍 / 👎.

}

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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading