diff --git a/spring/boot2-actuator-autoconfigure/src/test/resources/application-autoConfTest.yml b/spring/boot2-actuator-autoconfigure/src/test/resources/application-autoConfTest.yml index 36607b244df..5c0d4c7cea7 100644 --- a/spring/boot2-actuator-autoconfigure/src/test/resources/application-autoConfTest.yml +++ b/spring/boot2-actuator-autoconfigure/src/test/resources/application-autoConfTest.yml @@ -2,10 +2,10 @@ armeria: ports: - port: 0 protocol: HTTP - - ip: 127.0.0.1 + - address: 127.0.0.1 port: 0 protocol: HTTP - - ip: 0.0.0.0 + - address: 0.0.0.0 port: 0 protocol: HTTP diff --git a/spring/boot2-actuator-autoconfigure/src/test/resources/application-managedMetricPath.yml b/spring/boot2-actuator-autoconfigure/src/test/resources/application-managedMetricPath.yml index c61cc9ca49a..8a61e015e06 100644 --- a/spring/boot2-actuator-autoconfigure/src/test/resources/application-managedMetricPath.yml +++ b/spring/boot2-actuator-autoconfigure/src/test/resources/application-managedMetricPath.yml @@ -2,10 +2,10 @@ armeria: ports: - port: 0 protocol: HTTP - - ip: 127.0.0.1 + - address: 127.0.0.1 port: 0 protocol: HTTP - - ip: 0.0.0.0 + - address: 0.0.0.0 port: 0 protocol: HTTP metrics-path: '' diff --git a/spring/boot2-autoconfigure/src/main/java/com/linecorp/armeria/internal/spring/ArmeriaConfigurationNetUtil.java b/spring/boot2-autoconfigure/src/main/java/com/linecorp/armeria/internal/spring/ArmeriaConfigurationNetUtil.java index e8c204f8880..0353a26e56d 100644 --- a/spring/boot2-autoconfigure/src/main/java/com/linecorp/armeria/internal/spring/ArmeriaConfigurationNetUtil.java +++ b/spring/boot2-autoconfigure/src/main/java/com/linecorp/armeria/internal/spring/ArmeriaConfigurationNetUtil.java @@ -50,13 +50,12 @@ public static void configurePorts(ServerBuilder server, List ports) { requireNonNull(server, "server"); requireNonNull(ports, "ports"); ports.forEach(p -> { - final String ip = p.getIp(); final String iface = p.getIface(); final int port = p.getPort(); final List protocols = firstNonNull(p.getProtocols(), ImmutableList.of(SessionProtocol.HTTP)); - - if (ip == null) { + final InetSocketAddress socketAddress = createSocketAddress(p); + if (socketAddress == null) { if (iface == null) { server.port(new ServerPort(port, protocols)); } else { @@ -71,24 +70,42 @@ public static void configurePorts(ServerBuilder server, List ports) { } } } else if (iface == null) { - if (NetUtil.isValidIpV4Address(ip) || NetUtil.isValidIpV6Address(ip)) { - final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(ip); - try { - server.port(new ServerPort(new InetSocketAddress( - InetAddress.getByAddress(bytes), port), protocols)); - } catch (UnknownHostException e) { - // Should never happen. - throw new Error(e); - } - } else { - throw new IllegalStateException("invalid IP address: " + ip); - } + server.port(new ServerPort(socketAddress, protocols)); } else { throw new IllegalStateException("A port cannot have both IP and iface: " + p); } }); } + @Nullable + private static InetSocketAddress createSocketAddress(Port p) { + final InetAddress address = p.getAddress(); + final String ip = p.getIp(); + final int port = p.getPort(); + if (ip != null && address != null) { + throw new IllegalStateException("A port cannot have both IP and address: " + p); + } + final InetSocketAddress targetAddress; + if (ip != null) { + if (NetUtil.isValidIpV4Address(ip) || NetUtil.isValidIpV6Address(ip)) { + final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(ip); + try { + targetAddress = new InetSocketAddress(InetAddress.getByAddress(bytes), port); + } catch (UnknownHostException e) { + // Should never happen. + throw new Error(e); + } + } else { + throw new IllegalStateException("invalid IP address: " + ip); + } + } else if (address != null) { + targetAddress = new InetSocketAddress(address, port); + } else { + targetAddress = null; + } + return targetAddress; + } + /** * Returns a newly created {@link Port}. * {@code null} if the specified {@code code} is either {@code null} or a negative number. diff --git a/spring/boot2-autoconfigure/src/main/java/com/linecorp/armeria/spring/ArmeriaSettings.java b/spring/boot2-autoconfigure/src/main/java/com/linecorp/armeria/spring/ArmeriaSettings.java index fb4ef915820..83c30a67b53 100644 --- a/spring/boot2-autoconfigure/src/main/java/com/linecorp/armeria/spring/ArmeriaSettings.java +++ b/spring/boot2-autoconfigure/src/main/java/com/linecorp/armeria/spring/ArmeriaSettings.java @@ -15,6 +15,7 @@ */ package com.linecorp.armeria.spring; +import java.net.InetAddress; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -24,6 +25,7 @@ import org.springframework.validation.annotation.Validated; import com.codahale.metrics.json.MetricsModule; +import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; import com.linecorp.armeria.common.SessionProtocol; @@ -48,7 +50,7 @@ * ports: * - port: 8080 * protocol: HTTP - * - ip: 127.0.0.1 + * - address: 127.0.0.1 * port: 8081 * protocol:HTTP * - port: 8443 @@ -82,10 +84,19 @@ public class ArmeriaSettings { public static class Port { /** * IP address to bind to. If not set, will bind to all addresses, e.g. {@code 0.0.0.0}. + * + * @deprecated Use {@link #address} instead. */ + @Deprecated @Nullable private String ip; + /** + * Network address to bind to. If not set, will bind to all addresses, e.g. {@code 0.0.0.0}. + */ + @Nullable + private InetAddress address; + /** * Network interface to bind to. If not set, will bind to the first detected network interface. */ @@ -105,7 +116,10 @@ public static class Port { /** * Returns the IP address that the {@link Server} uses. + * + * @deprecated Use {@link #getAddress()} instead. */ + @Deprecated @Nullable public String getIp() { return ip; @@ -113,12 +127,31 @@ public String getIp() { /** * Registers an IP address that the {@link Server} uses. + * + * @deprecated Use {@link #setAddress(InetAddress)} instead. */ + @Deprecated public Port setIp(String ip) { this.ip = ip; return this; } + /** + * Returns the network address that the {@link Server} uses. + */ + @Nullable + public InetAddress getAddress() { + return address; + } + + /** + * Registers a network address that the {@link Server} uses. + */ + public Port setAddress(InetAddress address) { + this.address = address; + return this; + } + /** * Returns the network interface that the {@link Server} uses. */ @@ -173,6 +206,17 @@ public Port setProtocol(SessionProtocol protocol) { protocols = ImmutableList.of(protocol); return this; } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).omitNullValues() + .add("ip", ip) + .add("address", address) + .add("iface", iface) + .add("port", port) + .add("protocols", protocols) + .toString(); + } } /** diff --git a/spring/boot2-autoconfigure/src/test/java/com/linecorp/armeria/spring/DeprecatedIpTest.java b/spring/boot2-autoconfigure/src/test/java/com/linecorp/armeria/spring/DeprecatedIpTest.java new file mode 100644 index 00000000000..36e78f14cb4 --- /dev/null +++ b/spring/boot2-autoconfigure/src/test/java/com/linecorp/armeria/spring/DeprecatedIpTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2023 LINE Corporation + * + * LINE Corporation licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.linecorp.armeria.spring; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.InetAddress; +import java.util.Collection; + +import javax.inject.Inject; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import com.linecorp.armeria.server.Server; +import com.linecorp.armeria.server.ServerPort; +import com.linecorp.armeria.spring.ArmeriaSettings.Port; +import com.linecorp.armeria.spring.DeprecatedIpTest.TestConfiguration; + +/** + * Tests for keeping the behavior of deprecated {@link Port#getIp()}. + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestConfiguration.class) +@ActiveProfiles({ "local", "deprecatedIpTest" }) +@DirtiesContext +public class DeprecatedIpTest { + + @SpringBootApplication + static class TestConfiguration {} + + @Inject + private Server server; + + @Test + public void testIpCanBeUsed() { + final Collection serverPorts = server.activePorts().values(); + for (ServerPort sp : serverPorts) { + final InetAddress address = sp.localAddress().getAddress(); + if ("127.0.0.1".equals(address.getHostAddress())) { + assertThat(address.isLoopbackAddress()).isTrue(); + } else { + // Setting 0.0.0.0 at properties + assertThat(address.isAnyLocalAddress()).isTrue(); + } + } + } +} diff --git a/spring/boot2-autoconfigure/src/test/java/com/linecorp/armeria/spring/LocalhostAddressTest.java b/spring/boot2-autoconfigure/src/test/java/com/linecorp/armeria/spring/LocalhostAddressTest.java new file mode 100644 index 00000000000..3bf905c1bd0 --- /dev/null +++ b/spring/boot2-autoconfigure/src/test/java/com/linecorp/armeria/spring/LocalhostAddressTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023 LINE Corporation + * + * LINE Corporation licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.linecorp.armeria.spring; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.InetAddress; +import java.util.Collection; + +import javax.inject.Inject; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import com.linecorp.armeria.server.Server; +import com.linecorp.armeria.server.ServerPort; +import com.linecorp.armeria.spring.ArmeriaSettings.Port; +import com.linecorp.armeria.spring.LocalhostAddressTest.TestConfiguration; + +/** + * Tests for keeping the behavior of {@link Port#getIp()}. + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestConfiguration.class) +@ActiveProfiles({ "local", "localhostAddressTest" }) +@DirtiesContext +public class LocalhostAddressTest { + + @SpringBootApplication + static class TestConfiguration {} + + @Inject + private Server server; + + @Test + public void testLocalhostAddressCanBeUsed() { + final Collection serverPorts = server.activePorts().values(); + assertThat(serverPorts).hasSize(1); + for (ServerPort sp : serverPorts) { + final InetAddress address = sp.localAddress().getAddress(); + assertThat(address.isLoopbackAddress()).isTrue(); + } + } +} diff --git a/spring/boot2-autoconfigure/src/test/resources/config/application-autoConfTest.yml b/spring/boot2-autoconfigure/src/test/resources/config/application-autoConfTest.yml index 3f292b12bf7..a6c80eca7b2 100644 --- a/spring/boot2-autoconfigure/src/test/resources/config/application-autoConfTest.yml +++ b/spring/boot2-autoconfigure/src/test/resources/config/application-autoConfTest.yml @@ -8,10 +8,10 @@ armeria: ports: - port: 0 protocol: HTTP - - ip: 127.0.0.1 + - address: 127.0.0.1 port: 0 protocol: HTTP - - ip: 0.0.0.0 + - address: 0.0.0.0 port: 0 protocol: HTTP enable-auto-injection: true diff --git a/spring/boot2-autoconfigure/src/test/resources/config/application-deprecatedIpTest.yml b/spring/boot2-autoconfigure/src/test/resources/config/application-deprecatedIpTest.yml new file mode 100644 index 00000000000..1876681afc4 --- /dev/null +++ b/spring/boot2-autoconfigure/src/test/resources/config/application-deprecatedIpTest.yml @@ -0,0 +1,8 @@ +armeria: + ports: + - ip: 127.0.0.1 + port: 0 + protocol: HTTP + - ip: 0.0.0.0 + port: 0 + protocol: HTTP diff --git a/spring/boot2-autoconfigure/src/test/resources/config/application-localhostAddressTest.yml b/spring/boot2-autoconfigure/src/test/resources/config/application-localhostAddressTest.yml new file mode 100644 index 00000000000..9eba0dbd23c --- /dev/null +++ b/spring/boot2-autoconfigure/src/test/resources/config/application-localhostAddressTest.yml @@ -0,0 +1,5 @@ +armeria: + ports: + - address: localhost + port: 0 + protocol: HTTP