Fixes #9166 - Jetty 12: review/remove ByteBufferPool (#9195)

* Fixes #9166 - Jetty 12: review/remove ByteBufferPool

* Replaced usages of ByteBufferPool with RetainableByteBufferPool.
* Removed ByteBufferPool and related classes.
* Renamed oej.http2.frames.DataFrame.getData() -> getByteBuffer() for consistency.
* Removed Accumulator.acquire(), and updated code to use RetainableByteBufferPool.acquire() instead.
* Fixed HttpOutput callbacks to correctly call super.onCompleteSuccess() and super.onCompleteFailure().

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2023-01-27 13:40:49 +01:00 committed by GitHub
parent 63d963d526
commit ded18f523d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
294 changed files with 3632 additions and 5368 deletions

View File

@ -33,7 +33,7 @@ The `ClientConnector` primarily wraps the link:{javadoc-url}/org/eclipse/jetty/i
* a thread pool (in form of an `java.util.concurrent.Executor`)
* a scheduler (in form of `org.eclipse.jetty.util.thread.Scheduler`)
* a byte buffer pool (in form of `org.eclipse.jetty.io.ByteBufferPool`)
* a byte buffer pool (in form of `org.eclipse.jetty.io.RetainableByteBufferPool`)
* a TLS factory (in form of `org.eclipse.jetty.util.ssl.SslContextFactory.Client`)
The `ClientConnector` is where you want to set those components after you have configured them.

View File

@ -72,7 +72,7 @@ public class HTTP2Docs
}
// Get the content buffer.
ByteBuffer byteBuffer = data.frame().getData();
ByteBuffer byteBuffer = data.frame().getByteBuffer();
// Unwrap the Data object, converting it to a Chunk.
// The Data.release() semantic is maintained in the completion of the Callback.

View File

@ -387,7 +387,7 @@ public class ClientConnectorDocs
// Wrap the "telnet" ClientConnectionFactory with the SslClientConnectionFactory.
connectionFactory = new SslClientConnectionFactory(clientConnector.getSslContextFactory(),
clientConnector.getByteBufferPool(), clientConnector.getExecutor(), connectionFactory);
clientConnector.getRetainableByteBufferPool(), clientConnector.getExecutor(), connectionFactory);
// We will obtain a SslConnection now.
CompletableFuture<SslConnection> connectionPromise = new Promise.Completable<>();

View File

@ -63,7 +63,6 @@ import org.eclipse.jetty.http2.client.transport.ClientConnectionFactoryOverHTTP2
import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.http3.client.HTTP3Client;
import org.eclipse.jetty.http3.client.transport.HttpClientTransportOverHTTP3;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.Content;
@ -334,14 +333,13 @@ public class HTTPClientDocs
// An event happens in some other class, in some other thread.
class ContentPublisher
{
void publish(ByteBufferPool bufferPool, byte[] bytes, boolean lastContent)
void publish(byte[] bytes, boolean lastContent)
{
// Wrap the bytes into a new ByteBuffer.
ByteBuffer buffer = ByteBuffer.wrap(bytes);
// Offer the content, and release the ByteBuffer
// to the pool when the Callback is completed.
content.write(buffer, Callback.from(() -> bufferPool.release(buffer)));
// Write the content.
content.write(buffer, Callback.NOOP);
// Close AsyncRequestContent when all the content is arrived.
if (lastContent)

View File

@ -254,7 +254,7 @@ public class HTTP2ClientDocs
}
// Get the content buffer.
ByteBuffer buffer = data.frame().getData();
ByteBuffer buffer = data.frame().getByteBuffer();
// Consume the buffer, here - as an example - just log it.
System.getLogger("http2").log(INFO, "Consuming buffer {0}", buffer);
@ -368,7 +368,7 @@ public class HTTP2ClientDocs
}
// The pushed stream "response" content bytes.
ByteBuffer buffer = data.frame().getData();
ByteBuffer buffer = data.frame().getByteBuffer();
// Consume the buffer and release the Data object.
data.release();

View File

@ -159,7 +159,7 @@ public class HTTP2ServerDocs
}
// Get the content buffer.
ByteBuffer buffer = data.frame().getData();
ByteBuffer buffer = data.frame().getByteBuffer();
// Consume the buffer, here - as an example - just log it.
System.getLogger("http2").log(INFO, "Consuming buffer {0}", buffer);

View File

@ -52,7 +52,7 @@ public abstract class AbstractConnectorHttpClientTransport extends AbstractHttpC
{
HttpClient httpClient = getHttpClient();
connector.setBindAddress(httpClient.getBindAddress());
connector.setByteBufferPool(httpClient.getByteBufferPool());
connector.setRetainableByteBufferPool(httpClient.getRetainableByteBufferPool());
connector.setConnectBlocking(httpClient.isConnectBlocking());
connector.setConnectTimeout(Duration.ofMillis(httpClient.getConnectTimeout()));
connector.setExecutor(httpClient.getExecutor());

View File

@ -20,6 +20,7 @@ import java.util.Map;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.io.RetainableByteBuffer;
/**
* {@link ContentDecoder} decodes content bytes of a response.
@ -29,21 +30,14 @@ import org.eclipse.jetty.http.HttpHeader;
public interface ContentDecoder
{
/**
* <p>Decodes the bytes in the given {@code buffer} and returns decoded bytes, if any.</p>
* <p>Decodes the bytes in the given {@code buffer} and returns the decoded bytes.</p>
* <p>The returned {@link RetainableByteBuffer} containing the decoded bytes may
* be empty and <b>must</b> be released via {@link RetainableByteBuffer#release()}.</p>
*
* @param buffer the buffer containing encoded bytes
* @return a buffer containing decoded bytes, if any
* @return a buffer containing decoded bytes that must be released
*/
public abstract ByteBuffer decode(ByteBuffer buffer);
/**
* <p>Releases the ByteBuffer returned by {@link #decode(ByteBuffer)}.</p>
*
* @param decoded the ByteBuffer returned by {@link #decode(ByteBuffer)}
*/
public default void release(ByteBuffer decoded)
{
}
public abstract RetainableByteBuffer decode(ByteBuffer buffer);
/**
* Factory for {@link ContentDecoder}s; subclasses must implement {@link #newContentDecoder()}.

View File

@ -13,9 +13,8 @@
package org.eclipse.jetty.client;
import java.nio.ByteBuffer;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
/**
* {@link ContentDecoder} for the "gzip" encoding.
@ -34,13 +33,13 @@ public class GZIPContentDecoder extends org.eclipse.jetty.http.GZIPContentDecode
this(null, bufferSize);
}
public GZIPContentDecoder(ByteBufferPool byteBufferPool, int bufferSize)
public GZIPContentDecoder(RetainableByteBufferPool retainableByteBufferPool, int bufferSize)
{
super(byteBufferPool, bufferSize);
super(retainableByteBufferPool, bufferSize);
}
@Override
protected boolean decodedChunk(ByteBuffer chunk)
protected boolean decodedChunk(RetainableByteBuffer chunk)
{
super.decodedChunk(chunk);
return true;
@ -51,8 +50,8 @@ public class GZIPContentDecoder extends org.eclipse.jetty.http.GZIPContentDecode
*/
public static class Factory extends ContentDecoder.Factory
{
private final RetainableByteBufferPool retainableByteBufferPool;
private final int bufferSize;
private final ByteBufferPool byteBufferPool;
public Factory()
{
@ -64,22 +63,22 @@ public class GZIPContentDecoder extends org.eclipse.jetty.http.GZIPContentDecode
this(null, bufferSize);
}
public Factory(ByteBufferPool byteBufferPool)
public Factory(RetainableByteBufferPool retainableByteBufferPool)
{
this(byteBufferPool, DEFAULT_BUFFER_SIZE);
this(retainableByteBufferPool, DEFAULT_BUFFER_SIZE);
}
public Factory(ByteBufferPool byteBufferPool, int bufferSize)
public Factory(RetainableByteBufferPool retainableByteBufferPool, int bufferSize)
{
super("gzip");
this.byteBufferPool = byteBufferPool;
this.retainableByteBufferPool = retainableByteBufferPool;
this.bufferSize = bufferSize;
}
@Override
public ContentDecoder newContentDecoder()
{
return new GZIPContentDecoder(byteBufferPool, bufferSize);
return new GZIPContentDecoder(retainableByteBufferPool, bufferSize);
}
}
}

View File

