Skip to content

Commit 4934502

Browse files
committed
Merge branch '2.2.x'
Closes gh-21105
2 parents b73d503 + 93f7e2b commit 4934502

File tree

7 files changed

+84
-77
lines changed

7 files changed

+84
-77
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyWebServer.java

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.boot.web.embedded.jetty;
1818

1919
import java.io.IOException;
20-
import java.net.BindException;
2120
import java.time.Duration;
2221
import java.util.Arrays;
2322
import java.util.List;
@@ -174,8 +173,9 @@ public void start() throws WebServerException {
174173
connector.start();
175174
}
176175
catch (IOException ex) {
177-
if (connector instanceof NetworkConnector && findBindException(ex) != null) {
178-
throw new PortInUseException(((NetworkConnector) connector).getPort(), ex);
176+
if (connector instanceof NetworkConnector) {
177+
PortInUseException.throwIfPortBindingException(ex,
178+
() -> ((NetworkConnector) connector).getPort());
179179
}
180180
throw ex;
181181
}
@@ -195,16 +195,6 @@ public void start() throws WebServerException {
195195
}
196196
}
197197

198-
private BindException findBindException(Throwable ex) {
199-
if (ex == null) {
200-
return null;
201-
}
202-
if (ex instanceof BindException) {
203-
return (BindException) ex;
204-
}
205-
return findBindException(ex.getCause());
206-
}
207-
208198
private String getActualPortsDescription() {
209199
StringBuilder ports = new StringBuilder();
210200
for (Connector connector : this.server.getConnectors()) {

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,11 @@ public void start() throws WebServerException {
116116
this.disposableServer = startHttpServer();
117117
}
118118
catch (Exception ex) {
119-
ChannelBindException bindException = findBindException(ex);
120-
if (bindException != null && !isPermissionDenied(bindException.getCause())) {
121-
throw new PortInUseException(bindException.localPort(), ex);
122-
}
119+
PortInUseException.ifCausedBy(ex, ChannelBindException.class, (bindException) -> {
120+
if (!isPermissionDenied(bindException.getCause())) {
121+
throw new PortInUseException(bindException.localPort(), ex);
122+
}
123+
});
123124
throw new WebServerException("Unable to start Netty", ex);
124125
}
125126
logger.info("Netty started on port(s): " + getPort());
@@ -168,17 +169,6 @@ private void applyRouteProviders(HttpServerRoutes routes) {
168169
routes.route(ALWAYS, this.handler);
169170
}
170171

171-
private ChannelBindException findBindException(Exception ex) {
172-
Throwable candidate = ex;
173-
while (candidate != null) {
174-
if (candidate instanceof ChannelBindException) {
175-
return (ChannelBindException) candidate;
176-
}
177-
candidate = candidate.getCause();
178-
}
179-
return null;
180-
}
181-
182172
private void startDaemonAwaitThread(DisposableServer disposableServer) {
183173
Thread awaitThread = new Thread("server") {
184174

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.boot.web.embedded.tomcat;
1818

19-
import java.net.BindException;
2019
import java.time.Duration;
2120
import java.util.Arrays;
2221
import java.util.HashMap;
@@ -226,9 +225,7 @@ public void start() throws WebServerException {
226225
throw ex;
227226
}
228227
catch (Exception ex) {
229-
if (findBindException(ex) != null) {
230-
throw new PortInUseException(this.tomcat.getConnector().getPort());
231-
}
228+
PortInUseException.throwIfPortBindingException(ex, () -> this.tomcat.getConnector().getPort());
232229
throw new WebServerException("Unable to start embedded Tomcat server", ex);
233230
}
234231
finally {
@@ -251,16 +248,6 @@ private void checkConnectorHasStarted(Connector connector) {
251248
}
252249
}
253250

254-
private BindException findBindException(Throwable ex) {
255-
if (ex == null) {
256-
return null;
257-
}
258-
if (ex instanceof BindException) {
259-
return (BindException) ex;
260-
}
261-
return findBindException(ex.getCause());
262-
}
263-
264251
private void stopSilently() {
265252
try {
266253
stopTomcat();

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.boot.web.embedded.undertow;
1818

1919
import java.lang.reflect.Field;
20-
import java.net.BindException;
2120
import java.net.InetSocketAddress;
2221
import java.net.SocketAddress;
2322
import java.time.Duration;
@@ -173,14 +172,13 @@ public void start() throws WebServerException {
173172
}
174173
catch (Exception ex) {
175174
try {
176-
if (findBindException(ex) != null) {
175+
PortInUseException.ifPortBindingException(ex, (bindException) -> {
177176
List<Port> failedPorts = getConfiguredPorts();
178-
List<Port> actualPorts = getActualPorts();
179-
failedPorts.removeAll(actualPorts);
177+
failedPorts.removeAll(getActualPorts());
180178
if (failedPorts.size() == 1) {
181-
throw new PortInUseException(failedPorts.iterator().next().getNumber(), ex);
179+
throw new PortInUseException(failedPorts.get(0).getNumber());
182180
}
183-
}
181+
});
184182
throw new WebServerException("Unable to start embedded Undertow", ex);
185183
}
186184
finally {
@@ -207,17 +205,6 @@ private void stopSilently() {
207205
}
208206
}
209207

210-
private BindException findBindException(Exception ex) {
211-
Throwable candidate = ex;
212-
while (candidate != null) {
213-
if (candidate instanceof BindException) {
214-
return (BindException) candidate;
215-
}
216-
candidate = candidate.getCause();
217-
}
218-
return null;
219-
}
220-
221208
private Undertow createUndertowServer() throws ServletException {
222209
HttpHandler httpHandler = this.manager.start();
223210
httpHandler = getContextHandler(httpHandler);

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowWebServer.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.io.Closeable;
2020
import java.lang.reflect.Field;
21-
import java.net.BindException;
2221
import java.net.InetSocketAddress;
2322
import java.net.SocketAddress;
2423
import java.util.ArrayList;
@@ -121,14 +120,13 @@ public void start() throws WebServerException {
121120
}
122121
catch (Exception ex) {
123122
try {
124-
if (findBindException(ex) != null) {
125-
List<UndertowWebServer.Port> failedPorts = getConfiguredPorts();
126-
List<UndertowWebServer.Port> actualPorts = getActualPorts();
127-
failedPorts.removeAll(actualPorts);
123+
PortInUseException.ifPortBindingException(ex, (bindException) -> {
124+
List<Port> failedPorts = getConfiguredPorts();
125+
failedPorts.removeAll(getActualPorts());
128126
if (failedPorts.size() == 1) {
129-
throw new PortInUseException(failedPorts.iterator().next().getNumber(), ex);
127+
throw new PortInUseException(failedPorts.get(0).getNumber());
130128
}
131-
}
129+
});
132130
throw new WebServerException("Unable to start embedded Undertow", ex);
133131
}
134132
finally {
@@ -150,17 +148,6 @@ private void stopSilently() {
150148
}
151149
}
152150

153-
private BindException findBindException(Exception ex) {
154-
Throwable candidate = ex;
155-
while (candidate != null) {
156-
if (candidate instanceof BindException) {
157-
return (BindException) candidate;
158-
}
159-
candidate = candidate.getCause();
160-
}
161-
return null;
162-
}
163-
164151
private String getPortsDescription() {
165152
List<UndertowWebServer.Port> ports = getActualPorts();
166153
if (!ports.isEmpty()) {

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/PortInUseException.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@
1616

1717
package org.springframework.boot.web.server;
1818

19+
import java.net.BindException;
20+
import java.util.function.Consumer;
21+
import java.util.function.IntSupplier;
22+
1923
/**
2024
* A {@code PortInUseException} is thrown when a web server fails to start due to a port
2125
* already being in use.
2226
*
2327
* @author Andy Wilkinson
28+
* @author Phillip Webb
2429
* @since 2.0.0
2530
*/
2631
public class PortInUseException extends WebServerException {
@@ -53,4 +58,53 @@ public int getPort() {
5358
return this.port;
5459
}
5560

61+
/**
62+
* Throw a {@link PortInUseException} if the given exception was caused by a "port in
63+
* use" {@link BindException}.
64+
* @param ex the source exception
65+
* @param port a suppler used to provide the port
66+
* @since 2.2.7
67+
*/
68+
public static void throwIfPortBindingException(Exception ex, IntSupplier port) {
69+
ifPortBindingException(ex, (bindException) -> {
70+
throw new PortInUseException(port.getAsInt(), ex);
71+
});
72+
}
73+
74+
/**
75+
* Perform an action if the given exception was caused by a "port in use"
76+
* {@link BindException}.
77+
* @param ex the source exception
78+
* @param action the action to perform
79+
* @since 2.2.7
80+
*/
81+
public static void ifPortBindingException(Exception ex, Consumer<BindException> action) {
82+
ifCausedBy(ex, BindException.class, (bindException) -> {
83+
// bind exception can be also thrown because an address can't be assigned
84+
if (bindException.getMessage().toLowerCase().contains("in use")) {
85+
action.accept(bindException);
86+
}
87+
});
88+
}
89+
90+
/**
91+
* Perform an action if the given exception was caused by a specific exception type.
92+
* @param <E> the cause exception type
93+
* @param ex the source exception
94+
* @param causedBy the required cause type
95+
* @param action the action to perform
96+
* @since 2.2.7
97+
*/
98+
@SuppressWarnings("unchecked")
99+
public static <E extends Exception> void ifCausedBy(Exception ex, Class<E> causedBy, Consumer<E> action) {
100+
Throwable candidate = ex;
101+
while (candidate != null) {
102+
if (causedBy.isInstance(candidate)) {
103+
action.accept((E) candidate);
104+
return;
105+
}
106+
candidate = candidate.getCause();
107+
}
108+
}
109+
56110
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.io.IOException;
2323
import java.io.InputStream;
2424
import java.io.PrintWriter;
25+
import java.net.InetAddress;
2526
import java.net.InetSocketAddress;
2627
import java.net.MalformedURLException;
2728
import java.net.ServerSocket;
@@ -112,6 +113,7 @@
112113
import org.springframework.boot.web.server.Compression;
113114
import org.springframework.boot.web.server.ErrorPage;
114115
import org.springframework.boot.web.server.MimeMappings;
116+
import org.springframework.boot.web.server.PortInUseException;
115117
import org.springframework.boot.web.server.Shutdown;
116118
import org.springframework.boot.web.server.Ssl;
117119
import org.springframework.boot.web.server.Ssl.ClientAuth;
@@ -919,6 +921,16 @@ void portClashOfSecondaryConnectorResultsInPortInUseException() throws Exception
919921
});
920922
}
921923

924+
@Test
925+
void malformedAddress() throws Exception {
926+
AbstractServletWebServerFactory factory = getFactory();
927+
factory.setAddress(InetAddress.getByName("123456"));
928+
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> {
929+
this.webServer = factory.getWebServer();
930+
this.webServer.start();
931+
}).isNotInstanceOf(PortInUseException.class);
932+
}
933+
922934
@Test
923935
void localeCharsetMappingsAreConfigured() {
924936
AbstractServletWebServerFactory factory = getFactory();

0 commit comments

Comments
 (0)