Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
f6deb79
*** Phase 1 ***
lorban Apr 9, 2026
e9fe96e
*** Phase 2 ***
lorban Jun 3, 2026
ebf84ba
*** Phase 3 ***
lorban Jun 18, 2026
b86f0cd
consume the original buffers along when the wrapping AccumulatingRead…
lorban Jul 7, 2026
ce442d3
fix missing clearing of positions
lorban Jul 7, 2026
e3cfb4c
modify ZstandardDecoderSource to handle transformation of heap buffers
lorban Jul 7, 2026
d9c8b8e
fix incorrect buffer wrapping
lorban Jul 7, 2026
927967f
fix incorrect buffer modes
lorban Jul 7, 2026
d42a4f2
fix incorrect buffer modes
lorban Jul 7, 2026
843a211
fix buffer clearing and consumption reading
lorban Jul 7, 2026
3c2da5b
flatten the AccumulatingReadBuffers when wrapping a list of ReadableB…
lorban Jul 7, 2026
141c959
fix AccumulatingReadBuffer slice(pos,len)
lorban Jul 8, 2026
6c73aa9
fix FCGI failure handling
lorban Jul 8, 2026
578ed02
add missing get*(index) methods
lorban Jul 9, 2026
7c362b5
add more helper methods using the new buffers
lorban Jul 9, 2026
7a8ecf8
modify tries to use the new buffers
lorban Jul 9, 2026
535c772
fix limit
lorban Jul 14, 2026
8a28efc
fix length
lorban Jul 14, 2026
114f981
adapt HTTP/1 parser to new buffer APIs
lorban Jul 14, 2026
e10d9a1
remove incorrect retain()
lorban Jul 14, 2026
891c5c7
fix incorrect buffer consumption
lorban Jul 14, 2026
619b516
disable temporarily invalid assertions
lorban Jul 14, 2026
9cbbbce
fix unneeded retain()
lorban Jul 14, 2026
0ef5443
rework HttpTester to use new buffers API
lorban Jul 14, 2026
bc30452
change Content.Sink.write() API to take a ReadableBuffer
lorban Jul 23, 2026
60b80b9
restore logging file
lorban Jul 23, 2026
aa8fedd
fix buffer leak
lorban Jul 24, 2026
a2e1340
fix NPE when no content is generated
lorban Jul 24, 2026
69a6f54
- implement PathReadBuffer + FileChannel.transferTo() optimization
lorban Jul 28, 2026
d608e04
fix checkstyle
lorban Jul 28, 2026
74f03ec
fix tests
lorban Jul 29, 2026
71ee1f1
fix missing buffer consumption + do not create zero-size slices + cla…
lorban Jul 29, 2026
8717d7f
fix buffer leak
lorban Jul 29, 2026
66f63d9
fix missing call to Target.write() when accumulating buffer is empty
lorban Jul 29, 2026
995a93b
fix chunking buffer handling
lorban Jul 30, 2026
bd6209c
fix GZipHandler
lorban Jul 30, 2026
73ee748
fix notifyOnResponseWriteComplete() such as the buffer passed is not …
lorban Jul 30, 2026
7c73633
reverse the mode of the NIO BB passed to put(RB, BB)
lorban Jul 30, 2026
f6905bb
fix tests
lorban Jul 30, 2026
5a7e565
fix javadoc
lorban Jul 30, 2026
9ff6dc2
fix zstd encoder and decoder
lorban Jul 31, 2026
ef78530
fix get(byte[] b, int off, int len)
lorban Jul 31, 2026
217753e
fix retainability and closing
lorban Jul 31, 2026
2131838
fix flushing of empty buffers
lorban Jul 31, 2026
0e570b8
fix over-release in case of failure
lorban Jul 31, 2026
c0e5c24
add API to make ReadableBuffer read-only + change exception thrown on…
lorban Jul 31, 2026
71bacfe
fix leak
lorban Jul 31, 2026
dc0b5a0
fix test
lorban Jul 31, 2026
0231b2f
fix? tests: timeouts are fired after 4s
lorban Jul 31, 2026
94ebe75
disable assertion on H2 for now
lorban Jul 31, 2026
801587a
fix changed signatures
lorban Jul 31, 2026
ff0d692
fix tests by correctly fliiping nio buffer before and after filling it
lorban Jul 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.eclipse.jetty.util.CompletableTask;
import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.util.buffer.ReadableBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -268,7 +269,7 @@ public String getResult()
static class SinkWrong
{
// tag::sinkWrong[]
public void wrongWrite(Content.Sink sink, ByteBuffer content1, ByteBuffer content2)
public void wrongWrite(Content.Sink sink, ReadableBuffer content1, ReadableBuffer content2)
{
// Initiate a first write.
sink.write(false, content1, Callback.NOOP);
Expand All @@ -282,7 +283,7 @@ public void wrongWrite(Content.Sink sink, ByteBuffer content1, ByteBuffer conten
static class SinkMany
{
// tag::sinkMany[]
public void manyWrites(Content.Sink sink, ByteBuffer content1, ByteBuffer content2)
public void manyWrites(Content.Sink sink, ReadableBuffer content1, ReadableBuffer content2)
{
// Initiate a first write.
// Callback.Completable is-a CompletableFuture.
Expand Down Expand Up @@ -343,7 +344,7 @@ protected Action process() throws Throwable
boolean last = length == 0;

// Start the non-blocking write, passing "this" as the callback.
sink.write(last, byteBuffer, this);
sink.write(last, ReadableBuffer.wrap(byteBuffer), this);
return Action.SCHEDULED;
}

Expand Down Expand Up @@ -410,7 +411,7 @@ protected Action process() throws Throwable
throw chunk.getFailure();

// Copy the chunk by scheduling an asynchronous write.
sink.write(chunk.isLast(), chunk.getByteBuffer(), this);
sink.write(chunk.isLast(), ReadableBuffer.wrap(chunk.getByteBuffer()), this);
return Action.SCHEDULED;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.util.Callback;

@SuppressWarnings("unused")
Expand All @@ -48,12 +49,12 @@ public void dataDemanded() throws Exception
HeadersFrame headersFrame = new HeadersFrame(request, null, true);

// tag::dataUnwrap[]
record Chunk(ByteBuffer byteBuffer, Callback callback)
record Data(ByteBuffer buffer, Callback callback)
{
}

// A queue that consumers poll to consume content asynchronously.
Queue<Chunk> dataQueue = new ConcurrentLinkedQueue<>();
Queue<Data> dataQueue = new ConcurrentLinkedQueue<>();

// Implementation of Stream.Listener.onDataAvailable(Stream stream)
// in case of unwrapping of the Data object for asynchronous content
Expand All @@ -63,26 +64,26 @@ record Chunk(ByteBuffer byteBuffer, Callback callback)
@Override
public void onDataAvailable(Stream stream)
{
Stream.Data data = stream.readData();
Content.Chunk chunk = stream.read();

if (data == null)
if (chunk == null)
{
stream.demand();
return;
}

// Get the content buffer.
ByteBuffer byteBuffer = data.frame().getByteBuffer();
ByteBuffer byteBuffer = chunk.getByteBuffer();

// Unwrap the Data object, converting it to a Chunk.
// The Data.release() semantic is maintained in the completion of the Callback.
dataQueue.offer(new Chunk(byteBuffer, Callback.from(() ->
dataQueue.offer(new Data(byteBuffer, Callback.from(() ->
{
// When the buffer has been consumed, then:
// A) release the Data object.
data.release();
chunk.release();
// B) possibly demand more DATA frames.
if (!data.frame().isEndStream())
if (!chunk.isLast())
stream.demand();
})));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.PushPromiseFrame;
import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.NanoTime;
import org.eclipse.jetty.util.buffer.ReadableBuffer;

import static java.lang.System.Logger.Level.INFO;

Expand Down Expand Up @@ -192,17 +193,17 @@ public void newStreamWithData() throws Exception

// The request content, in two chunks.
String content1 = "{\"greet\": \"hello world\"}";
ByteBuffer buffer1 = StandardCharsets.UTF_8.encode(content1);
ReadableBuffer buffer1 = ReadableBuffer.wrap(StandardCharsets.UTF_8.encode(content1));
String content2 = "{\"user\": \"jetty\"}";
ByteBuffer buffer2 = StandardCharsets.UTF_8.encode(content2);
ReadableBuffer buffer2 = ReadableBuffer.wrap(StandardCharsets.UTF_8.encode(content2));

// Send the first DATA frame on the stream, with endStream=false
// to signal that there are more frames in this stream.
CompletableFuture<Stream> dataCF1 = stream.data(new DataFrame(stream.getId(), buffer1, false));
CompletableFuture<Stream> dataCF1 = stream.data(buffer1, false);

// Only when the first chunk has been sent we can send the second,
// with endStream=true to signal that there are no more frames.
dataCF1.thenCompose(s -> s.data(new DataFrame(s.getId(), buffer2, true)));
dataCF1.thenCompose(s -> s.data(buffer2, true));
// end::newStreamWithData[]
}

Expand Down Expand Up @@ -249,26 +250,26 @@ public void onHeaders(Stream stream, HeadersFrame frame)
@Override
public void onDataAvailable(Stream stream)
{
// Read a Data object.
Stream.Data data = stream.readData();
// Read a Chunk object.
Content.Chunk chunk = stream.read();

if (data == null)
if (chunk == null)
{
// Demand more DATA frames.
stream.demand();
return;
}

// Get the content buffer.
ByteBuffer buffer = data.frame().getByteBuffer();
ByteBuffer buffer = chunk.getByteBuffer();

// Consume the buffer, here - as an example - just log it.
System.getLogger("http2").log(INFO, "Consuming buffer {0}", buffer);

// Tell the implementation that the buffer has been consumed.
data.release();
chunk.release();

if (!data.frame().isEndStream())
if (!chunk.isLast())
{
// Demand more DATA frames when they are available.
stream.demand();
Expand Down Expand Up @@ -365,20 +366,20 @@ public void onDataAvailable(Stream stream)
{
// Handle the pushed stream "response" content.

Stream.Data data = stream.readData();
Content.Chunk chunk = stream.read();

if (data == null)
if (chunk == null)
{
stream.demand();
return;
}

// The pushed stream "response" content bytes.
ByteBuffer buffer = data.frame().getByteBuffer();
ByteBuffer buffer = chunk.getByteBuffer();
// Consume the buffer and release the Data object.
data.release();
chunk.release();

if (!data.frame().isEndStream())
if (!chunk.isLast())
{
// Demand more DATA frames when they are available.
stream.demand();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.eclipse.jetty.quic.quiche.client.QuicheTransport;
import org.eclipse.jetty.util.Blocker;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.buffer.ReadableBuffer;

import static java.lang.System.Logger.Level.INFO;

Expand Down Expand Up @@ -181,14 +182,14 @@ public void newStreamWithData() throws Exception

// Send the first DATA frame on the stream, with last=false
// to signal that there are more frames in this stream.
stream.data(new DataFrame(buffer1, false), new Promise.Invocable.NonBlocking<>()
stream.data(new DataFrame(ReadableBuffer.wrap(buffer1), false), new Promise.Invocable.NonBlocking<>()
{
@Override
public void succeeded(Stream result)
{
// Only when the first chunk has been sent we can send the second,
// with last=true to signal that there will be no more frames.
result.data(new DataFrame(buffer2, true), Promise.Invocable.noop());
result.data(new DataFrame(ReadableBuffer.wrap(buffer2), true), Promise.Invocable.noop());
}
});
// end::newStreamWithData[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.buffer.ReadableBuffer;

import static java.nio.charset.StandardCharsets.UTF_8;

Expand Down Expand Up @@ -608,7 +609,7 @@ public boolean handle(Request request, Response response, Callback callback) thr

// Explicit first write that writes the response status code, headers and content.
// When this write completes, the Handler callback is completed.
response.write(true, content, callback);
response.write(true, ReadableBuffer.wrap(content), callback);

return true;
}
Expand Down Expand Up @@ -639,7 +640,7 @@ public boolean handle(Request request, Response response, Callback callback) thr
{
// Now explicitly write the content as the last write.
// When this write completes, the Handler callback is completed.
response.write(true, content, callback);
response.write(true, ReadableBuffer.wrap(content), callback);
}
else
{
Expand Down Expand Up @@ -706,7 +707,7 @@ public boolean handle(Request request, Response response, Callback callback) thr
// The trailers have not been written yet; they will be written with the last write.
ByteBuffer content = UTF_8.encode("Hello World");
Callback.Completable completable = new Callback.Completable();
response.write(false, content, completable);
response.write(false, ReadableBuffer.wrap(content), completable);

completable.whenComplete((ignored, failure) ->
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.NanoTime;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.buffer.ReadableBuffer;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.ssl.KeyStoreScanner;
Expand Down Expand Up @@ -987,7 +988,7 @@ public boolean handle(Request request, Response response, Callback callback)
.whenComplete((ignored, failure) ->
{
if (failure == null)
response.write(true, UTF_8.encode("HELLO"), callback);
response.write(true, ReadableBuffer.wrap(UTF_8.encode("HELLO")), callback);
else
callback.failed(failure);
});
Expand Down Expand Up @@ -1030,7 +1031,7 @@ public boolean handle(Request request, Response response, Callback callback)
responseHeaders.put(HttpHeader.CONTENT_LENGTH, contentLength);

// Commit the response.
response.write(true, ByteBuffer.wrap(bytes), callback);
response.write(true, ReadableBuffer.wrap(bytes), callback);

// Return true because the callback will eventually be completed.
return true;
Expand Down
Loading
Loading