@ -49,10 +49,8 @@ import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpParser;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.util.Fields;
@ -201,11 +199,9 @@ public class HttpClient extends ContainerLifeCycle
int maxBucketSize = executor instanceof ThreadPool.SizedThreadPool
? ((ThreadPool.SizedThreadPool)executor).getMaxThreads() / 2
: ProcessorUtils.availableProcessors() * 2;
ByteBufferPool byteBufferPool = getByteBufferPool();
if (byteBufferPool == null)
setByteBufferPool(new MappedByteBufferPool(2048, maxBucketSize));
if (getBean(RetainableByteBufferPool.class) == null)
addBean(new ArrayRetainableByteBufferPool(0, 2048, 65536, maxBucketSize));
RetainableByteBufferPool retainableByteBufferPool = getRetainableByteBufferPool();
if (retainableByteBufferPool == null)
setRetainableByteBufferPool(new ArrayRetainableByteBufferPool(0, 2048, 65536, maxBucketSize));
Scheduler scheduler = getScheduler();
if (scheduler == null)
{
@ -224,7 +220,7 @@ public class HttpClient extends ContainerLifeCycle
handlers.put(new ProxyAuthenticationProtocolHandler(this));
handlers.put(new UpgradeProtocolHandler());
decoderFactories.put(new GZIPContentDecoder.Factory(byteBufferPool));
decoderFactories.put(new GZIPContentDecoder.Factory(retainableByteBufferPool));
cookieManager = newCookieManager();
cookieStore = cookieManager.getCookieStore();
@ -650,19 +646,19 @@ public class HttpClient extends ContainerLifeCycle
}
/**
* @return the {@link ByteBufferPool} of this HttpClient
* @return the {@link RetainableByteBufferPool} of this HttpClient
*/
public ByteBufferPool getByteBufferPool()
public RetainableByteBufferPool getRetainableByteBufferPool()
{
return connector.getByteBufferPool();
return connector.getRetainableByteBufferPool();
}
/**
* @param byteBufferPool the {@link ByteBufferPool} of this HttpClient
* @param retainableByteBufferPool the {@link RetainableByteBufferPool} of this HttpClient
*/
public void setByteBufferPool(ByteBufferPool byteBufferPool)
public void setRetainableByteBufferPool(RetainableByteBufferPool retainableByteBufferPool)
{
connector.setByteBufferPool(byteBufferPool);
connector.setRetainableByteBufferPool(retainableByteBufferPool);
}
/**
@ -1156,6 +1152,6 @@ public class HttpClient extends ContainerLifeCycle
{
if (sslContextFactory == null)
sslContextFactory = getSslContextFactory();
return new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), connectionFactory);
return new SslClientConnectionFactory(sslContextFactory, getRetainableByteBufferPool(), getExecutor(), connectionFactory);
}
}

View File

@ -14,7 +14,6 @@
package org.eclipse.jetty.client.internal;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@ -27,8 +26,8 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.content.ContentSourceTransformer;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.thread.AutoLock;
import org.eclipse.jetty.util.thread.SerializedInvoker;
@ -578,17 +577,17 @@ public abstract class HttpReceiver
_chunk.retain();
if (LOG.isDebugEnabled())
LOG.debug("decoding: {}", _chunk);
ByteBuffer decodedBuffer = _decoder.decode(_chunk.getByteBuffer());
RetainableByteBuffer decodedBuffer = _decoder.decode(_chunk.getByteBuffer());
if (LOG.isDebugEnabled())
LOG.debug("decoded: {}", BufferUtil.toDetailString(decodedBuffer));
LOG.debug("decoded: {}", decodedBuffer);
if (BufferUtil.hasContent(decodedBuffer))
if (decodedBuffer != null && decodedBuffer.hasRemaining())
{
// The decoded ByteBuffer is a transformed "copy" of the
// compressed one, so it has its own reference counter.
if (LOG.isDebugEnabled())
LOG.debug("returning decoded content");
return Content.Chunk.from(decodedBuffer, false, _decoder::release);
return Content.Chunk.asChunk(decodedBuffer.getByteBuffer(), false, decodedBuffer);
}
else
{

View File

@ -66,7 +66,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
parser.setHeaderCacheSize(httpTransport.getHeaderCacheSize());
parser.setHeaderCacheCaseSensitive(httpTransport.isHeaderCacheCaseSensitive());
}
retainableByteBufferPool = httpClient.getByteBufferPool().asRetainableByteBufferPool();
retainableByteBufferPool = httpClient.getRetainableByteBufferPool();
}
void receive()
@ -169,7 +169,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
protected ByteBuffer getResponseBuffer()
{
return networkBuffer == null ? null : networkBuffer.getBuffer();
return networkBuffer == null ? null : networkBuffer.getByteBuffer();
}
private void acquireNetworkBuffer()
@ -222,7 +222,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
HttpClient client = getHttpDestination().getHttpClient();
upgradeBuffer = BufferUtil.allocate(networkBuffer.remaining(), client.isUseInputDirectByteBuffers());
BufferUtil.clearToFill(upgradeBuffer);
BufferUtil.put(networkBuffer.getBuffer(), upgradeBuffer);
BufferUtil.put(networkBuffer.getByteBuffer(), upgradeBuffer);
BufferUtil.flipToFlush(upgradeBuffer, 0);
}
releaseNetworkBuffer();
@ -245,7 +245,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
while (true)
{
if (LOG.isDebugEnabled())
LOG.debug("Parsing {} in {}", BufferUtil.toDetailString(networkBuffer.getBuffer()), this);
LOG.debug("Parsing {} in {}", BufferUtil.toDetailString(networkBuffer.getByteBuffer()), this);
// Always parse even empty buffers to advance the parser.
if (parse())
{
@ -269,7 +269,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
reacquireNetworkBuffer();
// The networkBuffer may have been reacquired.
int read = endPoint.fill(networkBuffer.getBuffer());
int read = endPoint.fill(networkBuffer.getByteBuffer());
if (LOG.isDebugEnabled())
LOG.debug("Read {} bytes in {} from {} in {}", read, networkBuffer, endPoint, this);
@ -309,7 +309,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
{
while (true)
{
boolean handle = parser.parseNext(networkBuffer.getBuffer());
boolean handle = parser.parseNext(networkBuffer.getByteBuffer());
if (LOG.isDebugEnabled())
LOG.debug("Parse result={} on {}", handle, this);
Runnable action = getAndSetAction(null);
@ -347,7 +347,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
if (getHttpChannel().isTunnel(method, status))
return true;
if (networkBuffer.isEmpty())
if (!networkBuffer.hasRemaining())
return false;
if (!HttpStatus.isInformational(status))
@ -359,7 +359,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
return false;
}
if (networkBuffer.isEmpty())
if (!networkBuffer.hasRemaining())
return false;
}
}

View File

@ -23,9 +23,10 @@ import org.eclipse.jetty.client.internal.HttpSender;
import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IteratingCallback;
@ -41,7 +42,7 @@ public class HttpSenderOverHTTP extends HttpSender
private final HttpGenerator generator = new HttpGenerator();
private HttpExchange exchange;
private MetaData.Request metaData;
private ByteBuffer contentBuffer;
private ByteBuffer contentByteBuffer;
private boolean lastContent;
private Callback callback;
private boolean shutdown;
@ -63,7 +64,7 @@ public class HttpSenderOverHTTP extends HttpSender
try
{
this.exchange = exchange;
this.contentBuffer = contentBuffer;
this.contentByteBuffer = contentBuffer;
this.lastContent = lastContent;
this.callback = callback;
HttpRequest request = exchange.getRequest();
@ -92,7 +93,7 @@ public class HttpSenderOverHTTP extends HttpSender
try
{
this.exchange = exchange;
this.contentBuffer = contentBuffer;
this.contentByteBuffer = contentBuffer;
this.lastContent = lastContent;
this.callback = callback;
if (LOG.isDebugEnabled())
@ -144,8 +145,8 @@ public class HttpSenderOverHTTP extends HttpSender
private class HeadersCallback extends IteratingCallback
{
private ByteBuffer headerBuffer;
private ByteBuffer chunkBuffer;
private RetainableByteBuffer headerBuffer;
private RetainableByteBuffer chunkBuffer;
private boolean generated;
private HeadersCallback()
@ -157,52 +158,54 @@ public class HttpSenderOverHTTP extends HttpSender
protected Action process() throws Exception
{
HttpClient httpClient = getHttpChannel().getHttpDestination().getHttpClient();
ByteBufferPool byteBufferPool = httpClient.getByteBufferPool();
RetainableByteBufferPool bufferPool = httpClient.getRetainableByteBufferPool();
boolean useDirectByteBuffers = httpClient.isUseOutputDirectByteBuffers();
while (true)
{
HttpGenerator.Result result = generator.generateRequest(metaData, headerBuffer, chunkBuffer, contentBuffer, lastContent);
ByteBuffer headerByteBuffer = headerBuffer == null ? null : headerBuffer.getByteBuffer();
ByteBuffer chunkByteBuffer = chunkBuffer == null ? null : chunkBuffer.getByteBuffer();
HttpGenerator.Result result = generator.generateRequest(metaData, headerByteBuffer, chunkByteBuffer, contentByteBuffer, lastContent);
if (LOG.isDebugEnabled())
LOG.debug("Generated headers ({} bytes), chunk ({} bytes), content ({} bytes) - {}/{} for {}",
headerBuffer == null ? -1 : headerBuffer.remaining(),
chunkBuffer == null ? -1 : chunkBuffer.remaining(),
contentBuffer == null ? -1 : contentBuffer.remaining(),
headerByteBuffer == null ? -1 : headerByteBuffer.remaining(),
chunkByteBuffer == null ? -1 : chunkByteBuffer.remaining(),
contentByteBuffer == null ? -1 : contentByteBuffer.remaining(),
result, generator, exchange.getRequest());
switch (result)
{
case NEED_HEADER:
{
headerBuffer = byteBufferPool.acquire(httpClient.getRequestBufferSize(), useDirectByteBuffers);
headerBuffer = bufferPool.acquire(httpClient.getRequestBufferSize(), useDirectByteBuffers);
break;
}
case HEADER_OVERFLOW:
{
httpClient.getByteBufferPool().release(headerBuffer);
headerBuffer.release();
headerBuffer = null;
throw new IllegalArgumentException("Request header too large");
}
case NEED_CHUNK:
{
chunkBuffer = byteBufferPool.acquire(HttpGenerator.CHUNK_SIZE, useDirectByteBuffers);
chunkBuffer = bufferPool.acquire(HttpGenerator.CHUNK_SIZE, useDirectByteBuffers);
break;
}
case NEED_CHUNK_TRAILER:
{
chunkBuffer = byteBufferPool.acquire(httpClient.getRequestBufferSize(), useDirectByteBuffers);
chunkBuffer = bufferPool.acquire(httpClient.getRequestBufferSize(), useDirectByteBuffers);
break;
}
case FLUSH:
{
EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
if (headerBuffer == null)
headerBuffer = BufferUtil.EMPTY_BUFFER;
if (chunkBuffer == null)
chunkBuffer = BufferUtil.EMPTY_BUFFER;
if (contentBuffer == null)
contentBuffer = BufferUtil.EMPTY_BUFFER;
long bytes = headerBuffer.remaining() + chunkBuffer.remaining() + contentBuffer.remaining();
if (headerByteBuffer == null)
headerByteBuffer = BufferUtil.EMPTY_BUFFER;
if (chunkByteBuffer == null)
chunkByteBuffer = BufferUtil.EMPTY_BUFFER;
if (contentByteBuffer == null)
contentByteBuffer = BufferUtil.EMPTY_BUFFER;
long bytes = headerByteBuffer.remaining() + chunkByteBuffer.remaining() + contentByteBuffer.remaining();
getHttpChannel().getHttpConnection().addBytesOut(bytes);
endPoint.write(this, headerBuffer, chunkBuffer, contentBuffer);
endPoint.write(this, headerByteBuffer, chunkByteBuffer, contentByteBuffer);
generated = true;
return Action.SCHEDULED;
}
@ -263,21 +266,19 @@ public class HttpSenderOverHTTP extends HttpSender
private void release()
{
HttpClient httpClient = getHttpChannel().getHttpDestination().getHttpClient();
ByteBufferPool bufferPool = httpClient.getByteBufferPool();
if (!BufferUtil.isTheEmptyBuffer(headerBuffer))
bufferPool.release(headerBuffer);
if (headerBuffer != null)
headerBuffer.release();
headerBuffer = null;
if (!BufferUtil.isTheEmptyBuffer(chunkBuffer))
bufferPool.release(chunkBuffer);
if (chunkBuffer != null)
chunkBuffer.release();
chunkBuffer = null;
contentBuffer = null;
contentByteBuffer = null;
}
}
private class ContentCallback extends IteratingCallback
{
private ByteBuffer chunkBuffer;
private RetainableByteBuffer chunkBuffer;
public ContentCallback()
{
@ -288,14 +289,15 @@ public class HttpSenderOverHTTP extends HttpSender
protected Action process() throws Exception
{
HttpClient httpClient = getHttpChannel().getHttpDestination().getHttpClient();
ByteBufferPool bufferPool = httpClient.getByteBufferPool();
RetainableByteBufferPool bufferPool = httpClient.getRetainableByteBufferPool();
boolean useDirectByteBuffers = httpClient.isUseOutputDirectByteBuffers();
while (true)
{
HttpGenerator.Result result = generator.generateRequest(null, null, chunkBuffer, contentBuffer, lastContent);
ByteBuffer chunkByteBuffer = chunkBuffer == null ? null : chunkBuffer.getByteBuffer();
HttpGenerator.Result result = generator.generateRequest(null, null, chunkByteBuffer, contentByteBuffer, lastContent);
if (LOG.isDebugEnabled())
LOG.debug("Generated content ({} bytes, last={}) - {}/{}",
contentBuffer == null ? -1 : contentBuffer.remaining(),
contentByteBuffer == null ? -1 : contentByteBuffer.remaining(),
lastContent, result, generator);
switch (result)
{
@ -312,10 +314,10 @@ public class HttpSenderOverHTTP extends HttpSender
case FLUSH:
{
EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
if (chunkBuffer != null)
endPoint.write(this, chunkBuffer, contentBuffer);
if (chunkByteBuffer != null)
endPoint.write(this, chunkByteBuffer, contentByteBuffer);
else
endPoint.write(this, contentBuffer);
endPoint.write(this, contentByteBuffer);
return Action.SCHEDULED;
}
case SHUTDOWN_OUT:
@ -350,11 +352,10 @@ public class HttpSenderOverHTTP extends HttpSender
private void release()
{
HttpClient httpClient = getHttpChannel().getHttpDestination().getHttpClient();
ByteBufferPool bufferPool = httpClient.getByteBufferPool();
bufferPool.release(chunkBuffer);
if (chunkBuffer != null)
chunkBuffer.release();
chunkBuffer = null;
contentBuffer = null;
contentByteBuffer = null;
}
}
}

View File

@ -27,9 +27,9 @@ import java.util.zip.GZIPOutputStream;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.Callback;
@ -242,9 +242,9 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest
}
});
ByteBufferPool pool = client.getByteBufferPool();
assumeTrue(pool instanceof MappedByteBufferPool);
MappedByteBufferPool bufferPool = (MappedByteBufferPool)pool;
RetainableByteBufferPool pool = client.getRetainableByteBufferPool();
assumeTrue(pool instanceof ArrayRetainableByteBufferPool);
ArrayRetainableByteBufferPool bufferPool = (ArrayRetainableByteBufferPool)pool;
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
.scheme(scenario.getScheme())
@ -254,9 +254,9 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest
assertEquals(HttpStatus.OK_200, response.getStatus());
assertArrayEquals(content, response.getContent());
long directMemory = bufferPool.getMemory(true);
long directMemory = bufferPool.getDirectMemory();
assertThat(directMemory, lessThan((long)content.length));
long heapMemory = bufferPool.getMemory(false);
long heapMemory = bufferPool.getHeapMemory();
assertThat(heapMemory, lessThan((long)content.length));
}

View File

@ -44,9 +44,7 @@ import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.ArrayByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.Connection;
@ -632,7 +630,7 @@ public class HttpClientTLSTest
@Override
protected SslConnection newSslConnection(Connector connector, EndPoint endPoint, SSLEngine engine)
{
return new SslConnection(connector.getByteBufferPool(), connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
return new SslConnection(connector.getRetainableByteBufferPool(), connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected int networkFill(ByteBuffer input) throws IOException
@ -666,12 +664,12 @@ public class HttpClientTLSTest
{
if (sslContextFactory == null)
sslContextFactory = getSslContextFactory();
return new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), connectionFactory)
return new SslClientConnectionFactory(sslContextFactory, getRetainableByteBufferPool(), getExecutor(), connectionFactory)
{
@Override
protected SslConnection newSslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine engine)
protected SslConnection newSslConnection(RetainableByteBufferPool bufferPool, Executor executor, EndPoint endPoint, SSLEngine engine)
{
return new SslConnection(byteBufferPool, executor, endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
return new SslConnection(bufferPool, executor, endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected int networkFill(ByteBuffer input) throws IOException
@ -707,50 +705,6 @@ public class HttpClientTLSTest
assertEquals(0, clientBytes.get());
}
protected class TestRetained extends ArrayRetainableByteBufferPool
{
private final ByteBufferPool _pool;
public TestRetained(ByteBufferPool pool, int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory)
{
super(0, factor, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory);
_pool = pool;
}
@Override
protected ByteBuffer allocate(int capacity)
{
return _pool.acquire(capacity, false);
}
@Override
protected ByteBuffer allocateDirect(int capacity)
{
return _pool.acquire(capacity, true);
}
@Override
protected void removed(RetainableByteBuffer retainedBuffer)
{
_pool.release(retainedBuffer.getBuffer());
}
@Override
public Pool<RetainableByteBuffer> poolFor(int capacity, boolean direct)
{
return super.poolFor(capacity, direct);
}
}
private class TestByteBufferPool extends ArrayByteBufferPool
{
@Override
protected RetainableByteBufferPool newRetainableByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory)
{
return new TestRetained(this, factor, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory);
}
}
@Test
public void testEncryptedInputBufferRepooling() throws Exception
{
@ -759,9 +713,6 @@ public class HttpClientTLSTest
serverThreads.setName("server");
server = new Server(serverThreads);
ArrayByteBufferPool byteBufferPool = new TestByteBufferPool();
RetainableByteBufferPool retainableByteBufferPool = byteBufferPool.asRetainableByteBufferPool();
server.addBean(byteBufferPool);
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.addCustomizer(new SecureRequestCustomizer());
HttpConnectionFactory http = new HttpConnectionFactory(httpConfig);
@ -770,9 +721,8 @@ public class HttpClientTLSTest
@Override
protected SslConnection newSslConnection(Connector connector, EndPoint endPoint, SSLEngine engine)
{
ByteBufferPool byteBufferPool = connector.getByteBufferPool();
RetainableByteBufferPool retainableByteBufferPool = connector.getBean(RetainableByteBufferPool.class);
return new SslConnection(retainableByteBufferPool, byteBufferPool, connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
RetainableByteBufferPool bufferPool = connector.getRetainableByteBufferPool();
return new SslConnection(bufferPool, connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected int networkFill(ByteBuffer input) throws IOException
@ -803,11 +753,12 @@ public class HttpClientTLSTest
assertThrows(Exception.class, () -> client.newRequest("localhost", connector.getLocalPort()).scheme(HttpScheme.HTTPS.asString()).send());
Pool<RetainableByteBuffer> bucket = ((TestRetained)retainableByteBufferPool).poolFor(16 * 1024 + 1, connector.getConnectionFactory(HttpConnectionFactory.class).isUseInputDirectByteBuffers());
ArrayRetainableByteBufferPool bufferPool = (ArrayRetainableByteBufferPool)server.getRetainableByteBufferPool();
Pool<RetainableByteBuffer> bucket = bufferPool.poolFor(16 * 1024 + 1, connector.getConnectionFactory(HttpConnectionFactory.class).isUseInputDirectByteBuffers());
assertEquals(1, bucket.size());
assertEquals(1, bucket.getIdleCount());
long count = ssl.isDirectBuffersForDecryption() ? byteBufferPool.getDirectByteBufferCount() : byteBufferPool.getHeapByteBufferCount();
long count = ssl.isDirectBuffersForDecryption() ? bufferPool.getDirectByteBufferCount() : bufferPool.getHeapByteBufferCount();
assertEquals(1, count);
}
@ -817,26 +768,28 @@ public class HttpClientTLSTest
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
QueuedThreadPool serverThreads = new QueuedThreadPool();
serverThreads.setName("server");
server = new Server(serverThreads);
List<ByteBuffer> leakedBuffers = new CopyOnWriteArrayList<>();
ArrayByteBufferPool byteBufferPool = new ArrayByteBufferPool()
List<RetainableByteBuffer> leakedBuffers = new CopyOnWriteArrayList<>();
RetainableByteBufferPool bufferPool = new RetainableByteBufferPool.Wrapper(new ArrayRetainableByteBufferPool())
{
@Override
public ByteBuffer acquire(int size, boolean direct)
public RetainableByteBuffer acquire(int size, boolean direct)
{
ByteBuffer acquired = super.acquire(size, direct);
leakedBuffers.add(acquired);
return acquired;
}
@Override
public void release(ByteBuffer buffer)
{
leakedBuffers.remove(buffer);
super.release(buffer);
RetainableByteBuffer.Wrapper buffer = new RetainableByteBuffer.Wrapper(super.acquire(size, direct))
{
@Override
public boolean release()
{
boolean released = super.release();
if (released)
leakedBuffers.remove(this);
return released;
}
};
leakedBuffers.add(buffer);
return buffer;
}
};
server.addBean(byteBufferPool);
server = new Server(serverThreads, null, bufferPool);
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.addCustomizer(new SecureRequestCustomizer());
HttpConnectionFactory http = new HttpConnectionFactory(httpConfig);
@ -845,9 +798,8 @@ public class HttpClientTLSTest
@Override
protected SslConnection newSslConnection(Connector connector, EndPoint endPoint, SSLEngine engine)
{
ByteBufferPool byteBufferPool = connector.getByteBufferPool();
RetainableByteBufferPool retainableByteBufferPool = connector.getBean(RetainableByteBufferPool.class);
return new SslConnection(retainableByteBufferPool, byteBufferPool, connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
RetainableByteBufferPool bufferPool = connector.getRetainableByteBufferPool();
return new SslConnection(bufferPool, connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected boolean networkFlush(ByteBuffer output) throws IOException
@ -875,7 +827,7 @@ public class HttpClientTLSTest
assertThrows(Exception.class, () -> client.newRequest("localhost", connector.getLocalPort()).scheme(HttpScheme.HTTPS.asString()).send());
byteBufferPool.asRetainableByteBufferPool().clear();
bufferPool.clear();
await().atMost(5, TimeUnit.SECONDS).until(() -> leakedBuffers, is(empty()));
}
@ -886,26 +838,28 @@ public class HttpClientTLSTest
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
QueuedThreadPool serverThreads = new QueuedThreadPool();
serverThreads.setName("server");
server = new Server(serverThreads);
List<ByteBuffer> leakedBuffers = new CopyOnWriteArrayList<>();
ArrayByteBufferPool byteBufferPool = new ArrayByteBufferPool()
List<RetainableByteBuffer> leakedBuffers = new CopyOnWriteArrayList<>();
RetainableByteBufferPool bufferPool = new RetainableByteBufferPool.Wrapper(new ArrayRetainableByteBufferPool())
{
@Override
public ByteBuffer acquire(int size, boolean direct)
public RetainableByteBuffer acquire(int size, boolean direct)
{
ByteBuffer acquired = super.acquire(size, direct);
leakedBuffers.add(acquired);
return acquired;
}
@Override
public void release(ByteBuffer buffer)
{
leakedBuffers.remove(buffer);
super.release(buffer);
RetainableByteBuffer.Wrapper buffer = new RetainableByteBuffer.Wrapper(super.acquire(size, direct))
{
@Override
public boolean release()
{
boolean released = super.release();
if (released)
leakedBuffers.remove(this);
return released;
}
};
leakedBuffers.add(buffer);
return buffer;
}
};
server.addBean(byteBufferPool);
server = new Server(serverThreads, null, bufferPool);
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.addCustomizer(new SecureRequestCustomizer());
HttpConnectionFactory http = new HttpConnectionFactory(httpConfig);
@ -915,9 +869,8 @@ public class HttpClientTLSTest
@Override
protected SslConnection newSslConnection(Connector connector, EndPoint endPoint, SSLEngine engine)
{
ByteBufferPool byteBufferPool = connector.getByteBufferPool();
RetainableByteBufferPool retainableByteBufferPool = connector.getBean(RetainableByteBufferPool.class);
return new SslConnection(retainableByteBufferPool, byteBufferPool, connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
RetainableByteBufferPool bufferPool = connector.getRetainableByteBufferPool();
return new SslConnection(bufferPool, connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected boolean networkFlush(ByteBuffer output) throws IOException
@ -934,7 +887,7 @@ public class HttpClientTLSTest
server.setHandler(new EmptyServerHandler()
{
@Override
protected void service(Request request, Response response) throws Throwable
protected void service(Request request, Response response)
{
failFlush.set(true);
EndPoint endPoint = request.getConnectionMetaData().getConnection().getEndPoint();
@ -959,7 +912,7 @@ public class HttpClientTLSTest
assertThrows(Exception.class, () -> client.newRequest("localhost", connector.getLocalPort()).scheme(HttpScheme.HTTPS.asString()).send());
byteBufferPool.asRetainableByteBufferPool().clear();
bufferPool.clear();
await().atMost(5, TimeUnit.SECONDS).until(() -> leakedBuffers, is(empty()));
}
@ -970,26 +923,28 @@ public class HttpClientTLSTest
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
QueuedThreadPool serverThreads = new QueuedThreadPool();
serverThreads.setName("server");
server = new Server(serverThreads);
List<ByteBuffer> leakedBuffers = new CopyOnWriteArrayList<>();
ArrayByteBufferPool byteBufferPool = new ArrayByteBufferPool()
List<RetainableByteBuffer> leakedBuffers = new CopyOnWriteArrayList<>();
RetainableByteBufferPool bufferPool = new RetainableByteBufferPool.Wrapper(new ArrayRetainableByteBufferPool())
{
@Override
public ByteBuffer acquire(int size, boolean direct)
public RetainableByteBuffer acquire(int size, boolean direct)
{
ByteBuffer acquired = super.acquire(size, direct);
leakedBuffers.add(acquired);
return acquired;
}
@Override
public void release(ByteBuffer buffer)
{
leakedBuffers.remove(buffer);
super.release(buffer);
RetainableByteBuffer.Wrapper buffer = new RetainableByteBuffer.Wrapper(super.acquire(size, direct))
{
@Override
public boolean release()
{
boolean released = super.release();
if (released)
leakedBuffers.remove(this);
return released;
}
};
leakedBuffers.add(buffer);
return buffer;
}
};
server.addBean(byteBufferPool);
server = new Server(serverThreads, null, bufferPool);
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.addCustomizer(new SecureRequestCustomizer());
HttpConnectionFactory http = new HttpConnectionFactory(httpConfig);
@ -999,9 +954,8 @@ public class HttpClientTLSTest
@Override
protected SslConnection newSslConnection(Connector connector, EndPoint endPoint, SSLEngine engine)
{
ByteBufferPool byteBufferPool = connector.getByteBufferPool();
RetainableByteBufferPool retainableByteBufferPool = connector.getBean(RetainableByteBufferPool.class);
return new SslConnection(retainableByteBufferPool, byteBufferPool, connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
RetainableByteBufferPool bufferPool = connector.getRetainableByteBufferPool();
return new SslConnection(bufferPool, connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected boolean networkFlush(ByteBuffer output) throws IOException
@ -1018,7 +972,7 @@ public class HttpClientTLSTest
server.setHandler(new EmptyServerHandler()
{
@Override
protected void service(Request request, Response response) throws Throwable
protected void service(Request request, Response response)
{
failFlush.set(true);
EndPoint endPoint = request.getConnectionMetaData().getConnection().getEndPoint();
@ -1043,7 +997,7 @@ public class HttpClientTLSTest
assertThrows(Exception.class, () -> client.newRequest("localhost", connector.getLocalPort()).scheme(HttpScheme.HTTPS.asString()).send());
byteBufferPool.asRetainableByteBufferPool().clear();
bufferPool.clear();
await().atMost(5, TimeUnit.SECONDS).until(() -> leakedBuffers, is(empty()));
}
@ -1063,7 +1017,7 @@ public class HttpClientTLSTest
@Override
protected SslConnection newSslConnection(Connector connector, EndPoint endPoint, SSLEngine engine)
{
return new SslConnection(connector.getByteBufferPool(), connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
return new SslConnection(connector.getRetainableByteBufferPool(), connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected int networkFill(ByteBuffer input) throws IOException
@ -1098,12 +1052,12 @@ public class HttpClientTLSTest
{
if (sslContextFactory == null)
sslContextFactory = getSslContextFactory();
return new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), connectionFactory)
return new SslClientConnectionFactory(sslContextFactory, getRetainableByteBufferPool(), getExecutor(), connectionFactory)
{
@Override
protected SslConnection newSslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine engine)
protected SslConnection newSslConnection(RetainableByteBufferPool bufferPool, Executor executor, EndPoint endPoint, SSLEngine engine)
{
return new SslConnection(byteBufferPool, executor, endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
return new SslConnection(bufferPool, executor, endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected int networkFill(ByteBuffer input) throws IOException
@ -1160,12 +1114,12 @@ public class HttpClientTLSTest
{
if (sslContextFactory == null)
sslContextFactory = getSslContextFactory();
return new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), connectionFactory)
return new SslClientConnectionFactory(sslContextFactory, getRetainableByteBufferPool(), getExecutor(), connectionFactory)
{
@Override
protected SslConnection newSslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine engine)
protected SslConnection newSslConnection(RetainableByteBufferPool bufferPool, Executor executor, EndPoint endPoint, SSLEngine engine)
{
return new SslConnection(byteBufferPool, executor, endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
return new SslConnection(bufferPool, executor, endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected SSLEngineResult wrap(SSLEngine sslEngine, ByteBuffer[] input, ByteBuffer output) throws SSLException
@ -1204,7 +1158,7 @@ public class HttpClientTLSTest
@Override
protected SslConnection newSslConnection(Connector connector, EndPoint endPoint, SSLEngine engine)
{
return new SslConnection(connector.getByteBufferPool(), connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
return new SslConnection(connector.getRetainableByteBufferPool(), connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected SSLEngineResult unwrap(SSLEngine sslEngine, ByteBuffer input, ByteBuffer output) throws SSLException
@ -1240,12 +1194,12 @@ public class HttpClientTLSTest
{
if (sslContextFactory == null)
sslContextFactory = getSslContextFactory();
return new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), connectionFactory)
return new SslClientConnectionFactory(sslContextFactory, getRetainableByteBufferPool(), getExecutor(), connectionFactory)
{
@Override
protected SslConnection newSslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine engine)
protected SslConnection newSslConnection(RetainableByteBufferPool bufferPool, Executor executor, EndPoint endPoint, SSLEngine engine)
{
return new SslConnection(byteBufferPool, executor, endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
return new SslConnection(bufferPool, executor, endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
{
@Override
protected SSLEngineResult wrap(SSLEngine sslEngine, ByteBuffer[] input, ByteBuffer output) throws SSLException

View File

@ -19,10 +19,10 @@ import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLHandshakeException;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.ByteArrayEndPoint;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.BufferUtil;
@ -43,13 +43,13 @@ public class SslConnectionTest
sslContextFactory.setKeyStorePassword("storepwd");
sslContextFactory.start();
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.start();
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
SSLEngine sslEngine = sslContextFactory.newSSLEngine();
sslEngine.setUseClientMode(false);
SslConnection sslConnection = new SslConnection(byteBufferPool, threadPool, endPoint, sslEngine);
SslConnection sslConnection = new SslConnection(bufferPool, threadPool, endPoint, sslEngine);
EndPoint sslEndPoint = sslConnection.getDecryptedEndPoint();
sslEndPoint.setConnection(new AbstractConnection(sslEndPoint, threadPool)
{

View File

@ -283,7 +283,7 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
});
MultiPartRequestContent multiPart = new MultiPartRequestContent();
PathRequestContent content = new PathRequestContent(contentType, tmpPath, client.getByteBufferPool().asRetainableByteBufferPool());
PathRequestContent content = new PathRequestContent(contentType, tmpPath, client.getRetainableByteBufferPool());
content.setUseDirectByteBuffers(client.isUseOutputDirectByteBuffers());
multiPart.addPart(new MultiPart.ContentSourcePart(name, tmpPath.getFileName().toString(), null, content));
multiPart.close();

View File

@ -42,8 +42,8 @@
<!-- Consult the javadoc of o.e.j.util.thread.QueuedThreadPool -->
<!-- for all configuration that may be set here. -->
<!-- =========================================================== -->
<!-- uncomment to change type of threadpool
<Arg name="threadpool"><New id="threadpool" class="org.eclipse.jetty.util.thread.QueuedThreadPool"/></Arg>
<!-- uncomment to change type of thread pool
<Arg name="threadPool"><New id="threadPool" class="org.eclipse.jetty.util.thread.QueuedThreadPool"/></Arg>
-->
<Get name="ThreadPool">
<Set name="minThreads" type="int"><Property name="jetty.threadPool.minThreads" default="10"/></Set>

View File

@ -21,12 +21,13 @@ import org.eclipse.jetty.client.internal.HttpExchange;
import org.eclipse.jetty.client.internal.HttpReceiver;
import org.eclipse.jetty.client.internal.HttpSender;
import org.eclipse.jetty.fcgi.generator.Flusher;
import org.eclipse.jetty.fcgi.generator.Generator;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.IdleTimeout;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -161,9 +162,9 @@ public class HttpChannelOverFCGI extends HttpChannel
release();
}
protected void flush(Generator.Result... results)
protected void flush(RetainableByteBufferPool.Accumulator accumulator, Callback callback)
{
flusher.flush(results);
flusher.flush(accumulator, callback);
}
void receive()

View File

@ -81,7 +81,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements IConne
this.parser = new ClientParser(new ResponseListener());
requests.addLast(0);
HttpClient client = destination.getHttpClient();
this.networkByteBufferPool = client.getByteBufferPool().asRetainableByteBufferPool();
this.networkByteBufferPool = client.getRetainableByteBufferPool();
}
public HttpDestination getHttpDestination()
@ -161,14 +161,14 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements IConne
{
while (true)
{
if (parse(networkBuffer.getBuffer()))
if (parse(networkBuffer.getByteBuffer()))
return false;
if (networkBuffer.isRetained())
reacquireNetworkBuffer();
// The networkBuffer may have been reacquired.
int read = endPoint.fill(networkBuffer.getBuffer());
int read = endPoint.fill(networkBuffer.getByteBuffer());
if (LOG.isDebugEnabled())
LOG.debug("Read {} bytes from {}", read, endPoint);

View File

@ -26,10 +26,10 @@ import org.eclipse.jetty.client.internal.HttpSender;
import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.fcgi.client.transport.HttpClientTransportOverFCGI;
import org.eclipse.jetty.fcgi.generator.ClientGenerator;
import org.eclipse.jetty.fcgi.generator.Generator;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.StringUtil;
@ -42,7 +42,7 @@ public class HttpSenderOverFCGI extends HttpSender
{
super(channel);
HttpClient httpClient = channel.getHttpDestination().getHttpClient();
this.generator = new ClientGenerator(httpClient.getByteBufferPool(), httpClient.isUseOutputDirectByteBuffers());
this.generator = new ClientGenerator(httpClient.getRetainableByteBufferPool(), httpClient.isUseOutputDirectByteBuffers());
}
@Override
@ -98,18 +98,18 @@ public class HttpSenderOverFCGI extends HttpSender
HttpClientTransportOverFCGI transport = (HttpClientTransportOverFCGI)getHttpChannel().getHttpDestination().getHttpClient().getTransport();
transport.customize(request, fcgiHeaders);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
int id = getHttpChannel().getRequest();
if (contentBuffer.hasRemaining() || lastContent)
{
Generator.Result headersResult = generator.generateRequestHeaders(id, fcgiHeaders, Callback.NOOP);
Generator.Result contentResult = generator.generateRequestContent(id, contentBuffer, lastContent, callback);
getHttpChannel().flush(headersResult, contentResult);
generator.generateRequestHeaders(accumulator, id, fcgiHeaders);
generator.generateRequestContent(accumulator, id, contentBuffer, lastContent);
}
else
{
Generator.Result headersResult = generator.generateRequestHeaders(id, fcgiHeaders, callback);
getHttpChannel().flush(headersResult);
generator.generateRequestHeaders(accumulator, id, fcgiHeaders);
}
getHttpChannel().flush(accumulator, callback);
}
@Override
@ -117,9 +117,10 @@ public class HttpSenderOverFCGI extends HttpSender
{
if (contentBuffer.hasRemaining() || lastContent)
{
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
int request = getHttpChannel().getRequest();
Generator.Result result = generator.generateRequestContent(request, contentBuffer, lastContent, callback);
getHttpChannel().flush(result);
generator.generateRequestContent(accumulator, request, contentBuffer, lastContent);
getHttpChannel().flush(accumulator, callback);
}
else
{

View File

@ -22,9 +22,9 @@ import java.util.List;
import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
public class ClientGenerator extends Generator
{
@ -33,17 +33,17 @@ public class ClientGenerator extends Generator
// 0x7F_FF - 4 (the 4 is to make room for the name (or value) length).
public static final int MAX_PARAM_LENGTH = 0x7F_FF - 4;
public ClientGenerator(ByteBufferPool byteBufferPool)
public ClientGenerator(RetainableByteBufferPool bufferPool)
{
this(byteBufferPool, true);
this(bufferPool, true);
}
public ClientGenerator(ByteBufferPool byteBufferPool, boolean useDirectByteBuffers)
public ClientGenerator(RetainableByteBufferPool bufferPool, boolean useDirectByteBuffers)
{
super(byteBufferPool, useDirectByteBuffers);
super(bufferPool, useDirectByteBuffers);
}
public Result generateRequestHeaders(int request, HttpFields fields, Callback callback)
public void generateRequestHeaders(RetainableByteBufferPool.Accumulator accumulator, int request, HttpFields fields)
{
request &= 0xFF_FF;
@ -79,30 +79,31 @@ public class ClientGenerator extends Generator
// One FCGI_BEGIN_REQUEST + N FCGI_PARAMS + one last FCGI_PARAMS
ByteBuffer beginRequestBuffer = acquire(16);
BufferUtil.clearToFill(beginRequestBuffer);
Result result = new Result(getByteBufferPool(), callback);
result = result.append(beginRequestBuffer, true);
RetainableByteBuffer beginBuffer = getRetainableByteBufferPool().acquire(16, isUseDirectByteBuffers());
accumulator.append(beginBuffer);
ByteBuffer beginByteBuffer = beginBuffer.getByteBuffer();
BufferUtil.clearToFill(beginByteBuffer);
// Generate the FCGI_BEGIN_REQUEST frame
beginRequestBuffer.putInt(0x01_01_00_00 + request);
beginRequestBuffer.putInt(0x00_08_00_00);
beginByteBuffer.putInt(0x01_01_00_00 + request);
beginByteBuffer.putInt(0x00_08_00_00);
// Hardcode RESPONDER role and KEEP_ALIVE flag
beginRequestBuffer.putLong(0x00_01_01_00_00_00_00_00L);
BufferUtil.flipToFlush(beginRequestBuffer, 0);
beginByteBuffer.putLong(0x00_01_01_00_00_00_00_00L);
BufferUtil.flipToFlush(beginByteBuffer, 0);
int index = 0;
while (fieldsLength > 0)
{
int capacity = 8 + Math.min(maxCapacity, fieldsLength);
ByteBuffer buffer = acquire(capacity);
BufferUtil.clearToFill(buffer);
result = result.append(buffer, true);
RetainableByteBuffer buffer = getRetainableByteBufferPool().acquire(capacity, isUseDirectByteBuffers());
accumulator.append(buffer);
ByteBuffer byteBuffer = buffer.getByteBuffer();
BufferUtil.clearToFill(byteBuffer);
// Generate the FCGI_PARAMS frame
buffer.putInt(0x01_04_00_00 + request);
buffer.putShort((short)0);
buffer.putShort((short)0);
byteBuffer.putInt(0x01_04_00_00 + request);
byteBuffer.putShort((short)0);
byteBuffer.putShort((short)0);
capacity -= 8;
int length = 0;
@ -117,10 +118,10 @@ public class ClientGenerator extends Generator
if (required > capacity)
break;
putParamLength(buffer, nameLength);
putParamLength(buffer, valueLength);
buffer.put(nameBytes);
buffer.put(valueBytes);
putParamLength(byteBuffer, nameLength);
putParamLength(byteBuffer, valueLength);
byteBuffer.put(nameBytes);
byteBuffer.put(valueBytes);
length += required;
fieldsLength -= required;
@ -128,20 +129,19 @@ public class ClientGenerator extends Generator
index += 2;
}
buffer.putShort(4, (short)length);
BufferUtil.flipToFlush(buffer, 0);
byteBuffer.putShort(4, (short)length);
BufferUtil.flipToFlush(byteBuffer, 0);
}
ByteBuffer lastParamsBuffer = acquire(8);
BufferUtil.clearToFill(lastParamsBuffer);
result = result.append(lastParamsBuffer, true);
RetainableByteBuffer lastBuffer = getRetainableByteBufferPool().acquire(8, isUseDirectByteBuffers());
accumulator.append(lastBuffer);
ByteBuffer lastByteBuffer = lastBuffer.getByteBuffer();
BufferUtil.clearToFill(lastByteBuffer);
// Generate the last FCGI_PARAMS frame
lastParamsBuffer.putInt(0x01_04_00_00 + request);
lastParamsBuffer.putInt(0x00_00_00_00);
BufferUtil.flipToFlush(lastParamsBuffer, 0);
return result;
lastByteBuffer.putInt(0x01_04_00_00 + request);
lastByteBuffer.putInt(0x00_00_00_00);
BufferUtil.flipToFlush(lastByteBuffer, 0);
}
private int putParamLength(ByteBuffer buffer, int length)
@ -159,8 +159,8 @@ public class ClientGenerator extends Generator
return length > 127 ? 4 : 1;
}
public Result generateRequestContent(int request, ByteBuffer content, boolean lastContent, Callback callback)
public void generateRequestContent(RetainableByteBufferPool.Accumulator accumulator, int request, ByteBuffer content, boolean lastContent)
{
return generateContent(request, content, false, lastContent, callback, FCGI.FrameType.STDIN);
generateContent(accumulator, request, content, lastContent, FCGI.FrameType.STDIN);
}
}

View File

@ -15,9 +15,12 @@ package org.eclipse.jetty.fcgi.generator;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Queue;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.thread.AutoLock;
import org.slf4j.Logger;
@ -28,7 +31,7 @@ public class Flusher
private static final Logger LOG = LoggerFactory.getLogger(Flusher.class);
private final AutoLock lock = new AutoLock();
private final Queue<Generator.Result> queue = new ArrayDeque<>();
private final Queue<Entry> queue = new ArrayDeque<>();
private final IteratingCallback flushCallback = new FlushCallback();
private final EndPoint endPoint;
@ -37,24 +40,21 @@ public class Flusher
this.endPoint = endPoint;
}
public void flush(Generator.Result... results)
public void flush(RetainableByteBufferPool.Accumulator accumulator, Callback callback)
{
for (Generator.Result result : results)
{
offer(result);
}
offer(new Entry(accumulator, callback));
flushCallback.iterate();
}
private void offer(Generator.Result result)
private void offer(Entry entry)
{
try (AutoLock ignored = lock.lock())
{
queue.offer(result);
queue.offer(entry);
}
}
private Generator.Result poll()
private Entry poll()
{
try (AutoLock ignored = lock.lock())
{
@ -64,35 +64,32 @@ public class Flusher
public void shutdown()
{
flush(new ShutdownResult());
flush(null, Callback.from(() ->
{
if (LOG.isDebugEnabled())
LOG.debug("Shutting down {}", endPoint);
endPoint.shutdownOutput();
}));
}
private class FlushCallback extends IteratingCallback
{
private Generator.Result active;
private Entry active;
@Override
protected Action process() throws Exception
{
// Look if other writes are needed.
Generator.Result result = poll();
if (result == null)
Entry entry = poll();
if (entry == null)
{
// No more writes to do, return.
return Action.IDLE;
}
// Attempt to gather another result.
// Most often there is another result in the
// queue so this is a real optimization because
// it sends both results in just one TCP packet.
Generator.Result other = poll();
if (other != null)
result = result.join(other);
active = result;
ByteBuffer[] buffers = result.getByteBuffers();
endPoint.write(this, buffers);
active = entry;
List<ByteBuffer> buffers = entry.accumulator.getByteBuffers();
endPoint.write(this, buffers.toArray(ByteBuffer[]::new));
return Action.SCHEDULED;
}
@ -121,38 +118,30 @@ public class Flusher
while (true)
{
Generator.Result result = poll();
if (result == null)
Entry entry = poll();
if (entry == null)
break;
result.failed(x);
entry.failed(x);
}
}
}
private class ShutdownResult extends Generator.Result
private record Entry(RetainableByteBufferPool.Accumulator accumulator, Callback callback) implements Callback
{
private ShutdownResult()
{
super(null, null);
}
@Override
public void succeeded()
{
shutdown();
if (accumulator != null)
accumulator.release();
callback.succeeded();
}
@Override
public void failed(Throwable x)
{
shutdown();
}
private void shutdown()
{
if (LOG.isDebugEnabled())
LOG.debug("Shutting down {}", endPoint);
endPoint.shutdownOutput();
if (accumulator != null)
accumulator.release();
callback.failed(x);
}
}
}

View File

@ -14,150 +14,69 @@
package org.eclipse.jetty.fcgi.generator;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
public class Generator
{
public static final int MAX_CONTENT_LENGTH = 0xFF_FF;
private final ByteBufferPool byteBufferPool;
private final RetainableByteBufferPool bufferPool;
private final boolean useDirectByteBuffers;
public Generator(ByteBufferPool byteBufferPool, boolean useDirectByteBuffers)
public Generator(RetainableByteBufferPool bufferPool, boolean useDirectByteBuffers)
{
this.byteBufferPool = byteBufferPool;
this.bufferPool = bufferPool;
this.useDirectByteBuffers = useDirectByteBuffers;
}
ByteBufferPool getByteBufferPool()
public RetainableByteBufferPool getRetainableByteBufferPool()
{
return byteBufferPool;
return bufferPool;
}
ByteBuffer acquire(int capacity)
public boolean isUseDirectByteBuffers()
{
return byteBufferPool.acquire(capacity, useDirectByteBuffers);
return useDirectByteBuffers;
}
protected Result generateContent(int id, ByteBuffer content, boolean recycle, boolean lastContent, Callback callback, FCGI.FrameType frameType)
protected void generateContent(RetainableByteBufferPool.Accumulator accumulator, int id, ByteBuffer content, boolean lastContent, FCGI.FrameType frameType)
{
id &= 0xFF_FF;
int contentLength = content == null ? 0 : content.remaining();
Result result = new Result(byteBufferPool, callback);
while (contentLength > 0 || lastContent)
{
ByteBuffer buffer = acquire(8);
BufferUtil.clearToFill(buffer);
result = result.append(buffer, true);
RetainableByteBuffer buffer = getRetainableByteBufferPool().acquire(8, isUseDirectByteBuffers());
accumulator.append(buffer);
ByteBuffer byteBuffer = buffer.getByteBuffer();
BufferUtil.clearToFill(byteBuffer);
// Generate the frame header
buffer.put((byte)0x01);
buffer.put((byte)frameType.code);
buffer.putShort((short)id);
// Generate the frame header.
byteBuffer.put((byte)0x01);
byteBuffer.put((byte)frameType.code);
byteBuffer.putShort((short)id);
int length = Math.min(MAX_CONTENT_LENGTH, contentLength);
buffer.putShort((short)length);
buffer.putShort((short)0);
BufferUtil.flipToFlush(buffer, 0);
byteBuffer.putShort((short)length);
byteBuffer.putShort((short)0);
BufferUtil.flipToFlush(byteBuffer, 0);
if (contentLength == 0)
break;
// Slice the content to avoid copying
// Slice the content to avoid copying.
int limit = content.limit();
content.limit(content.position() + length);
ByteBuffer slice = content.slice();
// Don't recycle the slice
result = result.append(slice, false);
// Don't recycle the slice.
accumulator.append(RetainableByteBuffer.wrap(slice));
content.position(content.limit());
content.limit(limit);
contentLength -= length;
// Recycle the content buffer if needed
if (recycle && contentLength == 0)
result = result.append(content, true);
}
return result;
}
// TODO: rewrite this class in light of ByteBufferPool.Lease.
public static class Result implements Callback
{
private final List<Callback> callbacks = new ArrayList<>(2);
private final List<ByteBuffer> buffers = new ArrayList<>(8);
private final List<Boolean> recycles = new ArrayList<>(8);
private final ByteBufferPool byteBufferPool;
public Result(ByteBufferPool byteBufferPool, Callback callback)
{
this.byteBufferPool = byteBufferPool;
this.callbacks.add(callback);
}
public Result append(ByteBuffer buffer, boolean recycle)
{
if (buffer != null)
{
buffers.add(buffer);
recycles.add(recycle);
}
return this;
}
public Result join(Result that)
{
callbacks.addAll(that.callbacks);
buffers.addAll(that.buffers);
recycles.addAll(that.recycles);
return this;
}
public ByteBuffer[] getByteBuffers()
{
return buffers.toArray(new ByteBuffer[0]);
}
@Override
@SuppressWarnings("ForLoopReplaceableByForEach")
public void succeeded()
{
recycle();
for (int i = 0; i < callbacks.size(); ++i)
{
Callback callback = callbacks.get(i);
if (callback != null)
callback.succeeded();
}
}
@Override
@SuppressWarnings("ForLoopReplaceableByForEach")
public void failed(Throwable x)
{
recycle();
for (int i = 0; i < callbacks.size(); ++i)
{
Callback callback = callbacks.get(i);
if (callback != null)
callback.failed(x);
}
}
protected void recycle()
{
for (int i = 0; i < buffers.size(); ++i)
{
ByteBuffer buffer = buffers.get(i);
if (recycles.get(i))
byteBufferPool.release(buffer);
}
}
}
}

View File

@ -23,9 +23,9 @@ import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
public class ServerGenerator extends Generator
{
@ -35,18 +35,18 @@ public class ServerGenerator extends Generator
private final boolean sendStatus200;
public ServerGenerator(ByteBufferPool byteBufferPool)
public ServerGenerator(RetainableByteBufferPool bufferPool)
{
this(byteBufferPool, true, true);
this(bufferPool, true, true);
}
public ServerGenerator(ByteBufferPool byteBufferPool, boolean useDirectByteBuffers, boolean sendStatus200)
public ServerGenerator(RetainableByteBufferPool bufferPool, boolean useDirectByteBuffers, boolean sendStatus200)
{
super(byteBufferPool, useDirectByteBuffers);
super(bufferPool, useDirectByteBuffers);
this.sendStatus200 = sendStatus200;
}
public Result generateResponseHeaders(int request, int code, String reason, HttpFields fields, Callback callback)
public void generateResponseHeaders(RetainableByteBufferPool.Accumulator accumulator, int request, int code, String reason, HttpFields fields)
{
request &= 0xFF_FF;
@ -83,50 +83,48 @@ public class ServerGenerator extends Generator
// End of headers
length += EOL.length;
ByteBuffer buffer = acquire(length);
BufferUtil.clearToFill(buffer);
ByteBuffer byteBuffer = BufferUtil.allocate(length, isUseDirectByteBuffers());
BufferUtil.clearToFill(byteBuffer);
for (int i = 0; i < bytes.size(); i += 2)
{
buffer.put(bytes.get(i)).put(COLON).put(bytes.get(i + 1)).put(EOL);
byteBuffer.put(bytes.get(i)).put(COLON).put(bytes.get(i + 1)).put(EOL);
}
buffer.put(EOL);
byteBuffer.put(EOL);
BufferUtil.flipToFlush(buffer, 0);
BufferUtil.flipToFlush(byteBuffer, 0);
return generateContent(request, buffer, true, false, callback, FCGI.FrameType.STDOUT);
generateContent(accumulator, request, byteBuffer, false, FCGI.FrameType.STDOUT);
}
public Result generateResponseContent(int request, ByteBuffer content, boolean lastContent, boolean aborted, Callback callback)
public void generateResponseContent(RetainableByteBufferPool.Accumulator accumulator, int request, ByteBuffer content, boolean lastContent, boolean aborted)
{
if (aborted)
{
Result result = new Result(getByteBufferPool(), callback);
if (lastContent)
result.append(generateEndRequest(request, true), true);
accumulator.append(generateEndRequest(request, true));
else
result.append(BufferUtil.EMPTY_BUFFER, false);
return result;
accumulator.append(RetainableByteBuffer.wrap(BufferUtil.EMPTY_BUFFER));
}
else
{
Result result = generateContent(request, content, false, lastContent, callback, FCGI.FrameType.STDOUT);
generateContent(accumulator, request, content, lastContent, FCGI.FrameType.STDOUT);
if (lastContent)
result.append(generateEndRequest(request, false), true);
return result;
accumulator.append(generateEndRequest(request, false));
}
}
private ByteBuffer generateEndRequest(int request, boolean aborted)
private RetainableByteBuffer generateEndRequest(int request, boolean aborted)
{
request &= 0xFF_FF;
ByteBuffer endRequestBuffer = acquire(16);
BufferUtil.clearToFill(endRequestBuffer);
endRequestBuffer.putInt(0x01_03_00_00 + request);
endRequestBuffer.putInt(0x00_08_00_00);
endRequestBuffer.putInt(aborted ? 1 : 0);
endRequestBuffer.putInt(0);
BufferUtil.flipToFlush(endRequestBuffer, 0);
RetainableByteBuffer endRequestBuffer = getRetainableByteBufferPool().acquire(16, isUseDirectByteBuffers());
ByteBuffer byteBuffer = endRequestBuffer.getByteBuffer();
BufferUtil.clearToFill(byteBuffer);
byteBuffer.putInt(0x01_03_00_00 + request);
byteBuffer.putInt(0x00_08_00_00);
byteBuffer.putInt(aborted ? 1 : 0);
byteBuffer.putInt(0);
BufferUtil.flipToFlush(byteBuffer, 0);
return endRequestBuffer;
}
}

View File

@ -21,8 +21,8 @@ import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.fcgi.parser.ServerParser;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -31,50 +31,51 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
public class ClientGeneratorTest
{
@Test
public void testGenerateRequestHeaders() throws Exception
public void testGenerateRequestHeaders()
{
HttpFields.Mutable fields = HttpFields.build();
// Short name, short value
final String shortShortName = "REQUEST_METHOD";
final String shortShortValue = "GET";
String shortShortValue = "GET";
fields.put(new HttpField(shortShortName, shortShortValue));
// Short name, long value
final String shortLongName = "REQUEST_URI";
// Be sure it's longer than 127 chars to test the large value
final String shortLongValue = "/api/0.6/map?bbox=-64.217736,-31.456810,-64.187736,-31.432322,filler=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
String shortLongValue = "/api/0.6/map?bbox=-64.217736,-31.456810,-64.187736,-31.432322,filler=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
fields.put(new HttpField(shortLongName, shortLongValue));
// Long name, short value
// Be sure it's longer than 127 chars to test the large name
final String longShortName = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
final String longShortValue = "api.openstreetmap.org";
String longShortValue = "api.openstreetmap.org";
fields.put(new HttpField(longShortName, longShortValue));
// Long name, long value
char[] chars = new char[ClientGenerator.MAX_PARAM_LENGTH];
Arrays.fill(chars, 'z');
final String longLongName = new String(chars);
final String longLongValue = new String(chars);
String longLongName = new String(chars);
String longLongValue = new String(chars);
fields.put(new HttpField(longLongName, longLongValue));
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ClientGenerator generator = new ClientGenerator(byteBufferPool);
final int id = 13;
Generator.Result result = generator.generateRequestHeaders(id, fields, null);
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
ClientGenerator generator = new ClientGenerator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
int id = 13;
generator.generateRequestHeaders(accumulator, id, fields);
// Use the fundamental theorem of arithmetic to test the results.
// This way we know onHeader() has been called the right number of
// times with the right arguments, and so onHeaders().
final int[] primes = new int[]{2, 3, 5, 7, 11};
int[] primes = new int[]{2, 3, 5, 7, 11};
int value = 1;
for (int prime : primes)
{
value *= prime;
}
final AtomicInteger params = new AtomicInteger(1);
AtomicInteger params = new AtomicInteger(1);
ServerParser parser = new ServerParser(new ServerParser.Listener.Adapter()
{
@Override
@ -83,23 +84,27 @@ public class ClientGeneratorTest
assertEquals(id, request);
switch (field.getName())
{
case shortShortName:
case shortShortName ->
{
assertEquals(shortShortValue, field.getValue());
params.set(params.get() * primes[0]);
break;
case shortLongName:
}
case shortLongName ->
{
assertEquals(shortLongValue, field.getValue());
params.set(params.get() * primes[1]);
break;
case longShortName:
}
case longShortName ->
{
assertEquals(longShortValue, field.getValue());
params.set(params.get() * primes[2]);
break;
default:
}
default ->
{
assertEquals(longLongName, field.getName());
assertEquals(longLongValue, field.getValue());
params.set(params.get() * primes[3]);
break;
}
}
}
@ -112,7 +117,7 @@ public class ClientGeneratorTest
}
});
for (ByteBuffer buffer : result.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
parser.parse(buffer);
assertFalse(buffer.hasRemaining());
@ -122,17 +127,18 @@ public class ClientGeneratorTest
// Parse again byte by byte
params.set(1);
for (ByteBuffer buffer : result.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
buffer.flip();
while (buffer.hasRemaining())
{
parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
}
assertFalse(buffer.hasRemaining());
}
assertEquals(value, params.get());
accumulator.release();
}
@Test
@ -147,16 +153,17 @@ public class ClientGeneratorTest
testGenerateRequestContent(128 * 1024);
}
private void testGenerateRequestContent(final int contentLength) throws Exception
private void testGenerateRequestContent(int contentLength) throws Exception
{
ByteBuffer content = ByteBuffer.allocate(contentLength);
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ClientGenerator generator = new ClientGenerator(byteBufferPool);
final int id = 13;
Generator.Result result = generator.generateRequestContent(id, content, true, null);
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
ClientGenerator generator = new ClientGenerator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
int id = 13;
generator.generateRequestContent(accumulator, id, content, true);
final AtomicInteger totalLength = new AtomicInteger();
AtomicInteger totalLength = new AtomicInteger();
ServerParser parser = new ServerParser(new ServerParser.Listener.Adapter()
{
@Override
@ -175,21 +182,22 @@ public class ClientGeneratorTest
}
});
for (ByteBuffer buffer : result.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
parser.parse(buffer);
assertFalse(buffer.hasRemaining());
}
// Parse again one byte at a time
for (ByteBuffer buffer : result.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
buffer.flip();
while (buffer.hasRemaining())
{
parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
}
assertFalse(buffer.hasRemaining());
}
accumulator.release();
}
}

View File

@ -19,12 +19,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.fcgi.generator.Generator;
import org.eclipse.jetty.fcgi.generator.ServerGenerator;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -34,32 +33,33 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class ClientParserTest
{
@Test
public void testParseResponseHeaders() throws Exception
public void testParseResponseHeaders()
{
final int id = 13;
int id = 13;
HttpFields.Mutable fields = HttpFields.build();
final int statusCode = 200;
final String statusMessage = "OK";
final String contentTypeName = "Content-Type";
final String contentTypeValue = "text/html;charset=utf-8";
int statusCode = 200;
String statusMessage = "OK";
String contentTypeName = "Content-Type";
String contentTypeValue = "text/html;charset=utf-8";
fields.put(contentTypeName, contentTypeValue);
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ServerGenerator generator = new ServerGenerator(byteBufferPool);
Generator.Result result = generator.generateResponseHeaders(id, statusCode, statusMessage, fields, null);
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
ServerGenerator generator = new ServerGenerator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateResponseHeaders(accumulator, id, statusCode, statusMessage, fields);
// Use the fundamental theorem of arithmetic to test the results.
// This way we know onHeader() has been called the right number of
// times with the right arguments, and so onHeaders().
final int[] primes = new int[]{2, 3, 5};
int[] primes = new int[]{2, 3, 5};
int value = 1;
for (int prime : primes)
{
value *= prime;
}
final AtomicInteger params = new AtomicInteger(1);
AtomicInteger params = new AtomicInteger(1);
ClientParser parser = new ClientParser(new ClientParser.Listener.Adapter()
{
@Override
@ -74,14 +74,10 @@ public class ClientParserTest
public void onHeader(int request, HttpField field)
{
assertEquals(id, request);
switch (field.getName())
if (field.getName().equals(contentTypeName))
{
case contentTypeName:
assertEquals(contentTypeValue, field.getValue().toLowerCase(Locale.ENGLISH));
params.set(params.get() * primes[1]);
break;
default:
break;
assertEquals(contentTypeValue, field.getValue().toLowerCase(Locale.ENGLISH));
params.set(params.get() * primes[1]);
}
}
@ -94,28 +90,31 @@ public class ClientParserTest
}
});
for (ByteBuffer buffer : result.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
parser.parse(buffer);
assertFalse(buffer.hasRemaining());
}
assertEquals(value, params.get());
accumulator.release();
}
@Test
public void testParseNoResponseContent() throws Exception
{
final int id = 13;
int id = 13;
HttpFields fields = HttpFields.build()
.put("Content-Length", "0");
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ServerGenerator generator = new ServerGenerator(byteBufferPool);
Generator.Result result1 = generator.generateResponseHeaders(id, 200, "OK", fields, null);
Generator.Result result2 = generator.generateResponseContent(id, null, true, false, null);
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
ServerGenerator generator = new ServerGenerator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateResponseHeaders(accumulator, id, 200, "OK", fields);
generator.generateResponseContent(accumulator, id, null, true, false);
final AtomicInteger verifier = new AtomicInteger();
AtomicInteger verifier = new AtomicInteger();
ClientParser parser = new ClientParser(new ClientParser.Listener.Adapter()
{
@Override
@ -134,40 +133,38 @@ public class ClientParserTest
}
});
for (ByteBuffer buffer : result1.getByteBuffers())
{
parser.parse(buffer);
assertFalse(buffer.hasRemaining());
}
for (ByteBuffer buffer : result2.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
parser.parse(buffer);
assertFalse(buffer.hasRemaining());
}
assertEquals(3, verifier.get());
accumulator.release();
}
@Test
public void testParseSmallResponseContent() throws Exception
{
final int id = 13;
int id = 13;
HttpFields.Mutable fields = HttpFields.build();
ByteBuffer content = ByteBuffer.wrap(new byte[1024]);
final int contentLength = content.remaining();
int contentLength = content.remaining();
final int code = 200;
final String contentTypeName = "Content-Length";
final String contentTypeValue = String.valueOf(contentLength);
int code = 200;
String contentTypeName = "Content-Length";
String contentTypeValue = String.valueOf(contentLength);
fields.put(contentTypeName, contentTypeValue);
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ServerGenerator generator = new ServerGenerator(byteBufferPool);
Generator.Result result1 = generator.generateResponseHeaders(id, code, "OK", fields, null);
Generator.Result result2 = generator.generateResponseContent(id, content, true, false, null);
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
ServerGenerator generator = new ServerGenerator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateResponseHeaders(accumulator, id, code, "OK", fields);
generator.generateResponseContent(accumulator, id, content, true, false);
final AtomicInteger verifier = new AtomicInteger();
AtomicInteger verifier = new AtomicInteger();
ClientParser parser = new ClientParser(new ClientParser.Listener.Adapter()
{
@Override
@ -187,41 +184,39 @@ public class ClientParserTest
}
});
for (ByteBuffer buffer : result1.getByteBuffers())
{
parser.parse(buffer);
assertFalse(buffer.hasRemaining());
}
for (ByteBuffer buffer : result2.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
parser.parse(buffer);
assertFalse(buffer.hasRemaining());
}
assertEquals(5, verifier.get());
accumulator.release();
}
@Test
public void testParseLargeResponseContent() throws Exception
{
final int id = 13;
int id = 13;
HttpFields.Mutable fields = HttpFields.build();
ByteBuffer content = ByteBuffer.wrap(new byte[128 * 1024]);
final int contentLength = content.remaining();
int contentLength = content.remaining();
final int code = 200;
final String contentTypeName = "Content-Length";
final String contentTypeValue = String.valueOf(contentLength);
int code = 200;
String contentTypeName = "Content-Length";
String contentTypeValue = String.valueOf(contentLength);
fields.put(contentTypeName, contentTypeValue);
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ServerGenerator generator = new ServerGenerator(byteBufferPool);
Generator.Result result1 = generator.generateResponseHeaders(id, code, "OK", fields, null);
Generator.Result result2 = generator.generateResponseContent(id, content, true, false, null);
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
ServerGenerator generator = new ServerGenerator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateResponseHeaders(accumulator, id, code, "OK", fields);
generator.generateResponseContent(accumulator, id, content, true, false);
final AtomicInteger totalLength = new AtomicInteger();
final AtomicBoolean verifier = new AtomicBoolean();
AtomicInteger totalLength = new AtomicInteger();
AtomicBoolean verifier = new AtomicBoolean();
ClientParser parser = new ClientParser(new ClientParser.Listener.Adapter()
{
@Override
@ -241,17 +236,14 @@ public class ClientParserTest
}
});
for (ByteBuffer buffer : result1.getByteBuffers())
{
parser.parse(buffer);
assertFalse(buffer.hasRemaining());
}
for (ByteBuffer buffer : result2.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
parser.parse(buffer);
assertFalse(buffer.hasRemaining());
}
assertTrue(verifier.get());
accumulator.release();
}
}

View File

@ -18,7 +18,6 @@ import java.util.Locale;
import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.fcgi.generator.Flusher;
import org.eclipse.jetty.fcgi.generator.Generator;
import org.eclipse.jetty.fcgi.generator.ServerGenerator;
import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpField;
@ -30,6 +29,7 @@ import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpStream;
import org.eclipse.jetty.util.BufferUtil;
@ -229,8 +229,9 @@ public class HttpStreamOverFCGI implements HttpStream
{
if (last)
{
Generator.Result result = generateResponseContent(true, BufferUtil.EMPTY_BUFFER, callback);
flusher.flush(result);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generateResponseContent(accumulator, true, BufferUtil.EMPTY_BUFFER);
flusher.flush(accumulator, callback);
}
else
{
@ -240,8 +241,9 @@ public class HttpStreamOverFCGI implements HttpStream
}
else
{
Generator.Result result = generateResponseContent(last, content, callback);
flusher.flush(result);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generateResponseContent(accumulator, last, content);
flusher.flush(accumulator, callback);
}
if (last && _shutdown)
@ -258,40 +260,42 @@ public class HttpStreamOverFCGI implements HttpStream
boolean shutdown = _shutdown = info.getFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString());
RetainableByteBufferPool bufferPool = _generator.getRetainableByteBufferPool();
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
Flusher flusher = _connection.getFlusher();
if (head)
{
if (last)
{
Generator.Result headersResult = generateResponseHeaders(info, Callback.NOOP);
Generator.Result contentResult = generateResponseContent(true, BufferUtil.EMPTY_BUFFER, callback);
flusher.flush(headersResult, contentResult);
generateResponseHeaders(accumulator, info);
generateResponseContent(accumulator, true, BufferUtil.EMPTY_BUFFER);
flusher.flush(accumulator, callback);
}
else
{
Generator.Result headersResult = generateResponseHeaders(info, callback);
flusher.flush(headersResult);
generateResponseHeaders(accumulator, info);
flusher.flush(accumulator, callback);
}
}
else
{
Generator.Result headersResult = generateResponseHeaders(info, Callback.NOOP);
Generator.Result contentResult = generateResponseContent(last, content, callback);
flusher.flush(headersResult, contentResult);
generateResponseHeaders(accumulator, info);
generateResponseContent(accumulator, last, content);
flusher.flush(accumulator, callback);
}
if (last && shutdown)
flusher.shutdown();
}
private Generator.Result generateResponseHeaders(MetaData.Response info, Callback callback)
private void generateResponseHeaders(RetainableByteBufferPool.Accumulator accumulator, MetaData.Response info)
{
return _generator.generateResponseHeaders(_id, info.getStatus(), info.getReason(), info.getFields(), callback);
_generator.generateResponseHeaders(accumulator, _id, info.getStatus(), info.getReason(), info.getFields());
}
private Generator.Result generateResponseContent(boolean last, ByteBuffer buffer, Callback callback)
private void generateResponseContent(RetainableByteBufferPool.Accumulator accumulator, boolean last, ByteBuffer buffer)
{
return _generator.generateResponseContent(_id, buffer, last, _aborted, callback);
_generator.generateResponseContent(accumulator, _id, buffer, last, _aborted);
}
@Override

View File

@ -63,7 +63,7 @@ public class ServerFCGIConnection extends AbstractConnection implements Connecti
{
super(endPoint, connector.getExecutor());
this.connector = connector;
this.networkByteBufferPool = connector.getByteBufferPool().asRetainableByteBufferPool();
this.networkByteBufferPool = connector.getRetainableByteBufferPool();
this.flusher = new Flusher(endPoint);
this.configuration = configuration;
this.sendStatus200 = sendStatus200;
@ -212,7 +212,7 @@ public class ServerFCGIConnection extends AbstractConnection implements Connecti
LOG.debug("Read {} bytes from {} {}", read, getEndPoint(), this);
if (read > 0)
{
if (parse(networkBuffer.getBuffer()))
if (parse(networkBuffer.getByteBuffer()))
return;
}
else if (read == 0)
@ -252,7 +252,7 @@ public class ServerFCGIConnection extends AbstractConnection implements Connecti
// See also HttpConnection.parseAndFillForContent().
while (stream != null)
{
if (parse(networkBuffer.getBuffer()))
if (parse(networkBuffer.getByteBuffer()))
return;
// Check if the request was completed by the parsing.
if (stream == null)
@ -281,7 +281,7 @@ public class ServerFCGIConnection extends AbstractConnection implements Connecti
{
try
{
return getEndPoint().fill(networkBuffer.getBuffer());
return getEndPoint().fill(networkBuffer.getByteBuffer());
}
catch (Throwable x)
{
@ -333,7 +333,7 @@ public class ServerFCGIConnection extends AbstractConnection implements Connecti
if (stream != null)
throw new UnsupportedOperationException("FastCGI Multiplexing");
HttpChannel channel = httpChannelFactory.newHttpChannel(ServerFCGIConnection.this);
ServerGenerator generator = new ServerGenerator(connector.getByteBufferPool(), isUseOutputDirectByteBuffers(), sendStatus200);
ServerGenerator generator = new ServerGenerator(connector.getRetainableByteBufferPool(), isUseOutputDirectByteBuffers(), sendStatus200);
stream = new HttpStreamOverFCGI(ServerFCGIConnection.this, generator, channel, request);
channel.setHttpStream(stream);
if (LOG.isDebugEnabled())

View File

@ -21,10 +21,9 @@ import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.LeakTrackingConnectionPool;
import org.eclipse.jetty.fcgi.client.transport.HttpClientTransportOverFCGI;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.LeakTrackingByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Server;
@ -39,8 +38,8 @@ import static org.hamcrest.MatcherAssert.assertThat;
public abstract class AbstractHttpClientServerTest
{
private LeakTrackingByteBufferPool serverBufferPool;
protected ByteBufferPool clientBufferPool;
private RetainableByteBufferPool serverBufferPool;
protected RetainableByteBufferPool clientBufferPool;
private final AtomicLong connectionLeaks = new AtomicLong();
protected Server server;
protected ServerConnector connector;
@ -53,7 +52,8 @@ public abstract class AbstractHttpClientServerTest
serverThreads.setName("server");
server = new Server(serverThreads);
ServerFCGIConnectionFactory fcgiConnectionFactory = new ServerFCGIConnectionFactory(new HttpConfiguration());
serverBufferPool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged());
// TODO: restore leak tracking.
serverBufferPool = new ArrayRetainableByteBufferPool();
connector = new ServerConnector(server, null, null, serverBufferPool,
1, Math.max(1, ProcessorUtils.availableProcessors() / 2), fcgiConnectionFactory);
server.addConnector(connector);
@ -65,9 +65,10 @@ public abstract class AbstractHttpClientServerTest
QueuedThreadPool clientThreads = new QueuedThreadPool();
clientThreads.setName("client");
clientConnector.setExecutor(clientThreads);
// TODO: restore leak tracking.
if (clientBufferPool == null)
clientBufferPool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged());
clientConnector.setByteBufferPool(clientBufferPool);
clientBufferPool = new ArrayRetainableByteBufferPool();
clientConnector.setRetainableByteBufferPool(clientBufferPool);
HttpClientTransport transport = new HttpClientTransportOverFCGI(clientConnector, "");
transport.setConnectionPoolFactory(destination -> new LeakTrackingConnectionPool(destination, client.getMaxConnectionsPerDestination())
{
@ -86,22 +87,6 @@ public abstract class AbstractHttpClientServerTest
{
System.gc();
if (serverBufferPool != null)
{
assertThat("Server BufferPool - leaked acquires", serverBufferPool.getLeakedAcquires(), Matchers.is(0L));
assertThat("Server BufferPool - leaked releases", serverBufferPool.getLeakedReleases(), Matchers.is(0L));
assertThat("Server BufferPool - leaked removes", serverBufferPool.getLeakedRemoves(), Matchers.is(0L));
assertThat("Server BufferPool - unreleased", serverBufferPool.getLeakedResources(), Matchers.is(0L));
}
if ((clientBufferPool != null) && (clientBufferPool instanceof LeakTrackingByteBufferPool pool))
{
assertThat("Client BufferPool - leaked acquires", pool.getLeakedAcquires(), Matchers.is(0L));
assertThat("Client BufferPool - leaked releases", pool.getLeakedReleases(), Matchers.is(0L));
assertThat("Client BufferPool - leaked removes", pool.getLeakedRemoves(), Matchers.is(0L));
assertThat("Client BufferPool - unreleased", pool.getLeakedResources(), Matchers.is(0L));
}
assertThat("Connection Leaks", connectionLeaks.get(), Matchers.is(0L));
if (client != null)

View File

@ -36,7 +36,6 @@ import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpChannel;
@ -400,11 +399,6 @@ public class HttpClientTest extends AbstractHttpClientServerTest
@Test
public void testGZIPContentEncoding() throws Exception
{
// GZIPContentDecoder returns to application pooled
// buffers, which is fine, but in this test they will
// appear as "leaked", so we use a normal ByteBufferPool.
clientBufferPool = new MappedByteBufferPool.Tagged();
byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
start(new Handler.Abstract()
{

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.http;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
@ -21,7 +20,8 @@ import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.component.Destroyable;
import org.eclipse.jetty.util.compression.InflaterPool;
@ -36,8 +36,8 @@ public class GZIPContentDecoder implements Destroyable
// Unsigned Integer Max == 2^32
private static final long UINT_MAX = 0xFFFFFFFFL;
private final List<ByteBuffer> _inflateds = new ArrayList<>();
private final ByteBufferPool _pool;
private final List<RetainableByteBuffer> _inflateds = new ArrayList<>();
private final RetainableByteBufferPool _pool;
private final int _bufferSize;
private InflaterPool.Entry _inflaterEntry;
private Inflater _inflater;
@ -45,7 +45,7 @@ public class GZIPContentDecoder implements Destroyable
private int _size;
private long _value;
private byte _flags;
private ByteBuffer _inflated;
private RetainableByteBuffer _inflated;
public GZIPContentDecoder()
{
@ -57,24 +57,24 @@ public class GZIPContentDecoder implements Destroyable
this(null, bufferSize);
}
public GZIPContentDecoder(ByteBufferPool pool, int bufferSize)
public GZIPContentDecoder(RetainableByteBufferPool retainableByteBufferPool, int bufferSize)
{
this(new InflaterPool(0, true), pool, bufferSize);
this(new InflaterPool(0, true), retainableByteBufferPool, bufferSize);
}
public GZIPContentDecoder(InflaterPool inflaterPool, ByteBufferPool pool, int bufferSize)
public GZIPContentDecoder(InflaterPool inflaterPool, RetainableByteBufferPool retainableByteBufferPool, int bufferSize)
{
_inflaterEntry = inflaterPool.acquire();
_inflater = _inflaterEntry.get();
_bufferSize = bufferSize;
_pool = pool;
_pool = retainableByteBufferPool != null ? retainableByteBufferPool : new RetainableByteBufferPool.NonPooling();
reset();
}
/**
* <p>Inflates compressed data from a buffer.</p>
* <p>The buffers returned by this method should be released
* via {@link #release(ByteBuffer)}.</p>
* <p>The {@link RetainableByteBuffer} returned by this method
* <b>must</b> be released via {@link RetainableByteBuffer#release()}.</p>
* <p>This method may fully consume the input buffer, but return
* only a chunk of the inflated bytes, to allow applications to
* consume the inflated chunk before performing further inflation,
@ -83,21 +83,21 @@ public class GZIPContentDecoder implements Destroyable
* it's already fully consumed) and that will produce another
* chunk of inflated bytes. Termination happens when the input
* buffer is fully consumed, and the returned buffer is empty.</p>
* <p>See {@link #decodedChunk(ByteBuffer)} to perform inflating
* <p>See {@link #decodedChunk(RetainableByteBuffer)} to perform inflating
* in a non-blocking way that allows to apply backpressure.</p>
*
* @param compressed the buffer containing compressed data.
* @return a buffer containing inflated data.
*/
public ByteBuffer decode(ByteBuffer compressed)
public RetainableByteBuffer decode(ByteBuffer compressed)
{
decodeChunks(compressed);
if (_inflateds.isEmpty())
{
if (BufferUtil.isEmpty(_inflated) || _state == State.CRC || _state == State.ISIZE)
return BufferUtil.EMPTY_BUFFER;
ByteBuffer result = _inflated;
if ((_inflated == null || !_inflated.hasRemaining()) || _state == State.CRC || _state == State.ISIZE)
return acquire(0);
RetainableByteBuffer result = _inflated;
_inflated = null;
return result;
}
@ -105,12 +105,12 @@ public class GZIPContentDecoder implements Destroyable
{
_inflateds.add(_inflated);
_inflated = null;
int length = _inflateds.stream().mapToInt(Buffer::remaining).sum();
ByteBuffer result = acquire(length);
for (ByteBuffer buffer : _inflateds)
int length = _inflateds.stream().mapToInt(RetainableByteBuffer::remaining).sum();
RetainableByteBuffer result = acquire(length);
for (RetainableByteBuffer buffer : _inflateds)
{
BufferUtil.append(result, buffer);
release(buffer);
BufferUtil.append(result.getByteBuffer(), buffer.getByteBuffer());
buffer.release();
}
_inflateds.clear();
return result;
@ -132,38 +132,26 @@ public class GZIPContentDecoder implements Destroyable
* should return, allowing to consume the inflated chunk and apply
* backpressure
*/
protected boolean decodedChunk(ByteBuffer chunk)
protected boolean decodedChunk(RetainableByteBuffer chunk)
{
if (_inflated == null)
{
_inflated = chunk;
}
else
{
if (BufferUtil.space(_inflated) >= chunk.remaining())
{
BufferUtil.append(_inflated, chunk);
release(chunk);
}
else
{
_inflateds.add(_inflated);
_inflated = chunk;
}
}
// Retain the chunk because it is stored for later use.
chunk.retain();
if (_inflated != null)
_inflateds.add(_inflated);
_inflated = chunk;
return false;
}
/**
* <p>Inflates compressed data.</p>
* <p>Inflation continues until the compressed block end is reached, there is no
* more compressed data or a call to {@link #decodedChunk(ByteBuffer)} returns true.</p>
* more compressed data or a call to {@link #decodedChunk(RetainableByteBuffer)} returns true.</p>
*
* @param compressed the buffer of compressed data to inflate
*/
protected void decodeChunks(ByteBuffer compressed)
{
ByteBuffer buffer = null;
RetainableByteBuffer buffer = null;
try
{
while (true)
@ -211,9 +199,10 @@ public class GZIPContentDecoder implements Destroyable
try
{
int pos = BufferUtil.flipToFill(buffer);
_inflater.inflate(buffer);
BufferUtil.flipToFlush(buffer, pos);
ByteBuffer decoded = buffer.getByteBuffer();
int pos = BufferUtil.flipToFill(decoded);
_inflater.inflate(decoded);
BufferUtil.flipToFlush(decoded, pos);
}
catch (DataFormatException x)
{
@ -222,9 +211,10 @@ public class GZIPContentDecoder implements Destroyable
if (buffer.hasRemaining())
{
ByteBuffer decoded = buffer;
boolean stop = decodedChunk(buffer);
buffer.release();
buffer = null;
if (decodedChunk(decoded))
if (stop)
return;
}
else if (_inflater.needsInput())
@ -395,7 +385,7 @@ public class GZIPContentDecoder implements Destroyable
finally
{
if (buffer != null)
release(buffer);
buffer.release();
}
}
@ -430,23 +420,8 @@ public class GZIPContentDecoder implements Destroyable
* @param capacity capacity of the ByteBuffer to acquire
* @return a heap buffer of the configured capacity either from the pool or freshly allocated.
*/
public ByteBuffer acquire(int capacity)
public RetainableByteBuffer acquire(int capacity)
{
return _pool == null ? BufferUtil.allocate(capacity) : _pool.acquire(capacity, false);
}
/**
* <p>Releases an allocated buffer.</p>
* <p>This method calls {@link ByteBufferPool#release(ByteBuffer)} if a buffer pool has
* been configured.</p>
* <p>This method should be called once for all buffers returned from {@link #decode(ByteBuffer)}
* or passed to {@link #decodedChunk(ByteBuffer)}.</p>
*
* @param buffer the buffer to release.
*/
public void release(ByteBuffer buffer)
{
if (_pool != null && !BufferUtil.isTheEmptyBuffer(buffer))
_pool.release(buffer);
return _pool.acquire(capacity, false);
}
}

View File

@ -30,9 +30,9 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.NoopByteBufferPool;
import org.eclipse.jetty.io.Retainable;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.NanoTime;
import org.eclipse.jetty.util.StringUtil;
@ -69,16 +69,16 @@ public class CachingHttpContentFactory implements HttpContent.Factory
private final HttpContent.Factory _authority;
private final ConcurrentHashMap<String, CachingHttpContent> _cache = new ConcurrentHashMap<>();
private final AtomicLong _cachedSize = new AtomicLong();
private final ByteBufferPool _byteBufferPool;
private final RetainableByteBufferPool _bufferPool;
private int _maxCachedFileSize = DEFAULT_MAX_CACHED_FILE_SIZE;
private int _maxCachedFiles = DEFAULT_MAX_CACHED_FILES;
private long _maxCacheSize = DEFAULT_MAX_CACHE_SIZE;
private boolean _useDirectByteBuffers = true;
public CachingHttpContentFactory(HttpContent.Factory authority, ByteBufferPool byteBufferPool)
public CachingHttpContentFactory(HttpContent.Factory authority, RetainableByteBufferPool bufferPool)
{
_authority = authority;
_byteBufferPool = (byteBufferPool == null) ? new NoopByteBufferPool() : byteBufferPool;
_bufferPool = bufferPool != null ? bufferPool : new RetainableByteBufferPool.NonPooling();
}
protected ConcurrentMap<String, CachingHttpContent> getCache()
@ -294,7 +294,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
protected class CachedHttpContent extends HttpContent.Wrapper implements CachingHttpContent
{
private final ByteBuffer _buffer;
private final RetainableByteBuffer _buffer;
private final String _cacheKey;
private final HttpField _etagField;
private final long _contentLengthValue;
@ -327,21 +327,23 @@ public class CachingHttpContentFactory implements HttpContent.Factory
boolean isValid = true;
// Read the content into memory if the HttpContent does not already have a buffer.
RetainableByteBuffer buffer;
ByteBuffer byteBuffer = httpContent.getByteBuffer();
if (byteBuffer == null)
{
buffer = _bufferPool.acquire((int)_contentLengthValue, _useDirectByteBuffers);
try
{
if (_contentLengthValue <= _maxCachedFileSize)
{
byteBuffer = _byteBufferPool.acquire((int)_contentLengthValue, _useDirectByteBuffers);
try (ReadableByteChannel readableByteChannel = httpContent.getResource().newReadableByteChannel())
{
byteBuffer = buffer.getByteBuffer();
int read = BufferUtil.readFrom(readableByteChannel, byteBuffer);
if (read != _contentLengthValue)
{
_byteBufferPool.release(byteBuffer);
byteBuffer = null;
buffer.release();
buffer = null;
isValid = false;
}
}
@ -349,17 +351,19 @@ public class CachingHttpContentFactory implements HttpContent.Factory
}
catch (Throwable t)
{
if (buffer != null)
buffer.release();
buffer = null;
isValid = false;
if (byteBuffer != null)
{
_byteBufferPool.release(byteBuffer);
byteBuffer = null;
}
LOG.warn("Failed to read Resource", t);
}
}
else
{
buffer = RetainableByteBuffer.wrap(byteBuffer);
}
_buffer = byteBuffer;
_buffer = buffer;
_isValid = isValid;
_bytesOccupied = httpContent.getBytesOccupied();
_lastModifiedValue = httpContent.getLastModifiedValue();
@ -381,7 +385,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
@Override
public ByteBuffer getByteBuffer()
{
return _buffer == null ? null : _buffer.asReadOnlyBuffer();
return _buffer == null ? null : _buffer.getByteBuffer().asReadOnlyBuffer();
}
@Override
@ -420,7 +424,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory
if (_referenceCount.release())
{
if (_buffer != null)
_byteBufferPool.release(_buffer);
_buffer.release();
super.release();
}
}

View File

@ -19,7 +19,7 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.NanoTime;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.thread.Scheduler;
@ -55,13 +55,13 @@ public class ValidatingCachingHttpContentFactory extends CachingHttpContentFacto
*
* @param authority the wrapped {@link HttpContent.Factory} to use.
* @param validationPeriod time between filesystem checks in ms to see if an {@link HttpContent} is still valid (-1 never validate, 0 always validate).
* @param byteBufferPool the {@link org.eclipse.jetty.io.ByteBufferPool} to use.
* @param bufferPool the {@link org.eclipse.jetty.io.RetainableByteBufferPool} to use.
*/
public ValidatingCachingHttpContentFactory(@Name("authority") HttpContent.Factory authority,
@Name("validationPeriod") long validationPeriod,
@Name("byteBufferPool") ByteBufferPool byteBufferPool)
@Name("bufferPool") RetainableByteBufferPool bufferPool)
{
this(authority, validationPeriod, byteBufferPool, null, -1, -1);
this(authority, validationPeriod, bufferPool, null, -1, -1);
}
/**
@ -70,19 +70,19 @@ public class ValidatingCachingHttpContentFactory extends CachingHttpContentFacto
*
* @param authority the wrapped {@link HttpContent.Factory} to use.
* @param validationPeriod time between filesystem checks in ms to see if an {@link HttpContent} is still valid (-1 never validate, 0 always validate).
* @param byteBufferPool the {@link org.eclipse.jetty.io.ByteBufferPool} to use.
* @param bufferPool the {@link org.eclipse.jetty.io.RetainableByteBufferPool} to use.
* @param scheduler scheduler to use for the sweeper, can be null to not use sweeper.
* @param sweepPeriod time between runs of the sweeper in ms (if 0 never sweep for invalid entries).
* @param idleTimeout amount of time in ms an entry can be unused before evicted by the sweeper (if 0 never evict unused entries).
*/
public ValidatingCachingHttpContentFactory(@Name("authority") HttpContent.Factory authority,
@Name("validationPeriod") long validationPeriod,
@Name("byteBufferPool") ByteBufferPool byteBufferPool,
@Name("byteBufferPool") RetainableByteBufferPool bufferPool,
@Name("scheduler") Scheduler scheduler,
@Name("sweepPeriod") long sweepPeriod,
@Name("idleTimeout") long idleTimeout)
{
super(authority, byteBufferPool);
super(authority, bufferPool);
_validationTime = validationPeriod;
_scheduler = scheduler;
_sweepDelay = sweepPeriod;

View File

@ -23,7 +23,9 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.eclipse.jetty.io.ArrayByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -39,28 +41,29 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class GZIPContentDecoderTest
{
private ArrayByteBufferPool pool;
private AtomicInteger buffers = new AtomicInteger(0);
private final AtomicInteger counter = new AtomicInteger();
private RetainableByteBufferPool pool;
@BeforeEach
public void before()
{
buffers.set(0);
pool = new ArrayByteBufferPool()
pool = new RetainableByteBufferPool.Wrapper(new ArrayRetainableByteBufferPool())
{
@Override
public ByteBuffer acquire(int size, boolean direct)
public RetainableByteBuffer acquire(int size, boolean direct)
{
buffers.incrementAndGet();
return super.acquire(size, direct);
}
@Override
public void release(ByteBuffer buffer)
{
buffers.decrementAndGet();
super.release(buffer);
counter.incrementAndGet();
return new RetainableByteBuffer.Wrapper(super.acquire(size, direct))
{
@Override
public boolean release()
{
boolean released = super.release();
if (released)
counter.decrementAndGet();
return released;
}
};
}
};
}
@ -68,7 +71,7 @@ public class GZIPContentDecoderTest
@AfterEach
public void after()
{
assertEquals(0, buffers.get());
assertThat(counter.get(), is(0));
}
@Test
@ -126,8 +129,9 @@ public class GZIPContentDecoderTest
byte[] bytes = baos.toByteArray();
GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
RetainableByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
assertEquals(0, decoded.remaining());
decoded.release();
}
@Test
@ -142,9 +146,9 @@ public class GZIPContentDecoderTest
byte[] bytes = baos.toByteArray();
GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
decoder.release(decoded);
RetainableByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded.getByteBuffer()).toString());
decoded.release();
}
@Test
@ -165,11 +169,12 @@ public class GZIPContentDecoderTest
System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(0, decoded.capacity());
RetainableByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(0, decoded.remaining());
decoded.release();
decoded = decoder.decode(ByteBuffer.wrap(bytes2));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
decoder.release(decoded);
assertEquals(data, StandardCharsets.UTF_8.decode(decoded.getByteBuffer()).toString());
decoded.release();
}
@Test
@ -190,14 +195,14 @@ public class GZIPContentDecoderTest
System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
RetainableByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded.getByteBuffer()).toString());
assertFalse(decoder.isFinished());
decoder.release(decoded);
decoded.release();
decoded = decoder.decode(ByteBuffer.wrap(bytes2));
assertEquals(0, decoded.remaining());
assertTrue(decoder.isFinished());
decoder.release(decoded);
decoded.release();
}
@Test
@ -218,12 +223,12 @@ public class GZIPContentDecoderTest
System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(0, decoded.capacity());
decoder.release(decoded);
RetainableByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(0, decoded.remaining());
decoded.release();
decoded = decoder.decode(ByteBuffer.wrap(bytes2));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
decoder.release(decoded);
assertEquals(data, StandardCharsets.UTF_8.decode(decoded.getByteBuffer()).toString());
decoded.release();
}
@Test
@ -249,16 +254,16 @@ public class GZIPContentDecoderTest
GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
ByteBuffer decoded = decoder.decode(buffer);
assertEquals(data1, StandardCharsets.UTF_8.decode(decoded).toString());
RetainableByteBuffer decoded = decoder.decode(buffer);
assertEquals(data1, StandardCharsets.UTF_8.decode(decoded.getByteBuffer()).toString());
assertTrue(decoder.isFinished());
assertTrue(buffer.hasRemaining());
decoder.release(decoded);
decoded.release();
decoded = decoder.decode(buffer);
assertEquals(data2, StandardCharsets.UTF_8.decode(decoded).toString());
assertEquals(data2, StandardCharsets.UTF_8.decode(decoded.getByteBuffer()).toString());
assertTrue(decoder.isFinished());
assertFalse(buffer.hasRemaining());
decoder.release(decoded);
decoded.release();
}
@Test
@ -280,9 +285,9 @@ public class GZIPContentDecoderTest
ByteBuffer buffer = ByteBuffer.wrap(bytes);
while (buffer.hasRemaining())
{
ByteBuffer decoded = decoder.decode(buffer);
result += StandardCharsets.UTF_8.decode(decoded).toString();
decoder.release(decoded);
RetainableByteBuffer decoded = decoder.decode(buffer);
result += StandardCharsets.UTF_8.decode(decoded.getByteBuffer()).toString();
decoded.release();
}
assertEquals(data, result);
}
@ -306,10 +311,10 @@ public class GZIPContentDecoderTest
ByteBuffer buffer = ByteBuffer.wrap(bytes);
while (buffer.hasRemaining())
{
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(new byte[]{buffer.get()}));
RetainableByteBuffer decoded = decoder.decode(ByteBuffer.wrap(new byte[]{buffer.get()}));
if (decoded.hasRemaining())
result += StandardCharsets.UTF_8.decode(decoded).toString();
decoder.release(decoded);
result += StandardCharsets.UTF_8.decode(decoded.getByteBuffer()).toString();
decoded.release();
}
assertEquals(data, result);
assertTrue(decoder.isFinished());
@ -341,10 +346,10 @@ public class GZIPContentDecoderTest
ByteBuffer buffer = ByteBuffer.wrap(bytes);
while (buffer.hasRemaining())
{
ByteBuffer decoded = decoder.decode(buffer);
RetainableByteBuffer decoded = decoder.decode(buffer);
if (decoded.hasRemaining())
result += StandardCharsets.UTF_8.decode(decoded).toString();
decoder.release(decoded);
result += StandardCharsets.UTF_8.decode(decoded.getByteBuffer()).toString();
decoded.release();
if (decoder.isFinished())
break;
}
@ -414,12 +419,12 @@ public class GZIPContentDecoderTest
ByteBuffer buf = ByteBuffer.wrap(b, off, len);
while (buf.hasRemaining())
{
ByteBuffer decoded = decoder.decode(buf);
RetainableByteBuffer decoded = decoder.decode(buf);
if (decoded.hasRemaining())
{
decodedByteCount += decoded.remaining();
}
decoder.release(decoded);
decoded.release();
}
}

