From 23625ee6982557435557697d05793b1d655ab431 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 11 Dec 2025 09:40:42 +0100 Subject: [PATCH] Do not send null HTTP header value in JdkClientHttpRequest Prior to this commit, the `JdkClientHttpRequest` would add all values from `HttpHeaders` to the native request builder. This could cause `NullPointerException` being thrown at runtime because the `HttpClient` does not support that. This commit replicates a fix that was applied to the `SimpleClientHttpRequest`, turning null values into empty "". Fixes gh-35996 --- .../http/client/JdkClientHttpRequest.java | 2 +- .../http/client/OkHttp3ClientHttpRequest.java | 2 +- .../client/RestClientIntegrationTests.java | 23 +++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java index 0d14667f83a..73157f5ab9a 100644 --- a/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java @@ -155,7 +155,7 @@ class JdkClientHttpRequest extends AbstractStreamingClientHttpRequest { headers.forEach((headerName, headerValues) -> { if (!DISALLOWED_HEADERS.contains(headerName.toLowerCase(Locale.ROOT))) { for (String headerValue : headerValues) { - builder.header(headerName, headerValue); + builder.header(headerName, (headerValue != null) ? headerValue : ""); } } }); diff --git a/spring-web/src/main/java/org/springframework/http/client/OkHttp3ClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/OkHttp3ClientHttpRequest.java index 9ead1f58c30..25de1587fb2 100644 --- a/spring-web/src/main/java/org/springframework/http/client/OkHttp3ClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/OkHttp3ClientHttpRequest.java @@ -90,7 +90,7 @@ class OkHttp3ClientHttpRequest extends AbstractStreamingClientHttpRequest { builder.method(this.method.name(), requestBody); headers.forEach((headerName, headerValues) -> { for (String headerValue : headerValues) { - builder.addHeader(headerName, headerValue); + builder.addHeader(headerName, (headerValue != null) ? headerValue : ""); } }); Request request = builder.build(); diff --git a/spring-web/src/test/java/org/springframework/web/client/RestClientIntegrationTests.java b/spring-web/src/test/java/org/springframework/web/client/RestClientIntegrationTests.java index fe1c9e07fb0..9fbd9ad7c4d 100644 --- a/spring-web/src/test/java/org/springframework/web/client/RestClientIntegrationTests.java +++ b/spring-web/src/test/java/org/springframework/web/client/RestClientIntegrationTests.java @@ -961,6 +961,29 @@ class RestClientIntegrationTests { expectRequest(request -> assertThat(request.getHeader("foo")).isEqualTo("bar")); } + + @ParameterizedRestClientTest + void sendNullHeaderValue(ClientHttpRequestFactory requestFactory) throws IOException { + startServer(requestFactory); + + prepareResponse(builder -> builder + .setHeader("Content-Type", "text/plain").setBody("Hello Spring!")); + + String result = this.restClient.get() + .uri("/greeting") + .httpRequest(request -> request.getHeaders().add("X-Test-Header", null)) + .retrieve() + .body(String.class); + + assertThat(result).isEqualTo("Hello Spring!"); + + expectRequestCount(1); + expectRequest(request -> { + assertThat(request.getHeaders().get("X-Test-Header")).isNullOrEmpty(); + assertThat(request.getPath()).isEqualTo("/greeting"); + }); + } + @ParameterizedRestClientTest void defaultRequest(ClientHttpRequestFactory requestFactory) { startServer(requestFactory);