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();
}
}
}
}
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();
}
}
}
}
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;
}
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();
}
}
}
}
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;
}
Aggregations