Skip to content

Commit 6b410df

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 0017256 commit 6b410df

File tree

2 files changed

+79
-11
lines changed

2 files changed

+79
-11
lines changed

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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;
@@ -37,6 +38,7 @@
3738
import org.springframework.util.StreamUtils;
3839

3940
import static org.assertj.core.api.Assertions.assertThat;
41+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
4042
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
4143
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
4244

@@ -389,18 +391,25 @@ void getServerNameViaHostHeaderWithPort() {
389391
assertThat(request.getServerName()).isEqualTo(testServer);
390392
}
391393

394+
@Test
395+
void getServerNameWithInvalidIpv6AddressViaHostHeader() {
396+
request.addHeader(HOST, "[::ffff:abcd:abcd"); // missing closing bracket
397+
assertThatIllegalStateException()
398+
.isThrownBy(() -> request.getServerName())
399+
.withMessageStartingWith("Invalid Host header: ");
400+
}
401+
392402
@Test
393403
void getServerNameViaHostHeaderAsIpv6AddressWithoutPort() {
394-
String ipv6Address = "[2001:db8:0:1]";
395-
request.addHeader(HOST, ipv6Address);
396-
assertThat(request.getServerName()).isEqualTo("2001:db8:0:1");
404+
String host = "[2001:db8:0:1]";
405+
request.addHeader(HOST, host);
406+
assertThat(request.getServerName()).isEqualTo(host);
397407
}
398408

399409
@Test
400410
void getServerNameViaHostHeaderAsIpv6AddressWithPort() {
401-
String ipv6Address = "[2001:db8:0:1]:8081";
402-
request.addHeader(HOST, ipv6Address);
403-
assertThat(request.getServerName()).isEqualTo("2001:db8:0:1");
411+
request.addHeader(HOST, "[2001:db8:0:1]:8081");
412+
assertThat(request.getServerName()).isEqualTo("[2001:db8:0:1]");
404413
}
405414

406415
@Test
@@ -414,6 +423,22 @@ void getServerPortWithCustomPort() {
414423
assertThat(request.getServerPort()).isEqualTo(8080);
415424
}
416425

426+
@Test
427+
void getServerPortWithInvalidIpv6AddressViaHostHeader() {
428+
request.addHeader(HOST, "[::ffff:abcd:abcd:8080"); // missing closing bracket
429+
assertThatIllegalStateException()
430+
.isThrownBy(() -> request.getServerPort())
431+
.withMessageStartingWith("Invalid Host header: ");
432+
}
433+
434+
@Test
435+
void getServerPortWithIpv6AddressAndInvalidPortViaHostHeader() {
436+
request.addHeader(HOST, "[::ffff:abcd:abcd]:bogus"); // "bogus" is not a port number
437+
assertThatExceptionOfType(NumberFormatException.class)
438+
.isThrownBy(() -> request.getServerPort())
439+
.withMessageContaining("bogus");
440+
}
441+
417442
@Test
418443
void getServerPortViaHostHeaderAsIpv6AddressWithoutPort() {
419444
String testServer = "[2001:db8:0:1]";
@@ -478,6 +503,43 @@ void getRequestURLWithHostHeaderAndPort() {
478503
assertThat(requestURL.toString()).isEqualTo(("http://" + testServer));
479504
}
480505

506+
@Test
507+
void getRequestURLWithIpv6AddressViaServerNameWithoutPort() throws Exception {
508+
request.setServerName("[::ffff:abcd:abcd]");
509+
URL url = new java.net.URL(request.getRequestURL().toString());
510+
assertThat(url).asString().isEqualTo("http://[::ffff:abcd:abcd]");
511+
}
512+
513+
@Test
514+
void getRequestURLWithIpv6AddressViaServerNameWithPort() throws Exception {
515+
request.setServerName("[::ffff:abcd:abcd]");
516+
request.setServerPort(9999);
517+
URL url = new java.net.URL(request.getRequestURL().toString());
518+
assertThat(url).asString().isEqualTo("http://[::ffff:abcd:abcd]:9999");
519+
}
520+
521+
@Test
522+
void getRequestURLWithInvalidIpv6AddressViaHostHeader() {
523+
request.addHeader(HOST, "[::ffff:abcd:abcd"); // missing closing bracket
524+
assertThatIllegalStateException()
525+
.isThrownBy(() -> request.getRequestURL())
526+
.withMessageStartingWith("Invalid Host header: ");
527+
}
528+
529+
@Test
530+
void getRequestURLWithIpv6AddressViaHostHeaderWithoutPort() throws Exception {
531+
request.addHeader(HOST, "[::ffff:abcd:abcd]");
532+
URL url = new java.net.URL(request.getRequestURL().toString());
533+
assertThat(url).asString().isEqualTo("http://[::ffff:abcd:abcd]");
534+
}
535+
536+
@Test
537+
void getRequestURLWithIpv6AddressViaHostHeaderWithPort() throws Exception {
538+
request.addHeader(HOST, "[::ffff:abcd:abcd]:9999");
539+
URL url = new java.net.URL(request.getRequestURL().toString());
540+
assertThat(url).asString().isEqualTo("http://[::ffff:abcd:abcd]:9999");
541+
}
542+
481543
@Test
482544
void getRequestURLWithNullRequestUri() {
483545
request.setRequestURI(null);

0 commit comments

Comments
 (0)