Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ByteChannelContentSource #11910

Merged
merged 14 commits into from
Jun 24, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,17 @@ public PathRequestContent(String contentType, Path filePath) throws IOException

public PathRequestContent(String contentType, Path filePath, int bufferSize) throws IOException
{
this(contentType, filePath, null);
setBufferSize(bufferSize);
this(contentType, filePath, new ByteBufferPool.Sized(null, false, bufferSize));
}

public PathRequestContent(String contentType, Path filePath, ByteBufferPool bufferPool) throws IOException
{
super(filePath, bufferPool);
this(contentType, filePath, bufferPool instanceof ByteBufferPool.Sized sized ? sized : new ByteBufferPool.Sized(bufferPool));
}

public PathRequestContent(String contentType, Path filePath, ByteBufferPool.Sized sizedBufferPool)
{
super(filePath, sizedBufferPool);
this.contentType = contentType;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.MultiPart;
import org.eclipse.jetty.http.MultiPartFormData;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
Expand Down Expand Up @@ -283,8 +284,7 @@ protected void process(MultiPartFormData.Parts parts) throws Exception
});

MultiPartRequestContent multiPart = new MultiPartRequestContent();
PathRequestContent content = new PathRequestContent(contentType, tmpPath, client.getByteBufferPool());
content.setUseDirectByteBuffers(client.isUseOutputDirectByteBuffers());
PathRequestContent content = new PathRequestContent(contentType, tmpPath, new ByteBufferPool.Sized(client.getByteBufferPool(), client.isUseOutputDirectByteBuffers(), -1));
multiPart.addPart(new MultiPart.ContentSourcePart(name, tmpPath.getFileName().toString(), null, content));
multiPart.close();
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@

import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.content.ByteBufferContentSource;
import org.eclipse.jetty.io.content.ByteChannelContentSource;
import org.eclipse.jetty.io.content.ChunksContentSource;
import org.eclipse.jetty.io.content.PathContentSource;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.QuotedStringTokenizer;
Expand Down Expand Up @@ -475,7 +475,8 @@ public Path getPath()
@Override
public Content.Source newContentSource()
{
return new PathContentSource(getPath());
// TODO: use a ByteBuffer pool and direct ByteBuffers?
gregw marked this conversation as resolved.
Show resolved Hide resolved
return new ByteChannelContentSource.PathContentSource(getPath());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Iterator;
Expand All @@ -26,6 +24,7 @@
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.IOResources;
import org.eclipse.jetty.io.content.ByteChannelContentSource;
import org.eclipse.jetty.io.content.ContentSourceCompletableFuture;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.thread.AutoLock;
Expand Down Expand Up @@ -165,46 +164,14 @@ protected int fillBufferFromInputStream(InputStream inputStream, byte[] buffer)
}

/**
* <p>A specialized {@link org.eclipse.jetty.io.content.PathContentSource}
* <p>A specialized {@link org.eclipse.jetty.io.content.ByteChannelContentSource.PathContentSource}
* whose content is sliced by a byte range.</p>
*/
public static class PathContentSource extends org.eclipse.jetty.io.content.PathContentSource
public static class PathContentSource extends ByteChannelContentSource.PathContentSource
{
private final ByteRange byteRange;
private long toRead;

public PathContentSource(Path path, ByteRange byteRange)
{
super(path);
this.byteRange = byteRange;
}

@Override
protected SeekableByteChannel open() throws IOException
{
SeekableByteChannel channel = super.open();
channel.position(byteRange.first());
toRead = byteRange.getLength();
return channel;
}

@Override
protected int read(SeekableByteChannel channel, ByteBuffer byteBuffer) throws IOException
{
int read = super.read(channel, byteBuffer);
if (read <= 0)
return read;

read = (int)Math.min(read, toRead);
toRead -= read;
byteBuffer.position(read);
return read;
}

@Override
protected boolean isReadComplete(long read)
{
return read == byteRange.getLength();
super(new ByteBufferPool.Sized(null), path, byteRange.first(), byteRange.getLength());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.eclipse.jetty.util.BufferUtil;

Expand Down Expand Up @@ -92,6 +93,56 @@ public void clear()
}
}