View File

@ -90,7 +90,7 @@ public class HttpClientTransportOverHTTP2 extends AbstractHttpClientTransport
HttpClient httpClient = getHttpClient();
client.setExecutor(httpClient.getExecutor());
client.setScheduler(httpClient.getScheduler());
client.setByteBufferPool(httpClient.getByteBufferPool());
client.setRetainableByteBufferPool(httpClient.getRetainableByteBufferPool());
client.setConnectTimeout(httpClient.getConnectTimeout());
client.setIdleTimeout(httpClient.getIdleTimeout());
client.setInputBufferSize(httpClient.getResponseBufferSize());

View File

@ -76,7 +76,7 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements HTTP2Channel.
DataFrame frame = data.frame();
boolean last = frame.remaining() == 0 && frame.isEndStream();
if (!last)
return Content.Chunk.asChunk(frame.getData(), last, data);
return Content.Chunk.asChunk(frame.getByteBuffer(), last, data);
data.release();
responseSuccess(getHttpExchange(), null);
return Content.Chunk.EOF;

View File

@ -28,9 +28,9 @@ import org.eclipse.jetty.http2.FlowControlStrategy;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
@ -153,14 +153,14 @@ public class HTTP2Client extends ContainerLifeCycle
connector.setScheduler(scheduler);
}
public ByteBufferPool getByteBufferPool()
public RetainableByteBufferPool getRetainableByteBufferPool()
{
return connector.getByteBufferPool();
return connector.getRetainableByteBufferPool();
}
public void setByteBufferPool(ByteBufferPool bufferPool)
public void setRetainableByteBufferPool(RetainableByteBufferPool bufferPool)
{
connector.setByteBufferPool(bufferPool);
connector.setRetainableByteBufferPool(bufferPool);
}
public FlowControlStrategy.Factory getFlowControlStrategyFactory()
@ -435,7 +435,7 @@ public class HTTP2Client extends ContainerLifeCycle
{
if (isUseALPN())
factory = new ALPNClientConnectionFactory(getExecutor(), factory, getProtocols());
factory = new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), factory);
factory = new SslClientConnectionFactory(sslContextFactory, getRetainableByteBufferPool(), getExecutor(), factory);
}
return factory;
}

