Skip to content

Commit 26a93b6

Browse files
committed
Client request implementations enforce RFC 6265 (cookies in a single header)
Issue: SPR-12196
1 parent 7387475 commit 26a93b6

5 files changed

+43
-48
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import org.springframework.http.HttpHeaders;
3434
import org.springframework.http.HttpMethod;
35+
import org.springframework.util.StringUtils;
3536

3637
/**
3738
* {@link org.springframework.http.client.ClientHttpRequest} implementation that uses
@@ -41,6 +42,7 @@
4142
*
4243
* @author Oleg Kalnichevski
4344
* @author Arjen Poutsma
45+
* @author Juergen Hoeller
4446
* @since 3.1
4547
* @see HttpComponentsClientHttpRequestFactory#createRequest(URI, HttpMethod)
4648
*/
@@ -97,8 +99,12 @@ protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] buffere
9799
static void addHeaders(HttpUriRequest httpRequest, HttpHeaders headers) {
98100
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
99101
String headerName = entry.getKey();
100-
if (!headerName.equalsIgnoreCase(HTTP.CONTENT_LEN) &&
101-
!headerName.equalsIgnoreCase(HTTP.TRANSFER_ENCODING)) {
102+
if (HttpHeaders.COOKIE.equalsIgnoreCase(headerName)) { // RFC 6265
103+
String headerValue = StringUtils.collectionToDelimitedString(entry.getValue(), "; ");
104+
httpRequest.addHeader(headerName, headerValue);
105+
}
106+
else if (!HTTP.CONTENT_LEN.equalsIgnoreCase(headerName) &&
107+
!HTTP.TRANSFER_ENCODING.equalsIgnoreCase(headerName)) {
102108
for (String headerValue : entry.getValue()) {
103109
httpRequest.addHeader(headerName, headerValue);
104110
}

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

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
import java.net.HttpURLConnection;
2121
import java.net.URI;
2222
import java.net.URISyntaxException;
23-
import java.util.List;
24-
import java.util.Map;
2523
import java.util.concurrent.Callable;
2624

2725
import org.springframework.core.task.AsyncListenableTaskExecutor;
@@ -32,7 +30,7 @@
3230

3331
/**
3432
* {@link org.springframework.http.client.ClientHttpRequest} implementation that uses
35-
* standard J2SE facilities to execute buffered requests. Created via the
33+
* standard JDK facilities to execute buffered requests. Created via the
3634
* {@link org.springframework.http.client.SimpleClientHttpRequestFactory}.
3735
*
3836
* @author Arjen Poutsma
@@ -79,12 +77,7 @@ protected ListenableFuture<ClientHttpResponse> executeInternal(
7977
return this.taskExecutor.submitListenable(new Callable<ClientHttpResponse>() {
8078
@Override
8179
public ClientHttpResponse call() throws Exception {
82-
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
83-
String headerName = entry.getKey();
84-
for (String headerValue : entry.getValue()) {
85-
connection.addRequestProperty(headerName, headerValue);
86-
}
87-
}
80+
SimpleBufferingClientHttpRequest.addHeaders(connection, headers);
8881
if (connection.getDoOutput() && outputStreaming) {
8982
connection.setFixedLengthStreamingMode(bufferedOutput.length);
9083
}

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 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.
@@ -26,12 +26,14 @@
2626
import org.springframework.http.HttpHeaders;
2727
import org.springframework.http.HttpMethod;
2828
import org.springframework.util.FileCopyUtils;
29+
import org.springframework.util.StringUtils;
2930

3031
/**
31-
* {@link ClientHttpRequest} implementation that uses standard J2SE facilities to execute buffered requests.
32-
* Created via the {@link SimpleClientHttpRequestFactory}.
32+
* {@link ClientHttpRequest} implementation that uses standard JDK facilities to
33+
* execute buffered requests. Created via the {@link SimpleClientHttpRequestFactory}.
3334
*
3435
* @author Arjen Poutsma
36+
* @author Juergen Hoeller
3537
* @since 3.0
3638
* @see SimpleClientHttpRequestFactory#createRequest(java.net.URI, HttpMethod)
3739
*/
@@ -65,12 +67,7 @@ public URI getURI() {
6567

6668
@Override
6769
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
68-
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
69-
String headerName = entry.getKey();
70-
for (String headerValue : entry.getValue()) {
71-
this.connection.addRequestProperty(headerName, headerValue);
72-
}
73-
}
70+
addHeaders(this.connection, headers);
7471

7572
if (this.connection.getDoOutput() && this.outputStreaming) {
7673
this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
@@ -83,4 +80,25 @@ protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] buffere
8380
return new SimpleClientHttpResponse(this.connection);
8481
}
8582

83+
84+
/**
85+
* Add the given headers to the given HTTP connection.
86+
* @param connection the connection to add the headers to
87+
* @param headers the headers to add
88+
*/
89+
static void addHeaders(HttpURLConnection connection, HttpHeaders headers) {
90+
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
91+
String headerName = entry.getKey();
92+
if (HttpHeaders.COOKIE.equalsIgnoreCase(headerName)) { // RFC 6265
93+
String headerValue = StringUtils.collectionToDelimitedString(entry.getValue(), "; ");
94+
connection.setRequestProperty(headerName, headerValue);
95+
}
96+
else {
97+
for (String headerValue : entry.getValue()) {
98+
connection.addRequestProperty(headerName, headerValue);
99+
}
100+
}
101+
}
102+
}
103+
86104
}

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

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
import java.net.HttpURLConnection;
2222
import java.net.URI;
2323
import java.net.URISyntaxException;
24-
import java.util.List;
25-
import java.util.Map;
2624
import java.util.concurrent.Callable;
2725

