Commit 9b6b663c authored by Andy Wilkinson's avatar Andy Wilkinson

Throw a PortInUseException when Netty start fails with a BindException

Closes gh-8737
parent ded7cea7
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
package org.springframework.boot.web.embedded.netty; package org.springframework.boot.web.embedded.netty;
import java.net.BindException; import java.net.BindException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
...@@ -24,6 +26,7 @@ import reactor.ipc.netty.http.HttpResources; ...@@ -24,6 +26,7 @@ import reactor.ipc.netty.http.HttpResources;
import reactor.ipc.netty.http.server.HttpServer; import reactor.ipc.netty.http.server.HttpServer;
import reactor.ipc.netty.tcp.BlockingNettyContext; import reactor.ipc.netty.tcp.BlockingNettyContext;
import org.springframework.boot.web.server.PortInUseException;
import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerException; import org.springframework.boot.web.server.WebServerException;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter; import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
...@@ -35,6 +38,7 @@ import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter; ...@@ -35,6 +38,7 @@ import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
* *
* @author Brian Clozel * @author Brian Clozel
* @author Madhura Bhave * @author Madhura Bhave
* @author Andy Wilkinson
* @since 2.0.0 * @since 2.0.0
*/ */
public class NettyWebServer implements WebServer { public class NettyWebServer implements WebServer {
...@@ -61,7 +65,11 @@ public class NettyWebServer implements WebServer { ...@@ -61,7 +65,11 @@ public class NettyWebServer implements WebServer {
} }
catch (Exception ex) { catch (Exception ex) {
if (findBindException(ex) != null) { if (findBindException(ex) != null) {
// throw new PortInUseException(); SocketAddress address = this.reactorServer.options().getAddress();
if (address instanceof InetSocketAddress) {
throw new PortInUseException(
((InetSocketAddress) address).getPort());
}
} }
throw new WebServerException("Unable to start Netty", ex); throw new WebServerException("Unable to start Netty", ex);
} }
...@@ -100,7 +108,8 @@ public class NettyWebServer implements WebServer { ...@@ -100,7 +108,8 @@ public class NettyWebServer implements WebServer {
if (this.nettyContext != null) { if (this.nettyContext != null) {
this.nettyContext.shutdown(); this.nettyContext.shutdown();
// temporary fix for gh-9146 // temporary fix for gh-9146
this.nettyContext.getContext().onClose().doOnSuccess(aVoid -> HttpResources.reset()).block(); this.nettyContext.getContext().onClose()
.doOnSuccess(aVoid -> HttpResources.reset()).block();
this.nettyContext = null; this.nettyContext = null;
} }
} }
......
...@@ -25,6 +25,7 @@ import reactor.core.publisher.Mono; ...@@ -25,6 +25,7 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
import org.springframework.boot.testsupport.rule.OutputCapture; import org.springframework.boot.testsupport.rule.OutputCapture;
import org.springframework.boot.web.server.PortInUseException;
import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.WebServer;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
...@@ -37,6 +38,7 @@ import org.springframework.web.reactive.function.client.ClientResponse; ...@@ -37,6 +38,7 @@ import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
/** /**
* Base for testing classes that extends {@link AbstractReactiveWebServerFactory}. * Base for testing classes that extends {@link AbstractReactiveWebServerFactory}.
...@@ -102,6 +104,19 @@ public abstract class AbstractReactiveWebServerFactoryTests { ...@@ -102,6 +104,19 @@ public abstract class AbstractReactiveWebServerFactoryTests {
assertThat(this.webServer.getPort()).isEqualTo(specificPort); assertThat(this.webServer.getPort()).isEqualTo(specificPort);
} }
@Test
public void portInUseExceptionIsThrownWhenPortIsAlreadyInUse() throws Exception {
AbstractReactiveWebServerFactory factory = getFactory();
factory.setPort(0);
this.webServer = factory.getWebServer(new EchoHandler());
this.webServer.start();
factory.setPort(this.webServer.getPort());
this.thrown.expect(PortInUseException.class);
this.thrown.expectMessage(
equalTo("Port " + this.webServer.getPort() + " is already in use"));
factory.getWebServer(new EchoHandler()).start();
}
protected WebClient getWebClient() { protected WebClient getWebClient() {
return WebClient.create("http://localhost:" + this.webServer.getPort()); return WebClient.create("http://localhost:" + this.webServer.getPort());
} }
......
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