Affects: 5.0.2 - 5.2.5
The latest versions of spring-test since 5.0.2 don't include the IPV6 address in the getRequestURL() in correct []-quoting.
For example if the MockHttpServletRequest is constructed using "GET", "/" and then the server name is set with a call to setServerName("::ffff:abcd:abcd"), then getRequestURL() returns "http://[::ffff:abcd:abcd]/" in the old versions, but latest versions return "http://::ffff:abcd:abcd/" which cannot be parsed by java.net.URL.
The problem seems to happen in the getRequestURL() implementation which uses getServerName() and does not check if the serverName is actually IPV6 address which should be quoted with brackets.
See RFC 2732 for reference.
@Test
public void testIPV6() {
String ipv6 = "::ffff:abcd:abcd";
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
request.addHeader("Host", "["+ipv6+"]");
request.setServerName("["+ipv6+"]");
String urlString = request.getRequestURL().toString();
System.out.println("#URL: \"" + urlString+"\"");
// The URL should look like: "http://[::ffff:abcd:abcd]/"
try {
java.net.URL url = new java.net.URL(urlString);
} catch (java.net.MalformedURLException e) {
assertEquals(e, null);
}
}
Comment From: sbrannen
This is related to #16704 and #20686.
The work done in conjunction with #20686 appears to have resulted in this change of behavior. Note, however, that those changes were made in 5.0.2 but backported to 4.3.13.
Comment From: sbrannen
After introducing the following two tests in MockHttpServletRequestTests on master, I can confirm that getRequestURLWithIpv6AddressViaHostHeader() fails; whereas, the other one passes.
Thus, the URL returned by getRequestURL() cannot be parsed by java.net.URL if an IPV6 Host header was set in the request.
@Test
void getRequestURLWithIpv6AddressViaServerName() throws Exception {
String ipv6Address = "[::ffff:abcd:abcd]";
request.setServerName(ipv6Address);
URL url = new java.net.URL(request.getRequestURL().toString());
assertThat(url).asString().isEqualTo("http://[::ffff:abcd:abcd]");
}
@Test
void getRequestURLWithIpv6AddressViaHostHeader() throws Exception {
String ipv6Address = "[::ffff:abcd:abcd]";
request.addHeader("Host", ipv6Address);
URL url = new java.net.URL(request.getRequestURL().toString());
assertThat(url).asString().isEqualTo("http://[::ffff:abcd:abcd]");
}
Comment From: sbrannen
@jusmaki, thanks for bringing this to our attention!
After further investigation, I have determined that the change I made in #16704 actually introduced a regression in Spring Framework 4.1 for the getServerName() method, and the changes in #20686 introduced a regression in getRequestURL() by delegating to the getServerName() method.
We will therefore ensure that enclosing brackets are no longer stripped from IPV6 host names when supplied via the Host header in a MockHttpServletRequest, and we'll backport the fix to all currently maintained branches.
For example, when using Tomcat as the Servlet container, a request sent to http://[0:0:0:0:0:0:0:1]:8080/events from a browser results in the following in the Servlet that processes the ServletRequest.
request.getHeader("Host"):[::1]:8080request.getServerName():[::1]request.getRequestURL():http://[::1]:8080/events