View File

@ -28,7 +28,6 @@ import org.eclipse.jetty.http2.internal.HTTP2Connection;
import org.eclipse.jetty.http2.internal.HTTP2Session;
import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
@ -49,14 +48,14 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
public Connection newConnection(EndPoint endPoint, Map<String, Object> context)
{
HTTP2Client client = (HTTP2Client)context.get(CLIENT_CONTEXT_KEY);
ByteBufferPool byteBufferPool = client.getByteBufferPool();
RetainableByteBufferPool bufferPool = client.getRetainableByteBufferPool();
Executor executor = client.getExecutor();
Scheduler scheduler = client.getScheduler();
Session.Listener listener = (Session.Listener)context.get(SESSION_LISTENER_CONTEXT_KEY);
@SuppressWarnings("unchecked")
Promise<Session> promise = (Promise<Session>)context.get(SESSION_PROMISE_CONTEXT_KEY);
Generator generator = new Generator(byteBufferPool, client.getMaxDynamicTableSize(), client.getMaxHeaderBlockFragment());
Generator generator = new Generator(bufferPool, client.getMaxDynamicTableSize(), client.getMaxHeaderBlockFragment());
FlowControlStrategy flowControl = client.getFlowControlStrategyFactory().newFlowControlStrategy();
HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
session.setMaxRemoteStreams(client.getMaxConcurrentPushedStreams());
@ -64,13 +63,11 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
if (streamIdleTimeout > 0)
session.setStreamIdleTimeout(streamIdleTimeout);
Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
Parser parser = new Parser(bufferPool, session, 4096, 8192);
parser.setMaxFrameLength(client.getMaxFrameLength());
parser.setMaxSettingsKeys(client.getMaxSettingsKeys());
RetainableByteBufferPool retainableByteBufferPool = byteBufferPool.asRetainableByteBufferPool();
HTTP2ClientConnection connection = new HTTP2ClientConnection(client, retainableByteBufferPool, executor, endPoint,
HTTP2ClientConnection connection = new HTTP2ClientConnection(client, bufferPool, executor, endPoint,
parser, session, client.getInputBufferSize(), promise, listener);
connection.setUseInputDirectByteBuffers(client.isUseInputDirectByteBuffers());
connection.setUseOutputDirectByteBuffers(client.isUseOutputDirectByteBuffers());

View File

@ -313,10 +313,10 @@ public interface Stream
* <p>It is always guaranteed that invoking {@link Stream#demand()}
* from within this method will not cause a {@link StackOverflowError}.</p>
* <p>Typical usage:</p>
* <pre>
* <pre>{@code
* class MyStreamListener implements Stream.Listener
* {
* &#64;Override
* @Override
* public void onDataAvailable(Stream stream)
* {
* // Read a chunk of the content.
@ -329,7 +329,7 @@ public interface Stream
* else
* {
* // Process the content.
* process(data.getByteBuffer());
* process(data.frame().getByteBuffer());
* // Notify that the content has been consumed.
* data.release();
* if (!data.frame().isEndStream())
@ -340,7 +340,7 @@ public interface Stream
* }
* }
* }
* </pre>
* }</pre>
*
* @param stream the stream
* @see Stream#demand()

View File

@ -39,7 +39,7 @@ public class DataFrame extends StreamFrame
this.padding = padding;
}
public ByteBuffer getData()
public ByteBuffer getByteBuffer()
{
return data;
}
@ -68,12 +68,12 @@ public class DataFrame extends StreamFrame
@Override
public DataFrame withStreamId(int streamId)
{
return new DataFrame(streamId, getData(), isEndStream());
return new DataFrame(streamId, getByteBuffer(), isEndStream());
}
@Override
public String toString()
{
return String.format("%s#%d{length:%d,end=%b}", super.toString(), getStreamId(), data.remaining(), endStream);
return String.format("%s#%d{length:%d,end=%b}", super.toString(), getStreamId(), remaining(), isEndStream());
}
}

View File

@ -455,7 +455,7 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
public ByteBuffer getBuffer()
{
return delegate.getBuffer();
return delegate.getByteBuffer();
}
public boolean isRetained()
@ -494,7 +494,7 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
private void put(ByteBuffer source)
{
BufferUtil.append(delegate.getBuffer(), source);
BufferUtil.append(delegate.getByteBuffer(), source);
}
}
}

