Commit 7d68c7c4 authored by Phillip Webb's avatar Phillip Webb

Merge branch '2.1.x' into 2.2.x

Closes gh-21052
parents 4e0fdbee a2fdf23e
...@@ -148,7 +148,7 @@ public class JettyWebServer implements WebServer { ...@@ -148,7 +148,7 @@ public class JettyWebServer implements WebServer {
} }
catch (IOException ex) { catch (IOException ex) {
if (connector instanceof NetworkConnector && findBindException(ex) != null) { if (connector instanceof NetworkConnector && findBindException(ex) != null) {
throw new PortInUseException(((NetworkConnector) connector).getPort()); throw new PortInUseException(((NetworkConnector) connector).getPort(), ex);
} }
throw ex; throw ex;
} }
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -21,6 +21,7 @@ import java.util.Collections; ...@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
import io.netty.channel.unix.Errors.NativeIoException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import reactor.netty.ChannelBindException; import reactor.netty.ChannelBindException;
...@@ -47,7 +48,12 @@ import org.springframework.util.Assert; ...@@ -47,7 +48,12 @@ import org.springframework.util.Assert;
*/ */
public class NettyWebServer implements WebServer { public class NettyWebServer implements WebServer {
private static final Predicate<HttpServerRequest> ALWAYS = (r) -> true; /**
* Permission denied error code from {@code errno.h}.
*/
private static final int ERROR_NO_EACCES = -13;
private static final Predicate<HttpServerRequest> ALWAYS = (request) -> true;
private static final Log logger = LogFactory.getLog(NettyWebServer.class); private static final Log logger = LogFactory.getLog(NettyWebServer.class);
...@@ -81,8 +87,8 @@ public class NettyWebServer implements WebServer { ...@@ -81,8 +87,8 @@ public class NettyWebServer implements WebServer {
} }
catch (Exception ex) { catch (Exception ex) {
ChannelBindException bindException = findBindException(ex); ChannelBindException bindException = findBindException(ex);
if (bindException != null) { if (bindException != null && !isPermissionDenied(bindException.getCause())) {
throw new PortInUseException(bindException.localPort()); throw new PortInUseException(bindException.localPort(), ex);
} }
throw new WebServerException("Unable to start Netty", ex); throw new WebServerException("Unable to start Netty", ex);
} }
...@@ -91,6 +97,17 @@ public class NettyWebServer implements WebServer { ...@@ -91,6 +97,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() { private DisposableServer startHttpServer() {
HttpServer server = this.httpServer; HttpServer server = this.httpServer;
if (this.routeProviders.isEmpty()) { if (this.routeProviders.isEmpty()) {
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -151,7 +151,7 @@ public class UndertowServletWebServer implements WebServer { ...@@ -151,7 +151,7 @@ public class UndertowServletWebServer implements WebServer {
List<Port> actualPorts = getActualPorts(); List<Port> actualPorts = getActualPorts();
failedPorts.removeAll(actualPorts); failedPorts.removeAll(actualPorts);
if (failedPorts.size() == 1) { 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); throw new WebServerException("Unable to start embedded Undertow", ex);
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -109,7 +109,7 @@ public class UndertowWebServer implements WebServer { ...@@ -109,7 +109,7 @@ public class UndertowWebServer implements WebServer {
List<UndertowWebServer.Port> actualPorts = getActualPorts(); List<UndertowWebServer.Port> actualPorts = getActualPorts();
failedPorts.removeAll(actualPorts); failedPorts.removeAll(actualPorts);
if (failedPorts.size() == 1) { 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); throw new WebServerException("Unable to start embedded Undertow", ex);
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -32,7 +32,16 @@ public class PortInUseException extends WebServerException { ...@@ -32,7 +32,16 @@ public class PortInUseException extends WebServerException {
* @param port the port that was in use * @param port the port that was in use
*/ */
public PortInUseException(int port) { 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; this.port = port;
} }
......
...@@ -62,7 +62,7 @@ class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactor ...@@ -62,7 +62,7 @@ class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactor
this.webServer.start(); this.webServer.start();
factory.setPort(this.webServer.getPort()); factory.setPort(this.webServer.getPort());
assertThatExceptionOfType(PortInUseException.class).isThrownBy(factory.getWebServer(new EchoHandler())::start) assertThatExceptionOfType(PortInUseException.class).isThrownBy(factory.getWebServer(new EchoHandler())::start)
.satisfies(this::portMatchesRequirement); .satisfies(this::portMatchesRequirement).withCauseInstanceOf(Throwable.class);
} }
private void portMatchesRequirement(PortInUseException exception) { private void portMatchesRequirement(PortInUseException exception) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment