Search in sources :

Example 26 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class HttpReadListener method handleEventWithNoRunningRequest.

public void handleEventWithNoRunningRequest(final ConduitStreamSourceChannel channel) {
    PooledByteBuffer existing = connection.getExtraBytes();
    if ((existing == null && connection.getOriginalSourceConduit().isReadShutdown()) || connection.getOriginalSinkConduit().isWriteShutdown()) {
        IoUtils.safeClose(connection);
        channel.suspendReads();
        return;
    }
    final PooledByteBuffer pooled = existing == null ? connection.getByteBufferPool().allocate() : existing;
    final ByteBuffer buffer = pooled.getBuffer();
    boolean free = true;
    try {
        int res;
        boolean bytesRead = false;
        do {
            if (existing == null) {
                buffer.clear();
                try {
                    res = channel.read(buffer);
                } catch (IOException e) {
                    UndertowLogger.REQUEST_IO_LOGGER.debug("Error reading request", e);
                    IoUtils.safeClose(connection);
                    return;
                }
            } else {
                res = buffer.remaining();
            }
            if (res <= 0) {
                if (bytesRead && parseTimeoutUpdater != null) {
                    parseTimeoutUpdater.failedParse();
                }
                handleFailedRead(channel, res);
                return;
            } else {
                bytesRead = true;
            }
            if (existing != null) {
                existing = null;
                connection.setExtraBytes(null);
            } else {
                buffer.flip();
            }
            int begin = buffer.remaining();
            if (httpServerExchange == null) {
                httpServerExchange = new HttpServerExchange(connection, maxEntitySize);
            }
            parser.handle(buffer, state, httpServerExchange);
            if (buffer.hasRemaining()) {
                free = false;
                connection.setExtraBytes(pooled);
            }
            int total = read + (begin - buffer.remaining());
            read = total;
            if (read > maxRequestSize) {
                UndertowLogger.REQUEST_LOGGER.requestHeaderWasTooLarge(connection.getPeerAddress(), maxRequestSize);
                sendBadRequestAndClose(connection.getChannel(), null);
                return;
            }
        } while (!state.isComplete());
        if (parseTimeoutUpdater != null) {
            parseTimeoutUpdater.requestStarted();
        }
        final HttpServerExchange httpServerExchange = this.httpServerExchange;
        httpServerExchange.setRequestScheme(connection.getSslSession() != null ? "https" : "http");
        this.httpServerExchange = null;
        requestStateUpdater.set(this, 1);
        if (httpServerExchange.getProtocol() == Protocols.HTTP_2_0) {
            free = handleHttp2PriorKnowledge(pooled, httpServerExchange);
            return;
        }
        if (!allowUnknownProtocols) {
            HttpString protocol = httpServerExchange.getProtocol();
            if (protocol != Protocols.HTTP_1_1 && protocol != Protocols.HTTP_1_0 && protocol != Protocols.HTTP_0_9) {
                UndertowLogger.REQUEST_IO_LOGGER.debugf("Closing connection from %s due to unknown protocol %s", connection.getChannel().getPeerAddress(), protocol);
                sendBadRequestAndClose(connection.getChannel(), new IOException());
                return;
            }
        }
        HttpTransferEncoding.setupRequest(httpServerExchange);
        if (recordRequestStartTime) {
            Connectors.setRequestStartTime(httpServerExchange);
        }
        connection.setCurrentExchange(httpServerExchange);
        if (connectorStatistics != null) {
            connectorStatistics.setup(httpServerExchange);
        }
        if (connection.getSslSession() != null) {
            //TODO: figure out a better solution for this
            //in order to improve performance we do not generally suspend reads, instead we a CAS to detect when
            //data arrives while a request is running and suspend lazily, as suspend/resume is relatively expensive
            //however this approach does not work for SSL, as the underlying channel is not thread safe
            //so we just suspend every time (the overhead is likely much less than the general SSL overhead anyway)
            channel.suspendReads();
        }
        if (requireHostHeader && !httpServerExchange.getRequestHeaders().contains(Headers.HOST)) {
            if (httpServerExchange.getProtocol().equals(Protocols.HTTP_1_1)) {
                sendBadRequestAndClose(connection.getChannel(), UndertowMessages.MESSAGES.noHostInHttp11Request());
                return;
            }
        }
        Connectors.executeRootHandler(connection.getRootHandler(), httpServerExchange);
    } catch (Exception e) {
        sendBadRequestAndClose(connection.getChannel(), e);
        return;
    } finally {
        if (free)
            pooled.close();
    }
}
Also used : HttpServerExchange(io.undertow.server.HttpServerExchange) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) IOException(java.io.IOException) HttpString(io.undertow.util.HttpString)

