Search in sources :

Example 1 with SendFrameHeader

use of io.undertow.server.protocol.framed.SendFrameHeader in project undertow by undertow-io.

the class AjpClientFramePriority method frameAdded.

@Override
public void frameAdded(AbstractAjpClientStreamSinkChannel addedFrame, List<AbstractAjpClientStreamSinkChannel> pendingFrames, Deque<AbstractAjpClientStreamSinkChannel> holdFrames) {
    Iterator<AbstractAjpClientStreamSinkChannel> it = holdFrames.iterator();
    while (it.hasNext()) {
        AbstractAjpClientStreamSinkChannel pending = it.next();
        if (pending instanceof AjpClientRequestClientStreamSinkChannel) {
            SendFrameHeader header = ((AjpClientRequestClientStreamSinkChannel) pending).generateSendFrameHeader();
            if (header.getByteBuffer() != null) {
                pendingFrames.add(pending);
                it.remove();
            } else {
                //we clear the header, as we want to generate a new real header when the flow control window is updated
                ((AjpClientRequestClientStreamSinkChannel) pending).clearHeader();
            }
        }
    }
}
Also used : SendFrameHeader(io.undertow.server.protocol.framed.SendFrameHeader)

Example 2 with SendFrameHeader

use of io.undertow.server.protocol.framed.SendFrameHeader in project undertow by undertow-io.

the class Http2FramePriority method frameAdded.

@Override
public void frameAdded(AbstractHttp2StreamSinkChannel addedFrame, List<AbstractHttp2StreamSinkChannel> pendingFrames, Deque<AbstractHttp2StreamSinkChannel> holdFrames) {
    Iterator<AbstractHttp2StreamSinkChannel> it = holdFrames.iterator();
    while (it.hasNext()) {
        AbstractHttp2StreamSinkChannel pending = it.next();
        boolean incrementNextId = false;
        if ((pending.getChannel().isClient() && pending instanceof Http2HeadersStreamSinkChannel) || pending instanceof Http2PushPromiseStreamSinkChannel) {
            if (pending instanceof Http2PushPromiseStreamSinkChannel) {
                int streamId = ((Http2PushPromiseStreamSinkChannel) pending).getStreamId();
                if (streamId > nextId) {
                    continue;
                } else if (streamId == nextId) {
                    incrementNextId = true;
                }
            } else {
                int streamId = ((Http2HeadersStreamSinkChannel) pending).getStreamId();
                if (streamId > nextId) {
                    continue;
                } else if (streamId == nextId) {
                    incrementNextId = true;
                }
            }
        }
        if (pending instanceof Http2StreamSinkChannel) {
            SendFrameHeader header = ((Http2StreamSinkChannel) pending).generateSendFrameHeader();
            if (header.getByteBuffer() != null) {
                pendingFrames.add(pending);
                it.remove();
                it = holdFrames.iterator();
                if (incrementNextId) {
                    nextId += 2;
                }
            } else {
                //we clear the header, as we want to generate a new real header when the flow control window is updated
                ((Http2StreamSinkChannel) pending).clearHeader();
            }
        }
    }
}
Also used : SendFrameHeader(io.undertow.server.protocol.framed.SendFrameHeader)

Example 3 with SendFrameHeader

use of io.undertow.server.protocol.framed.SendFrameHeader in project undertow by undertow-io.

the class Http2FramePriority method insertFrame.

@Override
public boolean insertFrame(AbstractHttp2StreamSinkChannel newFrame, List<AbstractHttp2StreamSinkChannel> pendingFrames) {
    //we need to deal with out of order streams
    //if multiple threads are creating streams they may not end up here in the correct order
    boolean incrementIfAccepted = false;
    if ((newFrame.getChannel().isClient() && newFrame instanceof Http2HeadersStreamSinkChannel) || newFrame instanceof Http2PushPromiseStreamSinkChannel) {
        if (newFrame instanceof Http2PushPromiseStreamSinkChannel) {
            int streamId = ((Http2PushPromiseStreamSinkChannel) newFrame).getStreamId();
            if (streamId > nextId) {
                return false;
            } else if (streamId == nextId) {
                incrementIfAccepted = true;
            }
        } else {
            int streamId = ((Http2HeadersStreamSinkChannel) newFrame).getStreamId();
            if (streamId > nextId) {
                return false;
            } else if (streamId == nextId) {
                incrementIfAccepted = true;
            }
        }
    }
    //first deal with flow control
    if (newFrame instanceof Http2StreamSinkChannel) {
        if (newFrame.isBroken() || !newFrame.isOpen()) {
            //just quietly drop the frame
            return true;
        }
        try {
            SendFrameHeader header = ((Http2StreamSinkChannel) newFrame).generateSendFrameHeader();
            //if no header is generated then flow control means we can't send anything
            if (header.getByteBuffer() == null) {
                //we clear the header, as we want to generate a new real header when the flow control window is updated
                ((Http2StreamSinkChannel) newFrame).clearHeader();
                return false;
            }
        } catch (Exception e) {
            UndertowLogger.REQUEST_LOGGER.debugf("Failed to generate header %s", newFrame);
        }
    }
    pendingFrames.add(newFrame);
    if (incrementIfAccepted) {
        nextId += 2;
    }
    return true;
}
Also used : SendFrameHeader(io.undertow.server.protocol.framed.SendFrameHeader)

Example 4 with SendFrameHeader

use of io.undertow.server.protocol.framed.SendFrameHeader in project undertow by undertow-io.

the class Http2DataStreamSinkChannel method createFrameHeaderImpl.