View File

@ -30,8 +30,8 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
import org.eclipse.jetty.http2.hpack.HpackException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.component.Dumpable;
@ -51,7 +51,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
private final Queue<Entry> pendingEntries = new ArrayDeque<>();
private final Collection<Entry> processedEntries = new ArrayList<>();
private final HTTP2Session session;
private final ByteBufferPool.Lease lease;
private final RetainableByteBufferPool.Accumulator accumulator;
private InvocationType invocationType = InvocationType.NON_BLOCKING;
private Throwable terminated;
private Entry stalledEntry;
@ -59,7 +59,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
public HTTP2Flusher(HTTP2Session session)
{
this.session = session;
this.lease = new ByteBufferPool.Lease(session.getGenerator().getByteBufferPool());
this.accumulator = new RetainableByteBufferPool.Accumulator();
}
@Override
@ -213,7 +213,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
try
{
if (entry.generate(lease))
if (entry.generate(accumulator))
{
if (LOG.isDebugEnabled())
LOG.debug("Generated {} frame bytes for {}", entry.getFrameBytesGenerated(), entry);
@ -266,7 +266,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
break;
int writeThreshold = session.getWriteThreshold();
if (lease.getTotalLength() >= writeThreshold)
if (accumulator.getTotalLength() >= writeThreshold)
{
if (LOG.isDebugEnabled())
LOG.debug("Write threshold {} exceeded", writeThreshold);
@ -274,7 +274,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
}
}
List<ByteBuffer> byteBuffers = lease.getByteBuffers();
List<ByteBuffer> byteBuffers = accumulator.getByteBuffers();
if (byteBuffers.isEmpty())
{
finish();
@ -284,7 +284,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
if (LOG.isDebugEnabled())
LOG.debug("Writing {} buffers ({} bytes) - entries processed/pending {}/{}: {}/{}",
byteBuffers.size(),
lease.getTotalLength(),
accumulator.getTotalLength(),
processedEntries.size(),
pendingEntries.size(),
processedEntries,
@ -308,7 +308,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
{
if (LOG.isDebugEnabled())
LOG.debug("Written {} buffers - entries processed/pending {}/{}: {}/{}",
lease.getByteBuffers().size(),
accumulator.getByteBuffers().size(),
processedEntries.size(),
pendingEntries.size(),
processedEntries,
@ -319,7 +319,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
private void finish()
{
lease.recycle();
accumulator.release();
processedEntries.forEach(Entry::succeeded);
processedEntries.clear();
@ -349,7 +349,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
@Override
protected void onCompleteFailure(Throwable x)
{
lease.recycle();
accumulator.release();
Throwable closed;
Set<Entry> allEntries;
@ -440,7 +440,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
return 0;
}
protected abstract boolean generate(ByteBufferPool.Lease lease) throws HpackException;
protected abstract boolean generate(RetainableByteBufferPool.Accumulator accumulator) throws HpackException;
public abstract long onFlushed(long bytes) throws IOException;

View File

@ -57,9 +57,9 @@ import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
import org.eclipse.jetty.http2.hpack.HpackException;
import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.CyclicTimeouts;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.WriteFlusher;
import org.eclipse.jetty.util.AtomicBiInteger;
import org.eclipse.jetty.util.Atomics;
@ -1206,9 +1206,9 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session
}
@Override
protected boolean generate(ByteBufferPool.Lease lease) throws HpackException
protected boolean generate(RetainableByteBufferPool.Accumulator accumulator) throws HpackException
{
frameBytes = generator.control(lease, frame);
frameBytes = generator.control(accumulator, frame);
beforeSend();
return true;
}
@ -1320,7 +1320,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session
}
@Override
protected boolean generate(ByteBufferPool.Lease lease)
protected boolean generate(RetainableByteBufferPool.Accumulator accumulator)
{
int dataRemaining = getDataBytesRemaining();
@ -1334,7 +1334,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session
// Only one DATA frame is generated.
DataFrame dataFrame = (DataFrame)frame;
int frameBytes = generator.data(lease, dataFrame, length);
int frameBytes = generator.data(accumulator, dataFrame, length);
this.frameBytes += frameBytes;
this.frameRemaining += frameBytes;

View File

@ -215,7 +215,7 @@ public abstract class HTTP2StreamEndPoint implements EndPoint
private int fillFromData(Stream.Data data, ByteBuffer sink)
{
int length = 0;
ByteBuffer source = data.frame().getData();
ByteBuffer source = data.frame().getByteBuffer();
boolean hasContent = source.hasRemaining();
if (hasContent)
{

View File

@ -19,7 +19,8 @@ import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class DataGenerator
@ -31,12 +32,12 @@ public class DataGenerator
this.headerGenerator = headerGenerator;
}
public int generate(ByteBufferPool.Lease lease, DataFrame frame, int maxLength)
public int generate(RetainableByteBufferPool.Accumulator accumulator, DataFrame frame, int maxLength)
{
return generateData(lease, frame.getStreamId(), frame.getData(), frame.isEndStream(), maxLength);
return generateData(accumulator, frame.getStreamId(), frame.getByteBuffer(), frame.isEndStream(), maxLength);
}
public int generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, int maxLength)
public int generateData(RetainableByteBufferPool.Accumulator accumulator, int streamId, ByteBuffer data, boolean last, int maxLength)
{
if (streamId < 0)
throw new IllegalArgumentException("Invalid stream id: " + streamId);
@ -46,7 +47,7 @@ public class DataGenerator
int length = Math.min(dataLength, Math.min(maxFrameSize, maxLength));
if (length == dataLength)
{
generateFrame(lease, streamId, data, last);
generateFrame(accumulator, streamId, data, last);
}
else
{
@ -56,12 +57,12 @@ public class DataGenerator
ByteBuffer slice = data.slice();
data.position(newLimit);
data.limit(limit);
generateFrame(lease, streamId, slice, false);
generateFrame(accumulator, streamId, slice, false);
}
return Frame.HEADER_LENGTH + length;
}
private void generateFrame(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last)
private void generateFrame(RetainableByteBufferPool.Accumulator accumulator, int streamId, ByteBuffer data, boolean last)
{
int length = data.remaining();
@ -69,11 +70,11 @@ public class DataGenerator
if (last)
flags |= Flags.END_STREAM;
ByteBuffer header = headerGenerator.generate(lease, FrameType.DATA, Frame.HEADER_LENGTH + length, length, flags, streamId);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
RetainableByteBuffer header = headerGenerator.generate(FrameType.DATA, Frame.HEADER_LENGTH + length, length, flags, streamId);
BufferUtil.flipToFlush(header.getByteBuffer(), 0);
accumulator.append(header);
// Skip empty data buffers.
if (data.remaining() > 0)
lease.append(data, false);
accumulator.append(RetainableByteBuffer.wrap(data));
}
}

View File

@ -20,7 +20,9 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.hpack.HpackEncoder;
import org.eclipse.jetty.http2.hpack.HpackException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public abstract class FrameGenerator
{
@ -31,11 +33,11 @@ public abstract class FrameGenerator
this.headerGenerator = headerGenerator;
}
public abstract int generate(ByteBufferPool.Lease lease, Frame frame) throws HpackException;
public abstract int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame) throws HpackException;
protected ByteBuffer generateHeader(ByteBufferPool.Lease lease, FrameType frameType, int length, int flags, int streamId)
protected RetainableByteBuffer generateHeader(FrameType frameType, int length, int flags, int streamId)
{
return headerGenerator.generate(lease, frameType, Frame.HEADER_LENGTH + length, length, flags, streamId);
return headerGenerator.generate(frameType, Frame.HEADER_LENGTH + length, length, flags, streamId);
}
public int getMaxFrameSize()
@ -48,17 +50,19 @@ public abstract class FrameGenerator
return headerGenerator.isUseDirectByteBuffers();
}
protected ByteBuffer encode(HpackEncoder encoder, ByteBufferPool.Lease lease, MetaData metaData, int maxFrameSize) throws HpackException
protected RetainableByteBuffer encode(HpackEncoder encoder, MetaData metaData, int maxFrameSize) throws HpackException
{
ByteBuffer hpacked = lease.acquire(maxFrameSize, isUseDirectByteBuffers());
RetainableByteBuffer hpacked = headerGenerator.getRetainableByteBufferPool().acquire(maxFrameSize, isUseDirectByteBuffers());
try
{
encoder.encode(hpacked, metaData);
ByteBuffer byteBuffer = hpacked.getByteBuffer();
BufferUtil.clearToFill(byteBuffer);
encoder.encode(byteBuffer, metaData);
return hpacked;
}
catch (HpackException x)
{
lease.release(hpacked);
hpacked.release();
throw x;
}
}

View File

@ -18,31 +18,31 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.hpack.HpackEncoder;
import org.eclipse.jetty.http2.hpack.HpackException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
public class Generator
{
private final ByteBufferPool byteBufferPool;
private final RetainableByteBufferPool bufferPool;
private final HeaderGenerator headerGenerator;
private final HpackEncoder hpackEncoder;
private final FrameGenerator[] generators;
private final DataGenerator dataGenerator;
public Generator(ByteBufferPool byteBufferPool)
public Generator(RetainableByteBufferPool bufferPool)
{
this(byteBufferPool, 4096, 0);
this(bufferPool, 4096, 0);
}
public Generator(ByteBufferPool byteBufferPool, int maxDynamicTableSize, int maxHeaderBlockFragment)
public Generator(RetainableByteBufferPool bufferPool, int maxDynamicTableSize, int maxHeaderBlockFragment)
{
this(byteBufferPool, true, maxDynamicTableSize, maxHeaderBlockFragment);
this(bufferPool, true, maxDynamicTableSize, maxHeaderBlockFragment);
}
public Generator(ByteBufferPool byteBufferPool, boolean useDirectByteBuffers, int maxDynamicTableSize, int maxHeaderBlockFragment)
public Generator(RetainableByteBufferPool bufferPool, boolean useDirectByteBuffers, int maxDynamicTableSize, int maxHeaderBlockFragment)
{
this.byteBufferPool = byteBufferPool;
this.bufferPool = bufferPool;
headerGenerator = new HeaderGenerator(useDirectByteBuffers);
headerGenerator = new HeaderGenerator(bufferPool, useDirectByteBuffers);
hpackEncoder = new HpackEncoder(maxDynamicTableSize);
this.generators = new FrameGenerator[FrameType.values().length];
@ -61,9 +61,9 @@ public class Generator
this.dataGenerator = new DataGenerator(headerGenerator);
}
public ByteBufferPool getByteBufferPool()
public RetainableByteBufferPool getRetainableByteBufferPool()
{
return byteBufferPool;
return bufferPool;
}
public void setValidateHpackEncoding(boolean validateEncoding)
@ -81,14 +81,14 @@ public class Generator
headerGenerator.setMaxFrameSize(maxFrameSize);
}
public int control(ByteBufferPool.Lease lease, Frame frame) throws HpackException
public int control(RetainableByteBufferPool.Accumulator accumulator, Frame frame) throws HpackException
{
return generators[frame.getType().getType()].generate(lease, frame);
return generators[frame.getType().getType()].generate(accumulator, frame);
}
public int data(ByteBufferPool.Lease lease, DataFrame frame, int maxLength)
public int data(RetainableByteBufferPool.Accumulator accumulator, DataFrame frame, int maxLength)
{
return dataGenerator.generate(lease, frame, maxLength);
return dataGenerator.generate(accumulator, frame, maxLength);
}
public void setMaxHeaderListSize(int value)

View File

@ -20,7 +20,8 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.frames.GoAwayFrame;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class GoAwayGenerator extends FrameGenerator
@ -31,13 +32,13 @@ public class GoAwayGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame)
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame)
{
GoAwayFrame goAwayFrame = (GoAwayFrame)frame;
return generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), goAwayFrame.getPayload());
return generateGoAway(accumulator, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), goAwayFrame.getPayload());
}
public int generateGoAway(ByteBufferPool.Lease lease, int lastStreamId, int error, byte[] payload)
public int generateGoAway(RetainableByteBufferPool.Accumulator accumulator, int lastStreamId, int error, byte[] payload)
{
if (lastStreamId < 0)
lastStreamId = 0;
@ -51,16 +52,17 @@ public class GoAwayGenerator extends FrameGenerator
payload = Arrays.copyOfRange(payload, 0, maxPayloadLength);
int length = fixedLength + (payload != null ? payload.length : 0);
ByteBuffer header = generateHeader(lease, FrameType.GO_AWAY, length, Flags.NONE, 0);
RetainableByteBuffer header = generateHeader(FrameType.GO_AWAY, length, Flags.NONE, 0);
ByteBuffer byteBuffer = header.getByteBuffer();
header.putInt(lastStreamId);
header.putInt(error);
byteBuffer.putInt(lastStreamId);
byteBuffer.putInt(error);
if (payload != null)
header.put(payload);
byteBuffer.put(payload);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
BufferUtil.flipToFlush(byteBuffer, 0);
accumulator.append(header);
return Frame.HEADER_LENGTH + length;
}

View File

@ -17,38 +17,49 @@ import java.nio.ByteBuffer;
import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class HeaderGenerator
{
private int maxFrameSize = Frame.DEFAULT_MAX_LENGTH;
private final RetainableByteBufferPool bufferPool;
private final boolean useDirectByteBuffers;
public HeaderGenerator()
public HeaderGenerator(RetainableByteBufferPool bufferPool)
{
this(true);
this(bufferPool, true);
}
public HeaderGenerator(boolean useDirectByteBuffers)
public HeaderGenerator(RetainableByteBufferPool bufferPool, boolean useDirectByteBuffers)
{
this.bufferPool = bufferPool;
this.useDirectByteBuffers = useDirectByteBuffers;
}
public RetainableByteBufferPool getRetainableByteBufferPool()
{
return bufferPool;
}
public boolean isUseDirectByteBuffers()
{
return useDirectByteBuffers;
}
public ByteBuffer generate(ByteBufferPool.Lease lease, FrameType frameType, int capacity, int length, int flags, int streamId)
public RetainableByteBuffer generate(FrameType frameType, int capacity, int length, int flags, int streamId)
{
ByteBuffer header = lease.acquire(capacity, isUseDirectByteBuffers());
RetainableByteBuffer buffer = getRetainableByteBufferPool().acquire(capacity, isUseDirectByteBuffers());
ByteBuffer header = buffer.getByteBuffer();
BufferUtil.clearToFill(header);
header.put((byte)((length & 0x00_FF_00_00) >>> 16));
header.put((byte)((length & 0x00_00_FF_00) >>> 8));
header.put((byte)((length & 0x00_00_00_FF)));
header.put((byte)frameType.getType());
header.put((byte)flags);
header.putInt(streamId);
return header;
return buffer;
}
public int getMaxFrameSize()

View File

@ -23,7 +23,8 @@ import org.eclipse.jetty.http2.frames.PriorityFrame;
import org.eclipse.jetty.http2.hpack.HpackEncoder;
import org.eclipse.jetty.http2.hpack.HpackException;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class HeadersGenerator extends FrameGenerator
@ -46,13 +47,13 @@ public class HeadersGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame) throws HpackException
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame) throws HpackException
{
HeadersFrame headersFrame = (HeadersFrame)frame;
return generateHeaders(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), headersFrame.getPriority(), headersFrame.isEndStream());
return generateHeaders(accumulator, headersFrame.getStreamId(), headersFrame.getMetaData(), headersFrame.getPriority(), headersFrame.isEndStream());
}
public int generateHeaders(ByteBufferPool.Lease lease, int streamId, MetaData metaData, PriorityFrame priority, boolean endStream) throws HpackException
public int generateHeaders(RetainableByteBufferPool.Accumulator accumulator, int streamId, MetaData metaData, PriorityFrame priority, boolean endStream) throws HpackException
{
if (streamId < 0)
throw new IllegalArgumentException("Invalid stream id: " + streamId);
@ -62,12 +63,13 @@ public class HeadersGenerator extends FrameGenerator
if (priority != null)
flags = Flags.PRIORITY;
ByteBuffer hpacked = encode(encoder, lease, metaData, getMaxFrameSize());
int hpackedLength = hpacked.position();
BufferUtil.flipToFlush(hpacked, 0);
RetainableByteBuffer hpack = encode(encoder, metaData, getMaxFrameSize());
ByteBuffer hpackByteBuffer = hpack.getByteBuffer();
int hpackLength = hpackByteBuffer.position();
BufferUtil.flipToFlush(hpackByteBuffer, 0);
// Split into CONTINUATION frames if necessary.
if (maxHeaderBlockFragment > 0 && hpackedLength > maxHeaderBlockFragment)
if (maxHeaderBlockFragment > 0 && hpackLength > maxHeaderBlockFragment)
{
if (endStream)
flags |= Flags.END_STREAM;
@ -76,35 +78,38 @@ public class HeadersGenerator extends FrameGenerator
if (priority != null)
length += PriorityFrame.PRIORITY_LENGTH;
ByteBuffer header = generateHeader(lease, FrameType.HEADERS, length, flags, streamId);
generatePriority(header, priority);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
hpacked.limit(maxHeaderBlockFragment);
lease.append(hpacked.slice(), false);
RetainableByteBuffer header = generateHeader(FrameType.HEADERS, length, flags, streamId);
ByteBuffer headerByteBuffer = header.getByteBuffer();
generatePriority(headerByteBuffer, priority);
BufferUtil.flipToFlush(headerByteBuffer, 0);
accumulator.append(header);
hpackByteBuffer.limit(maxHeaderBlockFragment);
accumulator.append(RetainableByteBuffer.wrap(hpackByteBuffer.slice()));
int totalLength = Frame.HEADER_LENGTH + length;
int position = maxHeaderBlockFragment;
int limit = position + maxHeaderBlockFragment;
while (limit < hpackedLength)
while (limit < hpackLength)
{
hpacked.position(position).limit(limit);
header = generateHeader(lease, FrameType.CONTINUATION, maxHeaderBlockFragment, Flags.NONE, streamId);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
lease.append(hpacked.slice(), false);
hpackByteBuffer.position(position).limit(limit);
header = generateHeader(FrameType.CONTINUATION, maxHeaderBlockFragment, Flags.NONE, streamId);
headerByteBuffer = header.getByteBuffer();
BufferUtil.flipToFlush(headerByteBuffer, 0);
accumulator.append(header);
accumulator.append(RetainableByteBuffer.wrap(hpackByteBuffer.slice()));
position += maxHeaderBlockFragment;
limit += maxHeaderBlockFragment;
totalLength += Frame.HEADER_LENGTH + maxHeaderBlockFragment;
}
hpacked.position(position).limit(hpackedLength);
header = generateHeader(lease, FrameType.CONTINUATION, hpacked.remaining(), Flags.END_HEADERS, streamId);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
lease.append(hpacked, true);
totalLength += Frame.HEADER_LENGTH + hpacked.remaining();
hpackByteBuffer.position(position).limit(hpackLength);
header = generateHeader(FrameType.CONTINUATION, hpack.remaining(), Flags.END_HEADERS, streamId);
headerByteBuffer = header.getByteBuffer();
BufferUtil.flipToFlush(headerByteBuffer, 0);
accumulator.append(header);
accumulator.append(hpack);
totalLength += Frame.HEADER_LENGTH + hpack.remaining();
return totalLength;
}
@ -114,15 +119,16 @@ public class HeadersGenerator extends FrameGenerator
if (endStream)
flags |= Flags.END_STREAM;
int length = hpackedLength;
int length = hpackLength;
if (priority != null)
length += PriorityFrame.PRIORITY_LENGTH;
ByteBuffer header = generateHeader(lease, FrameType.HEADERS, length, flags, streamId);
generatePriority(header, priority);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
lease.append(hpacked, true);
RetainableByteBuffer header = generateHeader(FrameType.HEADERS, length, flags, streamId);
ByteBuffer headerByteBuffer = header.getByteBuffer();
generatePriority(headerByteBuffer, priority);
BufferUtil.flipToFlush(headerByteBuffer, 0);
accumulator.append(header);
accumulator.append(hpack);
return Frame.HEADER_LENGTH + length;
}

View File

@ -14,7 +14,7 @@
package org.eclipse.jetty.http2.internal.generator;
import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
public class NoOpGenerator extends FrameGenerator
{
@ -24,7 +24,7 @@ public class NoOpGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame)
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame)
{
return 0;
}

View File

@ -19,7 +19,8 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.frames.PingFrame;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class PingGenerator extends FrameGenerator
@ -30,23 +31,24 @@ public class PingGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame)
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame)
{
PingFrame pingFrame = (PingFrame)frame;
return generatePing(lease, pingFrame.getPayload(), pingFrame.isReply());
return generatePing(accumulator, pingFrame.getPayload(), pingFrame.isReply());
}
public int generatePing(ByteBufferPool.Lease lease, byte[] payload, boolean reply)
public int generatePing(RetainableByteBufferPool.Accumulator accumulator, byte[] payload, boolean reply)
{
if (payload.length != PingFrame.PING_LENGTH)
throw new IllegalArgumentException("Invalid payload length: " + payload.length);
ByteBuffer header = generateHeader(lease, FrameType.PING, PingFrame.PING_LENGTH, reply ? Flags.ACK : Flags.NONE, 0);
RetainableByteBuffer header = generateHeader(FrameType.PING, PingFrame.PING_LENGTH, reply ? Flags.ACK : Flags.NONE, 0);
ByteBuffer byteBuffer = header.getByteBuffer();
header.put(payload);
byteBuffer.put(payload);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
BufferUtil.flipToFlush(byteBuffer, 0);
accumulator.append(header);
return Frame.HEADER_LENGTH + PingFrame.PING_LENGTH;
}

View File

@ -17,7 +17,8 @@ import java.nio.ByteBuffer;
import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.PrefaceFrame;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
public class PrefaceGenerator extends FrameGenerator
{
@ -27,9 +28,9 @@ public class PrefaceGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame)
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame)
{
lease.append(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false);
accumulator.append(RetainableByteBuffer.wrap(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES)));
return PrefaceFrame.PREFACE_BYTES.length;
}
}

View File

@ -19,7 +19,8 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.frames.PriorityFrame;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class PriorityGenerator extends FrameGenerator
@ -30,18 +31,19 @@ public class PriorityGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame)
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame)
{
PriorityFrame priorityFrame = (PriorityFrame)frame;
return generatePriority(lease, priorityFrame.getStreamId(), priorityFrame.getParentStreamId(), priorityFrame.getWeight(), priorityFrame.isExclusive());
return generatePriority(accumulator, priorityFrame.getStreamId(), priorityFrame.getParentStreamId(), priorityFrame.getWeight(), priorityFrame.isExclusive());
}
public int generatePriority(ByteBufferPool.Lease lease, int streamId, int parentStreamId, int weight, boolean exclusive)
public int generatePriority(RetainableByteBufferPool.Accumulator accumulator, int streamId, int parentStreamId, int weight, boolean exclusive)
{
ByteBuffer header = generateHeader(lease, FrameType.PRIORITY, PriorityFrame.PRIORITY_LENGTH, Flags.NONE, streamId);
generatePriorityBody(header, streamId, parentStreamId, weight, exclusive);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
RetainableByteBuffer header = generateHeader(FrameType.PRIORITY, PriorityFrame.PRIORITY_LENGTH, Flags.NONE, streamId);
ByteBuffer byteBuffer = header.getByteBuffer();
generatePriorityBody(byteBuffer, streamId, parentStreamId, weight, exclusive);
BufferUtil.flipToFlush(byteBuffer, 0);
accumulator.append(header);
return Frame.HEADER_LENGTH + PriorityFrame.PRIORITY_LENGTH;
}

View File

@ -22,7 +22,8 @@ import org.eclipse.jetty.http2.frames.PushPromiseFrame;
import org.eclipse.jetty.http2.hpack.HpackEncoder;
import org.eclipse.jetty.http2.hpack.HpackException;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class PushPromiseGenerator extends FrameGenerator
@ -36,13 +37,13 @@ public class PushPromiseGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame) throws HpackException
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame) throws HpackException
{
PushPromiseFrame pushPromiseFrame = (PushPromiseFrame)frame;
return generatePushPromise(lease, pushPromiseFrame.getStreamId(), pushPromiseFrame.getPromisedStreamId(), pushPromiseFrame.getMetaData());
return generatePushPromise(accumulator, pushPromiseFrame.getStreamId(), pushPromiseFrame.getPromisedStreamId(), pushPromiseFrame.getMetaData());
}
public int generatePushPromise(ByteBufferPool.Lease lease, int streamId, int promisedStreamId, MetaData metaData) throws HpackException
public int generatePushPromise(RetainableByteBufferPool.Accumulator accumulator, int streamId, int promisedStreamId, MetaData metaData) throws HpackException
{
if (streamId < 0)
throw new IllegalArgumentException("Invalid stream id: " + streamId);
@ -54,19 +55,21 @@ public class PushPromiseGenerator extends FrameGenerator
int extraSpace = 4;
maxFrameSize -= extraSpace;
ByteBuffer hpacked = encode(encoder, lease, metaData, maxFrameSize);
int hpackedLength = hpacked.position();
BufferUtil.flipToFlush(hpacked, 0);
RetainableByteBuffer hpack = encode(encoder, metaData, maxFrameSize);
ByteBuffer hpackByteBuffer = hpack.getByteBuffer();
int hpackLength = hpackByteBuffer.position();
BufferUtil.flipToFlush(hpackByteBuffer, 0);
int length = hpackedLength + extraSpace;
int length = hpackLength + extraSpace;
int flags = Flags.END_HEADERS;
ByteBuffer header = generateHeader(lease, FrameType.PUSH_PROMISE, length, flags, streamId);
header.putInt(promisedStreamId);
BufferUtil.flipToFlush(header, 0);
RetainableByteBuffer header = generateHeader(FrameType.PUSH_PROMISE, length, flags, streamId);
ByteBuffer headerByteBuffer = header.getByteBuffer();
headerByteBuffer.putInt(promisedStreamId);
BufferUtil.flipToFlush(headerByteBuffer, 0);
lease.append(header, true);
lease.append(hpacked, true);
accumulator.append(header);
accumulator.append(hpack);
return Frame.HEADER_LENGTH + length;
}

View File

@ -19,7 +19,8 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class ResetGenerator extends FrameGenerator
@ -30,21 +31,22 @@ public class ResetGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame)
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame)
{
ResetFrame resetFrame = (ResetFrame)frame;
return generateReset(lease, resetFrame.getStreamId(), resetFrame.getError());
return generateReset(accumulator, resetFrame.getStreamId(), resetFrame.getError());
}
public int generateReset(ByteBufferPool.Lease lease, int streamId, int error)
public int generateReset(RetainableByteBufferPool.Accumulator accumulator, int streamId, int error)
{
if (streamId < 0)
throw new IllegalArgumentException("Invalid stream id: " + streamId);
ByteBuffer header = generateHeader(lease, FrameType.RST_STREAM, ResetFrame.RESET_LENGTH, Flags.NONE, streamId);
header.putInt(error);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
RetainableByteBuffer header = generateHeader(FrameType.RST_STREAM, ResetFrame.RESET_LENGTH, Flags.NONE, streamId);
ByteBuffer byteBuffer = header.getByteBuffer();
byteBuffer.putInt(error);
BufferUtil.flipToFlush(byteBuffer, 0);
accumulator.append(header);
return Frame.HEADER_LENGTH + ResetFrame.RESET_LENGTH;
}

