spring-boot
spring-boot copied to clipboard
PortInUseException is not thrown if system language is not english
System language: german
The test Jetty10ServletWebServerFactoryTests#portClashOfPrimaryConnectorResultsInPortInUseException
only works if system language is set to english (export LANG=en
). But this should be a problem with production code, too.
The code in org.springframework.boot.web.server.PortInUseException#ifPortBindingException
checks if the error message contains the words "in use", which is not the case on non-english systems. On a german system the message is "java.net.BindException: Die Adresse wird bereits verwendet" for example.
One can workaround by setting LANG=en java -jar ...
when starting the application, then the error message will be english and PortInUseException
is thrown.
@mhalbritter I have checkout out the 2.5.x branch and I cannot see the portClashOfPrimaryConnectorResultsInPortInUseException test method in the org.springframework.boot.web.embedded.jetty.Jetty10ServletWebServerFactoryTests class.
It is inherited from a super-class: https://github.com/spring-projects/spring-boot/blob/1872af056ec059db2316db40ef19e2c1801af208/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java#L916
@wilkinsona Thanks for pointing it out! The problem here is that BindException contains just the error message - which is different for every language. Do you have any thoughts on what would be a good fix for this?
Should we just remove the if condition: if (bindException.getMessage().toLowerCase().contains("in use"))
and accept all BindExceptions
in the ifPortBindingException
method?
The error message comes from the operating system, and depends on the LANG
environment variable. We will have to find a better way to determine if there's a port clash going on than parsing the (localized) message. How we do that, I don't know at the moment.
Can we try based on the OS type -- lsof, netstat use for this? using ProcessBuilder
I don't think that's worth it.
Well then reading the OS error codes, 98 (EADDRINUSE) or 10048 (WSAEADDRINUSE) ..somewhere in the error stack would do it?
As far as I know, those error codes do not appear anywhere in the stack trace of the BindException
. If you have evidence to the contrary, please do share it.
try {
serverSocket.setReuseAddress(false);
serverSocket.bind(new InetSocketAddress(InetAddress.getByName("localhost"), 8080), 1);
serverSocket.bind(new InetSocketAddress(InetAddress.getByName("localhost"), 8080), 1);
} catch (SocketException be) {
if(serverSocket.isBound()) { // this check here should do it.
throw new BindException(be.getMessage());
}
}
The code that's trying to bind the socket isn't ours, it's part of the web server that we embed and, therefore, we cannot change it. All that we have available for analysis is the BindException
that's thrown by the JDK.
Well then we can translate the message/exception based on the lang/locale to en-US and then check for the port in use str?
Well then we can translate the message/exception based on the lang/locale to en-US and then check for the port in use str?
Any word here?
@somayaj I'm not sure that translating the message into every possible language is going to be feasible.
I don't think this one is fixable.