Skip to content

Commit 9ab7cde

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 fad9b50 commit 9ab7cde

File tree

3 files changed

+91
-17
lines changed

3 files changed

+91
-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-2019 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.
@@ -668,11 +668,14 @@ public void setServerName(String serverName) {
668668

669669
@Override
670670
public String getServerName() {
671-
String host = getHeader(HttpHeaders.HOST);
671+
String rawHostHeader = getHeader(HttpHeaders.HOST);
672+
String host = rawHostHeader;
672673
if (host != null) {
673674
host = host.trim();
674675
if (host.startsWith("[")) {
675-
host = host.substring(1, host.indexOf(']'));
676+
int indexOfClosingBracket = host.indexOf(']');
677+
Assert.state(indexOfClosingBracket > -1, () -> "Invalid Host header: " + rawHostHeader);
678+
host = host.substring(0, indexOfClosingBracket + 1);
676679
}
677680
else if (host.contains(":")) {
678681
host = host.substring(0, host.indexOf(':'));
@@ -690,12 +693,15 @@ public void setServerPort(int serverPort) {
690693

691694
@Override
692695
public int getServerPort() {
693-
String host = getHeader(HttpHeaders.HOST);
696+
String rawHostHeader = getHeader(HttpHeaders.HOST);
697+
String host = rawHostHeader;
694698
if (host != null) {
695699
host = host.trim();
696700
int idx;
697701
if (host.startsWith("[")) {
698-
idx = host.indexOf(':', host.indexOf(']'));
702+
int indexOfClosingBracket = host.indexOf(']');
703+
Assert.state(indexOfClosingBracket > -1, () -> "Invalid Host header: " + rawHostHeader);
704+
idx = host.indexOf(':', indexOfClosingBracket);
699705
}
700706
else {
701707
idx = host.indexOf(':');

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

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 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;
@@ -38,6 +39,7 @@
3839
import org.springframework.util.FileCopyUtils;
3940
import org.springframework.util.StreamUtils;
4041

42+
import static org.hamcrest.CoreMatchers.startsWith;
4143
import static org.junit.Assert.*;
4244

4345
/**
@@ -388,16 +390,23 @@ public void getServerNameViaHostHeaderWithPort() {
388390

389391
@Test
390392
public void getServerNameViaHostHeaderAsIpv6AddressWithoutPort() {
391-
String ipv6Address = "[2001:db8:0:1]";
392-
request.addHeader(HOST, ipv6Address);
393-
assertEquals("2001:db8:0:1", request.getServerName());
393+
String host = "[2001:db8:0:1]";
394+
request.addHeader(HOST, host);
395+
assertEquals(host, request.getServerName());
394396
}
395397

396398
@Test
397399
public void getServerNameViaHostHeaderAsIpv6AddressWithPort() {
398-
String ipv6Address = "[2001:db8:0:1]:8081";
399-
request.addHeader(HOST, ipv6Address);
400-
assertEquals("2001:db8:0:1", request.getServerName());
400+
request.addHeader(HOST, "[2001:db8:0:1]:8081");
401+
assertEquals("[2001:db8:0:1]", request.getServerName());
402+
}
403+
404+
@Test
405+
public void getServerNameWithInvalidIpv6AddressViaHostHeader() {
406+
request.addHeader(HOST, "[::ffff:abcd:abcd"); // missing closing bracket
407+
exception.expect(IllegalStateException.class);
408+
exception.expectMessage(startsWith("Invalid Host header: "));
409+
request.getServerName();
401410
}
402411

403412
@Test
@@ -411,6 +420,22 @@ public void getServerPortWithCustomPort() {
411420
assertEquals(8080, request.getServerPort());
412421
}
413422

423+
@Test
424+
public void getServerPortWithInvalidIpv6AddressViaHostHeader() {
425+
request.addHeader(HOST, "[::ffff:abcd:abcd:8080"); // missing closing bracket
426+
exception.expect(IllegalStateException.class);
427+
exception.expectMessage(startsWith("Invalid Host header: "));
428+
request.getServerPort();
429+
}
430+
431+
@Test
432+
public void getServerPortWithIpv6AddressAndInvalidPortViaHostHeader() {
433+
request.addHeader(HOST, "[::ffff:abcd:abcd]:bogus"); // "bogus" is not a port number
434+
exception.expect(NumberFormatException.class);
435+
exception.expectMessage("bogus");
436+
request.getServerPort();
437+
}
438+
414439
@Test
415440
public void getServerPortViaHostHeaderAsIpv6AddressWithoutPort() {
416441
String testServer = "[2001:db8:0:1]";
@@ -475,6 +500,43 @@ public void getRequestURLWithHostHeaderAndPort() {
475500
assertEquals("http://" + testServer, requestURL.toString());
476501
}
477502

503+
@Test
504+
public void getRequestURLWithIpv6AddressViaServerNameWithoutPort() throws Exception {
505+
request.setServerName("[::ffff:abcd:abcd]");
506+
URL url = new java.net.URL(request.getRequestURL().toString());
507+
assertEquals("http://[::ffff:abcd:abcd]", url.toString());
508+
}
509+
510+
@Test
511+
public void getRequestURLWithIpv6AddressViaServerNameWithPort() throws Exception {
512+
request.setServerName("[::ffff:abcd:abcd]");
513+
request.setServerPort(9999);
514+
URL url = new java.net.URL(request.getRequestURL().toString());
515+
assertEquals("http://[::ffff:abcd:abcd]:9999", url.toString());
516+
}
517+
518+
@Test
519+
public void getRequestURLWithInvalidIpv6AddressViaHostHeader() {
520+
request.addHeader(HOST, "[::ffff:abcd:abcd"); // missing closing bracket
521+
exception.expect(IllegalStateException.class);
522+
exception.expectMessage(startsWith("Invalid Host header: "));
523+
request.getRequestURL();
524+
}
525+
526+
@Test
527+
public void getRequestURLWithIpv6AddressViaHostHeaderWithoutPort() throws Exception {
528+
request.addHeader(HOST, "[::ffff:abcd:abcd]");
529+
URL url = new java.net.URL(request.getRequestURL().toString());
530+
assertEquals("http://[::ffff:abcd:abcd]", url.toString());
531+
}
532+
533+
@Test
534+
public void getRequestURLWithIpv6AddressViaHostHeaderWithPort() throws Exception {
535+
request.addHeader(HOST, "[::ffff:abcd:abcd]:9999");
536+
URL url = new java.net.URL(request.getRequestURL().toString());
537+
assertEquals("http://[::ffff:abcd:abcd]:9999", url.toString());
538+
}
539+
478540
@Test
479541
public void getRequestURLWithNullRequestUri() {
480542
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-2019 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.
@@ -668,11 +668,14 @@ public void setServerName(String serverName) {
668668

669669
@Override
670670
public String getServerName() {
671-
String host = getHeader(HttpHeaders.HOST);
671+
String rawHostHeader = getHeader(HttpHeaders.HOST);
672+
String host = rawHostHeader;
672673
if (host != null) {
673674
host = host.trim();
674675
if (host.startsWith("[")) {
675-
host = host.substring(1, host.indexOf(']'));
676+
int indexOfClosingBracket = host.indexOf(']');
677+
Assert.state(indexOfClosingBracket > -1, () -> "Invalid Host header: " + rawHostHeader);
678+
host = host.substring(0, indexOfClosingBracket + 1);
676679
}
677680
else if (host.contains(":")) {
678681
host = host.substring(0, host.indexOf(':'));
@@ -690,12 +693,15 @@ public void setServerPort(int serverPort) {
690693

691694
@Override
692695
public int getServerPort() {
693-
String host = getHeader(HttpHeaders.HOST);
696+
String rawHostHeader = getHeader(HttpHeaders.HOST);
697+
String host = rawHostHeader;
694698
if (host != null) {
695699
host = host.trim();
696700
int idx;
697701
if (host.startsWith("[")) {
698-
idx = host.indexOf(':', host.indexOf(']'));
702+
int indexOfClosingBracket = host.indexOf(']');
703+
Assert.state(indexOfClosingBracket > -1, () -> "Invalid Host header: " + rawHostHeader);
704+
idx = host.indexOf(':', indexOfClosingBracket);
699705
}
700706
else {
701707
idx = host.indexOf(':');

0 commit comments

Comments
 (0)