View File

@ -20,7 +20,8 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class SettingsGenerator extends FrameGenerator
@ -31,13 +32,13 @@ public class SettingsGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame)
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame)
{
SettingsFrame settingsFrame = (SettingsFrame)frame;
return generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply());
return generateSettings(accumulator, settingsFrame.getSettings(), settingsFrame.isReply());
}
public int generateSettings(ByteBufferPool.Lease lease, Map<Integer, Integer> settings, boolean reply)
public int generateSettings(RetainableByteBufferPool.Accumulator accumulator, Map<Integer, Integer> settings, boolean reply)
{
// Two bytes for the identifier, four bytes for the value.
int entryLength = 2 + 4;
@ -45,16 +46,17 @@ public class SettingsGenerator extends FrameGenerator
if (length > getMaxFrameSize())
throw new IllegalArgumentException("Invalid settings, too big");
ByteBuffer header = generateHeader(lease, FrameType.SETTINGS, length, reply ? Flags.ACK : Flags.NONE, 0);
RetainableByteBuffer header = generateHeader(FrameType.SETTINGS, length, reply ? Flags.ACK : Flags.NONE, 0);
ByteBuffer byteBuffer = header.getByteBuffer();
for (Map.Entry<Integer, Integer> entry : settings.entrySet())
{
header.putShort(entry.getKey().shortValue());
header.putInt(entry.getValue());
byteBuffer.putShort(entry.getKey().shortValue());
byteBuffer.putInt(entry.getValue());
}
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
BufferUtil.flipToFlush(byteBuffer, 0);
accumulator.append(header);
return Frame.HEADER_LENGTH + length;
}

View File

@ -19,7 +19,8 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class WindowUpdateGenerator extends FrameGenerator
@ -30,21 +31,22 @@ public class WindowUpdateGenerator extends FrameGenerator
}
@Override
public int generate(ByteBufferPool.Lease lease, Frame frame)
public int generate(RetainableByteBufferPool.Accumulator accumulator, Frame frame)
{
WindowUpdateFrame windowUpdateFrame = (WindowUpdateFrame)frame;
return generateWindowUpdate(lease, windowUpdateFrame.getStreamId(), windowUpdateFrame.getWindowDelta());
return generateWindowUpdate(accumulator, windowUpdateFrame.getStreamId(), windowUpdateFrame.getWindowDelta());
}
public int generateWindowUpdate(ByteBufferPool.Lease lease, int streamId, int windowUpdate)
public int generateWindowUpdate(RetainableByteBufferPool.Accumulator accumulator, int streamId, int windowUpdate)
{
if (windowUpdate < 0)
throw new IllegalArgumentException("Invalid window update: " + windowUpdate);
ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, WindowUpdateFrame.WINDOW_UPDATE_LENGTH, Flags.NONE, streamId);
header.putInt(windowUpdate);
BufferUtil.flipToFlush(header, 0);
lease.append(header, true);
RetainableByteBuffer header = generateHeader(FrameType.WINDOW_UPDATE, WindowUpdateFrame.WINDOW_UPDATE_LENGTH, Flags.NONE, streamId);
ByteBuffer byteBuffer = header.getByteBuffer();
byteBuffer.putInt(windowUpdate);
BufferUtil.flipToFlush(byteBuffer, 0);
accumulator.append(header);
return Frame.HEADER_LENGTH + WindowUpdateFrame.WINDOW_UPDATE_LENGTH;
}

View File

@ -20,6 +20,7 @@ import org.eclipse.jetty.http2.frames.ContinuationFrame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.RetainableByteBuffer;
public class ContinuationBodyParser extends BodyParser
{
@ -100,9 +101,9 @@ public class ContinuationBodyParser extends BodyParser
private boolean onHeaders(ByteBuffer buffer)
{
ByteBuffer headerBlock = headerBlockFragments.complete();
MetaData metaData = headerBlockParser.parse(headerBlock, headerBlock.remaining());
headerBlockFragments.getByteBufferPool().release(headerBlock);
RetainableByteBuffer headerBlock = headerBlockFragments.complete();
MetaData metaData = headerBlockParser.parse(headerBlock.getByteBuffer(), headerBlock.remaining());
headerBlock.release();
if (metaData == null)
return true;
if (metaData == HeaderBlockParser.SESSION_FAILURE)

View File

@ -16,24 +16,21 @@ package org.eclipse.jetty.http2.internal.parser;
import java.nio.ByteBuffer;
import org.eclipse.jetty.http2.frames.PriorityFrame;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
public class HeaderBlockFragments
{
private final ByteBufferPool byteBufferPool;
private final RetainableByteBufferPool bufferPool;
private PriorityFrame priorityFrame;
private boolean endStream;
private int streamId;
private ByteBuffer storage;
private RetainableByteBuffer storage;
public HeaderBlockFragments(ByteBufferPool byteBufferPool)
public HeaderBlockFragments(RetainableByteBufferPool bufferPool)
{
this.byteBufferPool = byteBufferPool;
}
public ByteBufferPool getByteBufferPool()
{
return byteBufferPool;
this.bufferPool = bufferPool;
}
public void storeFragment(ByteBuffer fragment, int length, boolean last)
@ -41,27 +38,28 @@ public class HeaderBlockFragments
if (storage == null)
{
int space = last ? length : length * 2;
storage = byteBufferPool.acquire(space, fragment.isDirect());
storage.clear();
storage = bufferPool.acquire(space, fragment.isDirect());
BufferUtil.flipToFill(storage.getByteBuffer());
}
// Grow the storage if necessary.
if (storage.remaining() < length)
{
ByteBuffer byteBuffer = storage.getByteBuffer();
int space = last ? length : length * 2;
int capacity = storage.position() + space;
ByteBuffer newStorage = byteBufferPool.acquire(capacity, storage.isDirect());
newStorage.clear();
storage.flip();
newStorage.put(storage);
byteBufferPool.release(storage);
int capacity = byteBuffer.position() + space;
RetainableByteBuffer newStorage = bufferPool.acquire(capacity, storage.isDirect());
BufferUtil.flipToFill(newStorage.getByteBuffer());
byteBuffer.flip();
newStorage.getByteBuffer().put(byteBuffer);
storage.release();
storage = newStorage;
}
// Copy the fragment into the storage.
int limit = fragment.limit();
fragment.limit(fragment.position() + length);
storage.put(fragment);
storage.getByteBuffer().put(fragment);
fragment.limit(limit);
}
@ -85,11 +83,11 @@ public class HeaderBlockFragments
this.endStream = endStream;
}
public ByteBuffer complete()
public RetainableByteBuffer complete()
{
ByteBuffer result = storage;
RetainableByteBuffer result = storage;
storage = null;
result.flip();
result.getByteBuffer().flip();
return result;
}

View File

@ -20,7 +20,8 @@ import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.hpack.HpackDecoder;
import org.eclipse.jetty.http2.hpack.HpackException;
import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -32,15 +33,15 @@ public class HeaderBlockParser
private static final Logger LOG = LoggerFactory.getLogger(HeaderBlockParser.class);
private final HeaderParser headerParser;
private final ByteBufferPool byteBufferPool;
private final RetainableByteBufferPool bufferPool;
private final HpackDecoder hpackDecoder;
private final BodyParser notifier;
private ByteBuffer blockBuffer;
private RetainableByteBuffer blockBuffer;
public HeaderBlockParser(HeaderParser headerParser, ByteBufferPool byteBufferPool, HpackDecoder hpackDecoder, BodyParser notifier)
public HeaderBlockParser(HeaderParser headerParser, RetainableByteBufferPool bufferPool, HpackDecoder hpackDecoder, BodyParser notifier)
{
this.headerParser = headerParser;
this.byteBufferPool = byteBufferPool;
this.bufferPool = bufferPool;
this.hpackDecoder = hpackDecoder;
this.notifier = notifier;
}
@ -61,17 +62,19 @@ public class HeaderBlockParser
// If they are not all available, accumulate them.
// When all are available, decode them.
int accumulated = blockBuffer == null ? 0 : blockBuffer.position();
ByteBuffer byteBuffer = blockBuffer == null ? null : blockBuffer.getByteBuffer();
int accumulated = byteBuffer == null ? 0 : byteBuffer.position();
int remaining = blockLength - accumulated;
if (buffer.remaining() < remaining)
{
if (blockBuffer == null)
{
blockBuffer = byteBufferPool.acquire(blockLength, buffer.isDirect());
BufferUtil.clearToFill(blockBuffer);
blockBuffer = bufferPool.acquire(blockLength, buffer.isDirect());
byteBuffer = blockBuffer.getByteBuffer();
BufferUtil.flipToFill(byteBuffer);
}
blockBuffer.put(buffer);
byteBuffer.put(buffer);
return null;
}
else
@ -79,11 +82,11 @@ public class HeaderBlockParser
int limit = buffer.limit();
buffer.limit(buffer.position() + remaining);
ByteBuffer toDecode;
if (blockBuffer != null)
if (byteBuffer != null)
{
blockBuffer.put(buffer);
BufferUtil.flipToFlush(blockBuffer, 0);
toDecode = blockBuffer;
byteBuffer.put(buffer);
BufferUtil.flipToFlush(byteBuffer, 0);
toDecode = byteBuffer;
}
else
{
@ -121,7 +124,7 @@ public class HeaderBlockParser
if (blockBuffer != null)
{
byteBufferPool.release(blockBuffer);
blockBuffer.release();
blockBuffer = null;
}
}

View File

@ -31,7 +31,7 @@ import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
import org.eclipse.jetty.http2.hpack.HpackDecoder;
import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -44,7 +44,7 @@ public class Parser
{
private static final Logger LOG = LoggerFactory.getLogger(Parser.class);
private final ByteBufferPool byteBufferPool;
private final RetainableByteBufferPool bufferPool;
private final Listener listener;
private final HeaderParser headerParser;
private final HpackDecoder hpackDecoder;
@ -55,14 +55,14 @@ public class Parser
private boolean continuation;
private State state = State.HEADER;
public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize)
public Parser(RetainableByteBufferPool bufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize)
{
this(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, RateControl.NO_RATE_CONTROL);
this(bufferPool, listener, maxDynamicTableSize, maxHeaderSize, RateControl.NO_RATE_CONTROL);
}
public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl)
public Parser(RetainableByteBufferPool bufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl)
{
this.byteBufferPool = byteBufferPool;
this.bufferPool = bufferPool;
this.listener = listener;
this.headerParser = new HeaderParser(rateControl == null ? RateControl.NO_RATE_CONTROL : rateControl);
this.hpackDecoder = new HpackDecoder(maxDynamicTableSize, maxHeaderSize);
@ -73,8 +73,8 @@ public class Parser
{
Listener listener = wrapper.apply(this.listener);
unknownBodyParser = new UnknownBodyParser(headerParser, listener);
HeaderBlockParser headerBlockParser = new HeaderBlockParser(headerParser, byteBufferPool, hpackDecoder, unknownBodyParser);
HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments(byteBufferPool);
HeaderBlockParser headerBlockParser = new HeaderBlockParser(headerParser, bufferPool, hpackDecoder, unknownBodyParser);
HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments(bufferPool);
bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener);
bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments);
bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener);

View File

@ -19,7 +19,7 @@ import org.eclipse.jetty.http2.RateControl;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -33,9 +33,9 @@ public class ServerParser extends Parser
private State state = State.PREFACE;
private boolean notifyPreface = true;
public ServerParser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl)
public ServerParser(RetainableByteBufferPool bufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl)
{
super(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, rateControl);
super(bufferPool, listener, maxDynamicTableSize, maxHeaderSize, rateControl);
this.listener = listener;
this.prefaceParser = new PrefaceParser(listener);
}

View File

@ -29,8 +29,8 @@ import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.generator.HeadersGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -42,11 +42,11 @@ public class ContinuationParseTest
@Test
public void testParseOneByteAtATime() throws Exception
{
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder());
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(bufferPool), new HpackEncoder());
final List<HeadersFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onHeaders(HeadersFrame frame)
@ -71,10 +71,10 @@ public class ContinuationParseTest
.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateHeaders(lease, streamId, metaData, null, true);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateHeaders(accumulator, streamId, metaData, null, true);
List<ByteBuffer> byteBuffers = lease.getByteBuffers();
List<ByteBuffer> byteBuffers = accumulator.getByteBuffers();
assertEquals(2, byteBuffers.size());
ByteBuffer headersBody = byteBuffers.remove(1);
@ -131,7 +131,7 @@ public class ContinuationParseTest
byteBuffers.add(headersBody.slice());
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{

View File

@ -22,8 +22,8 @@ import java.util.function.UnaryOperator;
import org.eclipse.jetty.http2.internal.generator.DataGenerator;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.junit.jupiter.api.Test;
@ -34,7 +34,7 @@ public class DataGenerateParseTest
{
private final byte[] smallContent = new byte[128];
private final byte[] largeContent = new byte[128 * 1024];
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
public DataGenerateParseTest()
{
@ -62,7 +62,7 @@ public class DataGenerateParseTest
DataFrame frame = frames.get(0);
assertTrue(frame.getStreamId() != 0);
assertTrue(frame.isEndStream());
assertEquals(content, frame.getData());
assertEquals(content, frame.getByteBuffer());
}
@Test
@ -77,7 +77,7 @@ public class DataGenerateParseTest
DataFrame frame = frames.get(i - 1);
assertTrue(frame.getStreamId() != 0);
assertEquals(i == frames.size(), frame.isEndStream());
aggregate.put(frame.getData());
aggregate.put(frame.getByteBuffer());
}
aggregate.flip();
assertEquals(content, aggregate);
@ -85,10 +85,10 @@ public class DataGenerateParseTest
private List<DataFrame> testGenerateParse(ByteBuffer data)
{
DataGenerator generator = new DataGenerator(new HeaderGenerator());
DataGenerator generator = new DataGenerator(new HeaderGenerator(bufferPool));
final List<DataFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onData(DataFrame frame)
@ -101,19 +101,19 @@ public class DataGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
ByteBuffer slice = data.slice();
int generated = 0;
while (true)
{
generated += generator.generateData(lease, 13, slice, true, slice.remaining());
generated += generator.generateData(accumulator, 13, slice, true, slice.remaining());
generated -= Frame.HEADER_LENGTH;
if (generated == data.remaining())
break;
}
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
parser.parse(buffer);
}
@ -125,10 +125,10 @@ public class DataGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime()
{
DataGenerator generator = new DataGenerator(new HeaderGenerator());
DataGenerator generator = new DataGenerator(new HeaderGenerator(bufferPool));
final List<DataFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onData(DataFrame frame)
@ -141,20 +141,20 @@ public class DataGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
ByteBuffer data = ByteBuffer.wrap(largeContent);
ByteBuffer slice = data.slice();
int generated = 0;
while (true)
{
generated += generator.generateData(lease, 13, slice, true, slice.remaining());
generated += generator.generateData(accumulator, 13, slice, true, slice.remaining());
generated -= Frame.HEADER_LENGTH;
if (generated == data.remaining())
break;
}
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{

View File

@ -24,8 +24,8 @@ import org.eclipse.jetty.http2.WindowRateControl;
import org.eclipse.jetty.http2.hpack.HpackEncoder;
import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -33,7 +33,7 @@ import static org.hamcrest.Matchers.lessThan;
public class FrameFloodTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
// Frame structure:
// | Len0 | Len1 | Len2 | Type | Flags | StreamID0 |StreamID1 |StreamID2 |StreamID3 | Payload... |
@ -72,7 +72,7 @@ public class FrameFloodTest
public void testInvalidHeadersFrameFlood() throws Exception
{
// Invalid MetaData (no method, no scheme, etc).
MetaData.Request metadata = new MetaData.Request(null, (String)null, null, null, HttpVersion.HTTP_2, null, -1);
MetaData.Request metadata = new MetaData.Request(null, null, null, null, HttpVersion.HTTP_2, null, -1);
HpackEncoder encoder = new HpackEncoder();
ByteBuffer buffer = ByteBuffer.allocate(1024);
encoder.encode(buffer, metadata);
@ -123,7 +123,7 @@ public class FrameFloodTest
private void testFrameFlood(byte[] preamble, byte[] bytes)
{
AtomicBoolean failed = new AtomicBoolean();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onConnectionFailure(int error, String reason)

View File

@ -22,8 +22,8 @@ import java.util.function.UnaryOperator;
import org.eclipse.jetty.http2.internal.generator.GoAwayGenerator;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
@ -32,15 +32,15 @@ import static org.junit.jupiter.api.Assertions.assertNull;
public class GoAwayGenerateParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testGenerateParse() throws Exception
{
GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator());
GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator(bufferPool));
final List<GoAwayFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onGoAway(GoAwayFrame frame)
@ -56,11 +56,11 @@ public class GoAwayGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateGoAway(lease, lastStreamId, error, null);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateGoAway(accumulator, lastStreamId, error, null);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -79,10 +79,10 @@ public class GoAwayGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime() throws Exception
{
GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator());
GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator(bufferPool));
final List<GoAwayFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onGoAway(GoAwayFrame frame)
@ -100,11 +100,11 @@ public class GoAwayGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateGoAway(lease, lastStreamId, error, payload);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateGoAway(accumulator, lastStreamId, error, payload);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{

View File

@ -28,8 +28,8 @@ import org.eclipse.jetty.http2.hpack.HpackEncoder;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.generator.HeadersGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -38,12 +38,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class HeadersGenerateParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testGenerateParse() throws Exception
{
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder());
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(bufferPool), new HpackEncoder());
int streamId = 13;
HttpFields fields = HttpFields.build()
@ -52,7 +52,7 @@ public class HeadersGenerateParseTest
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
final List<HeadersFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onHeaders(HeadersFrame frame)
@ -65,12 +65,12 @@ public class HeadersGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
PriorityFrame priorityFrame = new PriorityFrame(streamId, 3 * streamId, 200, true);
generator.generateHeaders(lease, streamId, metaData, priorityFrame, true);
generator.generateHeaders(accumulator, streamId, metaData, priorityFrame, true);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -102,10 +102,10 @@ public class HeadersGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime() throws Exception
{
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder());
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(bufferPool), new HpackEncoder());
final List<HeadersFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onHeaders(HeadersFrame frame)
@ -124,12 +124,12 @@ public class HeadersGenerateParseTest
.put("User-Agent", "Jetty");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
PriorityFrame priorityFrame = new PriorityFrame(streamId, 3 * streamId, 200, true);
generator.generateHeaders(lease, streamId, metaData, priorityFrame, true);
generator.generateHeaders(accumulator, streamId, metaData, priorityFrame, true);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
buffer = buffer.slice();
while (buffer.hasRemaining())

View File

@ -28,8 +28,8 @@ import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.generator.HeadersGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -37,7 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class HeadersTooLargeParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testProtocolErrorURITooLong() throws HpackException
@ -64,10 +64,10 @@ public class HeadersTooLargeParseTest
private void assertProtocolError(int maxHeaderSize, MetaData.Request metaData) throws HpackException
{
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder());
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(bufferPool), new HpackEncoder());
AtomicInteger failure = new AtomicInteger();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onConnectionFailure(int error, String reason)
@ -78,11 +78,11 @@ public class HeadersTooLargeParseTest
parser.init(UnaryOperator.identity());
int streamId = 48;
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
PriorityFrame priorityFrame = new PriorityFrame(streamId, 3 * streamId, 200, true);
int len = generator.generateHeaders(lease, streamId, metaData, priorityFrame, true);
int len = generator.generateHeaders(accumulator, streamId, metaData, priorityFrame, true);
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining() && failure.get() == 0)
{

View File

@ -19,15 +19,15 @@ import java.util.function.UnaryOperator;
import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MaxFrameSizeParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testMaxFrameSize()
@ -35,7 +35,7 @@ public class MaxFrameSizeParseTest
int maxFrameLength = Frame.DEFAULT_MAX_LENGTH + 16;
AtomicInteger failure = new AtomicInteger();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onConnectionFailure(int error, String reason)

View File

@ -22,8 +22,8 @@ import java.util.function.UnaryOperator;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.generator.PingGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.NanoTime;
import org.junit.jupiter.api.Test;
@ -33,15 +33,15 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class PingGenerateParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testGenerateParse() throws Exception
{
PingGenerator generator = new PingGenerator(new HeaderGenerator());
PingGenerator generator = new PingGenerator(new HeaderGenerator(bufferPool));
final List<PingFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onPing(PingFrame frame)
@ -57,11 +57,11 @@ public class PingGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generatePing(lease, payload, true);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generatePing(accumulator, payload, true);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -79,10 +79,10 @@ public class PingGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime() throws Exception
{
PingGenerator generator = new PingGenerator(new HeaderGenerator());
PingGenerator generator = new PingGenerator(new HeaderGenerator(bufferPool));
final List<PingFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onPing(PingFrame frame)
@ -98,11 +98,11 @@ public class PingGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generatePing(lease, payload, true);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generatePing(accumulator, payload, true);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -120,10 +120,10 @@ public class PingGenerateParseTest
@Test
public void testPayloadAsLong() throws Exception
{
PingGenerator generator = new PingGenerator(new HeaderGenerator());
PingGenerator generator = new PingGenerator(new HeaderGenerator(bufferPool));
final List<PingFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onPing(PingFrame frame)
@ -133,11 +133,11 @@ public class PingGenerateParseTest
}, 4096, 8192);
parser.init(UnaryOperator.identity());
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
PingFrame ping = new PingFrame(NanoTime.now(), true);
generator.generate(lease, ping);
generator.generate(accumulator, ping);
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{

View File

@ -21,23 +21,23 @@ import java.util.function.UnaryOperator;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.generator.PriorityGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class PriorityGenerateParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testGenerateParse() throws Exception
{
PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator());
PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator(bufferPool));
final List<PriorityFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onPriority(PriorityFrame frame)
@ -55,11 +55,11 @@ public class PriorityGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generatePriority(lease, streamId, parentStreamId, weight, exclusive);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generatePriority(accumulator, streamId, parentStreamId, weight, exclusive);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -79,10 +79,10 @@ public class PriorityGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime() throws Exception
{
PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator());
PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator(bufferPool));
final List<PriorityFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onPriority(PriorityFrame frame)
@ -100,11 +100,11 @@ public class PriorityGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generatePriority(lease, streamId, parentStreamId, weight, exclusive);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generatePriority(accumulator, streamId, parentStreamId, weight, exclusive);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{

View File

@ -28,8 +28,8 @@ import org.eclipse.jetty.http2.hpack.HpackEncoder;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.generator.PushPromiseGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -37,15 +37,15 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class PushPromiseGenerateParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testGenerateParse() throws Exception
{
PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder());
PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(bufferPool), new HpackEncoder());
final List<PushPromiseFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onPushPromise(PushPromiseFrame frame)
@ -65,11 +65,11 @@ public class PushPromiseGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generatePushPromise(lease, streamId, promisedStreamId, metaData);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generatePushPromise(accumulator, streamId, promisedStreamId, metaData);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -95,10 +95,10 @@ public class PushPromiseGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime() throws Exception
{
PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder());
PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(bufferPool), new HpackEncoder());
final List<PushPromiseFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onPushPromise(PushPromiseFrame frame)
@ -118,11 +118,11 @@ public class PushPromiseGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generatePushPromise(lease, streamId, promisedStreamId, metaData);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generatePushPromise(accumulator, streamId, promisedStreamId, metaData);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -134,7 +134,7 @@ public class PushPromiseGenerateParseTest
PushPromiseFrame frame = frames.get(0);
assertEquals(streamId, frame.getStreamId());
assertEquals(promisedStreamId, frame.getPromisedStreamId());
MetaData.Request request = (MetaData.Request)frame.getMetaData();
MetaData.Request request = frame.getMetaData();
assertEquals(metaData.getMethod(), request.getMethod());
assertEquals(metaData.getURI(), request.getURI());
for (int j = 0; j < fields.size(); ++j)

View File