@Override
protected SendFrameHeader createFrameHeaderImpl() {
    //TODO: this is a mess WRT re-using between headers and push_promise, sort out a more reasonable abstraction
    int dataPaddingBytes = getChannel().getPaddingBytes();
    int attempted = getBuffer().remaining() + dataPaddingBytes + (dataPaddingBytes > 0 ? 1 : 0);
    final int fcWindow = grabFlowControlBytes(attempted);
    if (fcWindow == 0 && getBuffer().hasRemaining()) {
        //flow control window is exhausted
        return new SendFrameHeader(getBuffer().remaining(), null);
    }
    if (fcWindow <= dataPaddingBytes + 1) {
        //so we won't actually be able to send any data, just padding, which is obviously not what we want
        if (getBuffer().remaining() >= fcWindow) {
            //easy fix, we just don't send any data
            dataPaddingBytes = 0;
        } else if (getBuffer().remaining() == dataPaddingBytes) {
            //corner case.
            dataPaddingBytes = 1;
        } else {
            dataPaddingBytes = fcWindow - getBuffer().remaining() - 1;
        }
    }
    final boolean finalFrame = isWritesShutdown() && fcWindow >= getBuffer().remaining();
    PooledByteBuffer firstHeaderBuffer = getChannel().getBufferPool().allocate();
    PooledByteBuffer[] allHeaderBuffers = null;
    ByteBuffer firstBuffer = firstHeaderBuffer.getBuffer();
    boolean firstFrame = false;
    if (first) {
        firstFrame = true;
        first = false;
        //back fill the length
        firstBuffer.put((byte) 0);
        firstBuffer.put((byte) 0);
        firstBuffer.put((byte) 0);
        //type
        firstBuffer.put((byte) frameType);
        //back fill the flags
        firstBuffer.put((byte) 0);
        Http2ProtocolUtils.putInt(firstBuffer, getStreamId());
        int paddingBytes = getChannel().getPaddingBytes();
        if (paddingBytes > 0) {
            firstBuffer.put((byte) (paddingBytes & 0xFF));
        }
        writeBeforeHeaderBlock(firstBuffer);
        HpackEncoder.State result = encoder.encode(headers, firstBuffer);
        PooledByteBuffer current = firstHeaderBuffer;
        int headerFrameLength = firstBuffer.position() - 9 + paddingBytes;
        firstBuffer.put(0, (byte) ((headerFrameLength >> 16) & 0xFF));
        firstBuffer.put(1, (byte) ((headerFrameLength >> 8) & 0xFF));
        firstBuffer.put(2, (byte) (headerFrameLength & 0xFF));
        //flags
        firstBuffer.put(4, (byte) ((isWritesShutdown() && !getBuffer().hasRemaining() && frameType == Http2Channel.FRAME_TYPE_HEADERS ? Http2Channel.HEADERS_FLAG_END_STREAM : 0) | (result == HpackEncoder.State.COMPLETE ? Http2Channel.HEADERS_FLAG_END_HEADERS : 0) | (paddingBytes > 0 ? Http2Channel.HEADERS_FLAG_PADDED : 0)));
        ByteBuffer currentBuffer = firstBuffer;
        if (currentBuffer.remaining() < paddingBytes) {
            allHeaderBuffers = allocateAll(allHeaderBuffers, current);
            current = allHeaderBuffers[allHeaderBuffers.length - 1];
            currentBuffer = current.getBuffer();
        }
        for (int i = 0; i < paddingBytes; ++i) {
            currentBuffer.put((byte) 0);
        }
        while (result != HpackEncoder.State.COMPLETE) {
            //todo: add some kind of limit here
            allHeaderBuffers = allocateAll(allHeaderBuffers, current);
            current = allHeaderBuffers[allHeaderBuffers.length - 1];
            //continuation frame
            //note that if the buffers are small we may not actually need a continuation here
            //but it greatly reduces the code complexity
            //back fill the length
            currentBuffer = current.getBuffer();
            currentBuffer.put((byte) 0);
            currentBuffer.put((byte) 0);
            currentBuffer.put((byte) 0);
            //type
            currentBuffer.put((byte) Http2Channel.FRAME_TYPE_CONTINUATION);
            //back fill the flags
            currentBuffer.put((byte) 0);
            Http2ProtocolUtils.putInt(currentBuffer, getStreamId());
            result = encoder.encode(headers, currentBuffer);
            int contFrameLength = currentBuffer.position() - 9;
            currentBuffer.put(0, (byte) ((contFrameLength >> 16) & 0xFF));
            currentBuffer.put(1, (byte) ((contFrameLength >> 8) & 0xFF));
            currentBuffer.put(2, (byte) (contFrameLength & 0xFF));
            //flags
            currentBuffer.put(4, (byte) (result == HpackEncoder.State.COMPLETE ? Http2Channel.HEADERS_FLAG_END_HEADERS : 0));
        }
    }
    PooledByteBuffer currentPooled = allHeaderBuffers == null ? firstHeaderBuffer : allHeaderBuffers[allHeaderBuffers.length - 1];
    ByteBuffer currentBuffer = currentPooled.getBuffer();
    ByteBuffer trailer = null;
    int remainingInBuffer = 0;
    if (getBuffer().remaining() > 0) {
        if (fcWindow > 0) {
            //make sure we have room in the header buffer
            if (currentBuffer.remaining() < 10) {
                allHeaderBuffers = allocateAll(allHeaderBuffers, currentPooled);
                currentPooled = allHeaderBuffers == null ? firstHeaderBuffer : allHeaderBuffers[allHeaderBuffers.length - 1];
                currentBuffer = currentPooled.getBuffer();
            }
            int toSend = fcWindow - dataPaddingBytes - (dataPaddingBytes > 0 ? 1 : 0);
            remainingInBuffer = getBuffer().remaining() - toSend;
            getBuffer().limit(getBuffer().position() + toSend);
            currentBuffer.put((byte) ((fcWindow >> 16) & 0xFF));
            currentBuffer.put((byte) ((fcWindow >> 8) & 0xFF));
            currentBuffer.put((byte) (fcWindow & 0xFF));
            //type
            currentBuffer.put((byte) Http2Channel.FRAME_TYPE_DATA);
            //flags
            currentBuffer.put((byte) ((finalFrame ? Http2Channel.DATA_FLAG_END_STREAM : 0) | (dataPaddingBytes > 0 ? Http2Channel.DATA_FLAG_PADDED : 0)));
            Http2ProtocolUtils.putInt(currentBuffer, getStreamId());
            if (dataPaddingBytes > 0) {
                currentBuffer.put((byte) (dataPaddingBytes & 0xFF));
                trailer = ByteBuffer.allocate(dataPaddingBytes);
            }
        } else {
            remainingInBuffer = getBuffer().remaining();
        }
    } else if (finalFrame && !firstFrame) {
        currentBuffer.put((byte) ((fcWindow >> 16) & 0xFF));
        currentBuffer.put((byte) ((fcWindow >> 8) & 0xFF));
        currentBuffer.put((byte) (fcWindow & 0xFF));
        //type
        currentBuffer.put((byte) Http2Channel.FRAME_TYPE_DATA);
        //flags
        currentBuffer.put((byte) ((Http2Channel.HEADERS_FLAG_END_STREAM & 0xFF) | (dataPaddingBytes > 0 ? Http2Channel.DATA_FLAG_PADDED : 0)));
        Http2ProtocolUtils.putInt(currentBuffer, getStreamId());
        if (dataPaddingBytes > 0) {
            currentBuffer.put((byte) (dataPaddingBytes & 0xFF));
            trailer = ByteBuffer.allocate(dataPaddingBytes);
        }
    }
    if (allHeaderBuffers == null) {
        //only one buffer required
        currentBuffer.flip();
        return new SendFrameHeader(remainingInBuffer, currentPooled, false, trailer);
    } else {
        //headers were too big to fit in one buffer
        //for now we will just copy them into a big buffer
        int length = 0;
        for (int i = 0; i < allHeaderBuffers.length; ++i) {
            length += allHeaderBuffers[i].getBuffer().position();
            allHeaderBuffers[i].getBuffer().flip();
        }
        try {
            ByteBuffer newBuf = ByteBuffer.allocate(length);
            for (int i = 0; i < allHeaderBuffers.length; ++i) {
                newBuf.put(allHeaderBuffers[i].getBuffer());
            }
            newBuf.flip();
            return new SendFrameHeader(remainingInBuffer, new ImmediatePooledByteBuffer(newBuf), false, trailer);
        } finally {
            //the allocate can oome
            for (int i = 0; i < allHeaderBuffers.length; ++i) {
                allHeaderBuffers[i].close();
            }
        }
    }
}
Also used : ImmediatePooledByteBuffer(io.undertow.util.ImmediatePooledByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) SendFrameHeader(io.undertow.server.protocol.framed.SendFrameHeader) ImmediatePooledByteBuffer(io.undertow.util.ImmediatePooledByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ByteBuffer(java.nio.ByteBuffer) ImmediatePooledByteBuffer(io.undertow.util.ImmediatePooledByteBuffer)

Example 5 with SendFrameHeader

use of io.undertow.server.protocol.framed.SendFrameHeader in project undertow by undertow-io.

the class AjpClientRequestClientStreamSinkChannel method createFrameHeader.

@Override
protected final SendFrameHeader createFrameHeader() {
    SendFrameHeader header = this.header;
    this.header = null;
    return header;
}
Also used : SendFrameHeader(io.undertow.server.protocol.framed.SendFrameHeader)

Aggregations

SendFrameHeader (io.undertow.server.protocol.framed.SendFrameHeader)13 ByteBuffer (java.nio.ByteBuffer)8 ImmediatePooledByteBuffer (io.undertow.util.ImmediatePooledByteBuffer)7 PooledByteBuffer (io.undertow.connector.PooledByteBuffer)4 AjpUtils.putString (io.undertow.protocols.ajp.AjpUtils.putString)1 HeaderMap (io.undertow.util.HeaderMap)1 HttpString (io.undertow.util.HttpString)1 BufferOverflowException (java.nio.BufferOverflowException)1