Add javadoc to public methods on QPACK encoder & decoder.

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2021-09-14 13:33:59 +10:00 committed by Simone Bordet
parent b6c65404d5
commit 7b2b74045d
3 changed files with 103 additions and 66 deletions

View File

@ -21,8 +21,8 @@ public interface Instruction
{
void encode(ByteBufferPool.Lease lease);
public interface Handler
interface Handler
{
void onInstructions(List<Instruction> instructions) throws QpackException;
void onInstructions(List<Instruction> instructions);
}
}

View File

@ -38,10 +38,6 @@ import org.slf4j.LoggerFactory;
import static org.eclipse.jetty.http3.qpack.QpackException.QPACK_DECODER_STREAM_ERROR;
import static org.eclipse.jetty.http3.qpack.QpackException.QPACK_DECOMPRESSION_FAILED;
/**
* Qpack Decoder
* <p>This is not thread safe and may only be called by 1 thread at a time.</p>
*/
public class QpackDecoder implements Dumpable
{
public static final Logger LOG = LoggerFactory.getLogger(QpackDecoder.class);
@ -95,6 +91,18 @@ public class QpackDecoder implements Dumpable
void onMetaData(long streamId, MetaData metadata);
}
/**
* <p>Decode a buffer into a {@link MetaData} object given a HTTP/3 stream ID. The buffer must be the complete content of a
* headers frame and will be fully consumed. It may be that the Dynamic Table does not yet contain the state required
* to decode this headers frame, in this case the encoded headers will be saved until the required state arrives on the
* instruction stream to update the dynamic table.</p>
* <p>This method may generate instructions to be sent back over the Decoder stream to the remote Encoder.</p>
* @param streamId the stream ID corresponding to this headers frame.
* @param buffer the content of the headers frame.
* @param handler a handler that is invoked when the MetaData is able to be decoded.
* @return true if the MetaData could be decoded immediately without requiring addition state in the DynamicTable.
* @throws QpackException if there was an error with the QPACK decompression.
*/
public boolean decode(long streamId, ByteBuffer buffer, Handler handler) throws QpackException
{
if (LOG.isDebugEnabled())
@ -156,6 +164,13 @@ public class QpackDecoder implements Dumpable
return hadMetaData;
}
/**
* Parse instructions from the Encoder stream. The Encoder stream carries an unframed sequence of instructions from
* the Encoder to the Decoder. This method will fully consume the supplied {@link ByteBuffer} and produce instructions
* to update the state of the Decoder and its Dynamic Table.
* @param buffer a buffer containing bytes from the Encoder stream.
* @throws QpackException if there was an error parsing or handling the instructions.
*/
public void parseInstructionBuffer(ByteBuffer buffer) throws QpackException
{
try

View File

@ -105,71 +105,21 @@ public class QpackEncoder implements Dumpable
* Set the capacity of the DynamicTable and send a instruction to set the capacity on the remote Decoder.
* @param capacity the new capacity.
*/
public void setCapacity(int capacity) throws QpackException
public void setCapacity(int capacity)
{
_context.getDynamicTable().setCapacity(capacity);
_handler.onInstructions(List.of(new SetCapacityInstruction(capacity)));
}
protected boolean shouldIndex(HttpField httpField)
{
return !DO_NOT_INDEX.contains(httpField.getHeader());
}
protected boolean shouldHuffmanEncode(HttpField httpField)
{
return !DO_NOT_HUFFMAN.contains(httpField.getHeader());
}
public void parseInstructionBuffer(ByteBuffer buffer) throws QpackException
{
while (BufferUtil.hasContent(buffer))
{
_parser.parse(buffer);
}
notifyInstructionHandler();
}
public boolean insert(HttpField field) throws QpackException
{
DynamicTable dynamicTable = _context.getDynamicTable();
if (field.getValue() == null)
field = new HttpField(field.getHeader(), field.getName(), "");
boolean canCreateEntry = shouldIndex(field) && dynamicTable.canInsert(field);
if (!canCreateEntry)
return false;
// We can always reference on insertion as it will always arrive before any eviction.
Entry entry = _context.get(field);
if (entry != null)
{
int index = _context.indexOf(entry);
dynamicTable.add(new Entry(field));
_instructions.add(new DuplicateInstruction(index));
notifyInstructionHandler();
return true;
}
boolean huffman = shouldHuffmanEncode(field);
Entry nameEntry = _context.get(field.getName());
if (nameEntry != null)
{
int index = _context.indexOf(nameEntry);
dynamicTable.add(new Entry(field));
_instructions.add(new IndexedNameEntryInstruction(!nameEntry.isStatic(), index, huffman, field.getValue()));
notifyInstructionHandler();
return true;
}
dynamicTable.add(new Entry(field));
_instructions.add(new LiteralNameEntryInstruction(field, huffman));
notifyInstructionHandler();
return true;
}
/**
* <p>Encodes a {@link MetaData} object into the supplied {@link ByteBuffer} for a specific HTTP/s stream.</p>
* <p>This method may generate instructions to be sent back over the Encoder stream to the remote Decoder.</p>
* @param buffer the buffer to take the bytes of the encoded {@link MetaData}.
* @param streamId the stream ID corresponding to this headers frame.
* @param metadata the {@link MetaData} to encode into the buffer.
* @throws QpackException if there was an error with the QPACK compression.
*/
public void encode(ByteBuffer buffer, long streamId, MetaData metadata) throws QpackException
{
if (LOG.isDebugEnabled())
@ -236,6 +186,78 @@ public class QpackEncoder implements Dumpable
notifyInstructionHandler();
}
/**
* Parse instructions from the Decoder stream. The Decoder stream carries an unframed sequence of instructions from
* the Decoder to the Encoder. This method will fully consume the supplied {@link ByteBuffer} and produce instructions
* to update the state of the Encoder and its Dynamic Table.
* @param buffer a buffer containing bytes from the Decoder stream.
* @throws QpackException if there was an error parsing or handling the instructions.
*/
public void parseInstructionBuffer(ByteBuffer buffer) throws QpackException
{
while (BufferUtil.hasContent(buffer))
{
_parser.parse(buffer);
}
notifyInstructionHandler();
}
/**
* A speculative insert of a Header into the Encoders Dynamic Table. This will also generate
* an instruction to be sent over the Encoder stream to the remote Decoder.
* @param field the field to insert into the Dynamic Table.
* @return true if the field was successfully inserted into the Dynamic Table.
*/
public boolean insert(HttpField field)
{
DynamicTable dynamicTable = _context.getDynamicTable();
if (field.getValue() == null)
field = new HttpField(field.getHeader(), field.getName(), "");
boolean canCreateEntry = shouldIndex(field) && dynamicTable.canInsert(field);
if (!canCreateEntry)
return false;
// We can always reference on insertion as it will always arrive before any eviction.
Entry entry = _context.get(field);
if (entry != null)
{
int index = _context.indexOf(entry);
dynamicTable.add(new Entry(field));
_instructions.add(new DuplicateInstruction(index));
notifyInstructionHandler();
return true;
}
boolean huffman = shouldHuffmanEncode(field);
Entry nameEntry = _context.get(field.getName());
if (nameEntry != null)
{
int index = _context.indexOf(nameEntry);
dynamicTable.add(new Entry(field));
_instructions.add(new IndexedNameEntryInstruction(!nameEntry.isStatic(), index, huffman, field.getValue()));
notifyInstructionHandler();
return true;
}
dynamicTable.add(new Entry(field));
_instructions.add(new LiteralNameEntryInstruction(field, huffman));
notifyInstructionHandler();
return true;
}
protected boolean shouldIndex(HttpField httpField)
{
return !DO_NOT_INDEX.contains(httpField.getHeader());
}
protected boolean shouldHuffmanEncode(HttpField httpField)
{
return !DO_NOT_HUFFMAN.contains(httpField.getHeader());
}
private EncodableEntry encode(StreamInfo streamInfo, HttpField field)
{
DynamicTable dynamicTable = _context.getDynamicTable();
@ -402,7 +424,7 @@ public class QpackEncoder implements Dumpable
return (reqInsertCount % (2 * maxEntries)) + 1;
}
private void notifyInstructionHandler() throws QpackException
private void notifyInstructionHandler()
{
if (!_instructions.isEmpty())
_handler.onInstructions(_instructions);