@ -21,23 +21,23 @@ import java.util.function.UnaryOperator;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.generator.ResetGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ResetGenerateParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testGenerateParse() throws Exception
{
ResetGenerator generator = new ResetGenerator(new HeaderGenerator());
ResetGenerator generator = new ResetGenerator(new HeaderGenerator(bufferPool));
final List<ResetFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onReset(ResetFrame frame)
@ -53,11 +53,11 @@ public class ResetGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateReset(lease, streamId, error);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateReset(accumulator, streamId, error);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -75,10 +75,10 @@ public class ResetGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime() throws Exception
{
ResetGenerator generator = new ResetGenerator(new HeaderGenerator());
ResetGenerator generator = new ResetGenerator(new HeaderGenerator(bufferPool));
final List<ResetFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onReset(ResetFrame frame)
@ -94,11 +94,11 @@ public class ResetGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateReset(lease, streamId, error);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateReset(accumulator, streamId, error);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{

View File

@ -26,8 +26,8 @@ import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.generator.SettingsGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -35,7 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class SettingsGenerateParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testGenerateParseNoSettings()
@ -69,10 +69,10 @@ public class SettingsGenerateParseTest
private List<SettingsFrame> testGenerateParse(Map<Integer, Integer> settings)
{
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator());
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator(bufferPool));
List<SettingsFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onSettings(SettingsFrame frame)
@ -85,11 +85,11 @@ public class SettingsGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateSettings(lease, settings, true);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateSettings(accumulator, settings, true);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -104,10 +104,10 @@ public class SettingsGenerateParseTest
@Test
public void testGenerateParseInvalidSettings()
{
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator());
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator(bufferPool));
AtomicInteger errorRef = new AtomicInteger();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onConnectionFailure(int error, String reason)
@ -119,13 +119,13 @@ public class SettingsGenerateParseTest
Map<Integer, Integer> settings1 = new HashMap<>();
settings1.put(13, 17);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateSettings(lease, settings1, true);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateSettings(accumulator, settings1, true);
// Modify the length of the frame to make it invalid
ByteBuffer bytes = lease.getByteBuffers().get(0);
ByteBuffer bytes = accumulator.getByteBuffers().get(0);
bytes.putShort(1, (short)(bytes.getShort(1) - 1));
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -139,10 +139,10 @@ public class SettingsGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime()
{
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator());
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator(bufferPool));
List<SettingsFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onSettings(SettingsFrame frame)
@ -160,11 +160,11 @@ public class SettingsGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateSettings(lease, settings1, true);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateSettings(accumulator, settings1, true);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -184,10 +184,10 @@ public class SettingsGenerateParseTest
@Test
public void testGenerateParseTooManyDifferentSettingsInOneFrame()
{
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator());
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator(bufferPool));
AtomicInteger errorRef = new AtomicInteger();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onConnectionFailure(int error, String reason)
@ -205,10 +205,10 @@ public class SettingsGenerateParseTest
settings.put(i + 10, i);
}
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateSettings(lease, settings, false);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateSettings(accumulator, settings, false);
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -227,7 +227,7 @@ public class SettingsGenerateParseTest
int maxSettingsKeys = pairs / 2;
AtomicInteger errorRef = new AtomicInteger();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192);
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter(), 4096, 8192);
parser.setMaxSettingsKeys(maxSettingsKeys);
parser.setMaxFrameLength(Frame.DEFAULT_MAX_LENGTH);
parser.init(listener -> new Parser.Listener.Wrapper(listener)
@ -265,10 +265,10 @@ public class SettingsGenerateParseTest
@Test
public void testGenerateParseTooManySettingsInMultipleFrames()
{
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator());
SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator(bufferPool));
AtomicInteger errorRef = new AtomicInteger();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onConnectionFailure(int error, String reason)
@ -283,13 +283,13 @@ public class SettingsGenerateParseTest
Map<Integer, Integer> settings = new HashMap<>();
settings.put(13, 17);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
for (int i = 0; i < maxSettingsKeys + 1; ++i)
{
generator.generateSettings(lease, settings, false);
generator.generateSettings(accumulator, settings, false);
}
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{

View File

@ -21,8 +21,8 @@ import java.util.function.UnaryOperator;
import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -30,7 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
public class UnknownParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testParse()
@ -48,7 +48,7 @@ public class UnknownParseTest
public void testInvalidFrameSize()
{
AtomicInteger failure = new AtomicInteger();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192);
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter(), 4096, 8192);
parser.init(listener -> new Parser.Listener.Wrapper(listener)
{
@Override
@ -73,7 +73,7 @@ public class UnknownParseTest
private void testParse(Function<ByteBuffer, ByteBuffer> fn)
{
AtomicBoolean failure = new AtomicBoolean();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onConnectionFailure(int error, String reason)

View File

@ -21,23 +21,23 @@ import java.util.function.UnaryOperator;
import org.eclipse.jetty.http2.internal.generator.HeaderGenerator;
import org.eclipse.jetty.http2.internal.generator.WindowUpdateGenerator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class WindowUpdateGenerateParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
private final RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
@Test
public void testGenerateParse() throws Exception
{
WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator());
WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator(bufferPool));
final List<WindowUpdateFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onWindowUpdate(WindowUpdateFrame frame)
@ -53,11 +53,11 @@ public class WindowUpdateGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateWindowUpdate(lease, streamId, windowUpdate);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateWindowUpdate(accumulator, streamId, windowUpdate);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{
@ -75,10 +75,10 @@ public class WindowUpdateGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime() throws Exception
{
WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator());
WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator(bufferPool));
final List<WindowUpdateFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onWindowUpdate(WindowUpdateFrame frame)
@ -94,11 +94,11 @@ public class WindowUpdateGenerateParseTest
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i)
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateWindowUpdate(lease, streamId, windowUpdate);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.generateWindowUpdate(accumulator, streamId, windowUpdate);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
while (buffer.hasRemaining())
{

View File

@ -271,7 +271,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
{
ServerSessionListener listener = newSessionListener(connector, endPoint);
Generator generator = new Generator(connector.getByteBufferPool(), isUseOutputDirectByteBuffers(), getMaxDynamicTableSize(), getMaxHeaderBlockFragment());
Generator generator = new Generator(connector.getRetainableByteBufferPool(), isUseOutputDirectByteBuffers(), getMaxDynamicTableSize(), getMaxHeaderBlockFragment());
FlowControlStrategy flowControl = getFlowControlStrategyFactory().newFlowControlStrategy();
HTTP2ServerSession session = new HTTP2ServerSession(connector.getScheduler(), endPoint, generator, listener, flowControl);
session.setMaxLocalStreams(getMaxConcurrentStreams());
@ -291,7 +291,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
parser.setMaxFrameLength(getMaxFrameLength());
parser.setMaxSettingsKeys(getMaxSettingsKeys());
RetainableByteBufferPool retainableByteBufferPool = connector.getByteBufferPool().asRetainableByteBufferPool();
RetainableByteBufferPool retainableByteBufferPool = connector.getRetainableByteBufferPool();
HTTP2Connection connection = new HTTP2ServerConnection(retainableByteBufferPool, connector,
endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener);
@ -305,7 +305,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
private ServerParser newServerParser(Connector connector, ServerParser.Listener listener, RateControl rateControl)
{
return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize(), rateControl);
return new ServerParser(connector.getRetainableByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize(), rateControl);
}
@ManagedObject("The container of HTTP/2 sessions")

View File

@ -253,7 +253,7 @@ public class HttpStreamOverHTTP2 implements HttpStream, HTTP2Channel.Server
data.release();
return Content.Chunk.EOF;
}
return Content.Chunk.asChunk(frame.getData(), frame.isEndStream(), data);
return Content.Chunk.asChunk(frame.getByteBuffer(), frame.isEndStream(), data);
}
@Override

View File

@ -29,8 +29,8 @@ import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
@ -42,7 +42,7 @@ import org.junit.jupiter.api.AfterEach;
public class AbstractServerTest
{
protected ServerConnector connector;
protected ByteBufferPool byteBufferPool;
protected RetainableByteBufferPool bufferPool;
protected Generator generator;
protected Server server;
protected String path;
@ -68,8 +68,8 @@ public class AbstractServerTest
connector = new ServerConnector(server, connectionFactory);
server.addConnector(connector);
path = "/test";
byteBufferPool = new MappedByteBufferPool();
generator = new Generator(byteBufferPool);
bufferPool = new ArrayRetainableByteBufferPool();
generator = new Generator(bufferPool);
}
protected MetaData.Request newRequest(String method, HttpFields fields)

View File

@ -31,7 +31,7 @@ import org.eclipse.jetty.http2.frames.PrefaceFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Request;
@ -97,8 +97,8 @@ public class BadURITest
}
});
ByteBufferPool byteBufferPool = connector.getByteBufferPool();
Generator generator = new Generator(byteBufferPool);
RetainableByteBufferPool bufferPool = connector.getRetainableByteBufferPool();
Generator generator = new Generator(bufferPool);
// Craft a request with a bad URI, it will not hit the Handler.
MetaData.Request metaData1 = new MetaData.Request(
@ -111,15 +111,15 @@ public class BadURITest
HttpFields.EMPTY,
-1
);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
generator.control(lease, new HeadersFrame(1, metaData1, null, true));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
generator.control(accumulator, new HeadersFrame(1, metaData1, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
@ -128,7 +128,7 @@ public class BadURITest
Thread.sleep(1000);
// Send a second request and verify that it hits the Handler.
lease.recycle();
accumulator.release();
MetaData.Request metaData2 = new MetaData.Request(
HttpMethod.GET.asString(),
HttpScheme.HTTP.asString(),
@ -138,8 +138,8 @@ public class BadURITest
HttpFields.EMPTY,
-1
);
generator.control(lease, new HeadersFrame(3, metaData2, null, true));
for (ByteBuffer buffer : lease.getByteBuffers())
generator.control(accumulator, new HeadersFrame(3, metaData2, null, true));
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}

View File

@ -37,7 +37,7 @@ import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.HTTP2Session;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
@ -74,21 +74,21 @@ public class CloseTest extends AbstractServerTest
}
});
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onHeaders(HeadersFrame frame)
@ -135,17 +135,17 @@ public class CloseTest extends AbstractServerTest
}
});
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(lease, new GoAwayFrame(1, ErrorCode.NO_ERROR.code, "OK".getBytes(StandardCharsets.UTF_8)));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new GoAwayFrame(1, ErrorCode.NO_ERROR.code, "OK".getBytes(StandardCharsets.UTF_8)));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
@ -153,7 +153,7 @@ public class CloseTest extends AbstractServerTest
// Don't close the connection; the server should close.
final CountDownLatch responseLatch = new CountDownLatch(1);
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onHeaders(HeadersFrame frame)
@ -202,23 +202,23 @@ public class CloseTest extends AbstractServerTest
});
connector.setIdleTimeout(idleTimeout);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
final CountDownLatch responseLatch = new CountDownLatch(1);
final CountDownLatch closeLatch = new CountDownLatch(1);
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onHeaders(HeadersFrame frame)

View File

@ -35,8 +35,8 @@ import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.internal.HTTP2Session;
import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise;
@ -119,7 +119,7 @@ public class DataDemandTest extends AbstractTest
await().atMost(1, TimeUnit.SECONDS).until(() -> serverQueue.size() == count.get() + 1);
count.incrementAndGet();
long sum = serverQueue.stream()
.mapToLong(data -> data.frame().getData().remaining())
.mapToLong(data -> data.frame().getByteBuffer().remaining())
.sum();
if (sum == length)
break;
@ -155,7 +155,7 @@ public class DataDemandTest extends AbstractTest
await().atMost(1, TimeUnit.SECONDS).until(() -> clientQueue.size() == count.get() + 1);
count.incrementAndGet();
long sum = clientQueue.stream()
.mapToLong(data -> data.frame().getData().remaining())
.mapToLong(data -> data.frame().getByteBuffer().remaining())
.sum();
if (sum == length)
break;
@ -365,17 +365,17 @@ public class DataDemandTest extends AbstractTest
// Generate a lot of small DATA frames and write them in a single
// write so that the server will continuously be notified and demand,
// which will test that it won't throw StackOverflowError.
MappedByteBufferPool byteBufferPool = new MappedByteBufferPool();
Generator generator = new Generator(byteBufferPool);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
Generator generator = new Generator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
for (int i = 512; i >= 0; --i)
generator.data(lease, new DataFrame(clientStream.getId(), ByteBuffer.allocate(1), i == 0), 1);
generator.data(accumulator, new DataFrame(clientStream.getId(), ByteBuffer.allocate(1), i == 0), 1);
// Since this is a naked write, we need to wait that the
// client finishes writing the SETTINGS reply to the server
// during connection initialization, or we risk a WritePendingException.
Thread.sleep(1000);
((HTTP2Session)clientStream.getSession()).getEndPoint().write(Callback.NOOP, lease.getByteBuffers().toArray(new ByteBuffer[0]));
((HTTP2Session)clientStream.getSession()).getEndPoint().write(Callback.NOOP, accumulator.getByteBuffers().toArray(ByteBuffer[]::new));
assertTrue(latch.await(15, TimeUnit.SECONDS));
}

View File

@ -51,7 +51,7 @@ import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.HTTP2Session;
import org.eclipse.jetty.http2.internal.HTTP2Stream;
import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
@ -667,7 +667,7 @@ public abstract class FlowControlStrategyTest
Stream.Data data = stream.readData();
DataFrame frame = data.frame();
int remaining = frame.remaining();
frame.getData().get(bytes, received, remaining);
frame.getByteBuffer().get(bytes, received, remaining);
this.received += remaining;
data.release();
if (frame.isEndStream())
@ -737,7 +737,7 @@ public abstract class FlowControlStrategyTest
public void onDataAvailable(Stream stream)
{
Stream.Data data = stream.readData();
responseContent.put(data.frame().getData());
responseContent.put(data.frame().getByteBuffer());
data.release();
if (data.frame().isEndStream())
latch.countDown();
@ -844,10 +844,10 @@ public abstract class FlowControlStrategyTest
// Now the client is supposed to not send more frames.
// If it does, the connection must be closed.
HTTP2Session http2Session = (HTTP2Session)session;
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(connector.getByteBufferPool());
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
ByteBuffer extraData = ByteBuffer.allocate(1024);
http2Session.getGenerator().data(lease, new DataFrame(stream.getId(), extraData, true), extraData.remaining());
List<ByteBuffer> buffers = lease.getByteBuffers();
http2Session.getGenerator().data(accumulator, new DataFrame(stream.getId(), extraData, true), extraData.remaining());
List<ByteBuffer> buffers = accumulator.getByteBuffers();
http2Session.getEndPoint().write(Callback.NOOP, buffers.toArray(new ByteBuffer[0]));
// Expect the connection to be closed.
@ -949,10 +949,10 @@ public abstract class FlowControlStrategyTest
// Now the client is supposed to not send more frames.
// If it does, the connection must be closed.
HTTP2Session http2Session = (HTTP2Session)session;
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(connector.getByteBufferPool());
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
ByteBuffer extraData = ByteBuffer.allocate(1024);
http2Session.getGenerator().data(lease, new DataFrame(stream.getId(), extraData, true), extraData.remaining());
List<ByteBuffer> buffers = lease.getByteBuffers();
http2Session.getGenerator().data(accumulator, new DataFrame(stream.getId(), extraData, true), extraData.remaining());
List<ByteBuffer> buffers = accumulator.getByteBuffers();
http2Session.getEndPoint().write(Callback.NOOP, buffers.toArray(new ByteBuffer[0]));
// Expect the connection to be closed.

View File

@ -38,10 +38,10 @@ import org.eclipse.jetty.http2.frames.PrefaceFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.ServerConnector;
@ -150,13 +150,13 @@ public class HTTP2CServerTest extends AbstractServerTest
assertTrue(upgrade.toString().startsWith("HTTP/1.1 101 "));
byteBufferPool = new MappedByteBufferPool();
generator = new Generator(byteBufferPool);
bufferPool = new ArrayRetainableByteBufferPool();
generator = new Generator(bufferPool);
final AtomicReference<HeadersFrame> headersRef = new AtomicReference<>();
final AtomicReference<DataFrame> dataRef = new AtomicReference<>();
final AtomicReference<CountDownLatch> latchRef = new AtomicReference<>(new CountDownLatch(2));
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onHeaders(HeadersFrame frame)
@ -186,7 +186,7 @@ public class HTTP2CServerTest extends AbstractServerTest
DataFrame responseData = dataRef.get();
assertNotNull(responseData);
String content = BufferUtil.toString(responseData.getData());
String content = BufferUtil.toString(responseData.getByteBuffer());
// The upgrade request is seen as HTTP/1.1.
assertThat(content, containsString("Hello from Jetty using HTTP/2.0"));
@ -196,12 +196,12 @@ public class HTTP2CServerTest extends AbstractServerTest
headersRef.set(null);
dataRef.set(null);
latchRef.set(new CountDownLatch(2));
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:" + connector.getLocalPort()), "/two", HttpVersion.HTTP_2, HttpFields.EMPTY, -1);
generator.control(lease, new HeadersFrame(3, metaData, null, true));
for (ByteBuffer buffer : lease.getByteBuffers())
generator.control(accumulator, new HeadersFrame(3, metaData, null, true));
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
@ -219,7 +219,7 @@ public class HTTP2CServerTest extends AbstractServerTest
responseData = dataRef.get();
assertNotNull(responseData);
content = BufferUtil.toString(responseData.getData());
content = BufferUtil.toString(responseData.getByteBuffer());
assertThat(content, containsString("Hello from Jetty using HTTP/2.0"));
assertThat(content, containsString("uri=/two"));
@ -231,28 +231,28 @@ public class HTTP2CServerTest extends AbstractServerTest
{
final CountDownLatch latch = new CountDownLatch(3);
byteBufferPool = new MappedByteBufferPool();
generator = new Generator(byteBufferPool);
bufferPool = new ArrayRetainableByteBufferPool();
generator = new Generator(bufferPool);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:" + connector.getLocalPort()), "/test", HttpVersion.HTTP_2, HttpFields.EMPTY, -1);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
client.setSoTimeout(5000);
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
final AtomicReference<HeadersFrame> headersRef = new AtomicReference<>();
final AtomicReference<DataFrame> dataRef = new AtomicReference<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onSettings(SettingsFrame frame)
@ -288,7 +288,7 @@ public class HTTP2CServerTest extends AbstractServerTest
DataFrame responseData = dataRef.get();
assertNotNull(responseData);
String s = BufferUtil.toString(responseData.getData());
String s = BufferUtil.toString(responseData.getByteBuffer());
assertThat(s, containsString("Hello from Jetty using HTTP/2.0"));
assertThat(s, containsString("uri=/test"));
@ -328,18 +328,18 @@ public class HTTP2CServerTest extends AbstractServerTest
// Now send an HTTP/2 direct request, which
// will have the PRI * HTTP/2.0 preface.
byteBufferPool = new MappedByteBufferPool();
generator = new Generator(byteBufferPool);
bufferPool = new ArrayRetainableByteBufferPool();
generator = new Generator(bufferPool);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
client.setSoTimeout(5000);
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}

View File

@ -47,8 +47,9 @@ import org.eclipse.jetty.http2.internal.Flags;
import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ManagedSelector;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.SocketChannelEndPoint;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.Handler;
@ -84,19 +85,19 @@ public class HTTP2ServerTest extends AbstractServerTest
// No preface bytes.
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
final CountDownLatch latch = new CountDownLatch(1);
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
CountDownLatch latch = new CountDownLatch(1);
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onGoAway(GoAwayFrame frame)
@ -115,7 +116,7 @@ public class HTTP2ServerTest extends AbstractServerTest
@Test
public void testRequestResponseNoContent() throws Exception
{
final CountDownLatch latch = new CountDownLatch(3);
CountDownLatch latch = new CountDownLatch(3);
startServer(new Handler.Abstract()
{
@Override
@ -127,22 +128,22 @@ public class HTTP2ServerTest extends AbstractServerTest
}
});
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
final AtomicReference<HeadersFrame> frameRef = new AtomicReference<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
AtomicReference<HeadersFrame> frameRef = new AtomicReference<>();
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onSettings(SettingsFrame frame)
@ -173,8 +174,8 @@ public class HTTP2ServerTest extends AbstractServerTest
@Test
public void testRequestResponseContent() throws Exception
{
final byte[] content = "Hello, world!".getBytes(StandardCharsets.UTF_8);
final CountDownLatch latch = new CountDownLatch(4);
byte[] content = "Hello, world!".getBytes(StandardCharsets.UTF_8);
CountDownLatch latch = new CountDownLatch(4);
startServer(new Handler.Abstract()
{
@Override
@ -186,23 +187,23 @@ public class HTTP2ServerTest extends AbstractServerTest
}
});
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
final AtomicReference<HeadersFrame> headersRef = new AtomicReference<>();
final AtomicReference<DataFrame> dataRef = new AtomicReference<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
AtomicReference<HeadersFrame> headersRef = new AtomicReference<>();
AtomicReference<DataFrame> dataRef = new AtomicReference<>();
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onSettings(SettingsFrame frame)
@ -237,7 +238,7 @@ public class HTTP2ServerTest extends AbstractServerTest
DataFrame responseData = dataRef.get();
assertNotNull(responseData);
assertArrayEquals(content, BufferUtil.toArray(responseData.getData()));
assertArrayEquals(content, BufferUtil.toArray(responseData.getByteBuffer()));
}
}
@ -254,23 +255,23 @@ public class HTTP2ServerTest extends AbstractServerTest
}
});
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
generator.control(lease, new PingFrame(new byte[8], false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
generator.control(accumulator, new PingFrame(new byte[8], false));
// Modify the length of the frame to a wrong one.
lease.getByteBuffers().get(2).putShort(0, (short)7);
accumulator.getByteBuffers().get(2).putShort(0, (short)7);
final CountDownLatch latch = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(1);
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onGoAway(GoAwayFrame frame)
@ -300,23 +301,23 @@ public class HTTP2ServerTest extends AbstractServerTest
}
});
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
generator.control(lease, new PingFrame(new byte[8], false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
generator.control(accumulator, new PingFrame(new byte[8], false));
// Modify the streamId of the frame to non zero.
lease.getByteBuffers().get(2).putInt(4, 1);
accumulator.getByteBuffers().get(2).putInt(4, 1);
final CountDownLatch latch = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(1);
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onGoAway(GoAwayFrame frame)
@ -336,8 +337,8 @@ public class HTTP2ServerTest extends AbstractServerTest
@Test
public void testCommitFailure() throws Exception
{
final long delay = 1000;
final AtomicBoolean broken = new AtomicBoolean();
long delay = 1000;
AtomicBoolean broken = new AtomicBoolean();
startServer(new Handler.Abstract()
{
@Override
@ -373,22 +374,22 @@ public class HTTP2ServerTest extends AbstractServerTest
server.addConnector(connector2);
server.start();
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector2.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
// The server will close the connection abruptly since it
// cannot write and therefore cannot even send the GO_AWAY.
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192);
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter(), 4096, 8192);
parser.init(UnaryOperator.identity());
boolean closed = parseResponse(client, parser, 2 * delay);
assertTrue(closed);
@ -413,22 +414,22 @@ public class HTTP2ServerTest extends AbstractServerTest
}
});
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
output.flush();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192);
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter(), 4096, 8192);
parser.init(UnaryOperator.identity());
boolean closed = parseResponse(client, parser);
@ -442,12 +443,12 @@ public class HTTP2ServerTest extends AbstractServerTest
{
testRequestWithContinuationFrames(null, () ->
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
return lease;
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
return accumulator;
});
}
@ -457,12 +458,12 @@ public class HTTP2ServerTest extends AbstractServerTest
PriorityFrame priority = new PriorityFrame(1, 13, 200, true);
testRequestWithContinuationFrames(priority, () ->
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, priority, true));
return lease;
generator.control(accumulator, new HeadersFrame(1, metaData, priority, true));
return accumulator;
});
}
@ -471,19 +472,19 @@ public class HTTP2ServerTest extends AbstractServerTest
{
testRequestWithContinuationFrames(null, () ->
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
// Take the HeadersFrame header and set the length to zero.
List<ByteBuffer> buffers = lease.getByteBuffers();
List<ByteBuffer> buffers = accumulator.getByteBuffers();
ByteBuffer headersFrameHeader = buffers.get(2);
headersFrameHeader.put(0, (byte)0);
headersFrameHeader.putShort(1, (short)0);
// Insert a CONTINUATION frame header for the body of the HEADERS frame.
lease.insert(3, buffers.get(4).slice(), false);
return lease;
accumulator.insert(3, RetainableByteBuffer.wrap(buffers.get(4).slice()));
return accumulator;
});
}
@ -493,19 +494,19 @@ public class HTTP2ServerTest extends AbstractServerTest
PriorityFrame priority = new PriorityFrame(1, 13, 200, true);
testRequestWithContinuationFrames(null, () ->
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, priority, true));
generator.control(accumulator, new HeadersFrame(1, metaData, priority, true));
// Take the HeadersFrame header and set the length to just the priority frame.
List<ByteBuffer> buffers = lease.getByteBuffers();
List<ByteBuffer> buffers = accumulator.getByteBuffers();
ByteBuffer headersFrameHeader = buffers.get(2);
headersFrameHeader.put(0, (byte)0);
headersFrameHeader.putShort(1, (short)PriorityFrame.PRIORITY_LENGTH);
// Insert a CONTINUATION frame header for the body of the HEADERS frame.
lease.insert(3, buffers.get(4).slice(), false);
return lease;
accumulator.insert(3, RetainableByteBuffer.wrap(buffers.get(4).slice()));
return accumulator;
});
}
@ -514,13 +515,13 @@ public class HTTP2ServerTest extends AbstractServerTest
{
testRequestWithContinuationFrames(null, () ->
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
// Take the ContinuationFrame header, duplicate it, and set the length to zero.
List<ByteBuffer> buffers = lease.getByteBuffers();
List<ByteBuffer> buffers = accumulator.getByteBuffers();
ByteBuffer continuationFrameHeader = buffers.get(4);
ByteBuffer duplicate = ByteBuffer.allocate(continuationFrameHeader.remaining());
duplicate.put(continuationFrameHeader).flip();
@ -528,8 +529,8 @@ public class HTTP2ServerTest extends AbstractServerTest
continuationFrameHeader.put(0, (byte)0);
continuationFrameHeader.putShort(1, (short)0);
// Insert a CONTINUATION frame header for the body of the previous CONTINUATION frame.
lease.insert(5, duplicate, false);
return lease;
accumulator.insert(5, RetainableByteBuffer.wrap(duplicate));
return accumulator;
});
}
@ -538,13 +539,13 @@ public class HTTP2ServerTest extends AbstractServerTest
{
testRequestWithContinuationFrames(null, () ->
{
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = newRequest("GET", HttpFields.EMPTY);
generator.control(lease, new HeadersFrame(1, metaData, null, true));
generator.control(accumulator, new HeadersFrame(1, metaData, null, true));
// Take the last CONTINUATION frame and reset the flag.
List<ByteBuffer> buffers = lease.getByteBuffers();
List<ByteBuffer> buffers = accumulator.getByteBuffers();
ByteBuffer continuationFrameHeader = buffers.get(buffers.size() - 2);
continuationFrameHeader.put(4, (byte)0);
// Add a last, empty, CONTINUATION frame.
@ -554,14 +555,14 @@ public class HTTP2ServerTest extends AbstractServerTest
(byte)Flags.END_HEADERS,
0, 0, 0, 1 // Stream ID
});
lease.append(last, false);
return lease;
accumulator.append(RetainableByteBuffer.wrap(last));
return accumulator;
});
}
private void testRequestWithContinuationFrames(PriorityFrame priorityFrame, Callable<ByteBufferPool.Lease> frames) throws Exception
private void testRequestWithContinuationFrames(PriorityFrame priorityFrame, Callable<RetainableByteBufferPool.Accumulator> frames) throws Exception
{
final CountDownLatch serverLatch = new CountDownLatch(1);
CountDownLatch serverLatch = new CountDownLatch(1);
startServer(new ServerSessionListener()
{
@Override
@ -585,14 +586,14 @@ public class HTTP2ServerTest extends AbstractServerTest
return null;
}
});
generator = new Generator(byteBufferPool, 4096, 4);
generator = new Generator(bufferPool, 4096, 4);
ByteBufferPool.Lease lease = frames.call();
RetainableByteBufferPool.Accumulator accumulator = frames.call();
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
@ -600,8 +601,8 @@ public class HTTP2ServerTest extends AbstractServerTest
assertTrue(serverLatch.await(5, TimeUnit.SECONDS));
final CountDownLatch clientLatch = new CountDownLatch(1);
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
CountDownLatch clientLatch = new CountDownLatch(1);
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onHeaders(HeadersFrame frame)

View File

@ -201,7 +201,7 @@ public class HTTP2Test extends AbstractTest
Stream.Data data = stream.readData();
DataFrame frame = data.frame();
assertTrue(frame.isEndStream());
assertEquals(ByteBuffer.wrap(content), frame.getData());
assertEquals(ByteBuffer.wrap(content), frame.getByteBuffer());
data.release();
latch.countDown();
}
@ -593,10 +593,10 @@ public class HTTP2Test extends AbstractTest
DataFrame data1 = new DataFrame(stream.getId(), ByteBuffer.allocate(1024), false)
{
@Override
public ByteBuffer getData()
public ByteBuffer getByteBuffer()
{
sleep(2 * sleep);
return super.getData();
return super.getByteBuffer();
}
};
DataFrame data2 = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true);

View File

