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 335473c234f..d7ce26a9ead 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 @@ -48,6 +48,7 @@ public class QpackDecoder implements Dumpable private final DecoderInstructionParser _parser; private final List _encodedFieldSections = new ArrayList<>(); private final NBitIntegerParser _integerDecoder = new NBitIntegerParser(); + private final InstructionHandler _instructionHandler = new InstructionHandler(); private final int _maxHeaderSize; private static class MetaDataNotification @@ -76,7 +77,7 @@ public class QpackDecoder implements Dumpable { _context = new QpackContext(); _handler = handler; - _parser = new DecoderInstructionParser(new InstructionHandler()); + _parser = new DecoderInstructionParser(_instructionHandler); _maxHeaderSize = maxHeaderSize; } @@ -211,56 +212,6 @@ public class QpackDecoder implements Dumpable } } - void setCapacity(int capacity) - { - _context.getDynamicTable().setCapacity(capacity); - } - - void insert(int index) throws QpackException - { - if (LOG.isDebugEnabled()) - LOG.debug("Duplicate: index={}", index); - - DynamicTable dynamicTable = _context.getDynamicTable(); - Entry referencedEntry = dynamicTable.get(index); - - // Add the new Entry to the DynamicTable. - Entry entry = new Entry(referencedEntry.getHttpField()); - dynamicTable.add(entry); - _instructions.add(new InsertCountIncrementInstruction(1)); - checkEncodedFieldSections(); - } - - void insert(int nameIndex, boolean isDynamicTableIndex, String value) throws QpackException - { - if (LOG.isDebugEnabled()) - LOG.debug("InsertNameReference: nameIndex={}, dynamic={}, value={}", nameIndex, isDynamicTableIndex, value); - - StaticTable staticTable = QpackContext.getStaticTable(); - DynamicTable dynamicTable = _context.getDynamicTable(); - Entry referencedEntry = isDynamicTableIndex ? dynamicTable.get(nameIndex) : staticTable.get(nameIndex); - - // Add the new Entry to the DynamicTable. - Entry entry = new Entry(new HttpField(referencedEntry.getHttpField().getHeader(), referencedEntry.getHttpField().getName(), value)); - dynamicTable.add(entry); - _instructions.add(new InsertCountIncrementInstruction(1)); - checkEncodedFieldSections(); - } - - void insert(String name, String value) throws QpackException - { - if (LOG.isDebugEnabled()) - LOG.debug("InsertLiteralEntry: name={}, value={}", name, value); - - Entry entry = new Entry(new HttpField(name, value)); - - // Add the new Entry to the DynamicTable. - DynamicTable dynamicTable = _context.getDynamicTable(); - dynamicTable.add(entry); - _instructions.add(new InsertCountIncrementInstruction(1)); - checkEncodedFieldSections(); - } - private static int decodeInsertCount(int encInsertCount, int totalNumInserts, int maxTableCapacity) throws QpackException { if (encInsertCount == 0) @@ -319,6 +270,11 @@ public class QpackDecoder implements Dumpable _metaDataNotifications.clear(); } + InstructionHandler getInstructionHandler() + { + return _instructionHandler; + } + /** * This delivers notifications from the DecoderInstruction parser directly into the Decoder. */ @@ -327,25 +283,55 @@ public class QpackDecoder implements Dumpable @Override public void onSetDynamicTableCapacity(int capacity) { - setCapacity(capacity); + _context.getDynamicTable().setCapacity(capacity); } @Override public void onDuplicate(int index) throws QpackException { - insert(index); + if (LOG.isDebugEnabled()) + LOG.debug("Duplicate: index={}", index); + + DynamicTable dynamicTable = _context.getDynamicTable(); + Entry referencedEntry = dynamicTable.get(index); + + // Add the new Entry to the DynamicTable. + Entry entry = new Entry(referencedEntry.getHttpField()); + dynamicTable.add(entry); + _instructions.add(new InsertCountIncrementInstruction(1)); + checkEncodedFieldSections(); } @Override public void onInsertNameWithReference(int nameIndex, boolean isDynamicTableIndex, String value) throws QpackException { - insert(nameIndex, isDynamicTableIndex, value); + if (LOG.isDebugEnabled()) + LOG.debug("InsertNameReference: nameIndex={}, dynamic={}, value={}", nameIndex, isDynamicTableIndex, value); + + StaticTable staticTable = QpackContext.getStaticTable(); + DynamicTable dynamicTable = _context.getDynamicTable(); + Entry referencedEntry = isDynamicTableIndex ? dynamicTable.get(nameIndex) : staticTable.get(nameIndex); + + // Add the new Entry to the DynamicTable. + Entry entry = new Entry(new HttpField(referencedEntry.getHttpField().getHeader(), referencedEntry.getHttpField().getName(), value)); + dynamicTable.add(entry); + _instructions.add(new InsertCountIncrementInstruction(1)); + checkEncodedFieldSections(); } @Override public void onInsertWithLiteralName(String name, String value) throws QpackException { - insert(name, value); + if (LOG.isDebugEnabled()) + LOG.debug("InsertLiteralEntry: name={}, value={}", name, value); + + Entry entry = new Entry(new HttpField(name, value)); + + // Add the new Entry to the DynamicTable. + DynamicTable dynamicTable = _context.getDynamicTable(); + dynamicTable.add(entry); + _instructions.add(new InsertCountIncrementInstruction(1)); + checkEncodedFieldSections(); } } } diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackEncoder.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackEncoder.java index 9ac136fcca3..e2bf93e1b69 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackEncoder.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackEncoder.java @@ -92,6 +92,7 @@ public class QpackEncoder implements Dumpable private final int _maxBlockedStreams; private final Map _streamInfoMap = new HashMap<>(); private final EncoderInstructionParser _parser; + private final InstructionHandler _instructionHandler = new InstructionHandler(); private int _knownInsertCount = 0; private int _blockedStreams = 0; @@ -100,7 +101,7 @@ public class QpackEncoder implements Dumpable _handler = handler; _context = new QpackContext(); _maxBlockedStreams = maxBlockedStreams; - _parser = new EncoderInstructionParser(new InstructionHandler()); + _parser = new EncoderInstructionParser(_instructionHandler); } /** @@ -361,52 +362,6 @@ public class QpackEncoder implements Dumpable } } - void insertCountIncrement(int increment) throws QpackException - { - if (LOG.isDebugEnabled()) - LOG.debug("InsertCountIncrement: increment={}", increment); - - int insertCount = _context.getDynamicTable().getInsertCount(); - if (_knownInsertCount + increment > insertCount) - throw new QpackException.SessionException(QPACK_ENCODER_STREAM_ERROR, "KnownInsertCount incremented over InsertCount"); - _knownInsertCount += increment; - } - - void sectionAcknowledgement(long streamId) throws QpackException - { - if (LOG.isDebugEnabled()) - LOG.debug("SectionAcknowledgement: streamId={}", streamId); - - StreamInfo streamInfo = _streamInfoMap.get(streamId); - if (streamInfo == null) - throw new QpackException.SessionException(QPACK_ENCODER_STREAM_ERROR, "No StreamInfo for " + streamId); - - // The KnownInsertCount should be updated to the earliest sent RequiredInsertCount on that stream. - StreamInfo.SectionInfo sectionInfo = streamInfo.acknowledge(); - sectionInfo.release(); - _knownInsertCount = Math.max(_knownInsertCount, sectionInfo.getRequiredInsertCount()); - - // If we have no more outstanding section acknowledgments remove the StreamInfo. - if (streamInfo.isEmpty()) - _streamInfoMap.remove(streamId); - } - - void streamCancellation(long streamId) throws QpackException - { - if (LOG.isDebugEnabled()) - LOG.debug("StreamCancellation: streamId={}", streamId); - - StreamInfo streamInfo = _streamInfoMap.remove(streamId); - if (streamInfo == null) - throw new QpackException.SessionException(QPACK_ENCODER_STREAM_ERROR, "No StreamInfo for " + streamId); - - // Release all referenced entries outstanding on the stream that was cancelled. - for (StreamInfo.SectionInfo sectionInfo : streamInfo) - { - sectionInfo.release(); - } - } - private boolean referenceEntry(Entry entry, StreamInfo streamInfo) { if (entry == null) @@ -463,24 +418,60 @@ public class QpackEncoder implements Dumpable _instructions.clear(); } + InstructionHandler getInstructionHandler() + { + return _instructionHandler; + } + class InstructionHandler implements EncoderInstructionParser.Handler { @Override public void onSectionAcknowledgement(long streamId) throws QpackException { - sectionAcknowledgement(streamId); + if (LOG.isDebugEnabled()) + LOG.debug("SectionAcknowledgement: streamId={}", streamId); + + StreamInfo streamInfo = _streamInfoMap.get(streamId); + if (streamInfo == null) + throw new QpackException.SessionException(QPACK_ENCODER_STREAM_ERROR, "No StreamInfo for " + streamId); + + // The KnownInsertCount should be updated to the earliest sent RequiredInsertCount on that stream. + StreamInfo.SectionInfo sectionInfo = streamInfo.acknowledge(); + sectionInfo.release(); + _knownInsertCount = Math.max(_knownInsertCount, sectionInfo.getRequiredInsertCount()); + + // If we have no more outstanding section acknowledgments remove the StreamInfo. + if (streamInfo.isEmpty()) + _streamInfoMap.remove(streamId); } @Override public void onStreamCancellation(long streamId) throws QpackException { - streamCancellation(streamId); + if (LOG.isDebugEnabled()) + LOG.debug("StreamCancellation: streamId={}", streamId); + + StreamInfo streamInfo = _streamInfoMap.remove(streamId); + if (streamInfo == null) + throw new QpackException.SessionException(QPACK_ENCODER_STREAM_ERROR, "No StreamInfo for " + streamId); + + // Release all referenced entries outstanding on the stream that was cancelled. + for (StreamInfo.SectionInfo sectionInfo : streamInfo) + { + sectionInfo.release(); + } } @Override public void onInsertCountIncrement(int increment) throws QpackException { - insertCountIncrement(increment); + if (LOG.isDebugEnabled()) + LOG.debug("InsertCountIncrement: increment={}", increment); + + int insertCount = _context.getDynamicTable().getInsertCount(); + if (_knownInsertCount + increment > insertCount) + throw new QpackException.SessionException(QPACK_ENCODER_STREAM_ERROR, "KnownInsertCount incremented over InsertCount"); + _knownInsertCount += increment; } } diff --git a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/DecoderParserDebugHandler.java b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/DecoderParserDebugHandler.java index 3a67aa56969..3491d14edf2 100644 --- a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/DecoderParserDebugHandler.java +++ b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/DecoderParserDebugHandler.java @@ -26,6 +26,7 @@ public class DecoderParserDebugHandler implements DecoderInstructionParser.Handl public Queue referencedNameEntries = new LinkedList<>(); private final QpackDecoder _decoder; + private final DecoderInstructionParser.Handler _decoderHandler; public DecoderParserDebugHandler() { @@ -35,6 +36,7 @@ public class DecoderParserDebugHandler implements DecoderInstructionParser.Handl public DecoderParserDebugHandler(QpackDecoder decoder) { _decoder = decoder; + _decoderHandler = decoder == null ? null : decoder.getInstructionHandler(); } public static class LiteralEntry @@ -64,11 +66,11 @@ public class DecoderParserDebugHandler implements DecoderInstructionParser.Handl } @Override - public void onSetDynamicTableCapacity(int capacity) + public void onSetDynamicTableCapacity(int capacity) throws QpackException { setCapacities.add(capacity); if (_decoder != null) - _decoder.setCapacity(capacity); + _decoderHandler.onSetDynamicTableCapacity(capacity); } @Override @@ -76,7 +78,7 @@ public class DecoderParserDebugHandler implements DecoderInstructionParser.Handl { duplicates.add(index); if (_decoder != null) - _decoder.insert(index); + _decoderHandler.onDuplicate(index); } @Override @@ -84,7 +86,7 @@ public class DecoderParserDebugHandler implements DecoderInstructionParser.Handl { referencedNameEntries.add(new ReferencedEntry(nameIndex, isDynamicTableIndex, value)); if (_decoder != null) - _decoder.insert(nameIndex, isDynamicTableIndex, value); + _decoderHandler.onInsertNameWithReference(nameIndex, isDynamicTableIndex, value); } @Override @@ -92,7 +94,7 @@ public class DecoderParserDebugHandler implements DecoderInstructionParser.Handl { literalNameEntries.add(new LiteralEntry(name, value)); if (_decoder != null) - _decoder.insert(name, value); + _decoderHandler.onInsertWithLiteralName(name, value); } public boolean isEmpty() diff --git a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/EncodeDecodeTest.java b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/EncodeDecodeTest.java index 49cd87808cf..1a0247c708b 100644 --- a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/EncodeDecodeTest.java +++ b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/EncodeDecodeTest.java @@ -148,6 +148,6 @@ public class EncodeDecodeTest instruction = _encoderHandler.getInstruction(); assertThat(instruction, instanceOf(LiteralNameEntryInstruction.class)); assertThat(QpackTestUtil.toHexString(instruction), QpackTestUtil.equalsHex("4a63 7573 746f 6d2d 6b65 790c 6375 7374 6f6d 2d76 616c 7565")); - _encoder.insertCountIncrement(1); + _encoder.getInstructionHandler().onInsertCountIncrement(1); } } diff --git a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/EncoderParserDebugHandler.java b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/EncoderParserDebugHandler.java index fe6caf655af..ab9233682aa 100644 --- a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/EncoderParserDebugHandler.java +++ b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/EncoderParserDebugHandler.java @@ -25,6 +25,7 @@ public class EncoderParserDebugHandler implements EncoderInstructionParser.Handl public Queue insertCountIncrements = new LinkedList<>(); private final QpackEncoder _encoder; + private final QpackEncoder.InstructionHandler _instructionHandler; public EncoderParserDebugHandler() { @@ -34,6 +35,7 @@ public class EncoderParserDebugHandler implements EncoderInstructionParser.Handl public EncoderParserDebugHandler(QpackEncoder encoder) { _encoder = encoder; + _instructionHandler = encoder == null ? null : encoder.getInstructionHandler(); } @Override @@ -41,7 +43,7 @@ public class EncoderParserDebugHandler implements EncoderInstructionParser.Handl { sectionAcknowledgements.add(streamId); if (_encoder != null) - _encoder.sectionAcknowledgement(streamId); + _instructionHandler.onSectionAcknowledgement(streamId); } @Override @@ -49,7 +51,7 @@ public class EncoderParserDebugHandler implements EncoderInstructionParser.Handl { streamCancellations.add(streamId); if (_encoder != null) - _encoder.streamCancellation(streamId); + _instructionHandler.onStreamCancellation(streamId); } @Override @@ -57,7 +59,7 @@ public class EncoderParserDebugHandler implements EncoderInstructionParser.Handl { insertCountIncrements.add(increment); if (_encoder != null) - _encoder.insertCountIncrement(increment); + _instructionHandler.onInsertCountIncrement(increment); } public boolean isEmpty()