2826
import org.springframework.core.task.AsyncListenableTaskExecutor;
@@ -91,22 +89,13 @@ protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
9189
this.connection.setChunkedStreamingMode(this.chunkSize);
9290
}
9391
}
94-
writeHeaders(headers);
92+
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
9593
this.connection.connect();
9694
this.body = this.connection.getOutputStream();
9795
}
9896
return StreamUtils.nonClosing(this.body);
9997
}
10098

101-
private void writeHeaders(HttpHeaders headers) {
102-
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
103-
String headerName = entry.getKey();
104-
for (String headerValue : entry.getValue()) {
105-
this.connection.addRequestProperty(headerName, headerValue);
106-
}
107-
}
108-
}
109-
11099
@Override
111100
protected ListenableFuture<ClientHttpResponse> executeInternal(final HttpHeaders headers) throws IOException {
112101
return this.taskExecutor.submitListenable(new Callable<ClientHttpResponse>() {
@@ -117,7 +106,7 @@ public ClientHttpResponse call() throws Exception {
117106
body.close();
118107
}
119108
else {
120-
writeHeaders(headers);
109+
SimpleBufferingClientHttpRequest.addHeaders(connection, headers);
121110
connection.connect();
122111
}
123112
}

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

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,14 @@
2121
import java.net.HttpURLConnection;
2222
import java.net.URI;
2323
import java.net.URISyntaxException;
24-
import java.util.List;
25-
import java.util.Map;
2624

2725
import org.springframework.http.HttpHeaders;
2826
import org.springframework.http.HttpMethod;
2927
import org.springframework.util.StreamUtils;
3028

3129
/**
32-
* {@link ClientHttpRequest} implementation that uses standard J2SE facilities to execute streaming requests.
33-
* Created via the {@link SimpleClientHttpRequestFactory}.
30+
* {@link ClientHttpRequest} implementation that uses standard JDK facilities to
31+
* execute streaming requests. Created via the {@link SimpleClientHttpRequestFactory}.
3432
*
3533
* @author Arjen Poutsma
3634
* @since 3.0
@@ -80,30 +78,21 @@ protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
8078
this.connection.setChunkedStreamingMode(this.chunkSize);
8179
}
8280
}
83-
writeHeaders(headers);
81+
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
8482
this.connection.connect();
8583
this.body = this.connection.getOutputStream();
8684
}
8785
return StreamUtils.nonClosing(this.body);
8886
}
8987

90-
private void writeHeaders(HttpHeaders headers) {
91-
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
92-
String headerName = entry.getKey();
93-
for (String headerValue : entry.getValue()) {
94-
this.connection.addRequestProperty(headerName, headerValue);
95-
}
96-
}
97-
}
98-
9988
@Override
10089
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
10190
try {
10291
if (this.body != null) {
10392
this.body.close();
10493
}
10594
else {
106-
writeHeaders(headers);
95+
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
10796
this.connection.connect();
10897
}
10998
}

0 commit comments

Comments
 (0)