Renaming and change package access.
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
da50072cc8
commit
a4938a3f4a
|
@ -16,7 +16,7 @@ package org.eclipse.jetty.http3.qpack;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
public class StreamInfo
|
class StreamInfo
|
||||||
{
|
{
|
||||||
private final int _streamId;
|
private final int _streamId;
|
||||||
private final Queue<SectionInfo> _sectionInfos = new LinkedList<>();
|
private final Queue<SectionInfo> _sectionInfos = new LinkedList<>();
|
||||||
|
|
|
@ -15,75 +15,95 @@ package org.eclipse.jetty.http3.qpack.parser;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.QpackEncoder;
|
import org.eclipse.jetty.http3.qpack.QpackDecoder;
|
||||||
import org.eclipse.jetty.http3.qpack.QpackException;
|
import org.eclipse.jetty.http3.qpack.QpackException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receives instructions coming from the remote Encoder as a sequence of unframed instructions.
|
* Parses a stream of unframed instructions for the Decoder. These instructions are sent from the remote Encoder.
|
||||||
*/
|
*/
|
||||||
public class DecoderInstructionParser
|
public class DecoderInstructionParser
|
||||||
{
|
{
|
||||||
private static final int SECTION_ACKNOWLEDGEMENT_PREFIX = 7;
|
|
||||||
private static final int STREAM_CANCELLATION_PREFIX = 6;
|
|
||||||
private static final int INSERT_COUNT_INCREMENT_PREFIX = 6;
|
|
||||||
|
|
||||||
private final Handler _handler;
|
private final Handler _handler;
|
||||||
|
private final NBitStringParser _stringParser;
|
||||||
private final NBitIntegerParser _integerParser;
|
private final NBitIntegerParser _integerParser;
|
||||||
private State _state = State.IDLE;
|
private State _state = State.PARSING;
|
||||||
|
private Operation _operation = Operation.NONE;
|
||||||
|
|
||||||
|
private boolean _referenceDynamicTable;
|
||||||
|
private int _index;
|
||||||
|
private String _name;
|
||||||
|
|
||||||
private enum State
|
private enum State
|
||||||
{
|
{
|
||||||
IDLE,
|
PARSING,
|
||||||
SECTION_ACKNOWLEDGEMENT,
|
SET_CAPACITY,
|
||||||
STREAM_CANCELLATION,
|
REFERENCED_NAME,
|
||||||
INSERT_COUNT_INCREMENT
|
LITERAL_NAME,
|
||||||
|
DUPLICATE
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Operation
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
INDEX,
|
||||||
|
NAME,
|
||||||
|
VALUE,
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Handler
|
public interface Handler
|
||||||
{
|
{
|
||||||
void onSectionAcknowledgement(int streamId) throws QpackException;
|
void onSetDynamicTableCapacity(int capacity) throws QpackException;
|
||||||
|
|
||||||
void onStreamCancellation(int streamId) throws QpackException;
|
void onDuplicate(int index) throws QpackException;
|
||||||
|
|
||||||
void onInsertCountIncrement(int increment) throws QpackException;
|
void onInsertNameWithReference(int nameIndex, boolean isDynamicTableIndex, String value) throws QpackException;
|
||||||
|
|
||||||
|
void onInsertWithLiteralName(String name, String value) throws QpackException;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EncoderHandler implements Handler
|
public static class DecoderAdapter implements Handler
|
||||||
{
|
{
|
||||||
private final QpackEncoder _encoder;
|
private final QpackDecoder _decoder;
|
||||||
|
|
||||||
public EncoderHandler(QpackEncoder encoder)
|
public DecoderAdapter(QpackDecoder decoder)
|
||||||
{
|
{
|
||||||
_encoder = encoder;
|
_decoder = decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSectionAcknowledgement(int streamId) throws QpackException
|
public void onSetDynamicTableCapacity(int capacity)
|
||||||
{
|
{
|
||||||
_encoder.sectionAcknowledgement(streamId);
|
_decoder.setCapacity(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStreamCancellation(int streamId) throws QpackException
|
public void onDuplicate(int index) throws QpackException
|
||||||
{
|
{
|
||||||
_encoder.streamCancellation(streamId);
|
_decoder.insert(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInsertCountIncrement(int increment) throws QpackException
|
public void onInsertNameWithReference(int nameIndex, boolean isDynamicTableIndex, String value) throws QpackException
|
||||||
{
|
{
|
||||||
_encoder.insertCountIncrement(increment);
|
_decoder.insert(nameIndex, isDynamicTableIndex, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInsertWithLiteralName(String name, String value) throws QpackException
|
||||||
|
{
|
||||||
|
_decoder.insert(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecoderInstructionParser(QpackEncoder encoder)
|
public DecoderInstructionParser(QpackDecoder decoder)
|
||||||
{
|
{
|
||||||
this(new EncoderHandler(encoder));
|
this(new DecoderAdapter(decoder));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecoderInstructionParser(Handler handler)
|
public DecoderInstructionParser(Handler handler)
|
||||||
{
|
{
|
||||||
_handler = handler;
|
_handler = handler;
|
||||||
|
_stringParser = new NBitStringParser();
|
||||||
_integerParser = new NBitIntegerParser();
|
_integerParser = new NBitIntegerParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,39 +114,46 @@ public class DecoderInstructionParser
|
||||||
|
|
||||||
switch (_state)
|
switch (_state)
|
||||||
{
|
{
|
||||||
case IDLE:
|
case PARSING:
|
||||||
// Get first byte without incrementing the buffers position.
|
|
||||||
byte firstByte = buffer.get(buffer.position());
|
byte firstByte = buffer.get(buffer.position());
|
||||||
if ((firstByte & 0x80) != 0)
|
if ((firstByte & 0x80) != 0)
|
||||||
{
|
{
|
||||||
_state = State.SECTION_ACKNOWLEDGEMENT;
|
_state = State.REFERENCED_NAME;
|
||||||
_integerParser.setPrefix(SECTION_ACKNOWLEDGEMENT_PREFIX);
|
parseInsertNameWithReference(buffer);
|
||||||
parseSectionAcknowledgment(buffer);
|
|
||||||
}
|
}
|
||||||
else if ((firstByte & 0x40) != 0)
|
else if ((firstByte & 0x40) != 0)
|
||||||
{
|
{
|
||||||
_state = State.STREAM_CANCELLATION;
|
_state = State.LITERAL_NAME;
|
||||||
_integerParser.setPrefix(STREAM_CANCELLATION_PREFIX);
|
parseInsertWithLiteralName(buffer);
|
||||||
parseStreamCancellation(buffer);
|
}
|
||||||
|
else if ((firstByte & 0x20) != 0)
|
||||||
|
{
|
||||||
|
_state = State.SET_CAPACITY;
|
||||||
|
_integerParser.setPrefix(5);
|
||||||
|
parseSetDynamicTableCapacity(buffer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_state = State.INSERT_COUNT_INCREMENT;
|
_state = State.DUPLICATE;
|
||||||
_integerParser.setPrefix(INSERT_COUNT_INCREMENT_PREFIX);
|
_integerParser.setPrefix(5);
|
||||||
parseInsertCountIncrement(buffer);
|
parseDuplicate(buffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SECTION_ACKNOWLEDGEMENT:
|
case SET_CAPACITY:
|
||||||
parseSectionAcknowledgment(buffer);
|
parseSetDynamicTableCapacity(buffer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STREAM_CANCELLATION:
|
case DUPLICATE:
|
||||||
parseStreamCancellation(buffer);
|
parseDuplicate(buffer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INSERT_COUNT_INCREMENT:
|
case LITERAL_NAME:
|
||||||
parseInsertCountIncrement(buffer);
|
parseInsertWithLiteralName(buffer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REFERENCED_NAME:
|
||||||
|
parseInsertNameWithReference(buffer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -134,39 +161,109 @@ public class DecoderInstructionParser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseSectionAcknowledgment(ByteBuffer buffer) throws QpackException
|
private void parseInsertNameWithReference(ByteBuffer buffer) throws QpackException
|
||||||
{
|
{
|
||||||
int streamId = _integerParser.decode(buffer);
|
while (true)
|
||||||
if (streamId >= 0)
|
|
||||||
{
|
{
|
||||||
reset();
|
switch (_operation)
|
||||||
_handler.onSectionAcknowledgement(streamId);
|
{
|
||||||
|
case NONE:
|
||||||
|
byte firstByte = buffer.get(buffer.position());
|
||||||
|
_referenceDynamicTable = (firstByte & 0x40) == 0;
|
||||||
|
_operation = Operation.INDEX;
|
||||||
|
_integerParser.setPrefix(6);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case INDEX:
|
||||||
|
_index = _integerParser.decode(buffer);
|
||||||
|
if (_index < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_operation = Operation.VALUE;
|
||||||
|
_stringParser.setPrefix(8);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case VALUE:
|
||||||
|
String value = _stringParser.decode(buffer);
|
||||||
|
if (value == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int index = _index;
|
||||||
|
boolean dynamic = _referenceDynamicTable;
|
||||||
|
reset();
|
||||||
|
_handler.onInsertNameWithReference(index, dynamic, value);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException(_operation.name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseStreamCancellation(ByteBuffer buffer) throws QpackException
|
private void parseInsertWithLiteralName(ByteBuffer buffer) throws QpackException
|
||||||
{
|
{
|
||||||
int streamId = _integerParser.decode(buffer);
|
while (true)
|
||||||
if (streamId >= 0)
|
|
||||||
{
|
{
|
||||||
reset();
|
switch (_operation)
|
||||||
_handler.onStreamCancellation(streamId);
|
{
|
||||||
|
case NONE:
|
||||||
|
_operation = Operation.NAME;
|
||||||
|
_stringParser.setPrefix(6);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case NAME:
|
||||||
|
_name = _stringParser.decode(buffer);
|
||||||
|
if (_name == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_operation = Operation.VALUE;
|
||||||
|
_stringParser.setPrefix(8);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case VALUE:
|
||||||
|
String value = _stringParser.decode(buffer);
|
||||||
|
if (value == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
String name = _name;
|
||||||
|
reset();
|
||||||
|
_handler.onInsertWithLiteralName(name, value);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException(_operation.name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseInsertCountIncrement(ByteBuffer buffer) throws QpackException
|
private void parseDuplicate(ByteBuffer buffer) throws QpackException
|
||||||
{
|
{
|
||||||
int increment = _integerParser.decode(buffer);
|
int index = _integerParser.decode(buffer);
|
||||||
if (increment >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
_handler.onInsertCountIncrement(increment);
|
_handler.onDuplicate(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseSetDynamicTableCapacity(ByteBuffer buffer) throws QpackException
|
||||||
|
{
|
||||||
|
int capacity = _integerParser.decode(buffer);
|
||||||
|
if (capacity >= 0)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
_handler.onSetDynamicTableCapacity(capacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset()
|
public void reset()
|
||||||
{
|
{
|
||||||
_state = State.IDLE;
|
_stringParser.reset();
|
||||||
_integerParser.reset();
|
_integerParser.reset();
|
||||||
|
_state = State.PARSING;
|
||||||
|
_operation = Operation.NONE;
|
||||||
|
_referenceDynamicTable = false;
|
||||||
|
_index = -1;
|
||||||
|
_name = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,6 +223,7 @@ public class EncodedFieldSection
|
||||||
|
|
||||||
private class IndexedNameField implements EncodedField
|
private class IndexedNameField implements EncodedField
|
||||||
{
|
{
|
||||||
|
// TODO: what to do with allow encoding?
|
||||||
private final boolean _allowEncoding;
|
private final boolean _allowEncoding;
|
||||||
private final boolean _dynamicTable;
|
private final boolean _dynamicTable;
|
||||||
private final int _nameIndex;
|
private final int _nameIndex;
|
||||||
|
@ -243,7 +244,7 @@ public class EncodedFieldSection
|
||||||
if (_dynamicTable)
|
if (_dynamicTable)
|
||||||
field = context.getDynamicTable().getAbsolute(_base + _nameIndex + 1).getHttpField();
|
field = context.getDynamicTable().getAbsolute(_base + _nameIndex + 1).getHttpField();
|
||||||
else
|
else
|
||||||
field = context.getStaticTable().get(_nameIndex).getHttpField();
|
field = QpackContext.getStaticTable().get(_nameIndex).getHttpField();
|
||||||
|
|
||||||
return new HttpField(field.getHeader(), field.getName(), _value);
|
return new HttpField(field.getHeader(), field.getName(), _value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,95 +15,75 @@ package org.eclipse.jetty.http3.qpack.parser;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.QpackDecoder;
|
import org.eclipse.jetty.http3.qpack.QpackEncoder;
|
||||||
import org.eclipse.jetty.http3.qpack.QpackException;
|
import org.eclipse.jetty.http3.qpack.QpackException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receives instructions coming from the remote Decoder as a sequence of unframed instructions.
|
* Parses a stream of unframed instructions for the Encoder. These instructions are sent from the remote Decoder.
|
||||||
*/
|
*/
|
||||||
public class EncoderInstructionParser
|
public class EncoderInstructionParser
|
||||||
{
|
{
|
||||||
private final Handler _handler;
|
private static final int SECTION_ACKNOWLEDGEMENT_PREFIX = 7;
|
||||||
private final NBitStringParser _stringParser;
|
private static final int STREAM_CANCELLATION_PREFIX = 6;
|
||||||
private final NBitIntegerParser _integerParser;
|
private static final int INSERT_COUNT_INCREMENT_PREFIX = 6;
|
||||||
private State _state = State.PARSING;
|
|
||||||
private Operation _operation = Operation.NONE;
|
|
||||||
|
|
||||||
private boolean _referenceDynamicTable;
|
private final Handler _handler;
|
||||||
private int _index;
|
private final NBitIntegerParser _integerParser;
|
||||||
private String _name;
|
private State _state = State.IDLE;
|
||||||
|
|
||||||
private enum State
|
private enum State
|
||||||
{
|
{
|
||||||
PARSING,
|
IDLE,
|
||||||
SET_CAPACITY,
|
SECTION_ACKNOWLEDGEMENT,
|
||||||
REFERENCED_NAME,
|
STREAM_CANCELLATION,
|
||||||
LITERAL_NAME,
|
INSERT_COUNT_INCREMENT
|
||||||
DUPLICATE
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum Operation
|
|
||||||
{
|
|
||||||
NONE,
|
|
||||||
INDEX,
|
|
||||||
NAME,
|
|
||||||
VALUE,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Handler
|
public interface Handler
|
||||||
{
|
{
|
||||||
void onSetDynamicTableCapacity(int capacity) throws QpackException;
|
void onSectionAcknowledgement(int streamId) throws QpackException;
|
||||||
|
|
||||||
void onDuplicate(int index) throws QpackException;
|
void onStreamCancellation(int streamId) throws QpackException;
|
||||||
|
|
||||||
void onInsertNameWithReference(int nameIndex, boolean isDynamicTableIndex, String value) throws QpackException;
|
void onInsertCountIncrement(int increment) throws QpackException;
|
||||||
|
|
||||||
void onInsertWithLiteralName(String name, String value) throws QpackException;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DecoderHandler implements Handler
|
public static class EncoderAdapter implements Handler
|
||||||
{
|
{
|
||||||
private final QpackDecoder _decoder;
|
private final QpackEncoder _encoder;
|
||||||
|
|
||||||
public DecoderHandler(QpackDecoder decoder)
|
public EncoderAdapter(QpackEncoder encoder)
|
||||||
{
|
{
|
||||||
_decoder = decoder;
|
_encoder = encoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetDynamicTableCapacity(int capacity)
|
public void onSectionAcknowledgement(int streamId) throws QpackException
|
||||||
{
|
{
|
||||||
_decoder.setCapacity(capacity);
|
_encoder.sectionAcknowledgement(streamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDuplicate(int index) throws QpackException
|
public void onStreamCancellation(int streamId) throws QpackException
|
||||||
{
|
{
|
||||||
_decoder.insert(index);
|
_encoder.streamCancellation(streamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInsertNameWithReference(int nameIndex, boolean isDynamicTableIndex, String value) throws QpackException
|
public void onInsertCountIncrement(int increment) throws QpackException
|
||||||
{
|
{
|
||||||
_decoder.insert(nameIndex, isDynamicTableIndex, value);
|
_encoder.insertCountIncrement(increment);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInsertWithLiteralName(String name, String value) throws QpackException
|
|
||||||
{
|
|
||||||
_decoder.insert(name, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public EncoderInstructionParser(QpackDecoder decoder)
|
public EncoderInstructionParser(QpackEncoder encoder)
|
||||||
{
|
{
|
||||||
this(new DecoderHandler(decoder));
|
this(new EncoderAdapter(encoder));
|
||||||
}
|
}
|
||||||
|
|
||||||
public EncoderInstructionParser(Handler handler)
|
public EncoderInstructionParser(Handler handler)
|
||||||
{
|
{
|
||||||
_handler = handler;
|
_handler = handler;
|
||||||
_stringParser = new NBitStringParser();
|
|
||||||
_integerParser = new NBitIntegerParser();
|
_integerParser = new NBitIntegerParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,46 +94,39 @@ public class EncoderInstructionParser
|
||||||
|
|
||||||
switch (_state)
|
switch (_state)
|
||||||
{
|
{
|
||||||
case PARSING:
|
case IDLE:
|
||||||
|
// Get first byte without incrementing the buffers position.
|
||||||
byte firstByte = buffer.get(buffer.position());
|
byte firstByte = buffer.get(buffer.position());
|
||||||
if ((firstByte & 0x80) != 0)
|
if ((firstByte & 0x80) != 0)
|
||||||
{
|
{
|
||||||
_state = State.REFERENCED_NAME;
|
_state = State.SECTION_ACKNOWLEDGEMENT;
|
||||||
parseInsertNameWithReference(buffer);
|
_integerParser.setPrefix(SECTION_ACKNOWLEDGEMENT_PREFIX);
|
||||||
|
parseSectionAcknowledgment(buffer);
|
||||||
}
|
}
|
||||||
else if ((firstByte & 0x40) != 0)
|
else if ((firstByte & 0x40) != 0)
|
||||||
{
|
{
|
||||||
_state = State.LITERAL_NAME;
|
_state = State.STREAM_CANCELLATION;
|
||||||
parseInsertWithLiteralName(buffer);
|
_integerParser.setPrefix(STREAM_CANCELLATION_PREFIX);
|
||||||
}
|
parseStreamCancellation(buffer);
|
||||||
else if ((firstByte & 0x20) != 0)
|
|
||||||
{
|
|
||||||
_state = State.SET_CAPACITY;
|
|
||||||
_integerParser.setPrefix(5);
|
|
||||||
parseSetDynamicTableCapacity(buffer);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_state = State.DUPLICATE;
|
_state = State.INSERT_COUNT_INCREMENT;
|
||||||
_integerParser.setPrefix(5);
|
_integerParser.setPrefix(INSERT_COUNT_INCREMENT_PREFIX);
|
||||||
parseDuplicate(buffer);
|
parseInsertCountIncrement(buffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SET_CAPACITY:
|
case SECTION_ACKNOWLEDGEMENT:
|
||||||
parseSetDynamicTableCapacity(buffer);
|
parseSectionAcknowledgment(buffer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DUPLICATE:
|
case STREAM_CANCELLATION:
|
||||||
parseDuplicate(buffer);
|
parseStreamCancellation(buffer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_NAME:
|
case INSERT_COUNT_INCREMENT:
|
||||||
parseInsertWithLiteralName(buffer);
|
parseInsertCountIncrement(buffer);
|
||||||
break;
|
|
||||||
|
|
||||||
case REFERENCED_NAME:
|
|
||||||
parseInsertNameWithReference(buffer);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -161,109 +134,39 @@ public class EncoderInstructionParser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseInsertNameWithReference(ByteBuffer buffer) throws QpackException
|
private void parseSectionAcknowledgment(ByteBuffer buffer) throws QpackException
|
||||||
{
|
{
|
||||||
while (true)
|
int streamId = _integerParser.decode(buffer);
|
||||||
{
|
if (streamId >= 0)
|
||||||
switch (_operation)
|
|
||||||
{
|
|
||||||
case NONE:
|
|
||||||
byte firstByte = buffer.get(buffer.position());
|
|
||||||
_referenceDynamicTable = (firstByte & 0x40) == 0;
|
|
||||||
_operation = Operation.INDEX;
|
|
||||||
_integerParser.setPrefix(6);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case INDEX:
|
|
||||||
_index = _integerParser.decode(buffer);
|
|
||||||
if (_index < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_operation = Operation.VALUE;
|
|
||||||
_stringParser.setPrefix(8);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case VALUE:
|
|
||||||
String value = _stringParser.decode(buffer);
|
|
||||||
if (value == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int index = _index;
|
|
||||||
boolean dynamic = _referenceDynamicTable;
|
|
||||||
reset();
|
|
||||||
_handler.onInsertNameWithReference(index, dynamic, value);
|
|
||||||
return;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException(_operation.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseInsertWithLiteralName(ByteBuffer buffer) throws QpackException
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
switch (_operation)
|
|
||||||
{
|
|
||||||
case NONE:
|
|
||||||
_operation = Operation.NAME;
|
|
||||||
_stringParser.setPrefix(6);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case NAME:
|
|
||||||
_name = _stringParser.decode(buffer);
|
|
||||||
if (_name == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_operation = Operation.VALUE;
|
|
||||||
_stringParser.setPrefix(8);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case VALUE:
|
|
||||||
String value = _stringParser.decode(buffer);
|
|
||||||
if (value == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
String name = _name;
|
|
||||||
reset();
|
|
||||||
_handler.onInsertWithLiteralName(name, value);
|
|
||||||
return;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException(_operation.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseDuplicate(ByteBuffer buffer) throws QpackException
|
|
||||||
{
|
|
||||||
int index = _integerParser.decode(buffer);
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
_handler.onDuplicate(index);
|
_handler.onSectionAcknowledgement(streamId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseSetDynamicTableCapacity(ByteBuffer buffer) throws QpackException
|
private void parseStreamCancellation(ByteBuffer buffer) throws QpackException
|
||||||
{
|
{
|
||||||
int capacity = _integerParser.decode(buffer);
|
int streamId = _integerParser.decode(buffer);
|
||||||
if (capacity >= 0)
|
if (streamId >= 0)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
_handler.onSetDynamicTableCapacity(capacity);
|
_handler.onStreamCancellation(streamId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseInsertCountIncrement(ByteBuffer buffer) throws QpackException
|
||||||
|
{
|
||||||
|
int increment = _integerParser.decode(buffer);
|
||||||
|
if (increment >= 0)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
_handler.onInsertCountIncrement(increment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset()
|
public void reset()
|
||||||
{
|
{
|
||||||
_stringParser.reset();
|
_state = State.IDLE;
|
||||||
_integerParser.reset();
|
_integerParser.reset();
|
||||||
_state = State.PARSING;
|
|
||||||
_operation = Operation.NONE;
|
|
||||||
_referenceDynamicTable = false;
|
|
||||||
_index = -1;
|
|
||||||
_name = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,114 +20,118 @@ import java.util.Queue;
|
||||||
import org.eclipse.jetty.http3.qpack.parser.DecoderInstructionParser;
|
import org.eclipse.jetty.http3.qpack.parser.DecoderInstructionParser;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
import org.eclipse.jetty.util.TypeUtil;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class DecoderInstructionParserTest
|
public class DecoderInstructionParserTest
|
||||||
{
|
{
|
||||||
public static class DebugHandler implements DecoderInstructionParser.Handler
|
public static class DebugHandler implements DecoderInstructionParser.Handler
|
||||||
{
|
{
|
||||||
public Queue<Integer> sectionAcknowledgements = new LinkedList<>();
|
public Queue<Integer> setCapacities = new LinkedList<>();
|
||||||
public Queue<Integer> streamCancellations = new LinkedList<>();
|
public Queue<Integer> duplicates = new LinkedList<>();
|
||||||
public Queue<Integer> insertCountIncrements = new LinkedList<>();
|
public Queue<Entry> literalNameEntries = new LinkedList<>();
|
||||||
|
public Queue<ReferencedEntry> referencedNameEntries = new LinkedList<>();
|
||||||
|
|
||||||
@Override
|
public static class Entry
|
||||||
public void onSectionAcknowledgement(int streamId)
|
|
||||||
{
|
{
|
||||||
sectionAcknowledgements.add(streamId);
|
public Entry(String name, String value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
String name;
|
||||||
|
String value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ReferencedEntry
|
||||||
|
{
|
||||||
|
public ReferencedEntry(int index, boolean dynamic, String value)
|
||||||
|
{
|
||||||
|
this.index = index;
|
||||||
|
this.dynamic = dynamic;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index;
|
||||||
|
boolean dynamic;
|
||||||
|
String value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStreamCancellation(int streamId)
|
public void onSetDynamicTableCapacity(int capacity)
|
||||||
{
|
{
|
||||||
streamCancellations.add(streamId);
|
setCapacities.add(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInsertCountIncrement(int increment)
|
public void onDuplicate(int index)
|
||||||
{
|
{
|
||||||
insertCountIncrements.add(increment);
|
duplicates.add(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInsertNameWithReference(int nameIndex, boolean isDynamicTableIndex, String value)
|
||||||
|
{
|
||||||
|
referencedNameEntries.add(new ReferencedEntry(nameIndex, isDynamicTableIndex, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInsertWithLiteralName(String name, String value)
|
||||||
|
{
|
||||||
|
literalNameEntries.add(new Entry(name, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty()
|
public boolean isEmpty()
|
||||||
{
|
{
|
||||||
return sectionAcknowledgements.isEmpty() && streamCancellations.isEmpty() && insertCountIncrements.isEmpty();
|
return setCapacities.isEmpty() && duplicates.isEmpty() && literalNameEntries.isEmpty() && referencedNameEntries.isEmpty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private DecoderInstructionParser _instructionParser;
|
||||||
public void testSectionAcknowledgement() throws Exception
|
private DebugHandler _handler;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void before()
|
||||||
{
|
{
|
||||||
DebugHandler debugHandler = new DebugHandler();
|
_handler = new DebugHandler();
|
||||||
DecoderInstructionParser incomingEncoderStream = new DecoderInstructionParser(debugHandler);
|
_instructionParser = new DecoderInstructionParser(_handler);
|
||||||
|
|
||||||
// Example from the spec, section acknowledgement instruction with stream id 4.
|
|
||||||
String encoded = "84";
|
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
|
||||||
incomingEncoderStream.parse(buffer);
|
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(4));
|
|
||||||
assertTrue(debugHandler.isEmpty());
|
|
||||||
|
|
||||||
// 1111 1110 == FE is largest value we can do without continuation should be stream ID 126.
|
|
||||||
encoded = "FE";
|
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
|
||||||
incomingEncoderStream.parse(buffer);
|
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(126));
|
|
||||||
assertTrue(debugHandler.isEmpty());
|
|
||||||
|
|
||||||
// 1111 1111 0000 0000 == FF00 is next value, stream id 127.
|
|
||||||
encoded = "FF00";
|
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
|
||||||
incomingEncoderStream.parse(buffer);
|
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(127));
|
|
||||||
assertTrue(debugHandler.isEmpty());
|
|
||||||
|
|
||||||
// 1111 1111 0000 0001 == FF01 is next value, stream id 128.
|
|
||||||
encoded = "FF01";
|
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
|
||||||
incomingEncoderStream.parse(buffer);
|
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(128));
|
|
||||||
assertTrue(debugHandler.isEmpty());
|
|
||||||
|
|
||||||
// FFBA09 contains section ack with stream ID of 1337, this contains an octet with continuation bit.
|
|
||||||
encoded = "FFBA09";
|
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
|
||||||
incomingEncoderStream.parse(buffer);
|
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(1337));
|
|
||||||
assertTrue(debugHandler.isEmpty());
|
|
||||||
|
|
||||||
// Test with continuation.
|
|
||||||
encoded = "FFBA09";
|
|
||||||
byte[] bytes = TypeUtil.fromHexString(encoded);
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
ByteBuffer buffer1 = BufferUtil.toBuffer(bytes, 0, 2);
|
|
||||||
ByteBuffer buffer2 = BufferUtil.toBuffer(bytes, 2, 1);
|
|
||||||
incomingEncoderStream.parse(buffer1);
|
|
||||||
assertTrue(debugHandler.isEmpty());
|
|
||||||
incomingEncoderStream.parse(buffer2);
|
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(1337));
|
|
||||||
assertTrue(debugHandler.isEmpty());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Disabled
|
|
||||||
@Test
|
@Test
|
||||||
public void testStreamCancellation() throws Exception
|
public void testAddWithReferencedEntry() throws Exception
|
||||||
{
|
{
|
||||||
// TODO: Write this test.
|
String insertAuthorityEntry = "c00f7777772e6578616d706c652e636f6d";
|
||||||
throw new RuntimeException("TODO: testStreamCancellation");
|
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(insertAuthorityEntry));
|
||||||
|
_instructionParser.parse(buffer);
|
||||||
|
DebugHandler.ReferencedEntry entry = _handler.referencedNameEntries.poll();
|
||||||
|
assertNotNull(entry);
|
||||||
|
assertThat(entry.index, is(0));
|
||||||
|
assertThat(entry.dynamic, is(false));
|
||||||
|
assertThat(entry.value, is("www.example.com"));
|
||||||
|
|
||||||
|
String insertPathEntry = "c10c2f73616d706c652f70617468";
|
||||||
|
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(insertPathEntry));
|
||||||
|
_instructionParser.parse(buffer);
|
||||||
|
entry = _handler.referencedNameEntries.poll();
|
||||||
|
assertNotNull(entry);
|
||||||
|
assertThat(entry.index, is(1));
|
||||||
|
assertThat(entry.dynamic, is(false));
|
||||||
|
assertThat(entry.value, is("/sample/path"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Disabled
|
|
||||||
@Test
|
@Test
|
||||||
public void testInsertCountIncrement() throws Exception
|
public void testSetCapacity() throws Exception
|
||||||
{
|
{
|
||||||
// TODO: Write this test.
|
String setCapacityString = "3fbd01";
|
||||||
throw new RuntimeException("TODO: testInsertCountIncrement");
|
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(setCapacityString));
|
||||||
|
_instructionParser.parse(buffer);
|
||||||
|
assertThat(_handler.setCapacities.poll(), is(220));
|
||||||
|
assertTrue(_handler.isEmpty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,8 @@ public class EncodeDecodeTest
|
||||||
private TestDecoderHandler _decoderHandler;
|
private TestDecoderHandler _decoderHandler;
|
||||||
private TestEncoderHandler _encoderHandler;
|
private TestEncoderHandler _encoderHandler;
|
||||||
|
|
||||||
private DecoderInstructionParser _decoderInstructionParser;
|
|
||||||
private EncoderInstructionParser _encoderInstructionParser;
|
private EncoderInstructionParser _encoderInstructionParser;
|
||||||
|
private DecoderInstructionParser _decoderInstructionParser;
|
||||||
|
|
||||||
private static final int MAX_BLOCKED_STREAMS = 5;
|
private static final int MAX_BLOCKED_STREAMS = 5;
|
||||||
private static final int MAX_HEADER_SIZE = 1024;
|
private static final int MAX_HEADER_SIZE = 1024;
|
||||||
|
@ -66,8 +66,8 @@ public class EncodeDecodeTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_decoder = new QpackDecoder(_decoderHandler, MAX_HEADER_SIZE);
|
_decoder = new QpackDecoder(_decoderHandler, MAX_HEADER_SIZE);
|
||||||
_encoderInstructionParser = new EncoderInstructionParser(_decoder);
|
_encoderInstructionParser = new EncoderInstructionParser(_encoder);
|
||||||
_decoderInstructionParser = new DecoderInstructionParser(_encoder);
|
_decoderInstructionParser = new DecoderInstructionParser(_decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -88,7 +88,7 @@ public class EncodeDecodeTest
|
||||||
assertThat(_decoderHandler.getInstruction(), instanceOf(SectionAcknowledgmentInstruction.class));
|
assertThat(_decoderHandler.getInstruction(), instanceOf(SectionAcknowledgmentInstruction.class));
|
||||||
assertTrue(_decoderHandler.isEmpty());
|
assertTrue(_decoderHandler.isEmpty());
|
||||||
|
|
||||||
_decoderInstructionParser.parse(toBuffer(new SectionAcknowledgmentInstruction(streamId)));
|
_encoderInstructionParser.parse(toBuffer(new SectionAcknowledgmentInstruction(streamId)));
|
||||||
|
|
||||||
// B.2. Dynamic Table.
|
// B.2. Dynamic Table.
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ public class EncodeDecodeTest
|
||||||
assertThat(((SetCapacityInstruction)instruction).getCapacity(), is(220));
|
assertThat(((SetCapacityInstruction)instruction).getCapacity(), is(220));
|
||||||
assertThat(toString(instruction), equalsHex("3fbd01"));
|
assertThat(toString(instruction), equalsHex("3fbd01"));
|
||||||
|
|
||||||
_encoderInstructionParser.parse(toHex("3fbd01"));
|
_decoderInstructionParser.parse(toHex("3fbd01"));
|
||||||
assertThat(_decoder.getQpackContext().getDynamicTable().getCapacity(), is(220));
|
assertThat(_decoder.getQpackContext().getDynamicTable().getCapacity(), is(220));
|
||||||
|
|
||||||
// Insert with named referenced to static table. Test we get two instructions generated to add to the dynamic table.
|
// Insert with named referenced to static table. Test we get two instructions generated to add to the dynamic table.
|
||||||
|
@ -126,11 +126,11 @@ public class EncodeDecodeTest
|
||||||
_decoder.decode(streamId, buffer);
|
_decoder.decode(streamId, buffer);
|
||||||
assertNull(_decoderHandler.getHttpFields());
|
assertNull(_decoderHandler.getHttpFields());
|
||||||
|
|
||||||
_encoderInstructionParser.parse(toHex("c00f 7777 772e 6578 616d 706c 652e 636f 6d"));
|
_decoderInstructionParser.parse(toHex("c00f 7777 772e 6578 616d 706c 652e 636f 6d"));
|
||||||
assertNull(_decoderHandler.getHttpFields());
|
assertNull(_decoderHandler.getHttpFields());
|
||||||
assertThat(_decoderHandler.getInstruction(), instanceOf(InsertCountIncrementInstruction.class));
|
assertThat(_decoderHandler.getInstruction(), instanceOf(InsertCountIncrementInstruction.class));
|
||||||
|
|
||||||
_encoderInstructionParser.parse(toHex("c10c 2f73 616d 706c 652f 7061 7468"));
|
_decoderInstructionParser.parse(toHex("c10c 2f73 616d 706c 652f 7061 7468"));
|
||||||
assertThat(_decoderHandler.getHttpFields(), is(httpFields));
|
assertThat(_decoderHandler.getHttpFields(), is(httpFields));
|
||||||
assertThat(_decoderHandler.getInstruction(), instanceOf(InsertCountIncrementInstruction.class));
|
assertThat(_decoderHandler.getInstruction(), instanceOf(InsertCountIncrementInstruction.class));
|
||||||
|
|
||||||
|
@ -138,8 +138,8 @@ public class EncodeDecodeTest
|
||||||
assertTrue(_decoderHandler.isEmpty());
|
assertTrue(_decoderHandler.isEmpty());
|
||||||
|
|
||||||
// Parse the decoder instructions on the encoder.
|
// Parse the decoder instructions on the encoder.
|
||||||
_decoderInstructionParser.parse(toBuffer(new InsertCountIncrementInstruction(2)));
|
_encoderInstructionParser.parse(toBuffer(new InsertCountIncrementInstruction(2)));
|
||||||
_decoderInstructionParser.parse(toBuffer(new SectionAcknowledgmentInstruction(streamId)));
|
_encoderInstructionParser.parse(toBuffer(new SectionAcknowledgmentInstruction(streamId)));
|
||||||
|
|
||||||
// B.3. Speculative Insert
|
// B.3. Speculative Insert
|
||||||
_encoder.insert(new HttpField("custom-key", "custom-value"));
|
_encoder.insert(new HttpField("custom-key", "custom-value"));
|
||||||
|
|
|
@ -20,118 +20,114 @@ import java.util.Queue;
|
||||||
import org.eclipse.jetty.http3.qpack.parser.EncoderInstructionParser;
|
import org.eclipse.jetty.http3.qpack.parser.EncoderInstructionParser;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
import org.eclipse.jetty.util.TypeUtil;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class EncoderInstructionParserTest
|
public class EncoderInstructionParserTest
|
||||||
{
|
{
|
||||||
public static class DebugHandler implements EncoderInstructionParser.Handler
|
public static class DebugHandler implements EncoderInstructionParser.Handler
|
||||||
{
|
{
|
||||||
public Queue<Integer> setCapacities = new LinkedList<>();
|
public Queue<Integer> sectionAcknowledgements = new LinkedList<>();
|
||||||
public Queue<Integer> duplicates = new LinkedList<>();
|
public Queue<Integer> streamCancellations = new LinkedList<>();
|
||||||
public Queue<Entry> literalNameEntries = new LinkedList<>();
|
public Queue<Integer> insertCountIncrements = new LinkedList<>();
|
||||||
public Queue<ReferencedEntry> referencedNameEntries = new LinkedList<>();
|
|
||||||
|
|
||||||
public static class Entry
|
@Override
|
||||||
|
public void onSectionAcknowledgement(int streamId)
|
||||||
{
|
{
|
||||||
public Entry(String name, String value)
|
sectionAcknowledgements.add(streamId);
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
String name;
|
|
||||||
String value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ReferencedEntry
|
|
||||||
{
|
|
||||||
public ReferencedEntry(int index, boolean dynamic, String value)
|
|
||||||
{
|
|
||||||
this.index = index;
|
|
||||||
this.dynamic = dynamic;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int index;
|
|
||||||
boolean dynamic;
|
|
||||||
String value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetDynamicTableCapacity(int capacity)
|
public void onStreamCancellation(int streamId)
|
||||||
{
|
{
|
||||||
setCapacities.add(capacity);
|
streamCancellations.add(streamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDuplicate(int index)
|
public void onInsertCountIncrement(int increment)
|
||||||
{
|
{
|
||||||
duplicates.add(index);
|
insertCountIncrements.add(increment);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInsertNameWithReference(int nameIndex, boolean isDynamicTableIndex, String value)
|
|
||||||
{
|
|
||||||
referencedNameEntries.add(new ReferencedEntry(nameIndex, isDynamicTableIndex, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInsertWithLiteralName(String name, String value)
|
|
||||||
{
|
|
||||||
literalNameEntries.add(new Entry(name, value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty()
|
public boolean isEmpty()
|
||||||
{
|
{
|
||||||
return setCapacities.isEmpty() && duplicates.isEmpty() && literalNameEntries.isEmpty() && referencedNameEntries.isEmpty();
|
return sectionAcknowledgements.isEmpty() && streamCancellations.isEmpty() && insertCountIncrements.isEmpty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private EncoderInstructionParser _instructionParser;
|
@Test
|
||||||
private DebugHandler _handler;
|
public void testSectionAcknowledgement() throws Exception
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void before()
|
|
||||||
{
|
{
|
||||||
_handler = new DebugHandler();
|
DebugHandler debugHandler = new DebugHandler();
|
||||||
_instructionParser = new EncoderInstructionParser(_handler);
|
EncoderInstructionParser incomingEncoderStream = new EncoderInstructionParser(debugHandler);
|
||||||
|
|
||||||
|
// Example from the spec, section acknowledgement instruction with stream id 4.
|
||||||
|
String encoded = "84";
|
||||||
|
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
|
incomingEncoderStream.parse(buffer);
|
||||||
|
assertThat(debugHandler.sectionAcknowledgements.poll(), is(4));
|
||||||
|
assertTrue(debugHandler.isEmpty());
|
||||||
|
|
||||||
|
// 1111 1110 == FE is largest value we can do without continuation should be stream ID 126.
|
||||||
|
encoded = "FE";
|
||||||
|
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
|
incomingEncoderStream.parse(buffer);
|
||||||
|
assertThat(debugHandler.sectionAcknowledgements.poll(), is(126));
|
||||||
|
assertTrue(debugHandler.isEmpty());
|
||||||
|
|
||||||
|
// 1111 1111 0000 0000 == FF00 is next value, stream id 127.
|
||||||
|
encoded = "FF00";
|
||||||
|
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
|
incomingEncoderStream.parse(buffer);
|
||||||
|
assertThat(debugHandler.sectionAcknowledgements.poll(), is(127));
|
||||||
|
assertTrue(debugHandler.isEmpty());
|
||||||
|
|
||||||
|
// 1111 1111 0000 0001 == FF01 is next value, stream id 128.
|
||||||
|
encoded = "FF01";
|
||||||
|
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
|
incomingEncoderStream.parse(buffer);
|
||||||
|
assertThat(debugHandler.sectionAcknowledgements.poll(), is(128));
|
||||||
|
assertTrue(debugHandler.isEmpty());
|
||||||
|
|
||||||
|
// FFBA09 contains section ack with stream ID of 1337, this contains an octet with continuation bit.
|
||||||
|
encoded = "FFBA09";
|
||||||
|
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
|
incomingEncoderStream.parse(buffer);
|
||||||
|
assertThat(debugHandler.sectionAcknowledgements.poll(), is(1337));
|
||||||
|
assertTrue(debugHandler.isEmpty());
|
||||||
|
|
||||||
|
// Test with continuation.
|
||||||
|
encoded = "FFBA09";
|
||||||
|
byte[] bytes = TypeUtil.fromHexString(encoded);
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
ByteBuffer buffer1 = BufferUtil.toBuffer(bytes, 0, 2);
|
||||||
|
ByteBuffer buffer2 = BufferUtil.toBuffer(bytes, 2, 1);
|
||||||
|
incomingEncoderStream.parse(buffer1);
|
||||||
|
assertTrue(debugHandler.isEmpty());
|
||||||
|
incomingEncoderStream.parse(buffer2);
|
||||||
|
assertThat(debugHandler.sectionAcknowledgements.poll(), is(1337));
|
||||||
|
assertTrue(debugHandler.isEmpty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testAddWithReferencedEntry() throws Exception
|
public void testStreamCancellation() throws Exception
|
||||||
{
|
{
|
||||||
String insertAuthorityEntry = "c00f7777772e6578616d706c652e636f6d";
|
// TODO: Write this test.
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(insertAuthorityEntry));
|
throw new RuntimeException("TODO: testStreamCancellation");
|
||||||
_instructionParser.parse(buffer);
|
|
||||||
DebugHandler.ReferencedEntry entry = _handler.referencedNameEntries.poll();
|
|
||||||
assertNotNull(entry);
|
|
||||||
assertThat(entry.index, is(0));
|
|
||||||
assertThat(entry.dynamic, is(false));
|
|
||||||
assertThat(entry.value, is("www.example.com"));
|
|
||||||
|
|
||||||
String insertPathEntry = "c10c2f73616d706c652f70617468";
|
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(insertPathEntry));
|
|
||||||
_instructionParser.parse(buffer);
|
|
||||||
entry = _handler.referencedNameEntries.poll();
|
|
||||||
assertNotNull(entry);
|
|
||||||
assertThat(entry.index, is(1));
|
|
||||||
assertThat(entry.dynamic, is(false));
|
|
||||||
assertThat(entry.value, is("/sample/path"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testSetCapacity() throws Exception
|
public void testInsertCountIncrement() throws Exception
|
||||||
{
|
{
|
||||||
String setCapacityString = "3fbd01";
|
// TODO: Write this test.
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(setCapacityString));
|
throw new RuntimeException("TODO: testInsertCountIncrement");
|
||||||
_instructionParser.parse(buffer);
|
|
||||||
assertThat(_handler.setCapacities.poll(), is(220));
|
|
||||||
assertTrue(_handler.isEmpty());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue