From a2fdf23e41020a9cc54ea3334618686bf28685de Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 20 Apr 2020 17:31:03 -0700 Subject: [PATCH] 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 0f23b94b13ab..3c3a1e7359bf 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 @@ 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 @@ */ 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 void start() throws WebServerException { } 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 void start() throws WebServerException { } } + 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);