Skip to content

Commit

Permalink
Issue #9554 - move Hpack/Qpack common classes to jetty-http
Browse files Browse the repository at this point in the history
Signed-off-by: Lachlan Roberts <[email protected]>
  • Loading branch information
lachlan-roberts committed Apr 5, 2023
1 parent 2c74d93 commit f6688b0
Show file tree
Hide file tree
Showing 33 changed files with 230 additions and 797 deletions.
1 change: 1 addition & 0 deletions jetty-core/jetty-http/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
exports org.eclipse.jetty.http;
exports org.eclipse.jetty.http.pathmap;
exports org.eclipse.jetty.http.content;
exports org.eclipse.jetty.http.compression;

uses org.eclipse.jetty.http.HttpFieldPreEncoder;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// ========================================================================
//

package org.eclipse.jetty.http3.qpack.internal.util;
package org.eclipse.jetty.http.compression;

public class EncodingException extends Exception
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,80 @@
// ========================================================================
//

package org.eclipse.jetty.http3.qpack.internal.util;
package org.eclipse.jetty.http.compression;

import java.nio.ByteBuffer;

import org.eclipse.jetty.util.Utf8StringBuilder;

public class HuffmanDecoder
{
public static String decode(ByteBuffer buffer, int length) throws EncodingException
{
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 EncodingException("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 EncodingException("Incorrect padding");

node = lastNode;
break;
}

utf8.append((byte)(0xFF & rowsym[node]));
bits -= rowbits[node];
node = 0;
}

if (node != 0)
throw new EncodingException("Bad termination");

return utf8.toCompleteString();
}

static final char EOS = HuffmanEncoder.EOS;
static final char[] tree = HuffmanEncoder.tree;
static final char[] rowsym = HuffmanEncoder.rowsym;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// ========================================================================
//

package org.eclipse.jetty.http3.qpack.internal.util;
package org.eclipse.jetty.http.compression;

import java.nio.ByteBuffer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// ========================================================================
//

package org.eclipse.jetty.http3.qpack.internal.util;
package org.eclipse.jetty.http.compression;

import java.nio.ByteBuffer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,54 @@
// ========================================================================
//

package org.eclipse.jetty.http3.qpack.internal.util;
package org.eclipse.jetty.http.compression;

import java.nio.ByteBuffer;

public class NBitIntegerParser
{
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;
}

private int _prefix;
private long _total;
private long _multiplier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// ========================================================================
//

package org.eclipse.jetty.http3.qpack.internal.util;
package org.eclipse.jetty.http.compression;

import java.nio.ByteBuffer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http2.hpack.internal.Huffman;
import org.eclipse.jetty.http2.hpack.internal.NBitInteger;
import org.eclipse.jetty.http.compression.HuffmanEncoder;
import org.eclipse.jetty.http.compression.NBitIntegerEncoder;
import org.eclipse.jetty.http2.hpack.internal.StaticTableHttpField;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
Expand Down Expand Up @@ -460,19 +460,19 @@ public static class StaticEntry extends Entry
String value = field.getValue();
if (value != null && value.length() > 0)
{
int huffmanLen = Huffman.octetsNeeded(value);
int huffmanLen = HuffmanEncoder.octetsNeeded(value);
if (huffmanLen < 0)
throw new IllegalStateException("bad value");
int lenLen = NBitInteger.octetsNeeded(7, huffmanLen);
int lenLen = NBitIntegerEncoder.octetsNeeded(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);
NBitIntegerEncoder.encode(buffer, 7, huffmanLen);
// Encode value
Huffman.encode(buffer, value);
HuffmanEncoder.encode(buffer, value);
}
else
_huffmanValue = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpTokens;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http.compression.EncodingException;
import org.eclipse.jetty.http.compression.HuffmanDecoder;
import org.eclipse.jetty.http.compression.NBitIntegerParser;
import org.eclipse.jetty.http2.hpack.HpackContext.Entry;
import org.eclipse.jetty.http2.hpack.internal.AuthorityHttpField;
import org.eclipse.jetty.http2.hpack.internal.Huffman;
import org.eclipse.jetty.http2.hpack.internal.MetaDataBuilder;
import org.eclipse.jetty.http2.hpack.internal.NBitInteger;
import org.eclipse.jetty.util.BufferUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -83,7 +84,7 @@ public MetaData decode(ByteBuffer buffer) throws HpackException.SessionException
if (b < 0)
{
// 7.1 indexed if the high bit is set
int index = NBitInteger.decode(buffer, 7);
int index = NBitIntegerParser.decode(buffer, 7);
Entry entry = _context.get(index);
if (entry == null)
throw new HpackException.SessionException("Unknown index %d", index);
Expand Down Expand Up @@ -124,7 +125,7 @@ public MetaData decode(ByteBuffer buffer) throws HpackException.SessionException
case 2: // 7.3
case 3: // 7.3
// change table size
int size = NBitInteger.decode(buffer, 5);
int size = NBitIntegerParser.decode(buffer, 5);
if (LOG.isDebugEnabled())
LOG.debug("decode resize={}", size);
if (size > _localMaxDynamicTableSize)
Expand All @@ -137,15 +138,15 @@ public MetaData decode(ByteBuffer buffer) throws HpackException.SessionException
case 0: // 7.2.2
case 1: // 7.2.3
indexed = false;
nameIndex = NBitInteger.decode(buffer, 4);
nameIndex = NBitIntegerParser.decode(buffer, 4);
break;

case 4: // 7.2.1
case 5: // 7.2.1
case 6: // 7.2.1
case 7: // 7.2.1
indexed = true;
nameIndex = NBitInteger.decode(buffer, 6);
nameIndex = NBitIntegerParser.decode(buffer, 6);
break;

default:
Expand All @@ -164,10 +165,10 @@ public MetaData decode(ByteBuffer buffer) throws HpackException.SessionException
else
{
huffmanName = (buffer.get() & 0x80) == 0x80;
int length = NBitInteger.decode(buffer, 7);
int length = NBitIntegerParser.decode(buffer, 7);
_builder.checkSize(length, huffmanName);
if (huffmanName)
name = Huffman.decode(buffer, length);
name = huffmanDecode(buffer, length);
else
name = toASCIIString(buffer, length);
check:
Expand Down Expand Up @@ -205,10 +206,10 @@ public MetaData decode(ByteBuffer buffer) throws HpackException.SessionException

// decode the value
boolean huffmanValue = (buffer.get() & 0x80) == 0x80;
int length = NBitInteger.decode(buffer, 7);
int length = NBitIntegerParser.decode(buffer, 7);
_builder.checkSize(length, huffmanValue);
if (huffmanValue)
value = Huffman.decode(buffer, length);
value = huffmanDecode(buffer, length);
else
value = toASCIIString(buffer, length);

Expand Down Expand Up @@ -271,6 +272,20 @@ public MetaData decode(ByteBuffer buffer) throws HpackException.SessionException
return _builder.build();
}

private String huffmanDecode(ByteBuffer buffer, int length) throws HpackException.CompressionException
{
try
{
return HuffmanDecoder.decode(buffer, length);
}
catch (EncodingException e)
{
HpackException.CompressionException compressionException = new HpackException.CompressionException(e.getMessage());
compressionException.initCause(e);
throw compressionException;
}
}

public static String toASCIIString(ByteBuffer buffer, int length)
{
StringBuilder builder = new StringBuilder(length);
Expand Down
Loading

0 comments on commit f6688b0

Please sign in to comment.