From 85befdf10e57ea092974a9351d11b53a30a48d93 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 20 Apr 2020 17:30:58 -0700 Subject: [PATCH 1/3] Polish --- .../main/java/sample/webflux/SampleWebFluxApplication.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-samples/spring-boot-sample-webflux/src/main/java/sample/webflux/SampleWebFluxApplication.java b/spring-boot-samples/spring-boot-sample-webflux/src/main/java/sample/webflux/SampleWebFluxApplication.java index 3da0dadc72e..c303feb6e8e 100644 --- a/spring-boot-samples/spring-boot-sample-webflux/src/main/java/sample/webflux/SampleWebFluxApplication.java +++ b/spring-boot-samples/spring-boot-sample-webflux/src/main/java/sample/webflux/SampleWebFluxApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ import static org.springframework.web.reactive.function.server.RouterFunctions.r public class SampleWebFluxApplication { public static void main(String[] args) { - SpringApplication.run(SampleWebFluxApplication.class); + SpringApplication.run(SampleWebFluxApplication.class, args); } @Bean From c7611112f732586ea94d75939368e96a86cf7b3c Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 20 Apr 2020 17:29:50 -0700 Subject: [PATCH 2/3] Include cause when throwing PortInUseException Update classes that throw `PortInUseException` so that they also include the cause. Prior to this commit the cause was not included which could make diagnosing the real cause difficult. See gh-19807 --- .../boot/web/embedded/jetty/JettyWebServer.java | 2 +- .../boot/web/embedded/netty/NettyWebServer.java | 4 ++-- .../embedded/undertow/UndertowServletWebServer.java | 4 ++-- .../web/embedded/undertow/UndertowWebServer.java | 4 ++-- .../boot/web/server/PortInUseException.java | 13 +++++++++++-- .../netty/NettyReactiveWebServerFactoryTests.java | 2 +- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyWebServer.java index d174f2fc56a..ad98984b7ec 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyWebServer.java @@ -148,7 +148,7 @@ public class JettyWebServer implements WebServer { } catch (IOException ex) { if (connector instanceof NetworkConnector && findBindException(ex) != null) { - throw new PortInUseException(((NetworkConnector) connector).getPort()); + throw new PortInUseException(((NetworkConnector) connector).getPort(), ex); } throw ex; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java index 36f86ac9052..0f23b94b13a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -69,7 +69,7 @@ public class NettyWebServer implements WebServer { catch (Exception ex) { ChannelBindException bindException = findBindException(ex); if (bindException != null) { - throw new PortInUseException(bindException.localPort()); + throw new PortInUseException(bindException.localPort(), ex); } throw new WebServerException("Unable to start Netty", ex); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java index 4003d0f5ece..45ea5954f89 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -151,7 +151,7 @@ public class UndertowServletWebServer implements WebServer { List actualPorts = getActualPorts(); failedPorts.removeAll(actualPorts); if (failedPorts.size() == 1) { - throw new PortInUseException(failedPorts.iterator().next().getNumber()); + throw new PortInUseException(failedPorts.iterator().next().getNumber(), ex); } } throw new WebServerException("Unable to start embedded Undertow", ex); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowWebServer.java index 6f099dbdb6b..bb6f10d8daa 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowWebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -109,7 +109,7 @@ public class UndertowWebServer implements WebServer { List actualPorts = getActualPorts(); failedPorts.removeAll(actualPorts); if (failedPorts.size() == 1) { - throw new PortInUseException(failedPorts.iterator().next().getNumber()); + throw new PortInUseException(failedPorts.iterator().next().getNumber(), ex); } } throw new WebServerException("Unable to start embedded Undertow", ex); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/PortInUseException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/PortInUseException.java index 2b7e0bcfa44..edfb21c2a52 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/PortInUseException.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/PortInUseException.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,16 @@ public class PortInUseException extends WebServerException { * @param port the port that was in use */ public PortInUseException(int port) { - super("Port " + port + " is already in use", null); + this(port, null); + } + + /** + * Creates a new port in use exception for the given {@code port}. + * @param port the port that was in use + * @param cause the cause of the exception + */ + public PortInUseException(int port, Throwable cause) { + super("Port " + port + " is already in use", cause); this.port = port; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java index c455ae901bc..09f0eec85a0 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java @@ -62,7 +62,7 @@ public class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServe this.webServer.start(); factory.setPort(this.webServer.getPort()); assertThatExceptionOfType(PortInUseException.class).isThrownBy(factory.getWebServer(new EchoHandler())::start) - .satisfies(this::portMatchesRequirement); + .satisfies(this::portMatchesRequirement).withCauseInstanceOf(Throwable.class); } private void portMatchesRequirement(PortInUseException exception) { From a2fdf23e41020a9cc54ea3334618686bf28685de Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 20 Apr 2020 17:31:03 -0700 Subject: [PATCH 3/3] Don't throw NettyWebServer on permission errors Update `NettyWebServer` so that the `PortInUseException` is not thrown for permission denied errors. Fixes gh-19807 --- .../web/embedded/netty/NettyWebServer.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java index 0f23b94b13a..3c3a1e7359b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java @@ -18,6 +18,7 @@ package org.springframework.boot.web.embedded.netty; import java.time.Duration; +import io.netty.channel.unix.Errors.NativeIoException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import reactor.netty.ChannelBindException; @@ -42,6 +43,11 @@ import org.springframework.util.Assert; */ public class NettyWebServer implements WebServer { + /** + * Permission denied error code from {@code errno.h}. + */ + private static final int ERROR_NO_EACCES = -13; + private static final Log logger = LogFactory.getLog(NettyWebServer.class); private final HttpServer httpServer; @@ -68,7 +74,7 @@ public class NettyWebServer implements WebServer { } catch (Exception ex) { ChannelBindException bindException = findBindException(ex); - if (bindException != null) { + if (bindException != null && !isPermissionDenied(bindException.getCause())) { throw new PortInUseException(bindException.localPort(), ex); } throw new WebServerException("Unable to start Netty", ex); @@ -78,6 +84,17 @@ public class NettyWebServer implements WebServer { } } + private boolean isPermissionDenied(Throwable bindExceptionCause) { + try { + if (bindExceptionCause instanceof NativeIoException) { + return ((NativeIoException) bindExceptionCause).expectedErr() == ERROR_NO_EACCES; + } + } + catch (Throwable ex) { + } + return false; + } + private DisposableServer startHttpServer() { if (this.lifecycleTimeout != null) { return this.httpServer.handle(this.handlerAdapter).bindNow(this.lifecycleTimeout);