/**
* A ByteBufferPool with an additional no-args {@link #acquire()} method to obtain a buffer of a
* preconfigured specific size and type.
*/
class Sized extends Wrapper
gregw marked this conversation as resolved.
Show resolved Hide resolved
{
private final boolean _direct;
private final int _size;

/**
* Create a sized pool for non direct buffers of a default size from a wrapped pool.
* @param wrapped The actual {@link ByteBufferPool}
*/
public Sized(ByteBufferPool wrapped)
{
this(wrapped, false, -1);
}

/**
* Create a sized pool for a give directness and size from a wrapped pool.
* @param wrapped The actual {@link ByteBufferPool}
* @param direct {@code true} for direct buffers.
* @param size The specified size in bytes of the buffer, or -1 for a default
*/
public Sized(ByteBufferPool wrapped, boolean direct, int size)
{
super(Objects.requireNonNullElse(wrapped, NON_POOLING));
_direct = direct;
_size = size > 0 ? size : 4096;
}

public boolean isDirect()
{
return _direct;
}

public int getSize()
{
return _size;
}

/**
* @return A {@link RetainableByteBuffer} suitable for the specified preconfigured size and type.
*/
public RetainableByteBuffer acquire()
{
return getWrapped().acquire(_size, _direct);
}
}

/**
* <p>A {@link ByteBufferPool} that does not pool its
* {@link RetainableByteBuffer}s.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
import java.nio.file.Path;

import org.eclipse.jetty.io.content.ByteBufferContentSource;
import org.eclipse.jetty.io.content.ByteChannelContentSource;
import org.eclipse.jetty.io.content.InputStreamContentSource;
import org.eclipse.jetty.io.content.PathContentSource;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;
Expand Down Expand Up @@ -137,13 +137,7 @@ public static Content.Source asContentSource(Resource resource, ByteBufferPool b
Path path = resource.getPath();
if (path != null)
{
PathContentSource pathContentSource = new PathContentSource(path, bufferPool);
if (bufferSize > 0)
{
pathContentSource.setBufferSize(bufferSize);
pathContentSource.setUseDirectByteBuffers(direct);
}
return pathContentSource;
return new ByteChannelContentSource.PathContentSource(new ByteBufferPool.Sized(bufferPool, direct, bufferSize), path);
}
if (resource instanceof MemoryResource memoryResource)
{
Expand Down Expand Up @@ -187,13 +181,7 @@ public static Content.Source asContentSource(Resource resource, ByteBufferPool b
Path path = resource.getPath();
if (path != null)
{
RangedPathContentSource contentSource = new RangedPathContentSource(path, bufferPool, first, length);
if (bufferSize > 0)
{
contentSource.setBufferSize(bufferSize);
contentSource.setUseDirectByteBuffers(direct);
}
return contentSource;
return new ByteChannelContentSource.PathContentSource(new ByteBufferPool.Sized(bufferPool, direct, bufferSize), path, first, length);
}

// Try an optimization for MemoryResource.
Expand All @@ -206,13 +194,7 @@ public static Content.Source asContentSource(Resource resource, ByteBufferPool b
InputStream inputStream = resource.newInputStream();
if (inputStream == null)
throw new IllegalArgumentException("Resource does not support InputStream: " + resource);
RangedInputStreamContentSource contentSource = new RangedInputStreamContentSource(inputStream, bufferPool, first, length);
if (bufferSize > 0)
{
contentSource.setBufferSize(bufferSize);
contentSource.setUseDirectByteBuffers(direct);
}
return contentSource;
return new RangedInputStreamContentSource(inputStream, new ByteBufferPool.Sized(bufferPool, direct, bufferSize), first, length);
}
catch (IOException e)
{
Expand Down Expand Up @@ -430,57 +412,6 @@ protected void onCompleteFailure(Throwable x)
}
}

/**
* <p>A specialized {@link PathContentSource}
* whose content is sliced by a byte range.</p>
*/
private static class RangedPathContentSource extends PathContentSource
{
private final long first;
private final long length;
private long toRead;

public RangedPathContentSource(Path path, ByteBufferPool bufferPool, long first, long length)
{
super(path, bufferPool);
// TODO perform sanity checks on first and length?
this.first = first;
this.length = length;
}

@Override
protected SeekableByteChannel open() throws IOException
{
SeekableByteChannel channel = super.open();
if (first > -1)
channel.position(first);
toRead = length;
return channel;
}

@Override
protected int read(SeekableByteChannel channel, ByteBuffer byteBuffer) throws IOException
{
int read = super.read(channel, byteBuffer);
if (read <= 0)
return read;

read = (int)Math.min(read, toRead);
if (read > -1)
{
toRead -= read;
byteBuffer.position(read);
}
return read;
}

@Override
protected boolean isReadComplete(long read)
{
return read == length;
}
}

/**
* <p>A specialized {@link InputStreamContentSource}
* whose content is sliced by a byte range.</p>
Expand Down
Loading
Loading