21
21
import java .util .function .Function ;
22
22
23
23
import org .eclipse .jetty .client .HttpClient ;
24
- import org .eclipse .jetty .util . Callback ;
24
+ import org .eclipse .jetty .reactive . client . ContentChunk ;
25
25
import reactor .core .publisher .Flux ;
26
26
import reactor .core .publisher .Mono ;
27
27
33
33
import org .springframework .util .Assert ;
34
34
35
35
/**
36
- * Jetty ReactiveStreams HttpClient implementation of {@link ClientHttpConnector}.
37
- *
38
- * Implemented with buffer copy instead of optimized buffer wrapping because the latter
39
- * hangs since {@link Callback#succeeded()} doesn't allow releasing the buffer and
40
- * requesting more data at different times (required for {@code Mono<DataBuffer>} for example).
41
- * See https://github.com/eclipse/jetty.project/issues/2429 for more details.
36
+ * {@link ClientHttpConnector} for the Jetty Reactive Streams HttpClient.
42
37
*
43
38
* @author Sebastien Deleuze
44
39
* @since 5.1
@@ -63,7 +58,9 @@ public JettyClientHttpConnector() {
63
58
* @param resourceFactory the {@link JettyResourceFactory} to use
64
59
* @param customizer the lambda used to customize the {@link HttpClient}
65
60
*/
66
- public JettyClientHttpConnector (JettyResourceFactory resourceFactory , @ Nullable Consumer <HttpClient > customizer ) {
61
+ public JettyClientHttpConnector (
62
+ JettyResourceFactory resourceFactory , @ Nullable Consumer <HttpClient > customizer ) {
63
+
67
64
HttpClient httpClient = new HttpClient ();
68
65
httpClient .setExecutor (resourceFactory .getExecutor ());
69
66
httpClient .setByteBufferPool (resourceFactory .getByteBufferPool ());
@@ -107,16 +104,27 @@ public Mono<ClientHttpResponse> connect(HttpMethod method, URI uri,
107
104
108
105
JettyClientHttpRequest clientHttpRequest = new JettyClientHttpRequest (
109
106
this .httpClient .newRequest (uri ).method (method .toString ()), this .bufferFactory );
107
+
110
108
return requestCallback .apply (clientHttpRequest ).then (Mono .from (
111
- clientHttpRequest .getReactiveRequest ().response ((reactiveResponse , contentChunks ) -> {
112
- Flux <DataBuffer > content = Flux .from (contentChunks ).map (chunk -> {
113
- DataBuffer buffer = this .bufferFactory .allocateBuffer (chunk .buffer .capacity ());
114
- buffer .write (chunk .buffer );
115
- chunk .callback .succeeded ();
116
- return buffer ;
117
- });
118
- return Mono .just (new JettyClientHttpResponse (reactiveResponse , content ));
109
+ clientHttpRequest .getReactiveRequest ().response ((response , chunks ) -> {
110
+ Flux <DataBuffer > content = Flux .from (chunks ).map (this ::toDataBuffer );
111
+ return Mono .just (new JettyClientHttpResponse (response , content ));
119
112
})));
120
113
}
121
114
115
+ private DataBuffer toDataBuffer (ContentChunk chunk ) {
116
+
117
+ // We must copy until this is resolved:
118
+ // https://github.com/eclipse/jetty.project/issues/2429
119
+
120
+ // Use copy instead of buffer wrapping because Callback#succeeded() is
121
+ // used not only to release the buffer but also to request more data
122
+ // which is a problem for codecs that buffer data.
123
+
124
+ DataBuffer buffer = this .bufferFactory .allocateBuffer (chunk .buffer .capacity ());
125
+ buffer .write (chunk .buffer );
126
+ chunk .callback .succeeded ();
127
+ return buffer ;
128
+ }
129
+
122
130
}
0 commit comments