Search in sources :

Example 46 with PooledByteBuffer

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);
}
Also used : PooledByteBuffer(io.undertow.connector.PooledByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ByteBuffer(java.nio.ByteBuffer) SendFrameHeader(io.undertow.server.protocol.framed.SendFrameHeader)

Example 47 with PooledByteBuffer

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);
        }
    }
}
Also used : ClosedChannelException(java.nio.channels.ClosedChannelException) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) SSLException(javax.net.ssl.SSLException) InterruptedIOException(java.io.InterruptedIOException) RejectedExecutionException(java.util.concurrent.RejectedExecutionException) ClosedChannelException(java.nio.channels.ClosedChannelException) IOException(java.io.IOException) SSLException(javax.net.ssl.SSLException) SSLEngineResult(javax.net.ssl.SSLEngineResult) PooledByteBuffer(io.undertow.connector.PooledByteBuffer)

Example 48 with PooledByteBuffer

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);
    }
}
Also used : PooledByteBuffer(io.undertow.connector.PooledByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ByteBuffer(java.nio.ByteBuffer)

Example 49 with PooledByteBuffer

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);
        }
    }
}
Also used : ClosedChannelException(java.nio.channels.ClosedChannelException) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer)

Example 50 with PooledByteBuffer

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();
            }
        }
    }
}
Also used : PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer)

Aggregations

PooledByteBuffer (io.undertow.connector.PooledByteBuffer)58 ByteBuffer (java.nio.ByteBuffer)47 IOException (java.io.IOException)29 ImmediatePooledByteBuffer (io.undertow.util.ImmediatePooledByteBuffer)10 StreamSourceChannel (org.xnio.channels.StreamSourceChannel)8 HttpServerExchange (io.undertow.server.HttpServerExchange)7 ClosedChannelException (java.nio.channels.ClosedChannelException)7 ByteArrayOutputStream (java.io.ByteArrayOutputStream)5 ChannelListener (org.xnio.ChannelListener)5 HttpHandler (io.undertow.server.HttpHandler)4 HeaderMap (io.undertow.util.HeaderMap)4 StreamSinkChannel (org.xnio.channels.StreamSinkChannel)4 SendFrameHeader (io.undertow.server.protocol.framed.SendFrameHeader)3 HttpString (io.undertow.util.HttpString)3 ByteBufferPool (io.undertow.connector.ByteBufferPool)2 HeaderValues (io.undertow.util.HeaderValues)2 InterruptedIOException (java.io.InterruptedIOException)2 CharBuffer (java.nio.CharBuffer)2 CharsetDecoder (java.nio.charset.CharsetDecoder)2 IoCallback (io.undertow.io.IoCallback)1