diff options
author | Simone Bordet | 2015-09-25 11:00:26 +0000 |
---|---|---|
committer | Simone Bordet | 2015-09-25 11:00:26 +0000 |
commit | 0c9eba0485dfd666e4ad91af1a0478a00b26c295 (patch) | |
tree | d462afd6976fa3b62c90d5df03e6188337a1dfe4 /jetty-http2/http2-common | |
parent | 394c105d5db18e03e104e62e8667141d2c5f60a9 (diff) | |
download | org.eclipse.jetty.project-0c9eba0485dfd666e4ad91af1a0478a00b26c295.tar.gz org.eclipse.jetty.project-0c9eba0485dfd666e4ad91af1a0478a00b26c295.tar.xz org.eclipse.jetty.project-0c9eba0485dfd666e4ad91af1a0478a00b26c295.zip |
478275 - Priority information in HEADERS frame is not sent.
Now the priority information present in HEADERS frame is correctly
generated and sent as part of the HEADERS frame.
Diffstat (limited to 'jetty-http2/http2-common')
5 files changed, 89 insertions, 28 deletions
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java index d5b8e3c416..51f4b122b2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java @@ -20,6 +20,8 @@ package org.eclipse.jetty.http2.frames; public class PriorityFrame extends Frame { + public static final int PRIORITY_LENGTH = 5; + private final int streamId; private final int parentStreamId; private final int weight; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index b6bb95b385..e46c1d1230 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -25,6 +25,7 @@ import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; @@ -50,16 +51,30 @@ public class HeadersGenerator extends FrameGenerator public void generate(ByteBufferPool.Lease lease, Frame frame) { HeadersFrame headersFrame = (HeadersFrame)frame; - generateHeaders(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), !headersFrame.isEndStream()); + generateHeaders(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), headersFrame.getPriority(), headersFrame.isEndStream()); } - public void generateHeaders(ByteBufferPool.Lease lease, int streamId, MetaData metaData, boolean contentFollows) + public void generateHeaders(ByteBufferPool.Lease lease, int streamId, MetaData metaData, PriorityFrame priority, boolean endStream) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); - int maxFrameSize = getMaxFrameSize(); + int flags = Flags.NONE; + if (priority != null) + { + flags = Flags.PRIORITY; + int parentStreamId = priority.getParentStreamId(); + if (parentStreamId < 0) + throw new IllegalArgumentException("Invalid parent stream id: " + parentStreamId); + if (parentStreamId == streamId) + throw new IllegalArgumentException("Stream " + streamId + " cannot depend on stream " + parentStreamId); + int weight = priority.getWeight(); + if (weight > 255) + throw new IllegalArgumentException("Invalid weight: " + weight); + } + + int maxFrameSize = getMaxFrameSize(); ByteBuffer hpacked = lease.acquire(maxFrameSize, false); BufferUtil.clearToFill(hpacked); encoder.encode(hpacked, metaData); @@ -69,10 +84,19 @@ public class HeadersGenerator extends FrameGenerator // Split into CONTINUATION frames if necessary. if (maxHeaderBlockFragment > 0 && hpackedLength > maxHeaderBlockFragment) { - int flags = contentFollows ? Flags.NONE : Flags.END_STREAM; - ByteBuffer header = generateHeader(lease, FrameType.HEADERS, maxHeaderBlockFragment, flags, streamId); + if (endStream) + flags |= Flags.END_STREAM; + + int length = maxHeaderBlockFragment; + if (priority != null) + length += PriorityFrame.PRIORITY_LENGTH; + + ByteBuffer header = generateHeader(lease, FrameType.HEADERS, length, flags, streamId); BufferUtil.flipToFlush(header, 0); lease.append(header, true); + + generatePriority(lease, priority); + hpacked.limit(maxHeaderBlockFragment); lease.append(hpacked.slice(), false); @@ -97,13 +121,36 @@ public class HeadersGenerator extends FrameGenerator } else { - int flags = Flags.END_HEADERS; - if (!contentFollows) + flags |= Flags.END_HEADERS; + if (endStream) flags |= Flags.END_STREAM; - ByteBuffer header = generateHeader(lease, FrameType.HEADERS, hpackedLength, flags, streamId); + + int length = hpackedLength; + if (priority != null) + length += PriorityFrame.PRIORITY_LENGTH; + + ByteBuffer header = generateHeader(lease, FrameType.HEADERS, length, flags, streamId); BufferUtil.flipToFlush(header, 0); lease.append(header, true); + + generatePriority(lease, priority); + lease.append(hpacked, true); } } + + private void generatePriority(ByteBufferPool.Lease lease, PriorityFrame priority) + { + if (priority != null) + { + int parentStreamId = priority.getParentStreamId() & 0x7F_FF_FF_FF; + if (priority.isExclusive()) + parentStreamId |= 0x80_00_00_00; + ByteBuffer buffer = lease.acquire(PriorityFrame.PRIORITY_LENGTH, true); + buffer.putInt(parentStreamId); + buffer.put((byte)(priority.getWeight() & 0xFF)); + BufferUtil.flipToFlush(buffer, 0); + lease.append(buffer, true); + } + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java index 01acaf7d4a..a9e9e670e7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java @@ -42,7 +42,6 @@ public class ContinuationBodyParser extends BodyParser @Override protected void emptyBody(ByteBuffer buffer) { - reset(); if (hasFlag(Flags.END_HEADERS)) onHeaders(); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 7d413f3967..9bf7607320 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -36,7 +36,7 @@ public class HeadersBodyParser extends BodyParser private int length; private int paddingLength; private boolean exclusive; - private int streamId; + private int parentStreamId; private int weight; public HeadersBodyParser(HeaderParser headerParser, Parser.Listener listener, HeaderBlockParser headerBlockParser, HeaderBlockFragments headerBlockFragments) @@ -53,7 +53,7 @@ public class HeadersBodyParser extends BodyParser length = 0; paddingLength = 0; exclusive = false; - streamId = 0; + parentStreamId = 0; weight = 0; } @@ -70,9 +70,8 @@ public class HeadersBodyParser extends BodyParser headerBlockFragments.setStreamId(getStreamId()); headerBlockFragments.setEndStream(isEndStream()); if (hasFlag(Flags.PRIORITY)) - headerBlockFragments.setPriorityFrame(new PriorityFrame(streamId, getStreamId(), weight, exclusive)); + connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_priority_frame"); } - reset(); } @Override @@ -122,15 +121,15 @@ public class HeadersBodyParser extends BodyParser // because the 31 least significant bits represent the stream id. int currByte = buffer.get(buffer.position()); exclusive = (currByte & 0x80) == 0x80; - state = State.STREAM_ID; + state = State.PARENT_STREAM_ID; break; } - case STREAM_ID: + case PARENT_STREAM_ID: { if (buffer.remaining() >= 4) { - streamId = buffer.getInt(); - streamId &= 0x7F_FF_FF_FF; + parentStreamId = buffer.getInt(); + parentStreamId &= 0x7F_FF_FF_FF; length -= 4; state = State.WEIGHT; if (length < 1) @@ -138,22 +137,22 @@ public class HeadersBodyParser extends BodyParser } else { - state = State.STREAM_ID_BYTES; + state = State.PARENT_STREAM_ID_BYTES; cursor = 4; } break; } - case STREAM_ID_BYTES: + case PARENT_STREAM_ID_BYTES: { int currByte = buffer.get() & 0xFF; --cursor; - streamId += currByte << (8 * cursor); + parentStreamId += currByte << (8 * cursor); --length; if (cursor > 0 && length <= 0) return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame"); if (cursor == 0) { - streamId &= 0x7F_FF_FF_FF; + parentStreamId &= 0x7F_FF_FF_FF; state = State.WEIGHT; if (length < 1) return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame"); @@ -177,7 +176,7 @@ public class HeadersBodyParser extends BodyParser { state = State.PADDING; loop = paddingLength == 0; - onHeaders(streamId, weight, exclusive, metaData); + onHeaders(parentStreamId, weight, exclusive, metaData); } } else @@ -193,7 +192,7 @@ public class HeadersBodyParser extends BodyParser headerBlockFragments.setStreamId(getStreamId()); headerBlockFragments.setEndStream(isEndStream()); if (hasFlag(Flags.PRIORITY)) - headerBlockFragments.setPriorityFrame(new PriorityFrame(streamId, getStreamId(), weight, exclusive)); + headerBlockFragments.setPriorityFrame(new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive)); headerBlockFragments.storeFragment(buffer, length, false); state = State.PADDING; loop = paddingLength == 0; @@ -222,17 +221,17 @@ public class HeadersBodyParser extends BodyParser return false; } - private void onHeaders(int streamId, int weight, boolean exclusive, MetaData metaData) + private void onHeaders(int parentStreamId, int weight, boolean exclusive, MetaData metaData) { PriorityFrame priorityFrame = null; if (hasFlag(Flags.PRIORITY)) - priorityFrame = new PriorityFrame(streamId, getStreamId(), weight, exclusive); + priorityFrame = new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive); HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, priorityFrame, isEndStream()); notifyHeaders(frame); } private enum State { - PREPARE, PADDING_LENGTH, EXCLUSIVE, STREAM_ID, STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING + PREPARE, PADDING_LENGTH, EXCLUSIVE, PARENT_STREAM_ID, PARENT_STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING } } diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index 6503380fe9..a7796f0a32 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -66,7 +66,8 @@ public class HeadersGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateHeaders(lease, streamId, metaData, false); + PriorityFrame priorityFrame = new PriorityFrame(streamId, 3 * streamId, 200, true); + generator.generateHeaders(lease, streamId, metaData, priorityFrame, true); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -89,6 +90,12 @@ public class HeadersGenerateParseTest HttpField field = fields.getField(j); Assert.assertTrue(request.getFields().contains(field)); } + PriorityFrame priority = frame.getPriority(); + Assert.assertNotNull(priority); + Assert.assertEquals(priorityFrame.getStreamId(), priority.getStreamId()); + Assert.assertEquals(priorityFrame.getParentStreamId(), priority.getParentStreamId()); + Assert.assertEquals(priorityFrame.getWeight(), priority.getWeight()); + Assert.assertEquals(priorityFrame.isExclusive(), priority.isExclusive()); } } @@ -114,7 +121,8 @@ public class HeadersGenerateParseTest MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateHeaders(lease, streamId, metaData, false); + PriorityFrame priorityFrame = new PriorityFrame(streamId, 3 * streamId, 200, true); + generator.generateHeaders(lease, streamId, metaData, priorityFrame, true); for (ByteBuffer buffer : lease.getByteBuffers()) { @@ -136,5 +144,11 @@ public class HeadersGenerateParseTest HttpField field = fields.getField(j); Assert.assertTrue(request.getFields().contains(field)); } + PriorityFrame priority = frame.getPriority(); + Assert.assertNotNull(priority); + Assert.assertEquals(priorityFrame.getStreamId(), priority.getStreamId()); + Assert.assertEquals(priorityFrame.getParentStreamId(), priority.getParentStreamId()); + Assert.assertEquals(priorityFrame.getWeight(), priority.getWeight()); + Assert.assertEquals(priorityFrame.isExclusive(), priority.isExclusive()); } } |