@ -67,10 +67,10 @@ import org.eclipse.jetty.http2.internal.HTTP2Session;
import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.http2.internal.parser.ServerParser;
import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Request;
@ -111,7 +111,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
assertTrue(http2Client.isStarted());
assertSame(httpClient.getExecutor(), http2Client.getExecutor());
assertSame(httpClient.getScheduler(), http2Client.getScheduler());
assertSame(httpClient.getByteBufferPool(), http2Client.getByteBufferPool());
assertSame(httpClient.getRetainableByteBufferPool(), http2Client.getRetainableByteBufferPool());
assertEquals(httpClient.getConnectTimeout(), http2Client.getConnectTimeout());
assertEquals(httpClient.getIdleTimeout(), http2Client.getIdleTimeout());
assertEquals(httpClient.isUseInputDirectByteBuffers(), http2Client.isUseInputDirectByteBuffers());
@ -541,9 +541,9 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
resultLatch.countDown();
});
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
Generator generator = new Generator(byteBufferPool);
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
Generator generator = new Generator(bufferPool);
try (Socket socket = server.accept())
{
@ -551,7 +551,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
OutputStream output = socket.getOutputStream();
InputStream input = socket.getInputStream();
ServerParser parser = new ServerParser(byteBufferPool, new ServerParser.Listener.Adapter()
ServerParser parser = new ServerParser(bufferPool, new ServerParser.Listener.Adapter()
{
@Override
public void onPreface()
@ -559,9 +559,9 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
try
{
// Server's preface.
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
generator.control(accumulator, new SettingsFrame(new HashMap<>(), false));
// Reply to client's SETTINGS.
generator.control(lease, new SettingsFrame(new HashMap<>(), true));
generator.control(accumulator, new SettingsFrame(new HashMap<>(), true));
writeFrames();
}
catch (HpackException x)
@ -578,7 +578,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
// Response.
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
HeadersFrame response = new HeadersFrame(request.getStreamId(), metaData, null, true);
generator.control(lease, response);
generator.control(accumulator, response);
writeFrames();
}
catch (HpackException x)
@ -592,11 +592,11 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
try
{
// Write the frames.
for (ByteBuffer buffer : lease.getByteBuffers())
for (ByteBuffer buffer : accumulator.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
lease.recycle();
accumulator.release();
}
catch (Throwable x)
{

View File

@ -158,7 +158,7 @@ public class InterleavingTest extends AbstractTest
if (dataFrame.isEndStream())
++finished;
BufferUtil.writeTo(dataFrame.getData(), contents.get(streamId));
BufferUtil.writeTo(dataFrame.getByteBuffer(), contents.get(streamId));
data.release();
}

View File

@ -50,9 +50,9 @@ import org.eclipse.jetty.http2.internal.ErrorCode;
import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.http2.internal.parser.Parser;
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
@ -148,26 +148,26 @@ public class PrefaceTest extends AbstractTest
}
});
ByteBufferPool byteBufferPool = http2Client.getByteBufferPool();
RetainableByteBufferPool bufferPool = http2Client.getRetainableByteBufferPool();
try (SocketChannel socket = SocketChannel.open())
{
socket.connect(new InetSocketAddress("localhost", connector.getLocalPort()));
Generator generator = new Generator(byteBufferPool);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
Generator generator = new Generator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
Map<Integer, Integer> clientSettings = new HashMap<>();
clientSettings.put(SettingsFrame.ENABLE_PUSH, 0);
generator.control(lease, new SettingsFrame(clientSettings, false));
generator.control(accumulator, new SettingsFrame(clientSettings, false));
// The PING frame just to make sure the client stops reading.
generator.control(lease, new PingFrame(true));
generator.control(accumulator, new PingFrame(true));
List<ByteBuffer> buffers = lease.getByteBuffers();
List<ByteBuffer> buffers = accumulator.getByteBuffers();
socket.write(buffers.toArray(new ByteBuffer[0]));
Queue<SettingsFrame> settings = new ArrayDeque<>();
AtomicBoolean closed = new AtomicBoolean();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onSettings(SettingsFrame frame)
@ -183,7 +183,7 @@ public class PrefaceTest extends AbstractTest
}, 4096, 8192);
parser.init(UnaryOperator.identity());
ByteBuffer buffer = byteBufferPool.acquire(1024, true);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while (true)
{
BufferUtil.clearToFill(buffer);
@ -247,7 +247,7 @@ public class PrefaceTest extends AbstractTest
});
server.start();
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
RetainableByteBufferPool bufferPool = new ArrayRetainableByteBufferPool();
try (SocketChannel socket = SocketChannel.open())
{
socket.connect(new InetSocketAddress("localhost", connector.getLocalPort()));
@ -268,7 +268,7 @@ public class PrefaceTest extends AbstractTest
assertTrue(serverSettingsLatch.get().await(5, TimeUnit.SECONDS));
// The 101 response is the reply to the client preface SETTINGS frame.
ByteBuffer buffer = byteBufferPool.acquire(1024, true);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
http1:
while (true)
{
@ -295,13 +295,13 @@ public class PrefaceTest extends AbstractTest
serverSettingsLatch.set(new CountDownLatch(1));
// After the 101, the client must send the connection preface.
Generator generator = new Generator(byteBufferPool);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
Generator generator = new Generator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
Map<Integer, Integer> clientSettings = new HashMap<>();
clientSettings.put(SettingsFrame.ENABLE_PUSH, 1);
generator.control(lease, new SettingsFrame(clientSettings, false));
List<ByteBuffer> buffers = lease.getByteBuffers();
generator.control(accumulator, new SettingsFrame(clientSettings, false));
List<ByteBuffer> buffers = accumulator.getByteBuffers();
socket.write(buffers.toArray(new ByteBuffer[0]));
// However, we should not call onPreface() again.
@ -311,7 +311,7 @@ public class PrefaceTest extends AbstractTest
CountDownLatch clientSettingsLatch = new CountDownLatch(1);
AtomicBoolean responded = new AtomicBoolean();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
Parser parser = new Parser(bufferPool, new Parser.Listener.Adapter()
{
@Override
public void onSettings(SettingsFrame frame)

View File

@ -223,7 +223,7 @@ public class RawHTTP2ProxyTest
DataFrame frame = data.frame();
if (LOGGER.isDebugEnabled())
LOGGER.debug("CLIENT received {}", frame);
assertEquals(buffer1.slice(), frame.getData());
assertEquals(buffer1.slice(), frame.getByteBuffer());
data.release();
latch1.countDown();
if (!data.frame().isEndStream())
@ -461,7 +461,7 @@ public class RawHTTP2ProxyTest
case DATA ->
{
DataFrame clientToProxyFrame = (DataFrame)frameInfo.frame;
DataFrame proxyToServerFrame = new DataFrame(proxyToServerStream.getId(), clientToProxyFrame.getData(), clientToProxyFrame.isEndStream());
DataFrame proxyToServerFrame = new DataFrame(proxyToServerStream.getId(), clientToProxyFrame.getByteBuffer(), clientToProxyFrame.isEndStream());
proxyToServerStream.data(proxyToServerFrame, this);
yield Action.SCHEDULED;
}
@ -609,7 +609,7 @@ public class RawHTTP2ProxyTest
case DATA ->
{
DataFrame clientToProxyFrame = (DataFrame)frameInfo.frame;
DataFrame proxyToServerFrame = new DataFrame(serverToProxyStream.getId(), clientToProxyFrame.getData(), clientToProxyFrame.isEndStream());
DataFrame proxyToServerFrame = new DataFrame(serverToProxyStream.getId(), clientToProxyFrame.getByteBuffer(), clientToProxyFrame.isEndStream());
proxyToClientStream.data(proxyToServerFrame, this);
yield Action.SCHEDULED;
}

View File

@ -33,7 +33,7 @@ import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.http2.internal.HTTP2Session;
import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FuturePromise;
@ -201,10 +201,10 @@ public class StreamCountTest extends AbstractTest
HeadersFrame frame3 = new HeadersFrame(streamId3, metaData, null, false);
DataFrame data3 = new DataFrame(streamId3, BufferUtil.EMPTY_BUFFER, true);
Generator generator = ((HTTP2Session)session).getGenerator();
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(generator.getByteBufferPool());
generator.control(lease, frame3);
generator.data(lease, data3, data3.remaining());
((HTTP2Session)session).getEndPoint().write(Callback.NOOP, lease.getByteBuffers().toArray(new ByteBuffer[0]));
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, frame3);
generator.data(accumulator, data3, data3.remaining());
((HTTP2Session)session).getEndPoint().write(Callback.NOOP, accumulator.getByteBuffers().toArray(ByteBuffer[]::new));
// Expect 2 RST_STREAM frames.
assertTrue(sessionResetLatch.await(5, TimeUnit.SECONDS));

View File

@ -64,8 +64,8 @@ import org.eclipse.jetty.http2.internal.generator.Generator;
import org.eclipse.jetty.http2.server.AbstractHTTP2ServerConnectionFactory;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.io.AbstractEndPoint;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.WriteFlusher;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.Handler;
@ -671,7 +671,7 @@ public class StreamResetTest extends AbstractTest
Stream.Data data = stream.readData();
dataQueue.offer(data);
// Do not consume the data yet.
if (received.addAndGet(data.frame().getData().remaining()) == windowSize)
if (received.addAndGet(data.frame().getByteBuffer().remaining()) == windowSize)
latch.countDown();
else
stream.demand();
@ -724,7 +724,7 @@ public class StreamResetTest extends AbstractTest
Stream.Data data = stream.readData();
dataList.add(data);
// Do not release to stall the flow control window.
if (received.addAndGet(data.frame().getData().remaining()) == windowSize)
if (received.addAndGet(data.frame().getByteBuffer().remaining()) == windowSize)
latch.countDown();
else
stream.demand();
@ -784,7 +784,7 @@ public class StreamResetTest extends AbstractTest
Stream.Data data = stream.readData();
dataQueue.offer(data);
// Do not consume the data yet.
if (received.addAndGet(data.frame().getData().remaining()) == windowSize)
if (received.addAndGet(data.frame().getByteBuffer().remaining()) == windowSize)
latch.countDown();
else
stream.demand();
@ -887,30 +887,30 @@ public class StreamResetTest extends AbstractTest
}
});
ByteBufferPool byteBufferPool = http2Client.getByteBufferPool();
RetainableByteBufferPool bufferPool = http2Client.getRetainableByteBufferPool();
try (SocketChannel socket = SocketChannel.open())
{
String host = "localhost";
int port = connector.getLocalPort();
socket.connect(new InetSocketAddress(host, port));
Generator generator = new Generator(byteBufferPool);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
Generator generator = new Generator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
Map<Integer, Integer> clientSettings = new HashMap<>();
// Max stream HTTP/2 flow control window.
clientSettings.put(SettingsFrame.INITIAL_WINDOW_SIZE, Integer.MAX_VALUE);
generator.control(lease, new SettingsFrame(clientSettings, false));
generator.control(accumulator, new SettingsFrame(clientSettings, false));
// Max session HTTP/2 flow control window.
generator.control(lease, new WindowUpdateFrame(0, Integer.MAX_VALUE - FlowControlStrategy.DEFAULT_WINDOW_SIZE));
generator.control(accumulator, new WindowUpdateFrame(0, Integer.MAX_VALUE - FlowControlStrategy.DEFAULT_WINDOW_SIZE));
HttpURI uri = HttpURI.from("http", host, port, "/");
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, HttpFields.EMPTY);
int streamId = 3;
HeadersFrame headersFrame = new HeadersFrame(streamId, request, null, true);
generator.control(lease, headersFrame);
generator.control(accumulator, headersFrame);
List<ByteBuffer> buffers = lease.getByteBuffers();
List<ByteBuffer> buffers = accumulator.getByteBuffers();
socket.write(buffers.toArray(new ByteBuffer[0]));
// Wait until the server is TCP congested.
@ -918,9 +918,9 @@ public class StreamResetTest extends AbstractTest
WriteFlusher flusher = flusherRef.get();
waitUntilTCPCongested(flusher);
lease.recycle();
generator.control(lease, new ResetFrame(streamId, ErrorCode.CANCEL_STREAM_ERROR.code));
buffers = lease.getByteBuffers();
accumulator.release();
generator.control(accumulator, new ResetFrame(streamId, ErrorCode.CANCEL_STREAM_ERROR.code));
buffers = accumulator.getByteBuffers();
socket.write(buffers.toArray(new ByteBuffer[0]));
assertTrue(writeLatch1.await(5, TimeUnit.SECONDS));
@ -978,29 +978,29 @@ public class StreamResetTest extends AbstractTest
}
});
ByteBufferPool byteBufferPool = http2Client.getByteBufferPool();
RetainableByteBufferPool bufferPool = http2Client.getRetainableByteBufferPool();
try (SocketChannel socket = SocketChannel.open())
{
String host = "localhost";
int port = connector.getLocalPort();
socket.connect(new InetSocketAddress(host, port));
Generator generator = new Generator(byteBufferPool);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
Generator generator = new Generator(bufferPool);
RetainableByteBufferPool.Accumulator accumulator = new RetainableByteBufferPool.Accumulator();
generator.control(accumulator, new PrefaceFrame());
Map<Integer, Integer> clientSettings = new HashMap<>();
// Max stream HTTP/2 flow control window.
clientSettings.put(SettingsFrame.INITIAL_WINDOW_SIZE, Integer.MAX_VALUE);
generator.control(lease, new SettingsFrame(clientSettings, false));
generator.control(accumulator, new SettingsFrame(clientSettings, false));
// Max session HTTP/2 flow control window.
generator.control(lease, new WindowUpdateFrame(0, Integer.MAX_VALUE - FlowControlStrategy.DEFAULT_WINDOW_SIZE));
generator.control(accumulator, new WindowUpdateFrame(0, Integer.MAX_VALUE - FlowControlStrategy.DEFAULT_WINDOW_SIZE));
HttpURI uri = HttpURI.from("http", host, port, "/1");
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, HttpFields.EMPTY);
HeadersFrame headersFrame = new HeadersFrame(3, request, null, true);
generator.control(lease, headersFrame);
generator.control(accumulator, headersFrame);
List<ByteBuffer> buffers = lease.getByteBuffers();
List<ByteBuffer> buffers = accumulator.getByteBuffers();
socket.write(buffers.toArray(new ByteBuffer[0]));
waitUntilTCPCongested(exchanger.exchange(null));
@ -1010,15 +1010,15 @@ public class StreamResetTest extends AbstractTest
request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, HttpFields.EMPTY);
int streamId = 5;
headersFrame = new HeadersFrame(streamId, request, null, true);
generator.control(lease, headersFrame);
buffers = lease.getByteBuffers();
generator.control(accumulator, headersFrame);
buffers = accumulator.getByteBuffers();
socket.write(buffers.toArray(new ByteBuffer[0]));
assertTrue(requestLatch1.await(5, TimeUnit.SECONDS));
// Now reset the second request, which has not started writing yet.
lease.recycle();
generator.control(lease, new ResetFrame(streamId, ErrorCode.CANCEL_STREAM_ERROR.code));
buffers = lease.getByteBuffers();
accumulator.release();
generator.control(accumulator, new ResetFrame(streamId, ErrorCode.CANCEL_STREAM_ERROR.code));
buffers = accumulator.getByteBuffers();
socket.write(buffers.toArray(new ByteBuffer[0]));
// Wait to be sure that the server processed the reset.
Thread.sleep(1000);

View File

@ -69,7 +69,7 @@ public class HttpClientTransportOverHTTP3 extends AbstractHttpClientTransport im
ClientConnector clientConnector = this.client.getClientConnector();
clientConnector.setExecutor(httpClient.getExecutor());
clientConnector.setScheduler(httpClient.getScheduler());
clientConnector.setByteBufferPool(httpClient.getByteBufferPool());
clientConnector.setRetainableByteBufferPool(httpClient.getRetainableByteBufferPool());
clientConnector.setConnectTimeout(Duration.ofMillis(httpClient.getConnectTimeout()));
clientConnector.setConnectBlocking(httpClient.isConnectBlocking());
clientConnector.setBindAddress(httpClient.getBindAddress());

View File

@ -30,6 +30,7 @@ import org.eclipse.jetty.http3.internal.MessageFlusher;
import org.eclipse.jetty.http3.internal.UnidirectionalStreamConnection;
import org.eclipse.jetty.http3.qpack.QpackDecoder;
import org.eclipse.jetty.http3.qpack.QpackEncoder;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.quic.client.ClientProtocolSession;
import org.eclipse.jetty.quic.client.ClientQuicSession;
import org.eclipse.jetty.quic.common.QuicStreamEndPoint;
@ -63,7 +64,8 @@ public class ClientHTTP3Session extends ClientProtocolSession
long encoderStreamId = getQuicSession().newStreamId(StreamType.CLIENT_UNIDIRECTIONAL);
QuicStreamEndPoint encoderEndPoint = openInstructionEndPoint(encoderStreamId);
InstructionFlusher encoderInstructionFlusher = new InstructionFlusher(quicSession, encoderEndPoint, EncoderStreamConnection.STREAM_TYPE);
this.encoder = new QpackEncoder(new InstructionHandler(encoderInstructionFlusher), configuration.getMaxBlockedStreams());
RetainableByteBufferPool bufferPool = quicSession.getRetainableByteBufferPool();
this.encoder = new QpackEncoder(bufferPool, new InstructionHandler(encoderInstructionFlusher), configuration.getMaxBlockedStreams());
addBean(encoder);
if (LOG.isDebugEnabled())
LOG.debug("created encoder stream #{} on {}", encoderStreamId, encoderEndPoint);
@ -71,7 +73,7 @@ public class ClientHTTP3Session extends ClientProtocolSession
long decoderStreamId = getQuicSession().newStreamId(StreamType.CLIENT_UNIDIRECTIONAL);
QuicStreamEndPoint decoderEndPoint = openInstructionEndPoint(decoderStreamId);
InstructionFlusher decoderInstructionFlusher = new InstructionFlusher(quicSession, decoderEndPoint, DecoderStreamConnection.STREAM_TYPE);
this.decoder = new QpackDecoder(new InstructionHandler(decoderInstructionFlusher), configuration.getMaxResponseHeadersSize());
this.decoder = new QpackDecoder(bufferPool, new InstructionHandler(decoderInstructionFlusher), configuration.getMaxResponseHeadersSize());
addBean(decoder);
if (LOG.isDebugEnabled())
LOG.debug("created decoder stream #{} on {}", decoderStreamId, decoderEndPoint);
@ -83,7 +85,7 @@ public class ClientHTTP3Session extends ClientProtocolSession
if (LOG.isDebugEnabled())
LOG.debug("created control stream #{} on {}", controlStreamId, controlEndPoint);
this.messageFlusher = new MessageFlusher(quicSession.getByteBufferPool(), encoder, configuration.getMaxRequestHeadersSize(), configuration.isUseOutputDirectByteBuffers());
this.messageFlusher = new MessageFlusher(quicSession.getRetainableByteBufferPool(), encoder, configuration.getMaxRequestHeadersSize(), configuration.isUseOutputDirectByteBuffers());
addBean(messageFlusher);
}
@ -197,7 +199,7 @@ public class ClientHTTP3Session extends ClientProtocolSession
private void openUnidirectionalStreamEndPoint(QuicStreamEndPoint endPoint)
{
UnidirectionalStreamConnection connection = new UnidirectionalStreamConnection(endPoint, getQuicSession().getExecutor(), getQuicSession().getByteBufferPool(), encoder, decoder, session);
UnidirectionalStreamConnection connection = new UnidirectionalStreamConnection(endPoint, getQuicSession().getExecutor(), getQuicSession().getRetainableByteBufferPool(), encoder, decoder, session);
endPoint.setConnection(connection);
endPoint.opened();
}

View File

@ -21,6 +21,6 @@ public class ClientHTTP3StreamConnection extends HTTP3StreamConnection
{
public ClientHTTP3StreamConnection(QuicStreamEndPoint endPoint, ClientHTTP3Session session, MessageParser parser)
{
super(endPoint, session.getQuicSession().getExecutor(), session.getQuicSession().getByteBufferPool(), parser);
super(endPoint, session.getQuicSession().getExecutor(), session.getQuicSession().getRetainableByteBufferPool(), parser);
}
}

View File

@ -21,7 +21,8 @@ import java.util.Queue;
import org.eclipse.jetty.http3.frames.Frame;
import org.eclipse.jetty.http3.internal.generator.ControlGenerator;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.quic.common.QuicSession;
import org.eclipse.jetty.quic.common.QuicStreamEndPoint;
import org.eclipse.jetty.util.Callback;
@ -37,9 +38,9 @@ public class ControlFlusher extends IteratingCallback
private final AutoLock lock = new AutoLock();
private final Queue<Entry> queue = new ArrayDeque<>();
private final ByteBufferPool.Lease lease;
private final ControlGenerator generator;
private final QuicStreamEndPoint endPoint;
private final ControlGenerator generator;
private final RetainableByteBufferPool.Accumulator accumulator;
private boolean initialized;
private Throwable terminated;
private List<Entry> entries;
@ -47,15 +48,16 @@ public class ControlFlusher extends IteratingCallback
public ControlFlusher(QuicSession session, QuicStreamEndPoint endPoint, boolean useDirectByteBuffers)
{
this.lease = new ByteBufferPool.Lease(session.getByteBufferPool());
this.endPoint = endPoint;
this.generator = new ControlGenerator(useDirectByteBuffers);
RetainableByteBufferPool bufferPool = session.getRetainableByteBufferPool();
this.generator = new ControlGenerator(bufferPool, useDirectByteBuffers);
this.accumulator = new RetainableByteBufferPool.Accumulator();
}
public boolean offer(Frame frame, Callback callback)
{
Throwable closed;
try (AutoLock l = lock.lock())
try (AutoLock ignored = lock.lock())
{
closed = terminated;
if (closed == null)
@ -70,7 +72,7 @@ public class ControlFlusher extends IteratingCallback
@Override
protected Action process()
{
try (AutoLock l = lock.lock())
try (AutoLock ignored = lock.lock())
{
if (queue.isEmpty())
return Action.IDLE;
@ -83,7 +85,7 @@ public class ControlFlusher extends IteratingCallback
for (Entry entry : entries)
{
generator.generate(lease, endPoint.getStreamId(), entry.frame, null);
generator.generate(accumulator, endPoint.getStreamId(), entry.frame, null);
invocationType = Invocable.combine(invocationType, entry.callback.getInvocationType());
}
@ -93,12 +95,12 @@ public class ControlFlusher extends IteratingCallback
ByteBuffer buffer = ByteBuffer.allocate(VarLenInt.length(ControlStreamConnection.STREAM_TYPE));
VarLenInt.encode(buffer, ControlStreamConnection.STREAM_TYPE);
buffer.flip();
lease.insert(0, buffer, false);
accumulator.insert(0, RetainableByteBuffer.wrap(buffer));
}
List<ByteBuffer> buffers = lease.getByteBuffers();
List<ByteBuffer> buffers = accumulator.getByteBuffers();
if (LOG.isDebugEnabled())
LOG.debug("writing {} buffers ({} bytes) on {}", buffers.size(), lease.getTotalLength(), this);
LOG.debug("writing {} buffers ({} bytes) on {}", buffers.size(), accumulator.getTotalLength(), this);
endPoint.write(this, buffers.toArray(ByteBuffer[]::new));
return Action.SCHEDULED;
}
@ -109,7 +111,7 @@ public class ControlFlusher extends IteratingCallback
if (LOG.isDebugEnabled())
LOG.debug("succeeded to write {} on {}", entries, this);
lease.recycle();
accumulator.release();
entries.forEach(e -> e.callback.succeeded());
entries.clear();
@ -125,11 +127,11 @@ public class ControlFlusher extends IteratingCallback
if (LOG.isDebugEnabled())
LOG.debug("failed to write {} on {}", entries, this, failure);
lease.recycle();
accumulator.release();
List<Entry> allEntries = new ArrayList<>(entries);
entries.clear();
try (AutoLock l = lock.lock())
try (AutoLock ignored = lock.lock())
{
terminated = failure;
allEntries.addAll(queue);
@ -157,21 +159,7 @@ public class ControlFlusher extends IteratingCallback
return String.format("%s#%s", super.toString(), endPoint.getStreamId());
}
private static class Entry
private record Entry(Frame frame, Callback callback)
{
private final Frame frame;
private final Callback callback;
private Entry(Frame frame, Callback callback)
{
this.frame = frame;
this.callback = callback;
}
@Override
public String toString()
{
return frame.toString();
}
}
}

View File

@ -18,9 +18,10 @@ import java.util.concurrent.Executor;
import org.eclipse.jetty.http3.internal.parser.ControlParser;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -31,15 +32,15 @@ public class ControlStreamConnection extends AbstractConnection implements Conne
public static final long STREAM_TYPE = 0x00;
private static final Logger LOG = LoggerFactory.getLogger(ControlStreamConnection.class);
private final ByteBufferPool byteBufferPool;
private final RetainableByteBufferPool bufferPool;
private final ControlParser parser;
private boolean useInputDirectByteBuffers = true;
private ByteBuffer buffer;
private RetainableByteBuffer buffer;
public ControlStreamConnection(EndPoint endPoint, Executor executor, ByteBufferPool byteBufferPool, ControlParser parser)
public ControlStreamConnection(EndPoint endPoint, Executor executor, RetainableByteBufferPool bufferPool, ControlParser parser)
{
super(endPoint, executor);
this.byteBufferPool = byteBufferPool;
this.bufferPool = bufferPool;
this.parser = parser;
}
@ -57,17 +58,18 @@ public class ControlStreamConnection extends AbstractConnection implements Conne
public void onUpgradeTo(ByteBuffer upgrade)
{
int capacity = Math.max(upgrade.remaining(), getInputBufferSize());
buffer = byteBufferPool.acquire(capacity, isUseInputDirectByteBuffers());
int position = BufferUtil.flipToFill(buffer);
buffer.put(upgrade);
BufferUtil.flipToFlush(buffer, position);
buffer = bufferPool.acquire(capacity, isUseInputDirectByteBuffers());
ByteBuffer byteBuffer = buffer.getByteBuffer();
int position = BufferUtil.flipToFill(byteBuffer);
byteBuffer.put(upgrade);
BufferUtil.flipToFlush(byteBuffer, position);
}
@Override
public void onOpen()
{
super.onOpen();
if (BufferUtil.hasContent(buffer))
if (buffer != null && buffer.hasRemaining())
onFillable();
else
fillInterested();
@ -79,28 +81,28 @@ public class ControlStreamConnection extends AbstractConnection implements Conne
try
{
if (buffer == null)
buffer = byteBufferPool.acquire(getInputBufferSize(), isUseInputDirectByteBuffers());
buffer = bufferPool.acquire(getInputBufferSize(), isUseInputDirectByteBuffers());
ByteBuffer byteBuffer = buffer.getByteBuffer();
while (true)
{
// Parse first in case of bytes from the upgrade.
parser.parse(buffer);
parser.parse(byteBuffer);
// Then read from the EndPoint.
int filled = getEndPoint().fill(buffer);
int filled = getEndPoint().fill(byteBuffer);
if (LOG.isDebugEnabled())
LOG.debug("filled {} on {}", filled, this);
if (filled == 0)
{
byteBufferPool.release(buffer);
buffer.release();
buffer = null;
fillInterested();
break;
}
else if (filled < 0)
{
byteBufferPool.release(buffer);
buffer.release();
buffer = null;
getEndPoint().close();
break;
@ -111,7 +113,7 @@ public class ControlStreamConnection extends AbstractConnection implements Conne
{
if (LOG.isDebugEnabled())
LOG.debug("could not process control stream {}", getEndPoint(), x);
byteBufferPool.release(buffer);
buffer.release();
buffer = null;
getEndPoint().close(x);
}

View File

@ -18,8 +18,8 @@ import java.util.concurrent.Executor;
import org.eclipse.jetty.http3.qpack.QpackEncoder;
import org.eclipse.jetty.http3.qpack.QpackException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RetainableByteBufferPool;
public class DecoderStreamConnection extends InstructionStreamConnection
{
@ -28,9 +28,9 @@ public class DecoderStreamConnection extends InstructionStreamConnection
private final QpackEncoder encoder;
public DecoderStreamConnection(EndPoint endPoint, Executor executor, ByteBufferPool byteBufferPool, QpackEncoder encoder)
public DecoderStreamConnection(EndPoint endPoint, Executor executor, RetainableByteBufferPool bufferPool, QpackEncoder encoder)
{
super(endPoint, executor, byteBufferPool);
super(endPoint, executor, bufferPool);
this.encoder = encoder;
}

Some files were not shown because too many files have changed in this diff Show More