Example 27 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class PipeliningBufferingStreamSinkConduit method write.

@Override
public int write(ByteBuffer src) throws IOException {
    if (anyAreSet(state, SHUTDOWN)) {
        throw new ClosedChannelException();
    }
    if (anyAreSet(state, FLUSHING)) {
        boolean res = flushBuffer();
        if (!res) {
            return 0;
        }
    }
    PooledByteBuffer pooled = this.buffer;
    if (pooled == null) {
        this.buffer = pooled = pool.allocate();
    }
    final ByteBuffer buffer = pooled.getBuffer();
    if (buffer.remaining() > src.remaining()) {
        int put = src.remaining();
        buffer.put(src);
        return put;
    } else {
        return (int) flushBufferWithUserData(new ByteBuffer[] { src }, 0, 1);
    }
}
Also used : ClosedChannelException(java.nio.channels.ClosedChannelException) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer)

Example 28 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class AbstractFramedChannel method receive.

/**
     * receive method, returns null if no frame is ready. Otherwise returns a
     * channel that can be used to read the frame contents.
     * <p>
     * Calling this method can also have the side effect of making additional data available to
     * existing source channels. In general if you suspend receives or don't have some other way
     * of calling this method then it can prevent frame channels for being fully consumed.
     */
public synchronized R receive() throws IOException {
    if (readChannelDone && receiver == null) {
        //however it is much simpler just to have it here
        if (readData != null) {
            readData.close();
            readData = null;
        }
        channel.getSourceChannel().suspendReads();
        channel.getSourceChannel().shutdownReads();
        return null;
    }
    ReferenceCountedPooled pooled = this.readData;
    boolean hasData;
    if (pooled == null) {
        pooled = allocateReferenceCountedBuffer();
        if (pooled == null) {
            return null;
        }
        hasData = false;
    } else if (pooled.isFreed()) {
        //we attempt to re-used an existing buffer
        if (!pooled.tryUnfree()) {
            pooled = allocateReferenceCountedBuffer();
            if (pooled == null) {
                return null;
            }
        } else {
            pooled.getBuffer().limit(pooled.getBuffer().capacity());
        }
        hasData = false;
    } else {
        hasData = pooled.getBuffer().hasRemaining();
    }
    boolean forceFree = false;
    int read = 0;
    try {
        if (!hasData) {
            pooled.getBuffer().clear();
            read = channel.getSourceChannel().read(pooled.getBuffer());
            if (read == 0) {
                //no data, we just free the buffer
                forceFree = true;
                return null;
            } else if (read == -1) {
                forceFree = true;
                readChannelDone = true;
                lastDataRead();
                return null;
            } else if (isLastFrameReceived() && frameDataRemaining == 0) {
                //we got data, although we should have received the last frame
                forceFree = true;
                markReadsBroken(new ClosedChannelException());
            }
            pooled.getBuffer().flip();
        }
        if (frameDataRemaining > 0) {
            if (frameDataRemaining >= pooled.getBuffer().remaining()) {
                frameDataRemaining -= pooled.getBuffer().remaining();
                if (receiver != null) {
                    //we still create a pooled view, this means that if the buffer is still active we can re-used it
                    //which prevents attacks based on sending lots of small fragments
                    ByteBuffer buf = pooled.getBuffer().duplicate();
                    pooled.getBuffer().position(pooled.getBuffer().limit());
                    PooledByteBuffer frameData = pooled.createView(buf);
                    receiver.dataReady(null, frameData);
                } else {
                    //we are dropping a frame
                    pooled.close();
                    readData = null;
                }
                if (frameDataRemaining == 0) {
                    receiver = null;
                }
                return null;
            } else {
                ByteBuffer buf = pooled.getBuffer().duplicate();
                buf.limit((int) (buf.position() + frameDataRemaining));
                pooled.getBuffer().position((int) (pooled.getBuffer().position() + frameDataRemaining));
                frameDataRemaining = 0;
                PooledByteBuffer frameData = pooled.createView(buf);
                if (receiver != null) {
                    receiver.dataReady(null, frameData);
                } else {
                    //we are dropping the frame
                    frameData.close();
                }
                receiver = null;
            }
            //and not by the selector mechanism
            return null;
        }
        FrameHeaderData data = parseFrame(pooled.getBuffer());
        if (data != null) {
            PooledByteBuffer frameData;
            if (data.getFrameLength() >= pooled.getBuffer().remaining()) {
                frameDataRemaining = data.getFrameLength() - pooled.getBuffer().remaining();
                frameData = pooled.createView(pooled.getBuffer().duplicate());
                pooled.getBuffer().position(pooled.getBuffer().limit());
            } else {
                ByteBuffer buf = pooled.getBuffer().duplicate();
                buf.limit((int) (buf.position() + data.getFrameLength()));
                pooled.getBuffer().position((int) (pooled.getBuffer().position() + data.getFrameLength()));
                frameData = pooled.createView(buf);
            }
            AbstractFramedStreamSourceChannel<?, ?, ?> existing = data.getExistingChannel();
            if (existing != null) {
                if (data.getFrameLength() > frameData.getBuffer().remaining()) {
                    receiver = (R) existing;
                }
                existing.dataReady(data, frameData);
                if (isLastFrameReceived()) {
                    handleLastFrame(existing);
                }
                return null;
            } else {
                boolean moreData = data.getFrameLength() > frameData.getBuffer().remaining();
                R newChannel = createChannel(data, frameData);
                if (newChannel != null) {
                    if (!newChannel.isComplete()) {
                        receivers.add(newChannel);
                    }
                    if (moreData) {
                        receiver = newChannel;
                    }
                    if (isLastFrameReceived()) {
                        handleLastFrame(newChannel);
                    }
                } else {
                    frameData.close();
                }
                return newChannel;
            }
        }
        return null;
    } catch (IOException | RuntimeException e) {
        //something has code wrong with parsing, close the read side
        //we don't close the write side, as the underlying implementation will most likely want to send an error
        markReadsBroken(e);
        forceFree = true;
        throw e;
    } finally {
        //which will make readData null
        if (readData != null) {
            if (!pooled.getBuffer().hasRemaining() || forceFree) {
                if (pooled.getBuffer().limit() * 2 > pooled.getBuffer().capacity() || forceFree) {
                    //if we have used more than half the buffer we don't allow it to be re-aquired
                    readData = null;
                }
                //even though this is freed we may un-free it if we get a new packet
                //this prevents many small reads resulting in a large number of allocated buffers
                pooled.close();
            }
        }
    }
}
Also used : ClosedChannelException(java.nio.channels.ClosedChannelException) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ReferenceCountedPooled(io.undertow.util.ReferenceCountedPooled) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer)

