diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackDecoder.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackDecoder.java index 2ed19b6a59a..4acfe2b44a6 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackDecoder.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackDecoder.java @@ -19,6 +19,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpTokens; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http3.qpack.generator.Instruction; import org.eclipse.jetty.http3.qpack.table.Entry; import org.eclipse.jetty.util.BufferUtil; import org.slf4j.Logger; @@ -59,6 +60,13 @@ public class QpackDecoder _localMaxDynamicTableSize = localMaxdynamciTableSize; } + public interface Handler + { + void onMetadata(MetaData metaData); + + void onInstruction(Instruction instruction); + } + public MetaData decode(ByteBuffer buffer) throws QpackException.SessionException, QpackException.StreamException { if (LOG.isDebugEnabled()) diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/DecoderInstructionParser.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/DecoderInstructionParser.java index a15dd48a044..82730e44efc 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/DecoderInstructionParser.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/DecoderInstructionParser.java @@ -26,11 +26,11 @@ public class DecoderInstructionParser private final Handler _handler; private final NBitIntegerParser _integerParser; - private State _state = State.PARSING; + private State _state = State.IDLE; private enum State { - PARSING, + IDLE, SECTION_ACKNOWLEDGEMENT, STREAM_CANCELLATION, INSERT_COUNT_INCREMENT @@ -58,22 +58,25 @@ public class DecoderInstructionParser switch (_state) { - case PARSING: + case IDLE: // Get first byte without incrementing the buffers position. byte firstByte = buffer.get(buffer.position()); if ((firstByte & 0x80) != 0) { _state = State.SECTION_ACKNOWLEDGEMENT; + _integerParser.setPrefix(SECTION_ACKNOWLEDGEMENT_PREFIX); parseSectionAcknowledgment(buffer); } else if ((firstByte & 0x40) != 0) { _state = State.STREAM_CANCELLATION; + _integerParser.setPrefix(STREAM_CANCELLATION_PREFIX); parseStreamCancellation(buffer); } else { _state = State.INSERT_COUNT_INCREMENT; + _integerParser.setPrefix(INSERT_COUNT_INCREMENT_PREFIX); parseInsertCountIncrement(buffer); } break; @@ -97,31 +100,37 @@ public class DecoderInstructionParser private void parseSectionAcknowledgment(ByteBuffer buffer) { - int streamId = _integerParser.decode(buffer, SECTION_ACKNOWLEDGEMENT_PREFIX); + int streamId = _integerParser.decode(buffer); if (streamId >= 0) { - _state = State.PARSING; + reset(); _handler.onSectionAcknowledgement(streamId); } } private void parseStreamCancellation(ByteBuffer buffer) { - int streamId = _integerParser.decode(buffer, STREAM_CANCELLATION_PREFIX); + int streamId = _integerParser.decode(buffer); if (streamId >= 0) { - _state = State.PARSING; + reset(); _handler.onStreamCancellation(streamId); } } private void parseInsertCountIncrement(ByteBuffer buffer) { - int increment = _integerParser.decode(buffer, INSERT_COUNT_INCREMENT_PREFIX); + int increment = _integerParser.decode(buffer); if (increment >= 0) { - _state = State.PARSING; + reset(); _handler.onInsertCountIncrement(increment); } } + + public void reset() + { + _state = State.IDLE; + _integerParser.reset(); + } } diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/EncoderInstructionParser.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/EncoderInstructionParser.java index 7ea2d9bee61..fd44cd750e8 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/EncoderInstructionParser.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/EncoderInstructionParser.java @@ -89,11 +89,13 @@ public class EncoderInstructionParser else if ((firstByte & 0x20) != 0) { _state = State.SET_CAPACITY; + _integerParser.setPrefix(5); parseSetDynamicTableCapacity(buffer); } else { _state = State.DUPLICATE; + _integerParser.setPrefix(5); parseDuplicate(buffer); } break; @@ -129,24 +131,27 @@ public class EncoderInstructionParser byte firstByte = buffer.get(buffer.position()); _referenceDynamicTable = (firstByte & 0x40) == 0; _operation = Operation.INDEX; + _integerParser.setPrefix(6); continue; case INDEX: - _index = _integerParser.decode(buffer, 6); + _index = _integerParser.decode(buffer); if (_index < 0) return; - _stringParser.setPrefix(8); _operation = Operation.VALUE; + _stringParser.setPrefix(8); continue; case VALUE: String value = _stringParser.decode(buffer); if (value == null) return; - _operation = Operation.NONE; - _state = State.PARSING; - _handler.onInsertNameWithReference(_index, _referenceDynamicTable, value); + + int index = _index; + boolean dynamic = _referenceDynamicTable; + reset(); + _handler.onInsertNameWithReference(index, dynamic, value); return; default: @@ -162,8 +167,8 @@ public class EncoderInstructionParser switch (_operation) { case NONE: - _stringParser.setPrefix(6); _operation = Operation.NAME; + _stringParser.setPrefix(6); continue; case NAME: @@ -171,8 +176,8 @@ public class EncoderInstructionParser if (_name == null) return; - _stringParser.setPrefix(8); _operation = Operation.VALUE; + _stringParser.setPrefix(8); continue; case VALUE: @@ -180,9 +185,9 @@ public class EncoderInstructionParser if (value == null) return; - _operation = Operation.NONE; - _state = State.PARSING; - _handler.onInsertWithLiteralName(_name, value); + String name = _name; + reset(); + _handler.onInsertWithLiteralName(name, value); return; default: @@ -193,21 +198,32 @@ public class EncoderInstructionParser private void parseDuplicate(ByteBuffer buffer) { - int index = _integerParser.decode(buffer, 5); + int index = _integerParser.decode(buffer); if (index >= 0) { - _state = State.PARSING; + reset(); _handler.onDuplicate(index); } } private void parseSetDynamicTableCapacity(ByteBuffer buffer) { - int capacity = _integerParser.decode(buffer, 5); + int capacity = _integerParser.decode(buffer); if (capacity >= 0) { - _state = State.PARSING; + reset(); _handler.onSetDynamicTableCapacity(capacity); } } + + public void reset() + { + _stringParser.reset(); + _integerParser.reset(); + _state = State.PARSING; + _operation = Operation.NONE; + _referenceDynamicTable = false; + _index = -1; + _name = null; + } } diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/NBitIntegerParser.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/NBitIntegerParser.java index e2c6b8d4880..433380bb4ee 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/NBitIntegerParser.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/NBitIntegerParser.java @@ -22,7 +22,12 @@ public class NBitIntegerParser private int _multiplier; private boolean _started; - public int decode(ByteBuffer buffer, int prefix) + public void setPrefix(int prefix) + { + _prefix = prefix; + } + + public int decode(ByteBuffer buffer) { if (!_started) { @@ -30,7 +35,6 @@ public class NBitIntegerParser return -1; _started = true; - _prefix = prefix; _multiplier = 1; int nbits = 0xFF >>> (8 - _prefix); _total = buffer.get() & nbits; diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/NBitStringParser.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/NBitStringParser.java index 1e7d630de33..096fae5be83 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/NBitStringParser.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/parser/NBitStringParser.java @@ -59,10 +59,11 @@ public class NBitStringParser byte firstByte = buffer.get(buffer.position()); _huffman = ((0x80 >>> (8 - _prefix)) & firstByte) != 0; _state = State.LENGTH; + _integerParser.setPrefix(_prefix - 1); continue; case LENGTH: - _length = _integerParser.decode(buffer, _prefix - 1); + _length = _integerParser.decode(buffer); if (_length < 0) return null; _state = State.VALUE; diff --git a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/NBitIntegerParserTest.java b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/NBitIntegerParserTest.java index 0ae1d06da55..e615e994342 100644 --- a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/NBitIntegerParserTest.java +++ b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/NBitIntegerParserTest.java @@ -37,10 +37,12 @@ public class NBitIntegerParserTest ByteBuffer buffer1 = BufferUtil.toBuffer(bytes, 0, 2); ByteBuffer buffer2 = BufferUtil.toBuffer(bytes, 2, 1); - int value = parser.decode(buffer1, 7); + parser.setPrefix(7); + int value = parser.decode(buffer1); assertThat(value, is(-1)); - value = parser.decode(buffer2, 7); + parser.setPrefix(7); + value = parser.decode(buffer2); assertThat(value, is(1337)); } }