Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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 @@ -138,6 +138,9 @@ final class DefaultServerConfig implements ServerConfig {
private final ServerMetrics serverMetrics;
private final Function<? super String, ? extends EventLoopGroup> bossGroupFactory;

@Nullable
private volatile Int2ObjectMap<VirtualHost> actualPortToVirtualHost;

@Nullable
private String strVal;

Expand Down Expand Up @@ -332,8 +335,9 @@ private static Mapping<String, VirtualHost> buildDomainMapping(VirtualHost defau
// Set virtual host definitions and initialize their domain name mapping.
final DomainMappingBuilder<VirtualHost> mappingBuilder = new DomainMappingBuilder<>(defaultVirtualHost);
for (VirtualHost h : virtualHosts) {
if (h.port() > 0) {
if (h.port() > 0 || h.serverPort() != null) {
// A port-based virtual host will be handled by buildDomainAndPortMapping().
// A ServerPort-based virtual host (with port 0) will be resolved at runtime.
continue;
}
mappingBuilder.add(h.hostnamePattern(), h);
Expand Down Expand Up @@ -398,6 +402,26 @@ void setServer(Server server) {
this.server = requireNonNull(server, "server");
}

/**
* Builds the O(1) lookup map from actual bound ports to VirtualHosts.
* This should be called after all ports are bound.
*/
void buildActualPortMapping() {
final Int2ObjectMap<VirtualHost> mapping = new Int2ObjectOpenHashMap<>();
for (VirtualHost vh : virtualHosts) {
final ServerPort sp = vh.serverPort();
if (sp != null && sp.localAddress().getPort() == 0) {
final int actualPort = sp.actualPort();
if (actualPort > 0) {
mapping.put(actualPort, vh);
}
}
}
if (!mapping.isEmpty()) {
actualPortToVirtualHost = mapping;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we defer building domain and port mapping until the actual port is resolved instead of adding a new maping?

Copy link
Author

@junjunclub junjunclub Feb 10, 2026

Choose a reason for hiding this comment

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

That's a good point. Deferring virtualHostAndPortMapping until after ports are bound would let us unify the two maps into one. The tradeoff is that virtualHostAndPortMapping is currently final and would need to become volatile, and the buildDomainAndPortMapping() logic would need to incorporate actual port resolution. I'm happy to refactor if you prefer a unified approach.

}
}
Comment on lines 409 to 420
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find ServerBuilder and virtualHost method implementations
find . -name "ServerBuilder.java" -type f | head -5

Repository: line/armeria

Length of output: 123


🏁 Script executed:

# Search for virtualHost method with ServerPort parameter
rg -n "virtualHost.*ServerPort" --type=java -B2 -A10 | head -100

Repository: line/armeria

Length of output: 8958


🏁 Script executed:

# Search for ServerPort class definition
find . -name "ServerPort.java" -type f

Repository: line/armeria

Length of output: 120


🏁 Script executed:

# Look for port validation in ServerBuilder context
rg -n "ServerPort.*port.*0|ephemeral" --type=java -B2 -A2 | head -80

Repository: line/armeria

Length of output: 8867


🏁 Script executed:

# Check ServerPort implementation to understand the actual port handling
cat core/src/main/java/com/linecorp/armeria/server/ServerPort.java

Repository: line/armeria

Length of output: 12854


🏁 Script executed:

# Look at buildDomainMapping to understand the full context
sed -n '330,350p' core/src/main/java/com/linecorp/armeria/server/DefaultServerConfig.java

Repository: line/armeria

Length of output: 1158


🏁 Script executed:

# Check if there's any validation in ServerBuilder that would prevent non-ephemeral ServerPort
sed -n '1880,1920p' core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java

Repository: line/armeria

Length of output: 1940


🏁 Script executed:

# Look for any documentation or comments about ServerPort usage constraints
rg -n "ServerPort.*ephemeral|virtualHost.*ServerPort" --type=java --type=mdx | grep -i "comment\|javadoc\|ephemeral\|doc" | head -20

Repository: line/armeria

Length of output: 83


🏁 Script executed:

# Check if there's any validation added in ServerBuilder for ephemeral ports
rg -n "virtualHost.*ServerPort|port.*0|ephemeral" core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java -B3 -A3 | head -60

Repository: line/armeria

Length of output: 2365


🏁 Script executed:

# Check if buildActualPortMapping is tested with non-ephemeral ports
rg -n "buildActualPortMapping|ServerPort.*[89][0-9]{2,}" core/src/test/java/com/linecorp/armeria/server/ -B2 -A2 | head -80

Repository: line/armeria

Length of output: 1843


🏁 Script executed:

# Check what happens after buildActualPortMapping - how is actualPortToVirtualHost used?
sed -n '450,470p' core/src/main/java/com/linecorp/armeria/server/DefaultServerConfig.java

Repository: line/armeria

Length of output: 907


🏁 Script executed:

# Look for any VirtualHostBuilder validation that might restrict ServerPort to ephemeral
rg -n "class VirtualHostBuilder" core/src/main/java/com/linecorp/armeria/server/ -A 30 | head -80

Repository: line/armeria

Length of output: 3644


🏁 Script executed:

# Check if there are any test cases that try to use non-ephemeral ServerPort with virtualHost()
rg -n "virtualHost.*new ServerPort.*[89]" core/src/test/java/com/linecorp/armeria/server/ -B2 -A5

Repository: line/armeria

Length of output: 38


🏁 Script executed:

# Check the VirtualHostBuilder constructor to see if it validates ServerPort
sed -n '145,180p' core/src/main/java/com/linecorp/armeria/server/VirtualHostBuilder.java

Repository: line/armeria

Length of output: 1332


🏁 Script executed:

# Look for the build() method of VirtualHostBuilder to see if it creates VirtualHost with validation
rg -n "VirtualHostBuilder.*build\(\)|new VirtualHost" core/src/main/java/com/linecorp/armeria/server/VirtualHostBuilder.java -A 5 | head -60

Repository: line/armeria

Length of output: 2308


🏁 Script executed:

# Get the full build() method from VirtualHostBuilder
sed -n '1400,1530p' core/src/main/java/com/linecorp/armeria/server/VirtualHostBuilder.java

Repository: line/armeria

Length of output: 7353


🏁 Script executed:

# Check if there's validation for ephemeral port requirement for ServerPort-based VirtualHosts
rg -n "serverPort.*port.*0|ephemeral.*ServerPort|build\(\)" core/src/main/java/com/linecorp/armeria/server/VirtualHostBuilder.java -B3 -A3 | head -100

Repository: line/armeria

Length of output: 3314


🏁 Script executed:

# Check the VirtualHost constructor to see if it validates serverPort
rg -n "class VirtualHost|VirtualHost(" core/src/main/java/com/linecorp/armeria/server/VirtualHost.java -A 2 | head -50

Repository: line/armeria

Length of output: 166


🏁 Script executed:

# Check if there are any integration tests that would catch the unreachable VirtualHost issue
rg -n "virtualHost.*ServerPort.*8080|virtualHost.*new ServerPort.*[1-9]" core/src/test/java/com/linecorp/armeria/server/PortBasedVirtualHostTest.java -B2 -A5

Repository: line/armeria

Length of output: 38


🏁 Script executed:

# Check VirtualHost constructor
rg -n "public VirtualHost\(" core/src/main/java/com/linecorp/armeria/server/VirtualHost.java -A 30 | head -80

Repository: line/armeria

Length of output: 38


🏁 Script executed:

# Search for any validation logic in VirtualHost that checks serverPort
rg -n "serverPort.*port.*0|checkArgument.*serverPort|checkState.*serverPort" core/src/main/java/com/linecorp/armeria/server/VirtualHost.java -B2 -A2

Repository: line/armeria

Length of output: 38


🏁 Script executed:

# Check the actual port in the comment about ServerPort-based virtual hosts
sed -n '1860,1900p' core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java

Repository: line/armeria

Length of output: 1793


ServerBuilder.virtualHost(ServerPort) must validate that the port is ephemeral (port 0).

The Javadoc and design explicitly state this API is for "random port (port 0)", and buildActualPortMapping only handles ephemeral ports where sp.localAddress().getPort() == 0. However, the API accepts any ServerPort without validation. A user calling virtualHost(new ServerPort(8080, HTTP)) would create a silently unreachable VirtualHost—it would be skipped by both the domain mapping (line 338) and the actual port mapping (requires port == 0).

Add a port validation check in ServerBuilder.virtualHost(ServerPort) to enforce that serverPort.localAddress().getPort() == 0, or document this constraint with a runtime assertion.

🤖 Prompt for AI Agents
In `@core/src/main/java/com/linecorp/armeria/server/DefaultServerConfig.java`
around lines 405 - 423, ServerBuilder.virtualHost(ServerPort) currently accepts
any ServerPort but DefaultServerConfig.buildActualPortMapping only maps
ephemeral ports (where ServerPort.localAddress().getPort() == 0), so add a
validation in ServerBuilder.virtualHost(ServerPort) to enforce ephemeral ports:
check serverPort.localAddress().getPort() == 0 and throw an
IllegalArgumentException (or use Objects.requireNonNull/assert) with a clear
message if not ephemeral; reference ServerBuilder.virtualHost(ServerPort),
ServerPort.localAddress().getPort(), and
DefaultServerConfig.buildActualPortMapping to locate the related logic.


@Override
public List<ServerPort> ports() {
return ports;
Expand Down Expand Up @@ -425,6 +449,14 @@ public VirtualHost findVirtualHost(String hostname) {

@Override
public VirtualHost findVirtualHost(String hostname, int port) {
final Int2ObjectMap<VirtualHost> portMapping = actualPortToVirtualHost;
if (portMapping != null) {
final VirtualHost vh = portMapping.get(port);
if (vh != null) {
return vh;
}
}

if (virtualHostAndPortMapping == null) {
return defaultVirtualHost;
}
Expand All @@ -437,6 +469,7 @@ public VirtualHost findVirtualHost(String hostname, int port) {
return virtualHost;
}
}

// No port-based virtual host is configured. Look for named-based virtual host.
final Mapping<String, VirtualHost> nameBasedMapping = virtualHostAndPortMapping.get(-1);
assert nameBasedMapping != null;
Expand Down
18 changes: 14 additions & 4 deletions core/src/main/java/com/linecorp/armeria/server/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -487,8 +487,11 @@ protected CompletionStage<Void> doStart(@Nullable Void arg) {
try {
doStart(primary).addListener(new ServerPortStartListener(primary))
.addListener(new NextServerPortStartListener(this, it, future));
// Chain the future to set up server metrics first before server start future is completed.
return future.thenAccept(unused -> setupPendingResponsesMetrics());
// Chain the future to set up server metrics and port mapping before server start future is completed.
return future.thenAccept(unused -> {
config.delegate().buildActualPortMapping();
setupPendingResponsesMetrics();
});
} catch (Throwable cause) {
future.completeExceptionally(cause);
return future;
Expand Down Expand Up @@ -798,14 +801,16 @@ public void operationComplete(ChannelFuture f) {
if (localAddress instanceof InetSocketAddress) {
actualPort = new ServerPort((InetSocketAddress) localAddress,
port.protocols(),
port.portGroup());
port.portGroup(),
port);
} else if (localAddress instanceof io.netty.channel.unix.DomainSocketAddress) {
// Convert Netty's DomainSocketAddress to ours.
final DomainSocketAddress converted = DomainSocketAddress.of(
(io.netty.channel.unix.DomainSocketAddress) localAddress);
actualPort = new ServerPort(converted,
port.protocols(),
port.portGroup());
port.portGroup(),
port);
} else {
logger.warn("Unexpected local address type: {}", localAddress.getClass().getName());
return;
Expand All @@ -814,6 +819,11 @@ public void operationComplete(ChannelFuture f) {
assert serverPortMetric != null;
actualPort.setServerPortMetric(serverPortMetric);

// Set the actual port on the original ServerPort for ephemeral ports
if (port.localAddress().getPort() == 0) {
port.setActualPort(actualPort.localAddress().getPort());
}

// Update the boss thread so its name contains the actual port.
Thread.currentThread().setName(bossThreadName(actualPort));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,52 @@ public VirtualHostBuilder virtualHost(int port) {
return virtualHostBuilder;
}

/**
* Adds the <a href="https://en.wikipedia.org/wiki/Virtual_hosting#Port-based">port-based virtual host</a>
* with the specified {@link ServerPort}. This method can be used to bind a virtual host to a
* random port (port 0).
*
* <p>Note that you cannot configure TLS to the port-based virtual host. Configure it to the
* {@link ServerBuilder} or a {@linkplain #virtualHost(String) name-based virtual host}.
*
* <p>Example usage for random ports:
* <pre>{@code
* ServerPort port1 = new ServerPort(0, SessionProtocol.HTTP);
* ServerPort port2 = new ServerPort(0, SessionProtocol.HTTP);
*
* Server server = Server.builder()
* .port(port1)
* .virtualHost(port1)
* .service("/foo", (ctx, req) -> HttpResponse.of("foo"))
* .and()
* .port(port2)
* .virtualHost(port2)
* .service("/bar", (ctx, req) -> HttpResponse.of("bar"))
* .and()
* .build();
* }</pre>
*
* @param serverPort the {@link ServerPort} that this virtual host binds to
* @return {@link VirtualHostBuilder} for building the virtual host
*/
@UnstableApi
public VirtualHostBuilder virtualHost(ServerPort serverPort) {
requireNonNull(serverPort, "serverPort");

// Look for a virtual host that has already been made with the same ServerPort instance.
final Optional<VirtualHostBuilder> vhost =
virtualHostBuilders.stream()
.filter(v -> v.serverPort() == serverPort && v.defaultVirtualHost())
.findFirst();
if (vhost.isPresent()) {
return vhost.get();
}

final VirtualHostBuilder virtualHostBuilder = new VirtualHostBuilder(this, serverPort);
virtualHostBuilders.add(virtualHostBuilder);
return virtualHostBuilder;
}

private VirtualHostBuilder findOrCreateVirtualHostBuilder(String hostnamePattern) {
requireNonNull(hostnamePattern, "hostnamePattern");
final HostAndPort hostAndPort = HostAndPort.fromString(hostnamePattern);
Expand Down Expand Up @@ -2458,6 +2504,16 @@ DefaultServerConfig buildServerConfig(List<ServerPort> serverPorts) {
virtualHostPort, portNumbers);
}

for (VirtualHostBuilder vhb : virtualHostBuilders) {
final ServerPort serverPort = vhb.serverPort();
if (serverPort != null) {
final boolean presentByIdentity = this.ports.stream().anyMatch(p -> p == serverPort);
checkState(presentByIdentity,
"The ServerPort for a virtual host is not in the server's port list. " +
"Please add the ServerPort using port(ServerPort) before creating a virtual host.");
}
}

checkState(defaultSslContext == null || tlsProvider == null,
"Can't set %s with a static TLS setting", TlsProvider.class.getSimpleName());
if (defaultSslContext == null && tlsProvider == null) {
Expand Down
58 changes: 58 additions & 0 deletions core/src/main/java/com/linecorp/armeria/server/ServerPort.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.linecorp.armeria.server;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.linecorp.armeria.common.SessionProtocol.HTTP;
import static com.linecorp.armeria.common.SessionProtocol.HTTPS;
import static com.linecorp.armeria.common.SessionProtocol.PROXY;
Expand Down Expand Up @@ -68,6 +69,13 @@ static long nextPortGroup() {
private int hashCode;
@Nullable
private ServerPortMetric serverPortMetric;
@Nullable
private final ServerPort originalServerPort;

/**
* The actual port after binding. -1 means not set yet.
*/
private volatile int actualPort = -1;

@Nullable
private String strVal;
Expand Down Expand Up @@ -113,6 +121,15 @@ public ServerPort(InetSocketAddress localAddress, Iterable<SessionProtocol> prot
* will choose the same port number for them, rather than allocating two ephemeral ports.
*/
ServerPort(InetSocketAddress localAddress, Iterable<SessionProtocol> protocols, long portGroup) {
this(localAddress, protocols, portGroup, null);
}

/**
* Creates a new {@link ServerPort} with a reference to the original {@link ServerPort}.
* This constructor is used internally when binding to an ephemeral port.
*/
ServerPort(InetSocketAddress localAddress, Iterable<SessionProtocol> protocols, long portGroup,
@Nullable ServerPort originalServerPort) {
// Try to resolve the localAddress if not resolved yet.
if (requireNonNull(localAddress, "localAddress").isUnresolved()) {
try {
Expand All @@ -127,6 +144,7 @@ public ServerPort(InetSocketAddress localAddress, Iterable<SessionProtocol> prot
this.localAddress = localAddress;
this.protocols = checkProtocols(protocols);
this.portGroup = portGroup;
this.originalServerPort = originalServerPort;

if (localAddress instanceof DomainSocketAddress) {
comparisonStr = ((DomainSocketAddress) localAddress).authority() + '/' + protocols;
Expand Down Expand Up @@ -228,6 +246,46 @@ long portGroup() {
return portGroup;
}

/**
* Returns the actual port this {@link ServerPort} is bound to.
* If the port was configured as 0 (ephemeral) and has been bound, returns the actual bound port.
* Otherwise, returns the configured port from {@link #localAddress()}.
*/
@UnstableApi
public int actualPort() {
final int actualPort = this.actualPort;
if (actualPort > 0) {
return actualPort;
}
return localAddress.getPort();
}

/**
* Sets the actual port after binding.
* This is only allowed when the configured port is 0 (ephemeral) and hasn't been set yet.
*
* @param actualPort the actual bound port
* @throws IllegalArgumentException if actualPort is not positive
* @throws IllegalStateException if the configured port is not 0 or actualPort was already set
*/
void setActualPort(int actualPort) {
checkArgument(actualPort > 0, "actualPort: %s (expected: > 0)", actualPort);
checkState(localAddress.getPort() == 0,
"Cannot set actualPort for non-ephemeral port: %s", localAddress.getPort());
checkState(this.actualPort == -1,
"actualPort is already set to %s", this.actualPort);
this.actualPort = actualPort;
}

/**
* Returns the original {@link ServerPort} that this port was created from,
* or {@code null} if this is an original port.
*/
@Nullable
ServerPort originalServerPort() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Question) Is this only used for testing?

Copy link
Author

@junjunclub junjunclub Feb 10, 2026

Choose a reason for hiding this comment

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

Yes, with the actualPortToVirtualHost map replacing the old loop in findVirtualHost(), originalServerPort() is no longer used in production code only in tests. I can remove it if it's no longer needed.

return originalServerPort;
}

@Nullable
ServerPortMetric serverPortMetric() {
return serverPortMetric;
Expand Down
33 changes: 30 additions & 3 deletions core/src/main/java/com/linecorp/armeria/server/VirtualHost.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ public final class VirtualHost {
private final String hostnamePattern;
private final int port;
@Nullable
private final ServerPort serverPort;
@Nullable
private final SslContext sslContext;
@Nullable
private final TlsProvider tlsProvider;
Expand Down Expand Up @@ -112,6 +114,7 @@ public final class VirtualHost {
private final Function<RoutingContext, RequestId> requestIdGenerator;

VirtualHost(String defaultHostname, String hostnamePattern, int port,
@Nullable ServerPort serverPort,
Copy link
Contributor

Choose a reason for hiding this comment

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

This change seems to introduce a compilation error in RoutersBenchmark.

@Nullable SslContext sslContext,
@Nullable TlsProvider tlsProvider,
@Nullable TlsEngineType tlsEngineType,
Expand Down Expand Up @@ -142,6 +145,7 @@ public final class VirtualHost {
this.hostnamePattern = hostnamePattern;
}
this.port = port;
this.serverPort = serverPort;
this.sslContext = sslContext;
this.tlsProvider = tlsProvider;
this.tlsEngineType = tlsEngineType;
Expand Down Expand Up @@ -182,7 +186,8 @@ VirtualHost withNewSslContext(SslContext sslContext) {
ReferenceCountUtil.release(sslContext);
throw new IllegalStateException("Cannot set a new SslContext when TlsProvider is set.");
}
return new VirtualHost(originalDefaultHostname, originalHostnamePattern, port, sslContext, null,
return new VirtualHost(originalDefaultHostname, originalHostnamePattern, port, serverPort,
sslContext, null,
tlsEngineType, serviceConfigs, fallbackServiceConfig,
RejectedRouteHandler.DISABLED, host -> accessLogger, defaultServiceNaming,
defaultLogName, requestTimeoutMillis, maxRequestLength, verboseResponses,
Expand Down Expand Up @@ -309,9 +314,15 @@ void setServerConfig(ServerConfig serverConfig) {
}

/**
* Returns the default hostname of this virtual host.
* Returns the name of the default host.
*/
public String defaultHostname() {
if (serverPort != null && serverPort.localAddress() != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Question) Can localAddress be null?

Suggested change
if (serverPort != null && serverPort.localAddress() != null) {
if (serverPort != null) {

Copy link
Author

Choose a reason for hiding this comment

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

Thank you for catching this. You're right, localAddress() returns a final field that is initialized with requireNonNull in the constructor, so it can never be null. I'll remove the unnecessary null check.

final int actualPort = serverPort.localAddress().getPort();
if (actualPort > 0) {
return originalDefaultHostname + ':' + actualPort;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit; could this be cached? Depending on the call path, this may be called for every request. Ditto for hostnamePattern.

Copy link
Author

Choose a reason for hiding this comment

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

Thank you for the suggestion! Since actualPort is fixed after server start, caching the computed string would avoid unnecessary allocation on repeated calls. I'll add cached fields and compute them lazily on the first access after the port is bound. 👍👍

}
}
return defaultHostname;
}

Expand All @@ -320,6 +331,12 @@ public String defaultHostname() {
* <a href="https://datatracker.ietf.org/doc/html/rfc2818#section-3.1">the section 3.1 of RFC2818</a>.
*/
public String hostnamePattern() {
if (serverPort != null && serverPort.localAddress() != null) {
final int actualPort = serverPort.localAddress().getPort();
if (actualPort > 0) {
return originalHostnamePattern + ':' + actualPort;
}
}
return hostnamePattern;
}

Expand All @@ -331,6 +348,15 @@ public int port() {
return port;
}

/**
* Returns the {@link ServerPort} that this virtual host is bound to,
* or {@code null} if this virtual host is not based on a {@link ServerPort}.
*/
@Nullable
ServerPort serverPort() {
return serverPort;
}

/**
* Returns the {@link SslContext} of this virtual host.
*/
Expand Down Expand Up @@ -602,7 +628,8 @@ VirtualHost decorate(@Nullable Function<? super HttpService, ? extends HttpServi
final ServiceConfig fallbackServiceConfig =
this.fallbackServiceConfig.withDecoratedService(decorator);

return new VirtualHost(originalDefaultHostname, originalHostnamePattern, port, sslContext, tlsProvider,
return new VirtualHost(originalDefaultHostname, originalHostnamePattern, port, serverPort,
sslContext, tlsProvider,
tlsEngineType, serviceConfigs, fallbackServiceConfig,
RejectedRouteHandler.DISABLED, host -> accessLogger, defaultServiceNaming,
defaultLogName, requestTimeoutMillis, maxRequestLength, verboseResponses,
Expand Down
Loading
Loading