Example 29 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class AbstractFramedChannel method flushSenders.

/**
     * Flushes all ready stream sink conduits to the channel.
     * <p>
     * Frames will be batched up, to allow them all to be written out via a gathering
     * write. The {@link #framePriority} implementation will be invoked to decide which
     * frames are eligible for sending and in what order.
     */
protected synchronized void flushSenders() {
    if (flushingSenders) {
        throw UndertowMessages.MESSAGES.recursiveCallToFlushingSenders();
    }
    flushingSenders = true;
    try {
        int toSend = 0;
        while (!newFrames.isEmpty()) {
            S frame = newFrames.poll();
            frame.preWrite();
            if (framePriority.insertFrame(frame, pendingFrames)) {
                if (!heldFrames.isEmpty()) {
                    framePriority.frameAdded(frame, pendingFrames, heldFrames);
                }
            } else {
                heldFrames.add(frame);
            }
        }
        boolean finalFrame = false;
        ListIterator<S> it = pendingFrames.listIterator();
        while (it.hasNext()) {
            S sender = it.next();
            if (sender.isReadyForFlush()) {
                ++toSend;
            } else {
                break;
            }
            if (sender.isLastFrame()) {
                finalFrame = true;
            }
        }
        if (toSend == 0) {
            //if there is nothing to send we just attempt a flush on the underlying channel
            try {
                if (channel.getSinkChannel().flush()) {
                    channel.getSinkChannel().suspendWrites();
                }
            } catch (IOException e) {
                safeClose(channel);
                markWritesBroken(e);
            }
            return;
        }
        ByteBuffer[] data = new ByteBuffer[toSend * 3];
        int j = 0;
        it = pendingFrames.listIterator();
        try {
            while (j < toSend) {
                S next = it.next();
                //todo: rather than adding empty buffers just store the offsets
                SendFrameHeader frameHeader = next.getFrameHeader();
                PooledByteBuffer frameHeaderByteBuffer = frameHeader.getByteBuffer();
                ByteBuffer frameTrailerBuffer = frameHeader.getTrailer();
                data[j * 3] = frameHeaderByteBuffer != null ? frameHeaderByteBuffer.getBuffer() : Buffers.EMPTY_BYTE_BUFFER;
                data[(j * 3) + 1] = next.getBuffer() == null ? Buffers.EMPTY_BYTE_BUFFER : next.getBuffer();
                data[(j * 3) + 2] = frameTrailerBuffer != null ? frameTrailerBuffer : Buffers.EMPTY_BYTE_BUFFER;
                ++j;
            }
            long toWrite = Buffers.remaining(data);
            long res;
            do {
                res = channel.getSinkChannel().write(data);
                toWrite -= res;
            } while (res > 0 && toWrite > 0);
            int max = toSend;
            while (max > 0) {
                S sinkChannel = pendingFrames.get(0);
                PooledByteBuffer frameHeaderByteBuffer = sinkChannel.getFrameHeader().getByteBuffer();
                ByteBuffer frameTrailerBuffer = sinkChannel.getFrameHeader().getTrailer();
                if (frameHeaderByteBuffer != null && frameHeaderByteBuffer.getBuffer().hasRemaining() || sinkChannel.getBuffer() != null && sinkChannel.getBuffer().hasRemaining() || frameTrailerBuffer != null && frameTrailerBuffer.hasRemaining()) {
                    break;
                }
                sinkChannel.flushComplete();
                pendingFrames.remove(sinkChannel);
                max--;
            }
            if (!pendingFrames.isEmpty() || !channel.getSinkChannel().flush()) {
                channel.getSinkChannel().resumeWrites();
            } else {
                channel.getSinkChannel().suspendWrites();
            }
            if (pendingFrames.isEmpty() && finalFrame) {
                //all data has been sent. Close gracefully
                channel.getSinkChannel().shutdownWrites();
                if (!channel.getSinkChannel().flush()) {
                    channel.getSinkChannel().setWriteListener(ChannelListeners.flushingChannelListener(null, null));
                    channel.getSinkChannel().resumeWrites();
                }
            }
        } catch (IOException e) {
            safeClose(channel);
            markWritesBroken(e);
        }
    } finally {
        flushingSenders = false;
        if (!newFrames.isEmpty()) {
            runInIoThread(new Runnable() {

                @Override
                public void run() {
                    flushSenders();
                }
            });
        }
    }
}
Also used : PooledByteBuffer(io.undertow.connector.PooledByteBuffer) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer)

