Skip to content

Commit f60bb82

Browse files
committed
Retain brackets for IPV6 address in MockHttpServletRequest
According to the Javadoc for ServletRequest's getServerName() method, when the `Host` header is set, the server name is "the value of the part before ':' in the Host header value ...". For a value representing an IPV6 address such as `[::ffff:abcd:abcd]`, the enclosing square brackets should therefore not be stripped from the enclosed IPV6 address. However, the changes made in conjunction with gh-16704 introduced a regression in Spring Framework 4.1 for the getServerName() method in MockHttpServletRequest by stripping the enclosing brackets from the IPV6 address in the `Host` header. Similarly, the changes made in conjunction with gh-20686 introduced a regression in Spring Framework 4.3.13 and 5.0.2 in the getRequestURL() method in MockHttpServletRequest by delegating to the getServerName() method which strips the enclosing brackets. This commit fixes the implementation of getServerName() so that the enclosing brackets are no longer stripped from an IPV6 address in the `Host` header. The implementation of getRequestURL() is therefore also fixed. In addition, in order to avoid a NullPointerException, the implementations of getServerName() and getServerPort() now assert that an IPV6 address present in the `Host` header correctly contains an opening and closing bracket and throw an IllegalStateException if that is not the case. Closes gh-24916
1 parent f929109 commit f60bb82

File tree

3 files changed

+96
-17
lines changed

3 files changed

+96
-17
lines changed

spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -591,11 +591,14 @@ public void setServerName(String serverName) {
591591

592592
@Override
593593
public String getServerName() {
594-
String host = getHeader(HOST_HEADER);
594+
String rawHostHeader = getHeader(HOST_HEADER);
595+
String host = rawHostHeader;
595596
if (host != null) {
596597
host = host.trim();
597598
if (host.startsWith("[")) {
598-
host = host.substring(1, host.indexOf(']'));
599+
int indexOfClosingBracket = host.indexOf(']');
600+
Assert.state(indexOfClosingBracket > -1, "Invalid Host header: " + rawHostHeader);
601+
host = host.substring(0, indexOfClosingBracket + 1);
599602
}
600603
else if (host.contains(":")) {
601604
host = host.substring(0, host.indexOf(':'));
@@ -613,12 +616,15 @@ public void setServerPort(int serverPort) {
613616

614617
@Override
615618
public int getServerPort() {
616-
String host = getHeader(HOST_HEADER);
619+
String rawHostHeader = getHeader(HOST_HEADER);
620+
String host = rawHostHeader;
617621
if (host != null) {
618622
host = host.trim();
619623
int idx;
620624
if (host.startsWith("[")) {
621-
idx = host.indexOf(':', host.indexOf(']'));
625+
int indexOfClosingBracket = host.indexOf(']');
626+
Assert.state(indexOfClosingBracket > -1, "Invalid Host header: " + rawHostHeader);
627+
idx = host.indexOf(':', indexOfClosingBracket);
622628
}
623629
else {
624630
idx = host.indexOf(':');

spring-test/src/test/java/org/springframework/mock/web/MockHttpServletRequestTests.java

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.mock.web;
1818

1919
import java.io.IOException;
20+
import java.net.URL;
2021
import java.nio.charset.Charset;
2122
import java.util.ArrayList;
2223
import java.util.Arrays;
@@ -29,10 +30,13 @@
2930
import java.util.Map;
3031
import javax.servlet.http.Cookie;
3132

33+
import org.junit.Rule;
3234
import org.junit.Test;
35+
import org.junit.rules.ExpectedException;
3336

3437
import org.springframework.util.StreamUtils;
3538

39+
import static org.hamcrest.CoreMatchers.startsWith;
3640
import static org.junit.Assert.*;
3741

3842
/**
@@ -54,6 +58,9 @@ public class MockHttpServletRequestTests {
5458
private static final String IF_MODIFIED_SINCE = "If-Modified-Since";
5559

5660
private final MockHttpServletRequest request = new MockHttpServletRequest();
61+
62+
@Rule
63+
public ExpectedException exception = ExpectedException.none();
5764

5865

5966
@Test
@@ -289,16 +296,23 @@ public void getServerNameViaHostHeaderWithPort() {
289296

290297
@Test
291298
public void getServerNameViaHostHeaderAsIpv6AddressWithoutPort() {
292-
String ipv6Address = "[2001:db8:0:1]";
293-
request.addHeader(HOST, ipv6Address);
294-
assertEquals("2001:db8:0:1", request.getServerName());
299+
String host = "[2001:db8:0:1]";
300+
request.addHeader(HOST, host);
301+
assertEquals(host, request.getServerName());
295302
}
296303

297304
@Test
298305
public void getServerNameViaHostHeaderAsIpv6AddressWithPort() {
299-
String ipv6Address = "[2001:db8:0:1]:8081";
300-
request.addHeader(HOST, ipv6Address);
301-
assertEquals("2001:db8:0:1", request.getServerName());
306+
request.addHeader(HOST, "[2001:db8:0:1]:8081");
307+
assertEquals("[2001:db8:0:1]", request.getServerName());
308+
}
309+
310+
@Test
311+
public void getServerNameWithInvalidIpv6AddressViaHostHeader() {
312+
request.addHeader(HOST, "[::ffff:abcd:abcd"); // missing closing bracket
313+
exception.expect(IllegalStateException.class);
314+
exception.expectMessage(startsWith("Invalid Host header: "));
315+
request.getServerName();
302316
}
303317

304318
@Test
@@ -312,6 +326,22 @@ public void getServerPortWithCustomPort() {
312326
assertEquals(8080, request.getServerPort());
313327
}
314328

329+
@Test
330+
public void getServerPortWithInvalidIpv6AddressViaHostHeader() {
331+
request.addHeader(HOST, "[::ffff:abcd:abcd:8080"); // missing closing bracket
332+
exception.expect(IllegalStateException.class);
333+
exception.expectMessage(startsWith("Invalid Host header: "));
334+
request.getServerPort();
335+
}
336+
337+
@Test
338+
public void getServerPortWithIpv6AddressAndInvalidPortViaHostHeader() {
339+
request.addHeader(HOST, "[::ffff:abcd:abcd]:bogus"); // "bogus" is not a port number
340+
exception.expect(NumberFormatException.class);
341+
exception.expectMessage("bogus");
342+
request.getServerPort();
343+
}
344+
315345
@Test
316346
public void getServerPortViaHostHeaderAsIpv6AddressWithoutPort() {
317347
String testServer = "[2001:db8:0:1]";
@@ -376,6 +406,43 @@ public void getRequestURLWithHostHeaderAndPort() {
376406
assertEquals("http://" + testServer, requestURL.toString());
377407
}
378408

409+
@Test
410+
public void getRequestURLWithIpv6AddressViaServerNameWithoutPort() throws Exception {
411+
request.setServerName("[::ffff:abcd:abcd]");
412+
URL url = new java.net.URL(request.getRequestURL().toString());
413+
assertEquals("http://[::ffff:abcd:abcd]", url.toString());
414+
}
415+
416+
@Test
417+
public void getRequestURLWithIpv6AddressViaServerNameWithPort() throws Exception {
418+
request.setServerName("[::ffff:abcd:abcd]");
419+
request.setServerPort(9999);
420+
URL url = new java.net.URL(request.getRequestURL().toString());
421+
assertEquals("http://[::ffff:abcd:abcd]:9999", url.toString());
422+
}
423+
424+
@Test
425+
public void getRequestURLWithInvalidIpv6AddressViaHostHeader() {
426+
request.addHeader(HOST, "[::ffff:abcd:abcd"); // missing closing bracket
427+
exception.expect(IllegalStateException.class);
428+
exception.expectMessage(startsWith("Invalid Host header: "));
429+
request.getRequestURL();
430+
}
431+
432+
@Test
433+
public void getRequestURLWithIpv6AddressViaHostHeaderWithoutPort() throws Exception {
434+
request.addHeader(HOST, "[::ffff:abcd:abcd]");
435+
URL url = new java.net.URL(request.getRequestURL().toString());
436+
assertEquals("http://[::ffff:abcd:abcd]", url.toString());
437+
}
438+
439+
@Test
440+
public void getRequestURLWithIpv6AddressViaHostHeaderWithPort() throws Exception {
441+
request.addHeader(HOST, "[::ffff:abcd:abcd]:9999");
442+
URL url = new java.net.URL(request.getRequestURL().toString());
443+
assertEquals("http://[::ffff:abcd:abcd]:9999", url.toString());
444+
}
445+
379446
@Test
380447
public void getRequestURLWithNullRequestUri() {
381448
request.setRequestURI(null);

spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -591,11 +591,14 @@ public void setServerName(String serverName) {
591591

592592
@Override
593593
public String getServerName() {
594-
String host = getHeader(HOST_HEADER);
594+
String rawHostHeader = getHeader(HOST_HEADER);
595+
String host = rawHostHeader;
595596
if (host != null) {
596597
host = host.trim();
597598
if (host.startsWith("[")) {
598-
host = host.substring(1, host.indexOf(']'));
599+
int indexOfClosingBracket = host.indexOf(']');
600+
Assert.state(indexOfClosingBracket > -1, "Invalid Host header: " + rawHostHeader);
601+
host = host.substring(0, indexOfClosingBracket + 1);
599602
}
600603
else if (host.contains(":")) {
601604
host = host.substring(0, host.indexOf(':'));
@@ -613,12 +616,15 @@ public void setServerPort(int serverPort) {
613616

614617
@Override
615618
public int getServerPort() {
616-
String host = getHeader(HOST_HEADER);
619+
String rawHostHeader = getHeader(HOST_HEADER);
620+
String host = rawHostHeader;
617621
if (host != null) {
618622
host = host.trim();
619623
int idx;
620624
if (host.startsWith("[")) {
621-
idx = host.indexOf(':', host.indexOf(']'));
625+
int indexOfClosingBracket = host.indexOf(']');
626+
Assert.state(indexOfClosingBracket > -1, "Invalid Host header: " + rawHostHeader);
627+
idx = host.indexOf(':', indexOfClosingBracket);
622628
}
623629
else {
624630
idx = host.indexOf(':');

0 commit comments

Comments
 (0)