Refactor QPACK to use an internal package for non API classes.
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
f9606770b3
commit
ea70f599bb
|
@ -17,9 +17,6 @@ import org.eclipse.jetty.http3.qpack.QpackFieldPreEncoder;
|
||||||
module org.eclipse.jetty.http3.qpack
|
module org.eclipse.jetty.http3.qpack
|
||||||
{
|
{
|
||||||
exports org.eclipse.jetty.http3.qpack;
|
exports org.eclipse.jetty.http3.qpack;
|
||||||
exports org.eclipse.jetty.http3.qpack.table;
|
|
||||||
exports org.eclipse.jetty.http3.qpack.generator;
|
|
||||||
exports org.eclipse.jetty.http3.qpack.parser;
|
|
||||||
|
|
||||||
requires transitive org.eclipse.jetty.http;
|
requires transitive org.eclipse.jetty.http;
|
||||||
requires org.slf4j;
|
requires org.slf4j;
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
|
||||||
//
|
|
||||||
// This program and the accompanying materials are made available under the
|
|
||||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
||||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
|
||||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
|
||||||
// ========================================================================
|
|
||||||
//
|
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
|
||||||
|
|
||||||
public class HuffmanDecoder
|
|
||||||
{
|
|
||||||
static final char EOS = Huffman.EOS;
|
|
||||||
static final char[] tree = Huffman.tree;
|
|
||||||
static final char[] rowsym = Huffman.rowsym;
|
|
||||||
static final byte[] rowbits = Huffman.rowbits;
|
|
||||||
|
|
||||||
private final Utf8StringBuilder utf8 = new Utf8StringBuilder();
|
|
||||||
private int count = 0;
|
|
||||||
private int node = 0;
|
|
||||||
private int current = 0;
|
|
||||||
private int bits = 0;
|
|
||||||
|
|
||||||
public String decode(ByteBuffer buffer, int length) throws QpackException.CompressionException
|
|
||||||
{
|
|
||||||
for (; count < length; count++)
|
|
||||||
{
|
|
||||||
if (!buffer.hasRemaining())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
int b = buffer.get() & 0xFF;
|
|
||||||
current = (current << 8) | b;
|
|
||||||
bits += 8;
|
|
||||||
while (bits >= 8)
|
|
||||||
{
|
|
||||||
int c = (current >>> (bits - 8)) & 0xFF;
|
|
||||||
node = tree[node * 256 + c];
|
|
||||||
if (rowbits[node] != 0)
|
|
||||||
{
|
|
||||||
if (rowsym[node] == EOS)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
throw new QpackException.CompressionException("EOS in content");
|
|
||||||
}
|
|
||||||
|
|
||||||
// terminal node
|
|
||||||
utf8.append((byte)(0xFF & rowsym[node]));
|
|
||||||
bits -= rowbits[node];
|
|
||||||
node = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// non-terminal node
|
|
||||||
bits -= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (bits > 0)
|
|
||||||
{
|
|
||||||
int c = (current << (8 - bits)) & 0xFF;
|
|
||||||
int lastNode = node;
|
|
||||||
node = tree[node * 256 + c];
|
|
||||||
|
|
||||||
if (rowbits[node] == 0 || rowbits[node] > bits)
|
|
||||||
{
|
|
||||||
int requiredPadding = 0;
|
|
||||||
for (int i = 0; i < bits; i++)
|
|
||||||
{
|
|
||||||
requiredPadding = (requiredPadding << 1) | 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((c >> (8 - bits)) != requiredPadding)
|
|
||||||
throw new QpackException.CompressionException("Incorrect padding");
|
|
||||||
|
|
||||||
node = lastNode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
utf8.append((byte)(0xFF & rowsym[node]));
|
|
||||||
bits -= rowbits[node];
|
|
||||||
node = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node != 0)
|
|
||||||
throw new QpackException.CompressionException("Bad termination");
|
|
||||||
|
|
||||||
return utf8.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset()
|
|
||||||
{
|
|
||||||
utf8.reset();
|
|
||||||
count = 0;
|
|
||||||
current = 0;
|
|
||||||
node = 0;
|
|
||||||
bits = 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,7 +11,7 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.generator;
|
package org.eclipse.jetty.http3.qpack;
|
||||||
|
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
|
|
|
@ -21,15 +21,15 @@ import java.util.List;
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.InsertCountIncrementInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.QpackContext;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.Instruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.InsertCountIncrementInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.SectionAcknowledgmentInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.SectionAcknowledgmentInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.parser.DecoderInstructionParser;
|
import org.eclipse.jetty.http3.qpack.internal.parser.DecoderInstructionParser;
|
||||||
import org.eclipse.jetty.http3.qpack.parser.EncodedFieldSection;
|
import org.eclipse.jetty.http3.qpack.internal.parser.EncodedFieldSection;
|
||||||
import org.eclipse.jetty.http3.qpack.parser.NBitIntegerParser;
|
import org.eclipse.jetty.http3.qpack.internal.table.DynamicTable;
|
||||||
import org.eclipse.jetty.http3.qpack.table.DynamicTable;
|
import org.eclipse.jetty.http3.qpack.internal.table.Entry;
|
||||||
import org.eclipse.jetty.http3.qpack.table.Entry;
|
import org.eclipse.jetty.http3.qpack.internal.table.StaticTable;
|
||||||
import org.eclipse.jetty.http3.qpack.table.StaticTable;
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerParser;
|
||||||
import org.eclipse.jetty.util.component.Dumpable;
|
import org.eclipse.jetty.util.component.Dumpable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -46,7 +46,6 @@ public class QpackDecoder implements Dumpable
|
||||||
|
|
||||||
private final Handler _handler;
|
private final Handler _handler;
|
||||||
private final QpackContext _context;
|
private final QpackContext _context;
|
||||||
private final MetaDataBuilder _builder;
|
|
||||||
private final DecoderInstructionParser _parser;
|
private final DecoderInstructionParser _parser;
|
||||||
|
|
||||||
private final List<EncodedFieldSection> _encodedFieldSections = new ArrayList<>();
|
private final List<EncodedFieldSection> _encodedFieldSections = new ArrayList<>();
|
||||||
|
@ -58,12 +57,11 @@ public class QpackDecoder implements Dumpable
|
||||||
public QpackDecoder(Handler handler, int maxHeaderSize)
|
public QpackDecoder(Handler handler, int maxHeaderSize)
|
||||||
{
|
{
|
||||||
_context = new QpackContext();
|
_context = new QpackContext();
|
||||||
_builder = new MetaDataBuilder(maxHeaderSize);
|
|
||||||
_handler = handler;
|
_handler = handler;
|
||||||
_parser = new DecoderInstructionParser(new DecoderAdapter());
|
_parser = new DecoderInstructionParser(new DecoderAdapter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public QpackContext getQpackContext()
|
QpackContext getQpackContext()
|
||||||
{
|
{
|
||||||
return _context;
|
return _context;
|
||||||
}
|
}
|
||||||
|
@ -83,8 +81,8 @@ public class QpackDecoder implements Dumpable
|
||||||
LOG.debug(String.format("CtxTbl[%x] decoding %d octets", _context.hashCode(), buffer.remaining()));
|
LOG.debug(String.format("CtxTbl[%x] decoding %d octets", _context.hashCode(), buffer.remaining()));
|
||||||
|
|
||||||
// If the buffer is big, don't even think about decoding it
|
// If the buffer is big, don't even think about decoding it
|
||||||
if (buffer.remaining() > _builder.getMaxSize())
|
// if (buffer.remaining() > _builder.getMaxSize())
|
||||||
throw new QpackException.SessionException("431 Request Header Fields too large");
|
//throw new QpackException.SessionException("431 Request Header Fields too large");
|
||||||
|
|
||||||
_integerDecoder.setPrefix(8);
|
_integerDecoder.setPrefix(8);
|
||||||
int encodedInsertCount = _integerDecoder.decode(buffer);
|
int encodedInsertCount = _integerDecoder.decode(buffer);
|
||||||
|
@ -235,6 +233,9 @@ public class QpackDecoder implements Dumpable
|
||||||
return String.format("QpackDecoder@%x{%s}", hashCode(), _context);
|
return String.format("QpackDecoder@%x{%s}", hashCode(), _context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This delivers notifications from the DecoderInstruction parser directly into the Decoder.
|
||||||
|
*/
|
||||||
class DecoderAdapter implements DecoderInstructionParser.Handler
|
class DecoderAdapter implements DecoderInstructionParser.Handler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,14 +28,17 @@ import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.DuplicateInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.EncodableEntry;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.IndexedNameEntryInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.QpackContext;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.Instruction;
|
import org.eclipse.jetty.http3.qpack.internal.StreamInfo;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.LiteralNameEntryInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.DuplicateInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.SetCapacityInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.IndexedNameEntryInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.parser.EncoderInstructionParser;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.LiteralNameEntryInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.table.DynamicTable;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.SetCapacityInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.table.Entry;
|
import org.eclipse.jetty.http3.qpack.internal.parser.EncoderInstructionParser;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.table.DynamicTable;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.table.Entry;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.NullByteBufferPool;
|
import org.eclipse.jetty.io.NullByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
@ -126,7 +129,7 @@ public class QpackEncoder implements Dumpable
|
||||||
_parser = new EncoderInstructionParser(new EncoderAdapter());
|
_parser = new EncoderInstructionParser(new EncoderAdapter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public QpackContext getQpackContext()
|
QpackContext getQpackContext()
|
||||||
{
|
{
|
||||||
return _context;
|
return _context;
|
||||||
}
|
}
|
||||||
|
@ -302,8 +305,8 @@ public class QpackEncoder implements Dumpable
|
||||||
|
|
||||||
// Calculate the size required. TODO: it may be more efficient to just use a buffer of MAX_HEADER_SIZE?
|
// Calculate the size required. TODO: it may be more efficient to just use a buffer of MAX_HEADER_SIZE?
|
||||||
int spaceRequired = 0;
|
int spaceRequired = 0;
|
||||||
spaceRequired += 1 + NBitInteger.octectsNeeded(8, encodedInsertCount);
|
spaceRequired += 1 + NBitIntegerEncoder.octectsNeeded(8, encodedInsertCount);
|
||||||
spaceRequired += 1 + NBitInteger.octectsNeeded(7, deltaBase);
|
spaceRequired += 1 + NBitIntegerEncoder.octectsNeeded(7, deltaBase);
|
||||||
for (EncodableEntry encodableEntry : encodableEntries)
|
for (EncodableEntry encodableEntry : encodableEntries)
|
||||||
{
|
{
|
||||||
spaceRequired += encodableEntry.getRequiredSize(base);
|
spaceRequired += encodableEntry.getRequiredSize(base);
|
||||||
|
@ -313,9 +316,9 @@ public class QpackEncoder implements Dumpable
|
||||||
int pos = BufferUtil.flipToFill(buffer);
|
int pos = BufferUtil.flipToFill(buffer);
|
||||||
|
|
||||||
// Encode the Field Section Prefix into the ByteBuffer.
|
// Encode the Field Section Prefix into the ByteBuffer.
|
||||||
NBitInteger.encode(buffer, 8, encodedInsertCount);
|
NBitIntegerEncoder.encode(buffer, 8, encodedInsertCount);
|
||||||
buffer.put(signBit ? (byte)0x80 : (byte)0x00);
|
buffer.put(signBit ? (byte)0x80 : (byte)0x00);
|
||||||
NBitInteger.encode(buffer, 7, deltaBase);
|
NBitIntegerEncoder.encode(buffer, 7, deltaBase);
|
||||||
|
|
||||||
// Encode the field lines into the ByteBuffer.
|
// Encode the field lines into the ByteBuffer.
|
||||||
for (EncodableEntry entry : encodableEntries)
|
for (EncodableEntry entry : encodableEntries)
|
||||||
|
|
|
@ -19,8 +19,10 @@ import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpFieldPreEncoder;
|
import org.eclipse.jetty.http.HttpFieldPreEncoder;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpVersion;
|
import org.eclipse.jetty.http.HttpVersion;
|
||||||
import org.eclipse.jetty.http3.qpack.table.Entry;
|
import org.eclipse.jetty.http3.qpack.internal.EncodableEntry;
|
||||||
import org.eclipse.jetty.http3.qpack.table.StaticTable;
|
import org.eclipse.jetty.http3.qpack.internal.QpackContext;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.table.Entry;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.table.StaticTable;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
||||||
public class QpackFieldPreEncoder implements HttpFieldPreEncoder
|
public class QpackFieldPreEncoder implements HttpFieldPreEncoder
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
package org.eclipse.jetty.http3.qpack.internal;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -19,35 +19,37 @@ import java.util.Objects;
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpVersion;
|
import org.eclipse.jetty.http.HttpVersion;
|
||||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||||
import org.eclipse.jetty.http3.qpack.table.Entry;
|
import org.eclipse.jetty.http3.qpack.internal.table.Entry;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.HuffmanEncoder;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
|
|
||||||
abstract class EncodableEntry
|
public abstract class EncodableEntry
|
||||||
{
|
{
|
||||||
static EncodableEntry getReferencedEntry(Entry entry)
|
public static EncodableEntry getReferencedEntry(Entry entry)
|
||||||
{
|
{
|
||||||
return new ReferencedEntry(entry);
|
return new ReferencedEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static EncodableEntry getNameReferencedEntry(Entry nameEntry, HttpField field, boolean huffman)
|
public static EncodableEntry getNameReferencedEntry(Entry nameEntry, HttpField field, boolean huffman)
|
||||||
{
|
{
|
||||||
return new ReferencedNameEntry(nameEntry, field, huffman);
|
return new ReferencedNameEntry(nameEntry, field, huffman);
|
||||||
}
|
}
|
||||||
|
|
||||||
static EncodableEntry getLiteralEntry(HttpField field, boolean huffman)
|
public static EncodableEntry getLiteralEntry(HttpField field, boolean huffman)
|
||||||
{
|
{
|
||||||
return new LiteralEntry(field, huffman);
|
return new LiteralEntry(field, huffman);
|
||||||
}
|
}
|
||||||
|
|
||||||
static EncodableEntry getPreEncodedEntry(PreEncodedHttpField httpField)
|
public static EncodableEntry getPreEncodedEntry(PreEncodedHttpField httpField)
|
||||||
{
|
{
|
||||||
return new PreEncodedEntry(httpField);
|
return new PreEncodedEntry(httpField);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract void encode(ByteBuffer buffer, int base);
|
public abstract void encode(ByteBuffer buffer, int base);
|
||||||
|
|
||||||
abstract int getRequiredSize(int base);
|
public abstract int getRequiredSize(int base);
|
||||||
|
|
||||||
abstract int getRequiredInsertCount();
|
public abstract int getRequiredInsertCount();
|
||||||
|
|
||||||
private static class ReferencedEntry extends EncodableEntry
|
private static class ReferencedEntry extends EncodableEntry
|
||||||
{
|
{
|
||||||
|
@ -67,21 +69,21 @@ abstract class EncodableEntry
|
||||||
// Indexed Field Line with Static Reference.
|
// Indexed Field Line with Static Reference.
|
||||||
buffer.put((byte)(0x80 | 0x40));
|
buffer.put((byte)(0x80 | 0x40));
|
||||||
int relativeIndex = _entry.getIndex();
|
int relativeIndex = _entry.getIndex();
|
||||||
NBitInteger.encode(buffer, 6, relativeIndex);
|
NBitIntegerEncoder.encode(buffer, 6, relativeIndex);
|
||||||
}
|
}
|
||||||
else if (_entry.getIndex() < base)
|
else if (_entry.getIndex() < base)
|
||||||
{
|
{
|
||||||
// Indexed Field Line with Dynamic Reference.
|
// Indexed Field Line with Dynamic Reference.
|
||||||
buffer.put((byte)0x80);
|
buffer.put((byte)0x80);
|
||||||
int relativeIndex = base - (_entry.getIndex() + 1);
|
int relativeIndex = base - (_entry.getIndex() + 1);
|
||||||
NBitInteger.encode(buffer, 6, relativeIndex);
|
NBitIntegerEncoder.encode(buffer, 6, relativeIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Indexed Field Line with Post-Base Index.
|
// Indexed Field Line with Post-Base Index.
|
||||||
buffer.put((byte)0x10);
|
buffer.put((byte)0x10);
|
||||||
int relativeIndex = _entry.getIndex() - base;
|
int relativeIndex = _entry.getIndex() - base;
|
||||||
NBitInteger.encode(buffer, 4, relativeIndex);
|
NBitIntegerEncoder.encode(buffer, 4, relativeIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,19 +95,19 @@ abstract class EncodableEntry
|
||||||
{
|
{
|
||||||
// Indexed Field Line with Static Reference.
|
// Indexed Field Line with Static Reference.
|
||||||
int relativeIndex = _entry.getIndex();
|
int relativeIndex = _entry.getIndex();
|
||||||
return 1 + NBitInteger.octectsNeeded(6, relativeIndex);
|
return 1 + NBitIntegerEncoder.octectsNeeded(6, relativeIndex);
|
||||||
}
|
}
|
||||||
else if (_entry.getIndex() < base)
|
else if (_entry.getIndex() < base)
|
||||||
{
|
{
|
||||||
// Indexed Field Line with Dynamic Reference.
|
// Indexed Field Line with Dynamic Reference.
|
||||||
int relativeIndex = base - (_entry.getIndex() + 1);
|
int relativeIndex = base - (_entry.getIndex() + 1);
|
||||||
return 1 + NBitInteger.octectsNeeded(6, relativeIndex);
|
return 1 + NBitIntegerEncoder.octectsNeeded(6, relativeIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Indexed Field Line with Post-Base Index.
|
// Indexed Field Line with Post-Base Index.
|
||||||
int relativeIndex = _entry.getIndex() - base;
|
int relativeIndex = _entry.getIndex() - base;
|
||||||
return 1 + NBitInteger.octectsNeeded(4, relativeIndex);
|
return 1 + NBitIntegerEncoder.octectsNeeded(4, relativeIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,21 +145,21 @@ abstract class EncodableEntry
|
||||||
// Literal Field Line with Static Name Reference.
|
// Literal Field Line with Static Name Reference.
|
||||||
buffer.put((byte)(0x40 | allowIntermediary | 0x10));
|
buffer.put((byte)(0x40 | allowIntermediary | 0x10));
|
||||||
int relativeIndex = _nameEntry.getIndex();
|
int relativeIndex = _nameEntry.getIndex();
|
||||||
NBitInteger.encode(buffer, 4, relativeIndex);
|
NBitIntegerEncoder.encode(buffer, 4, relativeIndex);
|
||||||
}
|
}
|
||||||
else if (_nameEntry.getIndex() < base)
|
else if (_nameEntry.getIndex() < base)
|
||||||
{
|
{
|
||||||
// Literal Field Line with Dynamic Name Reference.
|
// Literal Field Line with Dynamic Name Reference.
|
||||||
buffer.put((byte)(0x40 | allowIntermediary));
|
buffer.put((byte)(0x40 | allowIntermediary));
|
||||||
int relativeIndex = base - (_nameEntry.getIndex() + 1);
|
int relativeIndex = base - (_nameEntry.getIndex() + 1);
|
||||||
NBitInteger.encode(buffer, 4, relativeIndex);
|
NBitIntegerEncoder.encode(buffer, 4, relativeIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Literal Field Line with Post-Base Name Reference.
|
// Literal Field Line with Post-Base Name Reference.
|
||||||
buffer.put(allowIntermediary);
|
buffer.put(allowIntermediary);
|
||||||
int relativeIndex = _nameEntry.getIndex() - base;
|
int relativeIndex = _nameEntry.getIndex() - base;
|
||||||
NBitInteger.encode(buffer, 3, relativeIndex);
|
NBitIntegerEncoder.encode(buffer, 3, relativeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode the value.
|
// Encode the value.
|
||||||
|
@ -165,13 +167,13 @@ abstract class EncodableEntry
|
||||||
if (_huffman)
|
if (_huffman)
|
||||||
{
|
{
|
||||||
buffer.put((byte)0x80);
|
buffer.put((byte)0x80);
|
||||||
NBitInteger.encode(buffer, 7, Huffman.octetsNeeded(value));
|
NBitIntegerEncoder.encode(buffer, 7, HuffmanEncoder.octetsNeeded(value));
|
||||||
Huffman.encode(buffer, value);
|
HuffmanEncoder.encode(buffer, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer.put((byte)0x00);
|
buffer.put((byte)0x00);
|
||||||
NBitInteger.encode(buffer, 7, value.length());
|
NBitIntegerEncoder.encode(buffer, 7, value.length());
|
||||||
buffer.put(value.getBytes());
|
buffer.put(value.getBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,8 +183,8 @@ abstract class EncodableEntry
|
||||||
{
|
{
|
||||||
String value = getValue();
|
String value = getValue();
|
||||||
int relativeIndex = _nameEntry.getIndex() - base;
|
int relativeIndex = _nameEntry.getIndex() - base;
|
||||||
int valueLength = _huffman ? Huffman.octetsNeeded(value) : value.length();
|
int valueLength = _huffman ? HuffmanEncoder.octetsNeeded(value) : value.length();
|
||||||
return 1 + NBitInteger.octectsNeeded(4, relativeIndex) + 1 + NBitInteger.octectsNeeded(7, valueLength) + valueLength;
|
return 1 + NBitIntegerEncoder.octectsNeeded(4, relativeIndex) + 1 + NBitIntegerEncoder.octectsNeeded(7, valueLength) + valueLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -220,20 +222,20 @@ abstract class EncodableEntry
|
||||||
if (_huffman)
|
if (_huffman)
|
||||||
{
|
{
|
||||||
buffer.put((byte)(0x28 | allowIntermediary));
|
buffer.put((byte)(0x28 | allowIntermediary));
|
||||||
NBitInteger.encode(buffer, 3, Huffman.octetsNeeded(name));
|
NBitIntegerEncoder.encode(buffer, 3, HuffmanEncoder.octetsNeeded(name));
|
||||||
Huffman.encode(buffer, name);
|
HuffmanEncoder.encode(buffer, name);
|
||||||
buffer.put((byte)0x80);
|
buffer.put((byte)0x80);
|
||||||
NBitInteger.encode(buffer, 7, Huffman.octetsNeeded(value));
|
NBitIntegerEncoder.encode(buffer, 7, HuffmanEncoder.octetsNeeded(value));
|
||||||
Huffman.encode(buffer, value);
|
HuffmanEncoder.encode(buffer, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: What charset should we be using? (this applies to the instruction generators as well).
|
// TODO: What charset should we be using? (this applies to the instruction generators as well).
|
||||||
buffer.put((byte)(0x20 | allowIntermediary));
|
buffer.put((byte)(0x20 | allowIntermediary));
|
||||||
NBitInteger.encode(buffer, 3, name.length());
|
NBitIntegerEncoder.encode(buffer, 3, name.length());
|
||||||
buffer.put(name.getBytes());
|
buffer.put(name.getBytes());
|
||||||
buffer.put((byte)0x00);
|
buffer.put((byte)0x00);
|
||||||
NBitInteger.encode(buffer, 7, value.length());
|
NBitIntegerEncoder.encode(buffer, 7, value.length());
|
||||||
buffer.put(value.getBytes());
|
buffer.put(value.getBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,9 +245,9 @@ abstract class EncodableEntry
|
||||||
{
|
{
|
||||||
String name = getName();
|
String name = getName();
|
||||||
String value = getValue();
|
String value = getValue();
|
||||||
int nameLength = _huffman ? Huffman.octetsNeeded(name) : name.length();
|
int nameLength = _huffman ? HuffmanEncoder.octetsNeeded(name) : name.length();
|
||||||
int valueLength = _huffman ? Huffman.octetsNeeded(value) : value.length();
|
int valueLength = _huffman ? HuffmanEncoder.octetsNeeded(value) : value.length();
|
||||||
return 2 + NBitInteger.octectsNeeded(3, nameLength) + nameLength + NBitInteger.octectsNeeded(7, valueLength) + valueLength;
|
return 2 + NBitIntegerEncoder.octectsNeeded(3, nameLength) + nameLength + NBitIntegerEncoder.octectsNeeded(7, valueLength) + valueLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -267,6 +269,7 @@ abstract class EncodableEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: pass in the HTTP version to avoid hard coding HTTP3?
|
||||||
private static class PreEncodedEntry extends EncodableEntry
|
private static class PreEncodedEntry extends EncodableEntry
|
||||||
{
|
{
|
||||||
private final PreEncodedHttpField _httpField;
|
private final PreEncodedHttpField _httpField;
|
|
@ -11,12 +11,12 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
package org.eclipse.jetty.http3.qpack.internal;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http3.qpack.table.DynamicTable;
|
import org.eclipse.jetty.http3.qpack.internal.table.DynamicTable;
|
||||||
import org.eclipse.jetty.http3.qpack.table.Entry;
|
import org.eclipse.jetty.http3.qpack.internal.table.Entry;
|
||||||
import org.eclipse.jetty.http3.qpack.table.StaticTable;
|
import org.eclipse.jetty.http3.qpack.internal.table.StaticTable;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
|
@ -11,7 +11,7 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
package org.eclipse.jetty.http3.qpack.internal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -19,9 +19,9 @@ import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.table.Entry;
|
import org.eclipse.jetty.http3.qpack.internal.table.Entry;
|
||||||
|
|
||||||
class StreamInfo implements Iterable<StreamInfo.SectionInfo>
|
public class StreamInfo implements Iterable<StreamInfo.SectionInfo>
|
||||||
{
|
{
|
||||||
private final int _streamId;
|
private final int _streamId;
|
||||||
private final Queue<SectionInfo> _sectionInfos = new LinkedList<>();
|
private final Queue<SectionInfo> _sectionInfos = new LinkedList<>();
|
|
@ -11,11 +11,12 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.generator;
|
package org.eclipse.jetty.http3.qpack.internal.instruction;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.NBitInteger;
|
import org.eclipse.jetty.http3.qpack.Instruction;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
||||||
|
@ -36,10 +37,10 @@ public class DuplicateInstruction implements Instruction
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteBufferPool.Lease lease)
|
public void encode(ByteBufferPool.Lease lease)
|
||||||
{
|
{
|
||||||
int size = NBitInteger.octectsNeeded(5, _index) + 1;
|
int size = NBitIntegerEncoder.octectsNeeded(5, _index) + 1;
|
||||||
ByteBuffer buffer = lease.acquire(size, false);
|
ByteBuffer buffer = lease.acquire(size, false);
|
||||||
buffer.put((byte)0x00);
|
buffer.put((byte)0x00);
|
||||||
NBitInteger.encode(buffer, 5, _index);
|
NBitIntegerEncoder.encode(buffer, 5, _index);
|
||||||
BufferUtil.flipToFlush(buffer, 0);
|
BufferUtil.flipToFlush(buffer, 0);
|
||||||
lease.append(buffer, true);
|
lease.append(buffer, true);
|
||||||
}
|
}
|
|
@ -11,12 +11,13 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.generator;
|
package org.eclipse.jetty.http3.qpack.internal.instruction;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.Huffman;
|
import org.eclipse.jetty.http3.qpack.Instruction;
|
||||||
import org.eclipse.jetty.http3.qpack.NBitInteger;
|
import org.eclipse.jetty.http3.qpack.internal.util.HuffmanEncoder;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
||||||
|
@ -53,24 +54,24 @@ public class IndexedNameEntryInstruction implements Instruction
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteBufferPool.Lease lease)
|
public void encode(ByteBufferPool.Lease lease)
|
||||||
{
|
{
|
||||||
int size = NBitInteger.octectsNeeded(6, _index) + (_huffman ? Huffman.octetsNeeded(_value) : _value.length()) + 2;
|
int size = NBitIntegerEncoder.octectsNeeded(6, _index) + (_huffman ? HuffmanEncoder.octetsNeeded(_value) : _value.length()) + 2;
|
||||||
ByteBuffer buffer = lease.acquire(size, false);
|
ByteBuffer buffer = lease.acquire(size, false);
|
||||||
|
|
||||||
// First bit indicates the instruction, second bit is whether it is a dynamic table reference or not.
|
// First bit indicates the instruction, second bit is whether it is a dynamic table reference or not.
|
||||||
buffer.put((byte)(0x80 | (_dynamic ? 0x00 : 0x40)));
|
buffer.put((byte)(0x80 | (_dynamic ? 0x00 : 0x40)));
|
||||||
NBitInteger.encode(buffer, 6, _index);
|
NBitIntegerEncoder.encode(buffer, 6, _index);
|
||||||
|
|
||||||
// We will not huffman encode the string.
|
// We will not huffman encode the string.
|
||||||
if (_huffman)
|
if (_huffman)
|
||||||
{
|
{
|
||||||
buffer.put((byte)(0x80));
|
buffer.put((byte)(0x80));
|
||||||
NBitInteger.encode(buffer, 7, Huffman.octetsNeeded(_value));
|
NBitIntegerEncoder.encode(buffer, 7, HuffmanEncoder.octetsNeeded(_value));
|
||||||
Huffman.encode(buffer, _value);
|
HuffmanEncoder.encode(buffer, _value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer.put((byte)(0x00));
|
buffer.put((byte)(0x00));
|
||||||
NBitInteger.encode(buffer, 7, _value.length());
|
NBitIntegerEncoder.encode(buffer, 7, _value.length());
|
||||||
buffer.put(_value.getBytes());
|
buffer.put(_value.getBytes());
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,12 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.generator;
|
package org.eclipse.jetty.http3.qpack.internal.instruction;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.NBitInteger;
|
import org.eclipse.jetty.http3.qpack.Instruction;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
||||||
|
@ -31,10 +32,10 @@ public class InsertCountIncrementInstruction implements Instruction
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteBufferPool.Lease lease)
|
public void encode(ByteBufferPool.Lease lease)
|
||||||
{
|
{
|
||||||
int size = NBitInteger.octectsNeeded(6, _increment) + 1;
|
int size = NBitIntegerEncoder.octectsNeeded(6, _increment) + 1;
|
||||||
ByteBuffer buffer = lease.acquire(size, false);
|
ByteBuffer buffer = lease.acquire(size, false);
|
||||||
buffer.put((byte)0x00);
|
buffer.put((byte)0x00);
|
||||||
NBitInteger.encode(buffer, 6, _increment);
|
NBitIntegerEncoder.encode(buffer, 6, _increment);
|
||||||
BufferUtil.flipToFlush(buffer, 0);
|
BufferUtil.flipToFlush(buffer, 0);
|
||||||
lease.append(buffer, true);
|
lease.append(buffer, true);
|
||||||
}
|
}
|
|
@ -11,12 +11,13 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.generator;
|
package org.eclipse.jetty.http3.qpack.internal.instruction;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.Huffman;
|
import org.eclipse.jetty.http3.qpack.Instruction;
|
||||||
import org.eclipse.jetty.http3.qpack.NBitInteger;
|
import org.eclipse.jetty.http3.qpack.internal.util.HuffmanEncoder;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
||||||
|
@ -48,33 +49,33 @@ public class LiteralNameEntryInstruction implements Instruction
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteBufferPool.Lease lease)
|
public void encode(ByteBufferPool.Lease lease)
|
||||||
{
|
{
|
||||||
int size = (_huffmanName ? Huffman.octetsNeeded(_name) : _name.length()) +
|
int size = (_huffmanName ? HuffmanEncoder.octetsNeeded(_name) : _name.length()) +
|
||||||
(_huffmanValue ? Huffman.octetsNeeded(_value) : _value.length()) + 2;
|
(_huffmanValue ? HuffmanEncoder.octetsNeeded(_value) : _value.length()) + 2;
|
||||||
ByteBuffer buffer = lease.acquire(size, false);
|
ByteBuffer buffer = lease.acquire(size, false);
|
||||||
|
|
||||||
if (_huffmanName)
|
if (_huffmanName)
|
||||||
{
|
{
|
||||||
buffer.put((byte)(0x40 | 0x20));
|
buffer.put((byte)(0x40 | 0x20));
|
||||||
NBitInteger.encode(buffer, 5, Huffman.octetsNeeded(_name));
|
NBitIntegerEncoder.encode(buffer, 5, HuffmanEncoder.octetsNeeded(_name));
|
||||||
Huffman.encode(buffer, _name);
|
HuffmanEncoder.encode(buffer, _name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer.put((byte)(0x40));
|
buffer.put((byte)(0x40));
|
||||||
NBitInteger.encode(buffer, 5, _name.length());
|
NBitIntegerEncoder.encode(buffer, 5, _name.length());
|
||||||
buffer.put(_name.getBytes());
|
buffer.put(_name.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_huffmanValue)
|
if (_huffmanValue)
|
||||||
{
|
{
|
||||||
buffer.put((byte)(0x80));
|
buffer.put((byte)(0x80));
|
||||||
NBitInteger.encode(buffer, 7, Huffman.octetsNeeded(_value));
|
NBitIntegerEncoder.encode(buffer, 7, HuffmanEncoder.octetsNeeded(_value));
|
||||||
Huffman.encode(buffer, _value);
|
HuffmanEncoder.encode(buffer, _value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer.put((byte)(0x00));
|
buffer.put((byte)(0x00));
|
||||||
NBitInteger.encode(buffer, 5, _value.length());
|
NBitIntegerEncoder.encode(buffer, 5, _value.length());
|
||||||
buffer.put(_value.getBytes());
|
buffer.put(_value.getBytes());
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,12 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.generator;
|
package org.eclipse.jetty.http3.qpack.internal.instruction;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.NBitInteger;
|
import org.eclipse.jetty.http3.qpack.Instruction;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
||||||
|
@ -31,10 +32,10 @@ public class SectionAcknowledgmentInstruction implements Instruction
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteBufferPool.Lease lease)
|
public void encode(ByteBufferPool.Lease lease)
|
||||||
{
|
{
|
||||||
int size = NBitInteger.octectsNeeded(7, _streamId) + 1;
|
int size = NBitIntegerEncoder.octectsNeeded(7, _streamId) + 1;
|
||||||
ByteBuffer buffer = lease.acquire(size, false);
|
ByteBuffer buffer = lease.acquire(size, false);
|
||||||
buffer.put((byte)0x80);
|
buffer.put((byte)0x80);
|
||||||
NBitInteger.encode(buffer, 7, _streamId);
|
NBitIntegerEncoder.encode(buffer, 7, _streamId);
|
||||||
BufferUtil.flipToFlush(buffer, 0);
|
BufferUtil.flipToFlush(buffer, 0);
|
||||||
lease.append(buffer, true);
|
lease.append(buffer, true);
|
||||||
}
|
}
|
|
@ -11,11 +11,12 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.generator;
|
package org.eclipse.jetty.http3.qpack.internal.instruction;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.NBitInteger;
|
import org.eclipse.jetty.http3.qpack.Instruction;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
||||||
|
@ -36,10 +37,10 @@ public class SetCapacityInstruction implements Instruction
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteBufferPool.Lease lease)
|
public void encode(ByteBufferPool.Lease lease)
|
||||||
{
|
{
|
||||||
int size = NBitInteger.octectsNeeded(5, _capacity) + 1;
|
int size = NBitIntegerEncoder.octectsNeeded(5, _capacity) + 1;
|
||||||
ByteBuffer buffer = lease.acquire(size, false);
|
ByteBuffer buffer = lease.acquire(size, false);
|
||||||
buffer.put((byte)0x20);
|
buffer.put((byte)0x20);
|
||||||
NBitInteger.encode(buffer, 5, _capacity);
|
NBitIntegerEncoder.encode(buffer, 5, _capacity);
|
||||||
BufferUtil.flipToFlush(buffer, 0);
|
BufferUtil.flipToFlush(buffer, 0);
|
||||||
lease.append(buffer, true);
|
lease.append(buffer, true);
|
||||||
}
|
}
|
|
@ -11,11 +11,12 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.generator;
|
package org.eclipse.jetty.http3.qpack.internal.instruction;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.NBitInteger;
|
import org.eclipse.jetty.http3.qpack.Instruction;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
||||||
|
@ -31,10 +32,10 @@ public class StreamCancellationInstruction implements Instruction
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteBufferPool.Lease lease)
|
public void encode(ByteBufferPool.Lease lease)
|
||||||
{
|
{
|
||||||
int size = NBitInteger.octectsNeeded(6, _streamId) + 1;
|
int size = NBitIntegerEncoder.octectsNeeded(6, _streamId) + 1;
|
||||||
ByteBuffer buffer = lease.acquire(size, false);
|
ByteBuffer buffer = lease.acquire(size, false);
|
||||||
buffer.put((byte)0x40);
|
buffer.put((byte)0x40);
|
||||||
NBitInteger.encode(buffer, 6, _streamId);
|
NBitIntegerEncoder.encode(buffer, 6, _streamId);
|
||||||
BufferUtil.flipToFlush(buffer, 0);
|
BufferUtil.flipToFlush(buffer, 0);
|
||||||
lease.append(buffer, true);
|
lease.append(buffer, true);
|
||||||
}
|
}
|
|
@ -11,11 +11,13 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.parser;
|
package org.eclipse.jetty.http3.qpack.internal.parser;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.QpackException;
|
import org.eclipse.jetty.http3.qpack.QpackException;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerParser;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitStringParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a stream of unframed instructions for the Decoder. These instructions are sent from the remote Encoder.
|
* Parses a stream of unframed instructions for the Decoder. These instructions are sent from the remote Encoder.
|
|
@ -11,7 +11,7 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.parser;
|
package org.eclipse.jetty.http3.qpack.internal.parser;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -19,8 +19,10 @@ import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http3.qpack.QpackContext;
|
|
||||||
import org.eclipse.jetty.http3.qpack.QpackException;
|
import org.eclipse.jetty.http3.qpack.QpackException;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.QpackContext;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerParser;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitStringParser;
|
||||||
|
|
||||||
public class EncodedFieldSection
|
public class EncodedFieldSection
|
||||||
{
|
{
|
|
@ -11,11 +11,12 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.parser;
|
package org.eclipse.jetty.http3.qpack.internal.parser;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.QpackException;
|
import org.eclipse.jetty.http3.qpack.QpackException;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a stream of unframed instructions for the Encoder. These instructions are sent from the remote Decoder.
|
* Parses a stream of unframed instructions for the Encoder. These instructions are sent from the remote Decoder.
|
|
@ -11,7 +11,7 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.table;
|
package org.eclipse.jetty.http3.qpack.internal.table;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
|
@ -11,11 +11,14 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.table;
|
package org.eclipse.jetty.http3.qpack.internal.table;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.HuffmanEncoder;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
|
||||||
public class Entry
|
public class Entry
|
||||||
|
@ -88,7 +91,7 @@ public class Entry
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return String.format("%s@%x{index=%d, refs=%d, field=\"%s\"}", getClass().getSimpleName(), hashCode(),
|
return String.format("%s@%x{index=%d, refs=%d, field=\"%s\"}", getClass().getSimpleName(), hashCode(),
|
||||||
_absoluteIndex, _referenceCount.get(), _field);
|
_absoluteIndex, _referenceCount.get(), _field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,4 +104,53 @@ public class Entry
|
||||||
{
|
{
|
||||||
return 32 + StringUtil.getLength(field.getName()) + StringUtil.getLength(field.getValue());
|
return 32 + StringUtil.getLength(field.getName()) + StringUtil.getLength(field.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class StaticEntry extends Entry
|
||||||
|
{
|
||||||
|
private final byte[] _huffmanValue;
|
||||||
|
private final byte _encodedField;
|
||||||
|
|
||||||
|
StaticEntry(int index, HttpField field)
|
||||||
|
{
|
||||||
|
super(index, field);
|
||||||
|
String value = field.getValue();
|
||||||
|
if (value != null && value.length() > 0)
|
||||||
|
{
|
||||||
|
int huffmanLen = HuffmanEncoder.octetsNeeded(value);
|
||||||
|
if (huffmanLen < 0)
|
||||||
|
throw new IllegalStateException("bad value");
|
||||||
|
int lenLen = NBitIntegerEncoder.octectsNeeded(7, huffmanLen);
|
||||||
|
_huffmanValue = new byte[1 + lenLen + huffmanLen];
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue);
|
||||||
|
|
||||||
|
// Indicate Huffman
|
||||||
|
buffer.put((byte)0x80);
|
||||||
|
// Add huffman length
|
||||||
|
NBitIntegerEncoder.encode(buffer, 7, huffmanLen);
|
||||||
|
// Encode value
|
||||||
|
HuffmanEncoder.encode(buffer, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_huffmanValue = null;
|
||||||
|
|
||||||
|
_encodedField = (byte)(0x80 | index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStatic()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getStaticHuffmanValue()
|
||||||
|
{
|
||||||
|
return _huffmanValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getEncodedField()
|
||||||
|
{
|
||||||
|
return _encodedField;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.table;
|
package org.eclipse.jetty.http3.qpack.internal.table;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -24,7 +24,7 @@ import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpScheme;
|
import org.eclipse.jetty.http.HttpScheme;
|
||||||
import org.eclipse.jetty.http3.qpack.StaticTableHttpField;
|
import org.eclipse.jetty.http3.qpack.internal.unused.StaticTableHttpField;
|
||||||
import org.eclipse.jetty.util.Index;
|
import org.eclipse.jetty.util.Index;
|
||||||
|
|
||||||
public class StaticTable implements Iterable<Entry>
|
public class StaticTable implements Iterable<Entry>
|
||||||
|
@ -135,17 +135,17 @@ public class StaticTable implements Iterable<Entry>
|
||||||
public static final int STATIC_SIZE = STATIC_TABLE.length - 1;
|
public static final int STATIC_SIZE = STATIC_TABLE.length - 1;
|
||||||
|
|
||||||
private final Map<HttpField, Entry> _staticFieldMap = new HashMap<>();
|
private final Map<HttpField, Entry> _staticFieldMap = new HashMap<>();
|
||||||
private final Index<StaticEntry> _staticNameMap;
|
private final Index<Entry.StaticEntry> _staticNameMap;
|
||||||
private final StaticEntry[] _staticTableByHeader = new StaticEntry[HttpHeader.values().length];
|
private final Entry.StaticEntry[] _staticTableByHeader = new Entry.StaticEntry[HttpHeader.values().length];
|
||||||
private final StaticEntry[] _staticTable = new StaticEntry[STATIC_TABLE.length];
|
private final Entry.StaticEntry[] _staticTable = new Entry.StaticEntry[STATIC_TABLE.length];
|
||||||
|
|
||||||
public StaticTable()
|
public StaticTable()
|
||||||
{
|
{
|
||||||
Index.Builder<StaticEntry> staticNameMapBuilder = new Index.Builder<StaticEntry>().caseSensitive(false);
|
Index.Builder<Entry.StaticEntry> staticNameMapBuilder = new Index.Builder<Entry.StaticEntry>().caseSensitive(false);
|
||||||
Set<String> added = new HashSet<>();
|
Set<String> added = new HashSet<>();
|
||||||
for (int i = 0; i < STATIC_TABLE.length; i++)
|
for (int i = 0; i < STATIC_TABLE.length; i++)
|
||||||
{
|
{
|
||||||
StaticEntry entry = null;
|
Entry.StaticEntry entry = null;
|
||||||
|
|
||||||
String name = STATIC_TABLE[i][0];
|
String name = STATIC_TABLE[i][0];
|
||||||
String value = STATIC_TABLE[i][1];
|
String value = STATIC_TABLE[i][1];
|
||||||
|
@ -159,7 +159,7 @@ public class StaticTable implements Iterable<Entry>
|
||||||
|
|
||||||
HttpMethod method = HttpMethod.CACHE.get(value);
|
HttpMethod method = HttpMethod.CACHE.get(value);
|
||||||
if (method != null)
|
if (method != null)
|
||||||
entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, method));
|
entry = new Entry.StaticEntry(i, new StaticTableHttpField(header, name, value, method));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,13 +168,13 @@ public class StaticTable implements Iterable<Entry>
|
||||||
|
|
||||||
HttpScheme scheme = HttpScheme.CACHE.get(value);
|
HttpScheme scheme = HttpScheme.CACHE.get(value);
|
||||||
if (scheme != null)
|
if (scheme != null)
|
||||||
entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, scheme));
|
entry = new Entry.StaticEntry(i, new StaticTableHttpField(header, name, value, scheme));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case C_STATUS:
|
case C_STATUS:
|
||||||
{
|
{
|
||||||
entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, value));
|
entry = new Entry.StaticEntry(i, new StaticTableHttpField(header, name, value, value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ public class StaticTable implements Iterable<Entry>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
entry = new StaticEntry(i, header == null ? new HttpField(STATIC_TABLE[i][0], value) : new HttpField(header, name, value));
|
entry = new Entry.StaticEntry(i, header == null ? new HttpField(STATIC_TABLE[i][0], value) : new HttpField(header, name, value));
|
||||||
|
|
||||||
_staticTable[i] = entry;
|
_staticTable[i] = entry;
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ public class StaticTable implements Iterable<Entry>
|
||||||
|
|
||||||
for (HttpHeader h : HttpHeader.values())
|
for (HttpHeader h : HttpHeader.values())
|
||||||
{
|
{
|
||||||
StaticEntry entry = _staticNameMap.get(h.asString());
|
Entry.StaticEntry entry = _staticNameMap.get(h.asString());
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
_staticTableByHeader[h.ordinal()] = entry;
|
_staticTableByHeader[h.ordinal()] = entry;
|
||||||
}
|
}
|
|
@ -11,11 +11,11 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
package org.eclipse.jetty.http3.qpack.internal.unused;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HostPortHttpField;
|
import org.eclipse.jetty.http.HostPortHttpField;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http3.qpack.table.StaticTable;
|
import org.eclipse.jetty.http3.qpack.internal.table.StaticTable;
|
||||||
|
|
||||||
public class AuthorityHttpField extends HostPortHttpField
|
public class AuthorityHttpField extends HostPortHttpField
|
||||||
{
|
{
|
|
@ -11,7 +11,7 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
package org.eclipse.jetty.http3.qpack.internal.unused;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HostPortHttpField;
|
import org.eclipse.jetty.http.HostPortHttpField;
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
|
@ -21,6 +21,7 @@ import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpScheme;
|
import org.eclipse.jetty.http.HttpScheme;
|
||||||
import org.eclipse.jetty.http.HttpVersion;
|
import org.eclipse.jetty.http.HttpVersion;
|
||||||
import org.eclipse.jetty.http.MetaData;
|
import org.eclipse.jetty.http.MetaData;
|
||||||
|
import org.eclipse.jetty.http3.qpack.QpackException;
|
||||||
import org.eclipse.jetty.http3.qpack.QpackException.SessionException;
|
import org.eclipse.jetty.http3.qpack.QpackException.SessionException;
|
||||||
|
|
||||||
public class MetaDataBuilder
|
public class MetaDataBuilder
|
|
@ -11,7 +11,7 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
package org.eclipse.jetty.http3.qpack.internal.unused;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
|
@ -0,0 +1,122 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
||||||
|
//
|
||||||
|
// This program and the accompanying materials are made available under the
|
||||||
|
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||||
|
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||||
|
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.http3.qpack.internal.util;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http3.qpack.QpackException;
|
||||||
|
import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||||
|
|
||||||
|
public class HuffmanDecoder
|
||||||
|
{
|
||||||
|
static final char EOS = HuffmanEncoder.EOS;
|
||||||
|
static final char[] tree = HuffmanEncoder.tree;
|
||||||
|
static final char[] rowsym = HuffmanEncoder.rowsym;
|
||||||
|
static final byte[] rowbits = HuffmanEncoder.rowbits;
|
||||||
|
|
||||||
|
private final Utf8StringBuilder _utf8 = new Utf8StringBuilder();
|
||||||
|
private int _length = 0;
|
||||||
|
private int _count = 0;
|
||||||
|
private int _node = 0;
|
||||||
|
private int _current = 0;
|
||||||
|
private int _bits = 0;
|
||||||
|
|
||||||
|
public void setLength(int length)
|
||||||
|
{
|
||||||
|
if (_count != 0)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String decode(ByteBuffer buffer) throws QpackException.CompressionException
|
||||||
|
{
|
||||||
|
for (; _count < _length; _count++)
|
||||||
|
{
|
||||||
|
if (!buffer.hasRemaining())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
int b = buffer.get() & 0xFF;
|
||||||
|
_current = (_current << 8) | b;
|
||||||
|
_bits += 8;
|
||||||
|
while (_bits >= 8)
|
||||||
|
{
|
||||||
|
int c = (_current >>> (_bits - 8)) & 0xFF;
|
||||||
|
_node = tree[_node * 256 + c];
|
||||||
|
if (rowbits[_node] != 0)
|
||||||
|
{
|
||||||
|
if (rowsym[_node] == EOS)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
throw new QpackException.CompressionException("EOS in content");
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminal node
|
||||||
|
_utf8.append((byte)(0xFF & rowsym[_node]));
|
||||||
|
_bits -= rowbits[_node];
|
||||||
|
_node = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// non-terminal node
|
||||||
|
_bits -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (_bits > 0)
|
||||||
|
{
|
||||||
|
int c = (_current << (8 - _bits)) & 0xFF;
|
||||||
|
int lastNode = _node;
|
||||||
|
_node = tree[_node * 256 + c];
|
||||||
|
|
||||||
|
if (rowbits[_node] == 0 || rowbits[_node] > _bits)
|
||||||
|
{
|
||||||
|
int requiredPadding = 0;
|
||||||
|
for (int i = 0; i < _bits; i++)
|
||||||
|
{
|
||||||
|
requiredPadding = (requiredPadding << 1) | 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((c >> (8 - _bits)) != requiredPadding)
|
||||||
|
throw new QpackException.CompressionException("Incorrect padding");
|
||||||
|
|
||||||
|
_node = lastNode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_utf8.append((byte)(0xFF & rowsym[_node]));
|
||||||
|
_bits -= rowbits[_node];
|
||||||
|
_node = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_node != 0)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
throw new QpackException.CompressionException("Bad termination");
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = _utf8.toString();
|
||||||
|
reset();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset()
|
||||||
|
{
|
||||||
|
_utf8.reset();
|
||||||
|
_count = 0;
|
||||||
|
_current = 0;
|
||||||
|
_node = 0;
|
||||||
|
_bits = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,13 +11,11 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
package org.eclipse.jetty.http3.qpack.internal.util;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
public class HuffmanEncoder
|
||||||
|
|
||||||
public class Huffman
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// Appendix C: Huffman Codes
|
// Appendix C: Huffman Codes
|
||||||
|
@ -348,77 +346,6 @@ public class Huffman
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String decode(ByteBuffer buffer) throws QpackException.CompressionException
|
|
||||||
{
|
|
||||||
return decode(buffer, buffer.remaining());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String decode(ByteBuffer buffer, int length) throws QpackException.CompressionException
|
|
||||||
{
|
|
||||||
Utf8StringBuilder utf8 = new Utf8StringBuilder(length * 2);
|
|
||||||
int node = 0;
|
|
||||||
int current = 0;
|
|
||||||
int bits = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
int b = buffer.get() & 0xFF;
|
|
||||||
current = (current << 8) | b;
|
|
||||||
bits += 8;
|
|
||||||
while (bits >= 8)
|
|
||||||
{
|
|
||||||
int c = (current >>> (bits - 8)) & 0xFF;
|
|
||||||
node = tree[node * 256 + c];
|
|
||||||
if (rowbits[node] != 0)
|
|
||||||
{
|
|
||||||
if (rowsym[node] == EOS)
|
|
||||||
throw new QpackException.CompressionException("EOS in content");
|
|
||||||
|
|
||||||
// terminal node
|
|
||||||
utf8.append((byte)(0xFF & rowsym[node]));
|
|
||||||
bits -= rowbits[node];
|
|
||||||
node = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// non-terminal node
|
|
||||||
bits -= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (bits > 0)
|
|
||||||
{
|
|
||||||
int c = (current << (8 - bits)) & 0xFF;
|
|
||||||
int lastNode = node;
|
|
||||||
node = tree[node * 256 + c];
|
|
||||||
|
|
||||||
if (rowbits[node] == 0 || rowbits[node] > bits)
|
|
||||||
{
|
|
||||||
int requiredPadding = 0;
|
|
||||||
for (int i = 0; i < bits; i++)
|
|
||||||
{
|
|
||||||
requiredPadding = (requiredPadding << 1) | 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((c >> (8 - bits)) != requiredPadding)
|
|
||||||
throw new QpackException.CompressionException("Incorrect padding");
|
|
||||||
|
|
||||||
node = lastNode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
utf8.append((byte)(0xFF & rowsym[node]));
|
|
||||||
bits -= rowbits[node];
|
|
||||||
node = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node != 0)
|
|
||||||
throw new QpackException.CompressionException("Bad termination");
|
|
||||||
|
|
||||||
return utf8.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int octetsNeeded(String s)
|
public static int octetsNeeded(String s)
|
||||||
{
|
{
|
||||||
return octetsNeeded(CODES, s);
|
return octetsNeeded(CODES, s);
|
|
@ -11,11 +11,11 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
package org.eclipse.jetty.http3.qpack.internal.util;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class NBitInteger
|
public class NBitIntegerEncoder
|
||||||
{
|
{
|
||||||
public static int octectsNeeded(int n, int i)
|
public static int octectsNeeded(int n, int i)
|
||||||
{
|
{
|
||||||
|
@ -101,46 +101,4 @@ public class NBitInteger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int decode(ByteBuffer buffer, int n)
|
|
||||||
{
|
|
||||||
if (n == 8)
|
|
||||||
{
|
|
||||||
int nbits = 0xFF;
|
|
||||||
|
|
||||||
int i = buffer.get() & 0xff;
|
|
||||||
|
|
||||||
if (i == nbits)
|
|
||||||
{
|
|
||||||
int m = 1;
|
|
||||||
int b;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
b = 0xff & buffer.get();
|
|
||||||
i = i + (b & 127) * m;
|
|
||||||
m = m * 128;
|
|
||||||
}
|
|
||||||
while ((b & 128) == 128);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nbits = 0xFF >>> (8 - n);
|
|
||||||
|
|
||||||
int i = buffer.get(buffer.position() - 1) & nbits;
|
|
||||||
|
|
||||||
if (i == nbits)
|
|
||||||
{
|
|
||||||
int m = 1;
|
|
||||||
int b;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
b = 0xff & buffer.get();
|
|
||||||
i = i + (b & 127) * m;
|
|
||||||
m = m * 128;
|
|
||||||
}
|
|
||||||
while ((b & 128) == 128);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.parser;
|
package org.eclipse.jetty.http3.qpack.internal.util;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
|
@ -11,11 +11,10 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.parser;
|
package org.eclipse.jetty.http3.qpack.internal.util;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.HuffmanDecoder;
|
|
||||||
import org.eclipse.jetty.http3.qpack.QpackException;
|
import org.eclipse.jetty.http3.qpack.QpackException;
|
||||||
|
|
||||||
public class NBitStringParser
|
public class NBitStringParser
|
||||||
|
@ -69,10 +68,11 @@ public class NBitStringParser
|
||||||
if (_length < 0)
|
if (_length < 0)
|
||||||
return null;
|
return null;
|
||||||
_state = State.VALUE;
|
_state = State.VALUE;
|
||||||
|
_huffmanBuilder.setLength(_length);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case VALUE:
|
case VALUE:
|
||||||
String value = _huffman ? _huffmanBuilder.decode(buffer, _length) : asciiStringDecode(buffer);
|
String value = _huffman ? _huffmanBuilder.decode(buffer) : asciiStringDecode(buffer);
|
||||||
if (value != null)
|
if (value != null)
|
||||||
reset();
|
reset();
|
||||||
return value;
|
return value;
|
|
@ -1,69 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
|
||||||
//
|
|
||||||
// This program and the accompanying materials are made available under the
|
|
||||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
||||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
|
||||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
|
||||||
// ========================================================================
|
|
||||||
//
|
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack.table;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpField;
|
|
||||||
import org.eclipse.jetty.http3.qpack.Huffman;
|
|
||||||
import org.eclipse.jetty.http3.qpack.NBitInteger;
|
|
||||||
|
|
||||||
public class StaticEntry extends Entry
|
|
||||||
{
|
|
||||||
private final byte[] _huffmanValue;
|
|
||||||
private final byte _encodedField;
|
|
||||||
|
|
||||||
StaticEntry(int index, HttpField field)
|
|
||||||
{
|
|
||||||
super(index, field);
|
|
||||||
String value = field.getValue();
|
|
||||||
if (value != null && value.length() > 0)
|
|
||||||
{
|
|
||||||
int huffmanLen = Huffman.octetsNeeded(value);
|
|
||||||
if (huffmanLen < 0)
|
|
||||||
throw new IllegalStateException("bad value");
|
|
||||||
int lenLen = NBitInteger.octectsNeeded(7, huffmanLen);
|
|
||||||
_huffmanValue = new byte[1 + lenLen + huffmanLen];
|
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue);
|
|
||||||
|
|
||||||
// Indicate Huffman
|
|
||||||
buffer.put((byte)0x80);
|
|
||||||
// Add huffman length
|
|
||||||
NBitInteger.encode(buffer, 7, huffmanLen);
|
|
||||||
// Encode value
|
|
||||||
Huffman.encode(buffer, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_huffmanValue = null;
|
|
||||||
|
|
||||||
_encodedField = (byte)(0x80 | index);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isStatic()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getStaticHuffmanValue()
|
|
||||||
{
|
|
||||||
return _huffmanValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getEncodedField()
|
|
||||||
{
|
|
||||||
return _encodedField;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,7 +17,7 @@ import java.nio.ByteBuffer;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.parser.DecoderInstructionParser;
|
import org.eclipse.jetty.http3.qpack.internal.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.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
|
@ -17,14 +17,13 @@ import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.IndexedNameEntryInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.IndexedNameEntryInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.InsertCountIncrementInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.InsertCountIncrementInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.Instruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.LiteralNameEntryInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.LiteralNameEntryInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.SectionAcknowledgmentInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.SectionAcknowledgmentInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.SetCapacityInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.SetCapacityInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.parser.DecoderInstructionParser;
|
||||||
import org.eclipse.jetty.http3.qpack.parser.DecoderInstructionParser;
|
import org.eclipse.jetty.http3.qpack.internal.parser.EncoderInstructionParser;
|
||||||
import org.eclipse.jetty.http3.qpack.parser.EncoderInstructionParser;
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import java.nio.ByteBuffer;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.parser.EncoderInstructionParser;
|
import org.eclipse.jetty.http3.qpack.internal.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.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
|
|
@ -18,6 +18,8 @@ import java.nio.ByteBuffer;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.HuffmanDecoder;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.HuffmanEncoder;
|
||||||
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.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
|
@ -51,7 +53,9 @@ public class HuffmanTest
|
||||||
public void testDecode(String specSection, String hex, String expected) throws Exception
|
public void testDecode(String specSection, String hex, String expected) throws Exception
|
||||||
{
|
{
|
||||||
byte[] encoded = TypeUtil.fromHexString(hex);
|
byte[] encoded = TypeUtil.fromHexString(hex);
|
||||||
String decoded = Huffman.decode(ByteBuffer.wrap(encoded));
|
HuffmanDecoder huffmanDecoder = new HuffmanDecoder();
|
||||||
|
huffmanDecoder.setLength(encoded.length);
|
||||||
|
String decoded = huffmanDecoder.decode(ByteBuffer.wrap(encoded));
|
||||||
assertEquals(expected, decoded, specSection);
|
assertEquals(expected, decoded, specSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,11 +65,11 @@ public class HuffmanTest
|
||||||
{
|
{
|
||||||
ByteBuffer buf = BufferUtil.allocate(1024);
|
ByteBuffer buf = BufferUtil.allocate(1024);
|
||||||
int pos = BufferUtil.flipToFill(buf);
|
int pos = BufferUtil.flipToFill(buf);
|
||||||
Huffman.encode(buf, expected);
|
HuffmanEncoder.encode(buf, expected);
|
||||||
BufferUtil.flipToFlush(buf, pos);
|
BufferUtil.flipToFlush(buf, pos);
|
||||||
String encoded = TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase(Locale.ENGLISH);
|
String encoded = TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase(Locale.ENGLISH);
|
||||||
assertEquals(hex, encoded, specSection);
|
assertEquals(hex, encoded, specSection);
|
||||||
assertEquals(hex.length() / 2, Huffman.octetsNeeded(expected));
|
assertEquals(hex.length() / 2, HuffmanEncoder.octetsNeeded(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest(name = "[{index}]") // don't include unprintable character in test display-name
|
@ParameterizedTest(name = "[{index}]") // don't include unprintable character in test display-name
|
||||||
|
@ -74,9 +78,9 @@ public class HuffmanTest
|
||||||
{
|
{
|
||||||
String s = "bad '" + bad + "'";
|
String s = "bad '" + bad + "'";
|
||||||
|
|
||||||
assertThat(Huffman.octetsNeeded(s), Matchers.is(-1));
|
assertThat(HuffmanEncoder.octetsNeeded(s), Matchers.is(-1));
|
||||||
|
|
||||||
assertThrows(BufferOverflowException.class,
|
assertThrows(BufferOverflowException.class,
|
||||||
() -> Huffman.encode(BufferUtil.allocate(32), s));
|
() -> HuffmanEncoder.encode(BufferUtil.allocate(32), s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,8 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.http3.qpack;
|
package org.eclipse.jetty.http3.qpack;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.generator.IndexedNameEntryInstruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.IndexedNameEntryInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.Instruction;
|
import org.eclipse.jetty.http3.qpack.internal.instruction.SectionAcknowledgmentInstruction;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.SectionAcknowledgmentInstruction;
|
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
|
@ -15,7 +15,7 @@ package org.eclipse.jetty.http3.qpack;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.parser.NBitIntegerParser;
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerParser;
|
||||||
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.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
|
@ -15,6 +15,8 @@ package org.eclipse.jetty.http3.qpack;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerEncoder;
|
||||||
|
import org.eclipse.jetty.http3.qpack.internal.util.NBitIntegerParser;
|
||||||
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.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -24,21 +26,22 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
@SuppressWarnings("PointlessArithmeticExpression")
|
@SuppressWarnings("PointlessArithmeticExpression")
|
||||||
public class NBitIntegerTest
|
public class NBitIntegerTest
|
||||||
{
|
{
|
||||||
|
private final NBitIntegerParser _parser = new NBitIntegerParser();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOctetsNeeded()
|
public void testOctetsNeeded()
|
||||||
{
|
{
|
||||||
assertEquals(0, NBitInteger.octectsNeeded(5, 10));
|
assertEquals(0, NBitIntegerEncoder.octectsNeeded(5, 10));
|
||||||
assertEquals(2, NBitInteger.octectsNeeded(5, 1337));
|
assertEquals(2, NBitIntegerEncoder.octectsNeeded(5, 1337));
|
||||||
assertEquals(1, NBitInteger.octectsNeeded(8, 42));
|
assertEquals(1, NBitIntegerEncoder.octectsNeeded(8, 42));
|
||||||
assertEquals(3, NBitInteger.octectsNeeded(8, 1337));
|
assertEquals(3, NBitIntegerEncoder.octectsNeeded(8, 1337));
|
||||||
|
|
||||||
assertEquals(0, NBitInteger.octectsNeeded(6, 62));
|
assertEquals(0, NBitIntegerEncoder.octectsNeeded(6, 62));
|
||||||
assertEquals(1, NBitInteger.octectsNeeded(6, 63));
|
assertEquals(1, NBitIntegerEncoder.octectsNeeded(6, 63));
|
||||||
assertEquals(1, NBitInteger.octectsNeeded(6, 64));
|
assertEquals(1, NBitIntegerEncoder.octectsNeeded(6, 64));
|
||||||
assertEquals(2, NBitInteger.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x01));
|
assertEquals(2, NBitIntegerEncoder.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x01));
|
||||||
assertEquals(3, NBitInteger.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x80));
|
assertEquals(3, NBitIntegerEncoder.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x80));
|
||||||
assertEquals(4, NBitInteger.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x80 * 0x80));
|
assertEquals(4, NBitIntegerEncoder.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x80 * 0x80));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -79,12 +82,12 @@ public class NBitIntegerTest
|
||||||
int p = BufferUtil.flipToFill(buf);
|
int p = BufferUtil.flipToFill(buf);
|
||||||
if (n < 8)
|
if (n < 8)
|
||||||
buf.put((byte)0x00);
|
buf.put((byte)0x00);
|
||||||
NBitInteger.encode(buf, n, i);
|
NBitIntegerEncoder.encode(buf, n, i);
|
||||||
BufferUtil.flipToFlush(buf, p);
|
BufferUtil.flipToFlush(buf, p);
|
||||||
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
|
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
|
||||||
assertEquals(expected, r);
|
assertEquals(expected, r);
|
||||||
|
|
||||||
assertEquals(expected.length() / 2, (n < 8 ? 1 : 0) + NBitInteger.octectsNeeded(n, i));
|
assertEquals(expected.length() / 2, (n < 8 ? 1 : 0) + NBitIntegerEncoder.octectsNeeded(n, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -122,8 +125,8 @@ public class NBitIntegerTest
|
||||||
public void testDecode(int n, int expected, String encoded)
|
public void testDecode(int n, int expected, String encoded)
|
||||||
{
|
{
|
||||||
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
|
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
|
||||||
buf.position(n == 8 ? 0 : 1);
|
_parser.setPrefix(n);
|
||||||
assertEquals(expected, NBitInteger.decode(buf, n));
|
assertEquals(expected, _parser.decode(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -133,7 +136,7 @@ public class NBitIntegerTest
|
||||||
int p = BufferUtil.flipToFill(buf);
|
int p = BufferUtil.flipToFill(buf);
|
||||||
buf.put((byte)0x77);
|
buf.put((byte)0x77);
|
||||||
buf.put((byte)0xFF);
|
buf.put((byte)0xFF);
|
||||||
NBitInteger.encode(buf, 5, 10);
|
NBitIntegerEncoder.encode(buf, 5, 10);
|
||||||
BufferUtil.flipToFlush(buf, p);
|
BufferUtil.flipToFlush(buf, p);
|
||||||
|
|
||||||
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
|
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
|
||||||
|
@ -145,9 +148,9 @@ public class NBitIntegerTest
|
||||||
public void testDecodeExampleD11()
|
public void testDecodeExampleD11()
|
||||||
{
|
{
|
||||||
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF"));
|
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF"));
|
||||||
buf.position(2);
|
buf.position(1);
|
||||||
|
_parser.setPrefix(5);
|
||||||
assertEquals(10, NBitInteger.decode(buf, 5));
|
assertEquals(10, _parser.decode(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -157,7 +160,7 @@ public class NBitIntegerTest
|
||||||
int p = BufferUtil.flipToFill(buf);
|
int p = BufferUtil.flipToFill(buf);
|
||||||
buf.put((byte)0x88);
|
buf.put((byte)0x88);
|
||||||
buf.put((byte)0x00);
|
buf.put((byte)0x00);
|
||||||
NBitInteger.encode(buf, 5, 1337);
|
NBitIntegerEncoder.encode(buf, 5, 1337);
|
||||||
BufferUtil.flipToFlush(buf, p);
|
BufferUtil.flipToFlush(buf, p);
|
||||||
|
|
||||||
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
|
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
|
||||||
|
@ -169,9 +172,9 @@ public class NBitIntegerTest
|
||||||
public void testDecodeExampleD12()
|
public void testDecodeExampleD12()
|
||||||
{
|
{
|
||||||
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff"));
|
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff"));
|
||||||
buf.position(2);
|
buf.position(1);
|
||||||
|
_parser.setPrefix(5);
|
||||||
assertEquals(1337, NBitInteger.decode(buf, 5));
|
assertEquals(1337, _parser.decode(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -181,7 +184,7 @@ public class NBitIntegerTest
|
||||||
int p = BufferUtil.flipToFill(buf);
|
int p = BufferUtil.flipToFill(buf);
|
||||||
buf.put((byte)0x88);
|
buf.put((byte)0x88);
|
||||||
buf.put((byte)0xFF);
|
buf.put((byte)0xFF);
|
||||||
NBitInteger.encode(buf, 8, 42);
|
NBitIntegerEncoder.encode(buf, 8, 42);
|
||||||
BufferUtil.flipToFlush(buf, p);
|
BufferUtil.flipToFlush(buf, p);
|
||||||
|
|
||||||
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
|
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
|
||||||
|
@ -194,7 +197,7 @@ public class NBitIntegerTest
|
||||||
{
|
{
|
||||||
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf"));
|
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf"));
|
||||||
buf.position(1);
|
buf.position(1);
|
||||||
|
_parser.setPrefix(8);
|
||||||
assertEquals(42, NBitInteger.decode(buf, 8));
|
assertEquals(42, _parser.decode(buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ package org.eclipse.jetty.http3.qpack;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.generator.Instruction;
|
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.NullByteBufferPool;
|
import org.eclipse.jetty.io.NullByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
|
@ -17,7 +17,6 @@ import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http3.qpack.generator.Instruction;
|
|
||||||
|
|
||||||
public class TestDecoderHandler implements QpackDecoder.Handler
|
public class TestDecoderHandler implements QpackDecoder.Handler
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,8 +16,6 @@ package org.eclipse.jetty.http3.qpack;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.generator.Instruction;
|
|
||||||
|
|
||||||
public class TestEncoderHandler implements QpackEncoder.Handler
|
public class TestEncoderHandler implements QpackEncoder.Handler
|
||||||
{
|
{
|
||||||
private final Queue<Instruction> _instructionList = new LinkedList<>();
|
private final Queue<Instruction> _instructionList = new LinkedList<>();
|
||||||
|
|
Loading…
Reference in New Issue