use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.
the class Http2SettingsStreamSinkChannel method createFrameHeaderImpl.
@Override
protected SendFrameHeader createFrameHeaderImpl() {
PooledByteBuffer pooled = getChannel().getBufferPool().allocate();
ByteBuffer currentBuffer = pooled.getBuffer();
if (settings != null) {
int size = settings.size() * 6;
currentBuffer.put((byte) ((size >> 16) & 0xFF));
currentBuffer.put((byte) ((size >> 8) & 0xFF));
currentBuffer.put((byte) (size & 0xFF));
// type
currentBuffer.put((byte) Http2Channel.FRAME_TYPE_SETTINGS);
// flags
currentBuffer.put((byte) 0);
Http2ProtocolUtils.putInt(currentBuffer, getStreamId());
for (Http2Setting setting : settings) {
currentBuffer.put((byte) ((setting.getId() >> 8) & 0xFF));
currentBuffer.put((byte) (setting.getId() & 0xFF));
currentBuffer.put((byte) ((setting.getValue() >> 24) & 0xFF));
currentBuffer.put((byte) ((setting.getValue() >> 16) & 0xFF));
currentBuffer.put((byte) ((setting.getValue() >> 8) & 0xFF));
currentBuffer.put((byte) (setting.getValue() & 0xFF));
}
} else {
currentBuffer.put((byte) 0);
currentBuffer.put((byte) 0);
currentBuffer.put((byte) 0);
// type
currentBuffer.put((byte) Http2Channel.FRAME_TYPE_SETTINGS);
// flags
currentBuffer.put((byte) Http2Channel.SETTINGS_FLAG_ACK);
Http2ProtocolUtils.putInt(currentBuffer, getStreamId());
}
currentBuffer.flip();
return new SendFrameHeader(pooled);
}
use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.
the class SslConduit method doUnwrap.
/**
* Unwrap channel data into the user buffers. If no user buffer is supplied (e.g. during handshaking) then the
* unwrap will happen into the channels unwrap buffer.
*
* If some data has already been unwrapped it will simply be copied into the user buffers
* and no unwrap will actually take place.
*
* @return true if the unwrap operation made progress, false otherwise
* @throws SSLException
*/
private synchronized long doUnwrap(ByteBuffer[] userBuffers, int off, int len) throws IOException {
if (anyAreSet(state, FLAG_CLOSED)) {
throw new ClosedChannelException();
}
if (outstandingTasks > 0) {
return 0;
}
if (anyAreSet(state, FLAG_READ_REQUIRES_WRITE)) {
doWrap(null, 0, 0);
if (allAreClear(state, FLAG_WRITE_REQUIRES_READ)) {
// unless a wrap is immediately required we just return
return 0;
}
}
boolean bytesProduced = false;
PooledByteBuffer unwrappedData = this.unwrappedData;
// copy any exiting data
if (unwrappedData != null) {
if (userBuffers != null) {
long copied = Buffers.copy(userBuffers, off, len, unwrappedData.getBuffer());
if (!unwrappedData.getBuffer().hasRemaining()) {
unwrappedData.close();
this.unwrappedData = null;
}
if (copied > 0) {
readListenerInvocationCount = 0;
}
return copied;
}
}
try {
// we need to store how much data is in the unwrap buffer. If no progress can be made then we unset
// the data to unwrap flag
int dataToUnwrapLength;
// try and read some data if we don't already have some
if (allAreClear(state, FLAG_DATA_TO_UNWRAP)) {
if (dataToUnwrap == null) {
dataToUnwrap = bufferPool.allocate();
}
int res;
try {
res = source.read(dataToUnwrap.getBuffer());
} catch (IOException | RuntimeException | Error e) {
dataToUnwrap.close();
dataToUnwrap = null;
throw e;
}
dataToUnwrap.getBuffer().flip();
if (res == -1) {
dataToUnwrap.close();
dataToUnwrap = null;
notifyReadClosed();
return -1;
} else if (res == 0 && engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
// if not we just close the buffer so it does not hang around
if (!dataToUnwrap.getBuffer().hasRemaining()) {
dataToUnwrap.close();
dataToUnwrap = null;
}
return 0;
}
}
dataToUnwrapLength = dataToUnwrap.getBuffer().remaining();
long original = 0;
if (userBuffers != null) {
original = Buffers.remaining(userBuffers);
}
// perform the actual unwrap operation
// if possible this is done into the the user buffers, however
// if none are supplied or this results in a buffer overflow then we allocate our own
SSLEngineResult result;
boolean unwrapBufferUsed = false;
try {
if (userBuffers != null) {
result = engine.unwrap(this.dataToUnwrap.getBuffer(), userBuffers, off, len);
if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
// not enough space in the user buffers
// we use our own
unwrappedData = bufferPool.allocate();
ByteBuffer[] d = new ByteBuffer[len + 1];
System.arraycopy(userBuffers, off, d, 0, len);
d[len] = unwrappedData.getBuffer();
result = engine.unwrap(this.dataToUnwrap.getBuffer(), d);
unwrapBufferUsed = true;
}
bytesProduced = result.bytesProduced() > 0;
} else {
unwrapBufferUsed = true;
if (unwrappedData == null) {
unwrappedData = bufferPool.allocate();
} else {
unwrappedData.getBuffer().compact();
}
result = engine.unwrap(this.dataToUnwrap.getBuffer(), unwrappedData.getBuffer());
bytesProduced = result.bytesProduced() > 0;
}
} finally {
if (unwrapBufferUsed) {
unwrappedData.getBuffer().flip();
if (!unwrappedData.getBuffer().hasRemaining()) {
unwrappedData.close();
unwrappedData = null;
}
}
this.unwrappedData = unwrappedData;
}
if (result.getStatus() == SSLEngineResult.Status.CLOSED) {
if (dataToUnwrap != null) {
dataToUnwrap.close();
dataToUnwrap = null;
}
notifyReadClosed();
return -1;
}
if (!handleHandshakeResult(result)) {
if (this.dataToUnwrap.getBuffer().hasRemaining() && result.getStatus() != SSLEngineResult.Status.BUFFER_UNDERFLOW && dataToUnwrap.getBuffer().remaining() != dataToUnwrapLength) {
state |= FLAG_DATA_TO_UNWRAP;
} else {
state &= ~FLAG_DATA_TO_UNWRAP;
}
return 0;
}
if (result.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
state &= ~FLAG_DATA_TO_UNWRAP;
} else if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
UndertowLogger.REQUEST_LOGGER.sslBufferOverflow(this);
IoUtils.safeClose(delegate);
} else if (this.dataToUnwrap.getBuffer().hasRemaining() && dataToUnwrap.getBuffer().remaining() != dataToUnwrapLength) {
state |= FLAG_DATA_TO_UNWRAP;
} else {
state &= ~FLAG_DATA_TO_UNWRAP;
}
if (userBuffers == null) {
return 0;
} else {
long res = original - Buffers.remaining(userBuffers);
if (res > 0) {
// if data has been successfully returned this is not a read loop
readListenerInvocationCount = 0;
}
return res;
}
} catch (SSLException e) {
try {
try {
// we make an effort to write out the final record
// this is best effort, there are no guarantees
clearWriteRequiresRead();
doWrap(null, 0, 0);
flush();
} catch (Exception e2) {
UndertowLogger.REQUEST_LOGGER.debug("Failed to write out final SSL record", e2);
}
close();
} catch (Throwable ex) {
// we ignore this
UndertowLogger.REQUEST_LOGGER.debug("Exception closing SSLConduit after exception in doUnwrap", ex);
}
throw e;
} catch (RuntimeException | IOException | Error e) {
try {
close();
} catch (Throwable ex) {
// we ignore this
UndertowLogger.REQUEST_LOGGER.debug("Exception closing SSLConduit after exception in doUnwrap", ex);
}
throw e;
} finally {
// if there is data in the buffer and reads are resumed we should re-run the listener
boolean requiresListenerInvocation = false;
// we always need to re-invoke if bytes have been produced, as the engine may have buffered some data
if (bytesProduced || (unwrappedData != null && unwrappedData.isOpen() && unwrappedData.getBuffer().hasRemaining())) {
requiresListenerInvocation = true;
}
if (dataToUnwrap != null) {
// if there is no data in the buffer we just free it
if (!dataToUnwrap.getBuffer().hasRemaining()) {
dataToUnwrap.close();
dataToUnwrap = null;
state &= ~FLAG_DATA_TO_UNWRAP;
} else if (allAreClear(state, FLAG_DATA_TO_UNWRAP)) {
// if there is not enough data in the buffer we compact it to make room for more
dataToUnwrap.getBuffer().compact();
} else {
// there is more data, make sure we trigger a read listener invocation
requiresListenerInvocation = true;
}
}
// as it is about to be invoked anyway
if (requiresListenerInvocation && (anyAreSet(state, FLAG_READS_RESUMED) || allAreSet(state, FLAG_WRITE_REQUIRES_READ | FLAG_WRITES_RESUMED)) && !invokingReadListenerHandshake) {
runReadListener(false);
}
}
}
use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.
the class ReadDataStreamSourceConduit method read.
@Override
public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException {
PooledByteBuffer eb = connection.getExtraBytes();
if (eb != null) {
final ByteBuffer buffer = eb.getBuffer();
int result = Buffers.copy(dsts, offs, len, buffer);
if (!buffer.hasRemaining()) {
eb.close();
connection.setExtraBytes(null);
}
return result;
} else {
return super.read(dsts, offs, len);
}
}
use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.
the class ChunkedStreamSourceConduit method read.
@Override
public int read(final ByteBuffer dst) throws IOException {
boolean invokeFinishListener = false;
try {
long chunkRemaining = chunkReader.getChunkRemaining();
// we have read the last chunk, we just return EOF
if (chunkRemaining == -1) {
if (!finishListenerInvoked) {
invokeFinishListener = true;
}
return -1;
}
if (closed) {
throw new ClosedChannelException();
}
PooledByteBuffer pooled = bufferWrapper.allocate();
ByteBuffer buf = pooled.getBuffer();
boolean free = true;
try {
// we need to do our initial read into a
int r = next.read(buf);
buf.flip();
if (r == -1) {
// Channel is broken, not sure how best to report it
throw new ClosedChannelException();
} else if (r == 0) {
return 0;
}
if (chunkRemaining == 0) {
chunkRemaining = chunkReader.readChunk(buf);
if (chunkRemaining <= 0) {
if (buf.hasRemaining()) {
free = false;
}
if (!finishListenerInvoked && chunkRemaining < 0) {
invokeFinishListener = true;
}
return (int) chunkRemaining;
}
}
final int originalLimit = dst.limit();
try {
// now we may have some stuff in the raw buffer
// or the raw buffer may be exhausted, and we should read directly into the destination buffer
// from the next
int read = 0;
long chunkInBuffer = Math.min(buf.remaining(), chunkRemaining);
int remaining = dst.remaining();
if (chunkInBuffer > remaining) {
// it won't fit
int orig = buf.limit();
buf.limit(buf.position() + remaining);
dst.put(buf);
buf.limit(orig);
chunkRemaining -= remaining;
updateRemainingAllowed(remaining);
free = false;
return remaining;
} else if (buf.hasRemaining()) {
int old = buf.limit();
buf.limit((int) Math.min(old, buf.position() + chunkInBuffer));
try {
dst.put(buf);
} finally {
buf.limit(old);
}
read += chunkInBuffer;
chunkRemaining -= chunkInBuffer;
}
// adjusting the limit as necessary to make sure we do not read too much
if (chunkRemaining > 0) {
int old = dst.limit();
try {
if (chunkRemaining < dst.remaining()) {
dst.limit((int) (dst.position() + chunkRemaining));
}
int c = 0;
do {
c = next.read(dst);
if (c > 0) {
read += c;
chunkRemaining -= c;
}
} while (c > 0 && chunkRemaining > 0);
if (c == -1) {
throw new ClosedChannelException();
}
} finally {
dst.limit(old);
}
} else {
free = false;
}
updateRemainingAllowed(read);
return read;
} finally {
// buffer will be freed if not needed in exitRead
dst.limit(originalLimit);
}
} finally {
if (chunkRemaining >= 0) {
chunkReader.setChunkRemaining(chunkRemaining);
}
if (!free && buf.hasRemaining()) {
bufferWrapper.pushBack(pooled);
} else {
pooled.close();
}
}
} catch (IOException | RuntimeException | Error e) {
IoUtils.safeClose(closeable);
throw e;
} finally {
if (invokeFinishListener) {
finishListenerInvoked = true;
finishListener.handleEvent(this);
}
}
}
use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.
the class DeflatingStreamSinkConduit method deflateData.
/**
* Runs the current data through the deflater. As much as possible this will be buffered in the current output
* stream.
*
* @throws IOException
*/
private void deflateData(boolean force) throws IOException {
// we don't need to flush here, as this should have been called already by the time we get to
// this point
boolean nextCreated = false;
try (PooledByteBuffer arrayPooled = this.exchange.getConnection().getByteBufferPool().getArrayBackedPool().allocate()) {
PooledByteBuffer pooled = this.currentBuffer;
final ByteBuffer outputBuffer = pooled.getBuffer();
final boolean shutdown = anyAreSet(state, SHUTDOWN);
ByteBuffer buf = arrayPooled.getBuffer();
while (force || !deflater.needsInput() || (shutdown && !deflater.finished())) {
int count = deflater.deflate(buf.array(), buf.arrayOffset(), buf.remaining(), force ? Deflater.SYNC_FLUSH : Deflater.NO_FLUSH);
Connectors.updateResponseBytesSent(exchange, count);
if (count != 0) {
int remaining = outputBuffer.remaining();
if (remaining > count) {
outputBuffer.put(buf.array(), buf.arrayOffset(), count);
} else {
if (remaining == count) {
outputBuffer.put(buf.array(), buf.arrayOffset(), count);
} else {
outputBuffer.put(buf.array(), buf.arrayOffset(), remaining);
additionalBuffer = ByteBuffer.allocate(count - remaining);
additionalBuffer.put(buf.array(), buf.arrayOffset() + remaining, count - remaining);
additionalBuffer.flip();
}
outputBuffer.flip();
this.state |= FLUSHING_BUFFER;
if (next == null) {
nextCreated = true;
this.next = createNextChannel();
}
if (!performFlushIfRequired()) {
return;
}
}
} else {
force = false;
}
}
} finally {
if (nextCreated) {
if (anyAreSet(state, WRITES_RESUMED)) {
next.resumeWrites();
}
}
}
}
Aggregations