Skip to content

Commit 46f1849

Browse files
committed
Polishing external contribution
See gh-30787 Closes gh-30788
1 parent 9900575 commit 46f1849

File tree

3 files changed

+48
-32
lines changed

3 files changed

+48
-32
lines changed

spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,16 @@
4747
*/
4848
class JdkClientHttpRequest extends AbstractStreamingClientHttpRequest {
4949

50-
/*
51-
* The JDK HttpRequest doesn't allow all headers to be set. The named headers are taken from the default
52-
* implementation for HttpRequest.
50+
private static final Set<String> DISALLOWED_HEADERS = disallowedHeaders();
51+
52+
/**
53+
* By default, {@link HttpRequest} does not allow {@code Connection},
54+
* {@code Content-Length}, {@code Expect}, {@code Host}, or {@code Upgrade}
55+
* headers to be set, but this can be overriden with the
56+
* {@code jdk.httpclient.allowRestrictedHeaders} system property.
57+
* @see jdk.internal.net.http.common.Utils#getDisallowedHeaders()
5358
*/
54-
protected static final Set<String> DISALLOWED_HEADERS = getDisallowedHeaders();
55-
56-
private static Set<String> getDisallowedHeaders() {
59+
private static Set<String> disallowedHeaders() {
5760
TreeSet<String> headers = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
5861
headers.addAll(Set.of("connection", "content-length", "expect", "host", "upgrade"));
5962

@@ -65,6 +68,7 @@ private static Set<String> getDisallowedHeaders() {
6568
return Collections.unmodifiableSet(headers);
6669
}
6770

71+
6872
private final HttpClient httpClient;
6973

7074
private final HttpMethod method;
@@ -123,11 +127,9 @@ private HttpRequest buildRequest(HttpHeaders headers, @Nullable Body body) {
123127
}
124128

125129
headers.forEach((headerName, headerValues) -> {
126-
if (!headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH)) {
127-
if (!DISALLOWED_HEADERS.contains(headerName.toLowerCase())) {
128-
for (String headerValue : headerValues) {
129-
builder.header(headerName, headerValue);
130-
}
130+
if (!DISALLOWED_HEADERS.contains(headerName.toLowerCase())) {
131+
for (String headerValue : headerValues) {
132+
builder.header(headerName, headerValue);
131133
}
132134
}
133135
});

spring-web/src/test/java/org/springframework/http/client/AbstractMockWebServerTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ else if(request.getPath().equals("/status/ok")) {
7979
else if(request.getPath().equals("/status/notfound")) {
8080
return new MockResponse().setResponseCode(404);
8181
}
82+
else if (request.getPath().equals("/status/299")) {
83+
assertThat(request.getHeader("Expect"))
84+
.contains("299");
85+
return new MockResponse().setResponseCode(299);
86+
}
8287
else if(request.getPath().startsWith("/params")) {
8388
assertThat(request.getPath()).contains("param1=value");
8489
assertThat(request.getPath()).contains("param2=value1&param2=value2");

spring-web/src/test/java/org/springframework/http/client/JdkClientHttpRequestFactoryTests.java

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616

1717
package org.springframework.http.client;
1818

19+
import java.io.IOException;
1920
import java.net.URI;
20-
import java.net.http.HttpClient;
21-
import java.time.Duration;
22-
import java.util.concurrent.Executor;
2321

22+
import org.junit.jupiter.api.AfterAll;
23+
import org.junit.jupiter.api.BeforeAll;
2424
import org.junit.jupiter.api.Test;
2525

2626
import org.springframework.http.HttpMethod;
27+
import org.springframework.http.HttpStatusCode;
28+
import org.springframework.lang.Nullable;
2729

2830
import static org.assertj.core.api.Assertions.assertThat;
2931

@@ -32,6 +34,25 @@
3234
*/
3335
public class JdkClientHttpRequestFactoryTests extends AbstractHttpRequestFactoryTests {
3436

37+
@Nullable
38+
private static String originalPropertyValue;
39+
40+
@BeforeAll
41+
public static void setProperty() {
42+
originalPropertyValue = System.getProperty("jdk.httpclient.allowRestrictedHeaders");
43+
System.setProperty("jdk.httpclient.allowRestrictedHeaders", "expect");
44+
}
45+
46+
@AfterAll
47+
public static void restoreProperty() {
48+
if (originalPropertyValue != null) {
49+
System.setProperty("jdk.httpclient.allowRestrictedHeaders", originalPropertyValue);
50+
}
51+
else {
52+
System.clearProperty("jdk.httpclient.allowRestrictedHeaders");
53+
}
54+
}
55+
3556
@Override
3657
protected ClientHttpRequestFactory createRequestFactory() {
3758
return new JdkClientHttpRequestFactory();
@@ -45,25 +66,13 @@ public void httpMethods() throws Exception {
4566
}
4667

4768
@Test
48-
public void customizeDisallowedHeaders() {
49-
String original = System.getProperty("jdk.httpclient.allowRestrictedHeaders");
50-
System.setProperty("jdk.httpclient.allowRestrictedHeaders", "host");
69+
public void customizeDisallowedHeaders() throws IOException {
70+
ClientHttpRequest request = factory.createRequest(URI.create(this.baseUrl + "/status/299"), HttpMethod.PUT);
71+
request.getHeaders().set("Expect", "299");
5172

52-
assertThat(TestJdkClientHttpRequest.DISALLOWED_HEADERS).doesNotContain("host");
53-
54-
if (original != null) {
55-
System.setProperty("jdk.httpclient.allowRestrictedHeaders", original);
56-
}
57-
else {
58-
System.clearProperty("jdk.httpclient.allowRestrictedHeaders");
59-
}
60-
}
61-
62-
static class TestJdkClientHttpRequest extends JdkClientHttpRequest {
63-
64-
public TestJdkClientHttpRequest(HttpClient httpClient, URI uri, HttpMethod method, Executor executor, Duration readTimeout) {
65-
super(httpClient, uri, method, executor, readTimeout);
66-
}
73+
try (ClientHttpResponse response = request.execute()) {
74+
assertThat(response.getStatusCode()).as("Invalid status code").isEqualTo(HttpStatusCode.valueOf(299));
75+
}
6776
}
6877

6978
}

0 commit comments

Comments
 (0)