Example 30 with PooledByteBuffer

use of io.undertow.connector.PooledByteBuffer in project undertow by undertow-io.

the class StringReadChannelListener method setup.

public void setup(final StreamSourceChannel channel) {
    PooledByteBuffer resource = bufferPool.allocate();
    ByteBuffer buffer = resource.getBuffer();
    try {
        int r = 0;
        do {
            r = channel.read(buffer);
            if (r == 0) {
                channel.getReadSetter().set(this);
                channel.resumeReads();
            } else if (r == -1) {
                stringDone(string.extract());
                IoUtils.safeClose(channel);
            } else {
                buffer.flip();
                string.write(buffer);
            }
        } while (r > 0);
    } catch (IOException e) {
        error(e);
    } finally {
        resource.close();
    }
}
Also used : PooledByteBuffer(io.undertow.connector.PooledByteBuffer) IOException(java.io.IOException) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ByteBuffer(java.nio.ByteBuffer)

Aggregations

PooledByteBuffer (io.undertow.connector.PooledByteBuffer)54 ByteBuffer (java.nio.ByteBuffer)45 IOException (java.io.IOException)28 ImmediatePooledByteBuffer (io.undertow.util.ImmediatePooledByteBuffer)9 StreamSourceChannel (org.xnio.channels.StreamSourceChannel)8 HttpServerExchange (io.undertow.server.HttpServerExchange)7 ClosedChannelException (java.nio.channels.ClosedChannelException)6 ByteArrayOutputStream (java.io.ByteArrayOutputStream)5 ChannelListener (org.xnio.ChannelListener)5 HttpHandler (io.undertow.server.HttpHandler)4 StreamSinkChannel (org.xnio.channels.StreamSinkChannel)4 SendFrameHeader (io.undertow.server.protocol.framed.SendFrameHeader)3 HeaderMap (io.undertow.util.HeaderMap)3 HttpString (io.undertow.util.HttpString)3 InterruptedIOException (java.io.InterruptedIOException)3 ByteBufferPool (io.undertow.connector.ByteBufferPool)2 CharBuffer (java.nio.CharBuffer)2 CharsetDecoder (java.nio.charset.CharsetDecoder)2 IoCallback (io.undertow.io.IoCallback)1 Sender (io.undertow.io.Sender)1