@ -21,7 +21,7 @@ import java.util.function.Consumer;
@@ -21,7 +21,7 @@ import java.util.function.Consumer;
import java.util.function.Function ;
import org.eclipse.jetty.client.HttpClient ;
import org.eclipse.jetty.util.Callbac k ;
import org.eclipse.jetty.reactive.client.ContentChun k ;
import reactor.core.publisher.Flux ;
import reactor.core.publisher.Mono ;
@ -33,12 +33,7 @@ import org.springframework.lang.Nullable;
@@ -33,12 +33,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert ;
/ * *
* Jetty ReactiveStreams HttpClient implementation of { @link ClientHttpConnector } .
*
* Implemented with buffer copy instead of optimized buffer wrapping because the latter
* hangs since { @link Callback # succeeded ( ) } doesn ' t allow releasing the buffer and
* requesting more data at different times ( required for { @code Mono < DataBuffer > } for example ) .
* See https : //github.com/eclipse/jetty.project/issues/2429 for more details.
* { @link ClientHttpConnector } for the Jetty Reactive Streams HttpClient .
*
* @author Sebastien Deleuze
* @since 5 . 1
@ -63,7 +58,9 @@ public class JettyClientHttpConnector implements ClientHttpConnector {
@@ -63,7 +58,9 @@ public class JettyClientHttpConnector implements ClientHttpConnector {
* @param resourceFactory the { @link JettyResourceFactory } to use
* @param customizer the lambda used to customize the { @link HttpClient }
* /
public JettyClientHttpConnector ( JettyResourceFactory resourceFactory , @Nullable Consumer < HttpClient > customizer ) {
public JettyClientHttpConnector (
JettyResourceFactory resourceFactory , @Nullable Consumer < HttpClient > customizer ) {
HttpClient httpClient = new HttpClient ( ) ;
httpClient . setExecutor ( resourceFactory . getExecutor ( ) ) ;
httpClient . setByteBufferPool ( resourceFactory . getByteBufferPool ( ) ) ;
@ -107,16 +104,27 @@ public class JettyClientHttpConnector implements ClientHttpConnector {
@@ -107,16 +104,27 @@ public class JettyClientHttpConnector implements ClientHttpConnector {
JettyClientHttpRequest clientHttpRequest = new JettyClientHttpRequest (
this . httpClient . newRequest ( uri ) . method ( method . toString ( ) ) , this . bufferFactory ) ;
return requestCallback . apply ( clientHttpRequest ) . then ( Mono . from (
clientHttpRequest . getReactiveRequest ( ) . response ( ( reactiveResponse , contentChunks ) - > {
Flux < DataBuffer > content = Flux . from ( contentChunks ) . map ( chunk - > {
DataBuffer buffer = this . bufferFactory . allocateBuffer ( chunk . buffer . capacity ( ) ) ;
buffer . write ( chunk . buffer ) ;
chunk . callback . succeeded ( ) ;
return buffer ;
} ) ;
return Mono . just ( new JettyClientHttpResponse ( reactiveResponse , content ) ) ;
clientHttpRequest . getReactiveRequest ( ) . response ( ( response , chunks ) - > {
Flux < DataBuffer > content = Flux . from ( chunks ) . map ( this : : toDataBuffer ) ;
return Mono . just ( new JettyClientHttpResponse ( response , content ) ) ;
} ) ) ) ;
}
private DataBuffer toDataBuffer ( ContentChunk chunk ) {
// We must copy until this is resolved:
// https://github.com/eclipse/jetty.project/issues/2429
// Use copy instead of buffer wrapping because Callback#succeeded() is
// used not only to release the buffer but also to request more data
// which is a problem for codecs that buffer data.
DataBuffer buffer = this . bufferFactory . allocateBuffer ( chunk . buffer . capacity ( ) ) ;
buffer . write ( chunk . buffer ) ;
chunk . callback . succeeded ( ) ;
return buffer ;
}
}