19
19
import java .net .URI ;
20
20
import java .net .http .HttpClient ;
21
21
import java .net .http .HttpRequest ;
22
- import java .net .http .HttpResponse ;
23
22
import java .nio .ByteBuffer ;
24
23
import java .util .List ;
25
24
import java .util .Map ;
26
- import java .util .Set ;
27
25
import java .util .concurrent .Flow ;
28
26
import java .util .function .Function ;
29
27
import java .util .stream .Collectors ;
35
33
36
34
import org .springframework .core .io .buffer .DataBuffer ;
37
35
import org .springframework .core .io .buffer .DataBufferFactory ;
36
+ import org .springframework .http .HttpCookie ;
38
37
import org .springframework .http .HttpHeaders ;
39
38
import org .springframework .http .HttpMethod ;
40
- import org .springframework .lang .Nullable ;
41
39
import org .springframework .util .Assert ;
42
40
43
41
/**
44
- * {@link ClientHttpRequest} implementation for Java's {@link HttpClient}.
42
+ * {@link ClientHttpRequest} for the Java {@link HttpClient}.
45
43
*
46
44
* @author Julien Eyraud
45
+ * @author Rossen Stoyanchev
47
46
* @since 6.0
48
47
*/
49
48
class JdkClientHttpRequest extends AbstractClientHttpRequest {
50
49
51
- private static final Set <String > DISALLOWED_HEADERS =
52
- Set .of ("connection" , "content-length" , "date" , "expect" , "from" , "host" , "upgrade" , "via" , "warning" );
53
-
54
-
55
- private final HttpClient httpClient ;
56
-
57
50
private final HttpMethod method ;
58
51
59
52
private final URI uri ;
60
53
61
- private final HttpRequest .Builder builder ;
62
-
63
54
private final DataBufferFactory bufferFactory ;
64
55
65
- @ Nullable
66
- private Mono <ClientHttpResponse > response ;
67
-
56
+ private final HttpRequest .Builder builder ;
68
57
69
- public JdkClientHttpRequest (
70
- HttpClient httpClient , HttpMethod httpMethod , URI uri , DataBufferFactory bufferFactory ) {
71
58
72
- Assert . notNull ( httpClient , "HttpClient should not be null" );
73
- Assert .notNull (httpMethod , "HttpMethod should not be null " );
74
- Assert .notNull (uri , "URI should not be null " );
75
- Assert .notNull (bufferFactory , "DataBufferFactory should not be null " );
59
+ public JdkClientHttpRequest ( HttpMethod httpMethod , URI uri , DataBufferFactory bufferFactory ) {
60
+ Assert .notNull (httpMethod , "HttpMethod is required " );
61
+ Assert .notNull (uri , "URI is required " );
62
+ Assert .notNull (bufferFactory , "DataBufferFactory is required " );
76
63
77
- this .httpClient = httpClient ;
78
64
this .method = httpMethod ;
79
65
this .uri = uri ;
80
- this .builder = HttpRequest .newBuilder (uri );
81
66
this .bufferFactory = bufferFactory ;
67
+ this .builder = HttpRequest .newBuilder (uri );
82
68
}
83
69
84
70
@@ -103,20 +89,16 @@ public <T> T getNativeRequest() {
103
89
return (T ) this .builder .build ();
104
90
}
105
91
106
- Mono <ClientHttpResponse > getResponse () {
107
- Assert .notNull (this .response , "Response is not set" );
108
- return this .response ;
109
- }
110
-
111
92
112
93
@ Override
113
94
protected void applyHeaders () {
114
- for (Map .Entry <String , List <String >> header : getHeaders ().entrySet ()) {
115
- if (DISALLOWED_HEADERS .contains (header .getKey ().toLowerCase ())) {
95
+ for (Map .Entry <String , List <String >> entry : getHeaders ().entrySet ()) {
96
+ if (entry .getKey ().equalsIgnoreCase (HttpHeaders .CONTENT_LENGTH )) {
97
+ // content-length is specified when writing
116
98
continue ;
117
99
}
118
- for (String value : header .getValue ()) {
119
- this .builder .header (header .getKey (), value );
100
+ for (String value : entry .getValue ()) {
101
+ this .builder .header (entry .getKey (), value );
120
102
}
121
103
}
122
104
if (!getHeaders ().containsKey (HttpHeaders .ACCEPT )) {
@@ -126,31 +108,28 @@ protected void applyHeaders() {
126
108
127
109
@ Override
128
110
protected void applyCookies () {
129
- this .builder .header (HttpHeaders .COOKIE ,
130
- getCookies ().values ().stream ()
131
- .flatMap (List ::stream )
132
- .map (cookie -> cookie .getName () + "=" + cookie .getValue ())
133
- .collect (Collectors .joining ("; " )));
111
+ this .builder .header (HttpHeaders .COOKIE , getCookies ().values ().stream ()
112
+ .flatMap (List ::stream ).map (HttpCookie ::toString ).collect (Collectors .joining (";" )));
134
113
}
135
114
136
115
@ Override
137
116
public Mono <Void > writeWith (Publisher <? extends DataBuffer > body ) {
138
117
return doCommit (() -> {
139
- Flow .Publisher <ByteBuffer > flow =
140
- JdkFlowAdapter .publisherToFlowPublisher (Flux .from (body ).map (DataBuffer ::asByteBuffer ));
118
+ this .builder .method (this .method .name (), toBodyPublisher (body ));
119
+ return Mono .empty ();
120
+ });
121
+ }
141
122
142
- HttpRequest .BodyPublisher bodyPublisher = (getHeaders ().getContentLength () >= 0 ?
143
- HttpRequest .BodyPublishers .fromPublisher (flow , getHeaders ().getContentLength ()) :
144
- HttpRequest .BodyPublishers .fromPublisher (flow ));
123
+ private HttpRequest .BodyPublisher toBodyPublisher (Publisher <? extends DataBuffer > body ) {
124
+ Publisher <ByteBuffer > byteBufferBody = (body instanceof Mono ?
125
+ Mono .from (body ).map (DataBuffer ::asByteBuffer ) :
126
+ Flux .from (body ).map (DataBuffer ::asByteBuffer ));
145
127
146
- this .response = Mono .fromCompletionStage (() -> {
147
- HttpRequest request = this .builder .method (this .method .name (), bodyPublisher ).build ();
148
- return this .httpClient .sendAsync (request , HttpResponse .BodyHandlers .ofPublisher ());
149
- })
150
- .map (response -> new JdkClientHttpResponse (response , this .bufferFactory ));
128
+ Flow .Publisher <ByteBuffer > bodyFlow = JdkFlowAdapter .publisherToFlowPublisher (byteBufferBody );
151
129
152
- return Mono .empty ();
153
- });
130
+ return (getHeaders ().getContentLength () > 0 ?
131
+ HttpRequest .BodyPublishers .fromPublisher (bodyFlow , getHeaders ().getContentLength ()) :
132
+ HttpRequest .BodyPublishers .fromPublisher (bodyFlow ));
154
133
}
155
134
156
135
@ Override
@@ -160,18 +139,8 @@ public Mono<Void> writeAndFlushWith(final Publisher<? extends Publisher<? extend
160
139
161
140
@ Override
162
141
public Mono <Void > setComplete () {
163
- if (isCommitted ()) {
164
- return Mono .empty ();
165
- }
166
-
167
142
return doCommit (() -> {
168
- this .response = Mono .fromCompletionStage (() -> {
169
- HttpRequest .BodyPublisher bodyPublisher = HttpRequest .BodyPublishers .noBody ();
170
- HttpRequest request = this .builder .method (this .method .name (), bodyPublisher ).build ();
171
- return this .httpClient .sendAsync (request , HttpResponse .BodyHandlers .ofPublisher ());
172
- })
173
- .map (response -> new JdkClientHttpResponse (response , this .bufferFactory ));
174
-
143
+ this .builder .method (this .method .name (), HttpRequest .BodyPublishers .noBody ());
175
144
return Mono .empty ();
176
145
});
177
146
}
0 commit comments