Merged branch 'jetty-10.0.x' into 'jetty-11.0.x'.
Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
commit
6ea2f68da0
|
@ -151,6 +151,13 @@ public class MetaData implements Iterable<HttpField>
|
|||
version, fields, contentLength);
|
||||
}
|
||||
|
||||
public Request(long beginNanoTime, String method, String scheme, HostPortHttpField authority, String uri, HttpVersion version, HttpFields fields, long contentLength)
|
||||
{
|
||||
this(beginNanoTime, method,
|
||||
HttpURI.build().scheme(scheme).host(authority == null ? null : authority.getHost()).port(authority == null ? -1 : authority.getPort()).pathQuery(uri),
|
||||
version, fields, contentLength);
|
||||
}
|
||||
|
||||
public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength, Supplier<HttpFields> trailers)
|
||||
{
|
||||
this(NanoTime.now(), method, uri, version, fields, contentLength, trailers);
|
||||
|
@ -222,9 +229,19 @@ public class MetaData implements Iterable<HttpField>
|
|||
this(scheme == null ? null : scheme.asString(), authority, path, fields, protocol);
|
||||
}
|
||||
|
||||
public ConnectRequest(long beginNanoTime, HttpScheme scheme, HostPortHttpField authority, String path, HttpFields fields, String protocol)
|
||||
{
|
||||
this(beginNanoTime, scheme == null ? null : scheme.asString(), authority, path, fields, protocol);
|
||||
}
|
||||
|
||||
public ConnectRequest(String scheme, HostPortHttpField authority, String path, HttpFields fields, String protocol)
|
||||
{
|
||||
super(HttpMethod.CONNECT.asString(),
|
||||
this(NanoTime.now(), scheme, authority, path, fields, protocol);
|
||||
}
|
||||
|
||||
public ConnectRequest(long beginNanoTime, String scheme, HostPortHttpField authority, String path, HttpFields fields, String protocol)
|
||||
{
|
||||
super(beginNanoTime, HttpMethod.CONNECT.asString(),
|
||||
HttpURI.build().scheme(scheme).host(authority == null ? null : authority.getHost()).port(authority == null ? -1 : authority.getPort()).pathQuery(path),
|
||||
HttpVersion.HTTP_2, fields, Long.MIN_VALUE, null);
|
||||
_protocol = protocol;
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.http2.frames.SettingsFrame;
|
|||
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
|
||||
import org.eclipse.jetty.http2.hpack.HpackDecoder;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -52,6 +53,8 @@ public class Parser
|
|||
private int maxSettingsKeys = SettingsFrame.DEFAULT_MAX_KEYS;
|
||||
private boolean continuation;
|
||||
private State state = State.HEADER;
|
||||
private long beginNanoTime;
|
||||
private boolean nanoTimeStored;
|
||||
|
||||
@Deprecated
|
||||
public Parser(ByteBufferPool byteBufferPool, int maxTableCapacity, int maxHeaderSize)
|
||||
|
@ -74,7 +77,7 @@ public class Parser
|
|||
{
|
||||
this.byteBufferPool = byteBufferPool;
|
||||
this.headerParser = new HeaderParser(rateControl == null ? RateControl.NO_RATE_CONTROL : rateControl);
|
||||
this.hpackDecoder = new HpackDecoder(maxHeaderSize);
|
||||
this.hpackDecoder = new HpackDecoder(maxHeaderSize, this::getBeginNanoTime);
|
||||
this.bodyParsers = new BodyParser[FrameType.values().length];
|
||||
}
|
||||
|
||||
|
@ -114,6 +117,25 @@ public class Parser
|
|||
state = State.HEADER;
|
||||
}
|
||||
|
||||
public long getBeginNanoTime()
|
||||
{
|
||||
return beginNanoTime;
|
||||
}
|
||||
|
||||
private void clearBeginNanoTime()
|
||||
{
|
||||
nanoTimeStored = false;
|
||||
}
|
||||
|
||||
private void storeBeginNanoTime()
|
||||
{
|
||||
if (!nanoTimeStored)
|
||||
{
|
||||
beginNanoTime = NanoTime.now();
|
||||
nanoTimeStored = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parses the given {@code buffer} bytes and emit events to a {@link Listener}.</p>
|
||||
* <p>When this method returns, the buffer may not be fully consumed, so invocations
|
||||
|
@ -135,6 +157,7 @@ public class Parser
|
|||
{
|
||||
case HEADER:
|
||||
{
|
||||
storeBeginNanoTime();
|
||||
if (!parseHeader(buffer))
|
||||
return;
|
||||
break;
|
||||
|
@ -143,6 +166,8 @@ public class Parser
|
|||
{
|
||||
if (!parseBody(buffer))
|
||||
return;
|
||||
if (!continuation)
|
||||
clearBeginNanoTime();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -158,6 +158,102 @@ public class ContinuationParseTest
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeginNanoTime() throws Exception
|
||||
{
|
||||
ByteBufferPool bufferPool = new MappedByteBufferPool(128);
|
||||
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder());
|
||||
|
||||
final List<HeadersFrame> frames = new ArrayList<>();
|
||||
Parser parser = new Parser(bufferPool, 8192);
|
||||
parser.init(new Parser.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(HeadersFrame frame)
|
||||
{
|
||||
frames.add(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailure(int error, String reason)
|
||||
{
|
||||
frames.add(new HeadersFrame(null, null, false));
|
||||
}
|
||||
});
|
||||
|
||||
int streamId = 13;
|
||||
HttpFields fields = HttpFields.build()
|
||||
.put("Accept", "text/html")
|
||||
.put("User-Agent", "Jetty");
|
||||
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1);
|
||||
|
||||
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(bufferPool);
|
||||
generator.generateHeaders(lease, streamId, metaData, null, true);
|
||||
|
||||
List<ByteBuffer> byteBuffers = lease.getByteBuffers();
|
||||
assertEquals(2, byteBuffers.size());
|
||||
|
||||
ByteBuffer headersBody = byteBuffers.remove(1);
|
||||
int start = headersBody.position();
|
||||
int length = headersBody.remaining();
|
||||
int firstHalf = length / 2;
|
||||
int lastHalf = length - firstHalf;
|
||||
|
||||
// Adjust the length of the HEADERS frame.
|
||||
ByteBuffer headersHeader = byteBuffers.get(0);
|
||||
headersHeader.put(0, (byte)((firstHalf >>> 16) & 0xFF));
|
||||
headersHeader.put(1, (byte)((firstHalf >>> 8) & 0xFF));
|
||||
headersHeader.put(2, (byte)(firstHalf & 0xFF));
|
||||
|
||||
// Remove the END_HEADERS flag from the HEADERS header.
|
||||
headersHeader.put(4, (byte)(headersHeader.get(4) & ~Flags.END_HEADERS));
|
||||
|
||||
// New HEADERS body.
|
||||
headersBody.position(start);
|
||||
headersBody.limit(start + firstHalf);
|
||||
byteBuffers.add(headersBody.slice());
|
||||
|
||||
// Split the rest of the HEADERS body into a CONTINUATION frame.
|
||||
byte[] continuationHeader = new byte[9];
|
||||
continuationHeader[0] = (byte)((lastHalf >>> 16) & 0xFF);
|
||||
continuationHeader[1] = (byte)((lastHalf >>> 8) & 0xFF);
|
||||
continuationHeader[2] = (byte)(lastHalf & 0xFF);
|
||||
continuationHeader[3] = (byte)FrameType.CONTINUATION.getType();
|
||||
continuationHeader[4] = Flags.END_HEADERS;
|
||||
continuationHeader[5] = 0x00;
|
||||
continuationHeader[6] = 0x00;
|
||||
continuationHeader[7] = 0x00;
|
||||
continuationHeader[8] = (byte)streamId;
|
||||
byteBuffers.add(ByteBuffer.wrap(continuationHeader));
|
||||
// CONTINUATION body.
|
||||
headersBody.position(start + firstHalf);
|
||||
headersBody.limit(start + length);
|
||||
byteBuffers.add(headersBody.slice());
|
||||
|
||||
assertEquals(4, byteBuffers.size());
|
||||
parser.parse(byteBuffers.get(0));
|
||||
long beginNanoTime = parser.getBeginNanoTime();
|
||||
parser.parse(byteBuffers.get(1));
|
||||
parser.parse(byteBuffers.get(2));
|
||||
parser.parse(byteBuffers.get(3));
|
||||
|
||||
assertEquals(1, frames.size());
|
||||
HeadersFrame frame = frames.get(0);
|
||||
assertEquals(streamId, frame.getStreamId());
|
||||
assertTrue(frame.isEndStream());
|
||||
MetaData.Request request = (MetaData.Request)frame.getMetaData();
|
||||
assertEquals(metaData.getMethod(), request.getMethod());
|
||||
assertEquals(metaData.getURIString(), request.getURIString());
|
||||
for (int i = 0; i < fields.size(); ++i)
|
||||
{
|
||||
HttpField field = fields.getField(i);
|
||||
assertTrue(request.getFields().contains(field));
|
||||
}
|
||||
PriorityFrame priority = frame.getPriority();
|
||||
assertNull(priority);
|
||||
assertEquals(beginNanoTime, request.getBeginNanoTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLargeHeadersBlock() throws Exception
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package org.eclipse.jetty.http2.hpack;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.LongSupplier;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -42,14 +43,18 @@ public class HpackDecoder
|
|||
private final MetaDataBuilder _builder;
|
||||
private final HuffmanDecoder _huffmanDecoder;
|
||||
private final NBitIntegerDecoder _integerDecoder;
|
||||
private final LongSupplier _beginNanoTimeSupplier;
|
||||
private int _maxTableCapacity;
|
||||
|
||||
/**
|
||||
* @param maxHeaderSize The maximum allowed size of a decoded headers block,
|
||||
* expressed as total of all name and value bytes, plus 32 bytes per field
|
||||
* @param beginNanoTimeSupplier The supplier of a nano timestamp taken at
|
||||
* the time the first byte was read
|
||||
*/
|
||||
public HpackDecoder(int maxHeaderSize)
|
||||
public HpackDecoder(int maxHeaderSize, LongSupplier beginNanoTimeSupplier)
|
||||
{
|
||||
_beginNanoTimeSupplier = beginNanoTimeSupplier;
|
||||
_context = new HpackContext(HpackContext.DEFAULT_MAX_TABLE_CAPACITY);
|
||||
_builder = new MetaDataBuilder(maxHeaderSize);
|
||||
_huffmanDecoder = new HuffmanDecoder();
|
||||
|
@ -305,6 +310,7 @@ public class HpackDecoder
|
|||
}
|
||||
}
|
||||
|
||||
_builder.setBeginNanoTime(_beginNanoTimeSupplier.getAsLong());
|
||||
return _builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.eclipse.jetty.http.HttpScheme;
|
|||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.hpack.HpackException.SessionException;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
|
||||
public class MetaDataBuilder
|
||||
{
|
||||
|
@ -38,6 +39,7 @@ public class MetaDataBuilder
|
|||
private HpackException.StreamException _streamException;
|
||||
private boolean _request;
|
||||
private boolean _response;
|
||||
private long _beginNanoTime = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* @param maxHeadersSize The maximum size of the headers, expressed as total name and value characters.
|
||||
|
@ -60,6 +62,13 @@ public class MetaDataBuilder
|
|||
_maxSize = maxSize;
|
||||
}
|
||||
|
||||
public void setBeginNanoTime(long beginNanoTime)
|
||||
{
|
||||
if (beginNanoTime == Long.MIN_VALUE)
|
||||
beginNanoTime++;
|
||||
_beginNanoTime = beginNanoTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size.
|
||||
*
|
||||
|
@ -248,10 +257,13 @@ public class MetaDataBuilder
|
|||
if (_path == null)
|
||||
throw new HpackException.StreamException("No Path");
|
||||
}
|
||||
long nanoTime = _beginNanoTime == Long.MIN_VALUE ? NanoTime.now() : _beginNanoTime;
|
||||
_beginNanoTime = Long.MIN_VALUE;
|
||||
if (isConnect)
|
||||
return new MetaData.ConnectRequest(_scheme, _authority, _path, fields, _protocol);
|
||||
return new MetaData.ConnectRequest(nanoTime, _scheme, _authority, _path, fields, _protocol);
|
||||
else
|
||||
return new MetaData.Request(
|
||||
nanoTime,
|
||||
_method,
|
||||
_scheme.asString(),
|
||||
_authority,
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.eclipse.jetty.http.MetaData;
|
|||
import org.eclipse.jetty.http2.hpack.HpackException.CompressionException;
|
||||
import org.eclipse.jetty.http2.hpack.HpackException.SessionException;
|
||||
import org.eclipse.jetty.http2.hpack.HpackException.StreamException;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -57,7 +58,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testDecodeD3() throws Exception
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
// First request
|
||||
String encoded = "828684410f7777772e6578616d706c652e636f6d";
|
||||
|
@ -105,7 +106,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testDecodeD4() throws Exception
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
// First request
|
||||
String encoded = "828684418cf1e3c2e5f23a6ba0ab90f4ff";
|
||||
|
@ -140,7 +141,7 @@ public class HpackDecoderTest
|
|||
{
|
||||
String value = "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==";
|
||||
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
String encoded = "8682418cF1E3C2E5F23a6bA0Ab90F4Ff841f0822426173696320515778685a475270626a70766347567549484e6c633246745a513d3d";
|
||||
byte[] bytes = StringUtil.fromHexString(encoded);
|
||||
byte[] array = new byte[bytes.length + 1];
|
||||
|
@ -162,7 +163,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testDecodeHuffmanWithArrayOffset() throws Exception
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "8286418cf1e3c2e5f23a6ba0ab90f4ff84";
|
||||
byte[] bytes = StringUtil.fromHexString(encoded);
|
||||
|
@ -186,7 +187,7 @@ public class HpackDecoderTest
|
|||
String encoded = "886196C361Be940b6a65B6850400B8A00571972e080a62D1Bf5f87497cA589D34d1f9a0f0d0234327690Aa69D29aFcA954D3A5358980Ae112e0f7c880aE152A9A74a6bF3";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
MetaData.Response response = (MetaData.Response)decoder.decode(buffer);
|
||||
|
||||
assertThat(response.getStatus(), is(200));
|
||||
|
@ -204,7 +205,7 @@ public class HpackDecoderTest
|
|||
{
|
||||
String encoded = "203f136687A0E41d139d090760881c6490B2Cd39Ba7f";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
MetaData metaData = decoder.decode(buffer);
|
||||
assertThat(metaData.getFields().get(HttpHeader.HOST), is("localhost0"));
|
||||
assertThat(metaData.getFields().get(HttpHeader.COOKIE), is("abcdefghij"));
|
||||
|
@ -226,7 +227,7 @@ public class HpackDecoderTest
|
|||
|
||||
String encoded = "203f136687A0E41d139d090760881c6490B2Cd39Ba7f20";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
try
|
||||
{
|
||||
decoder.decode(buffer);
|
||||
|
@ -244,7 +245,7 @@ public class HpackDecoderTest
|
|||
String encoded = "3f610f17FfEc02Df3990A190A0D4Ee5b3d2940Ec98Aa4a62D127D29e273a0aA20dEcAa190a503b262d8a2671D4A2672a927aA874988a2471D05510750c951139EdA2452a3a548cAa1aA90bE4B228342864A9E0D450A5474a92992a1aA513395448E3A0Aa17B96cFe3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f14E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F353F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F54f";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
decoder.setMaxTableCapacity(128);
|
||||
MetaData metaData = decoder.decode(buffer);
|
||||
|
||||
|
@ -258,7 +259,7 @@ public class HpackDecoderTest
|
|||
String encoded = "BE";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
decoder.setMaxTableCapacity(128);
|
||||
|
||||
try
|
||||
|
@ -444,7 +445,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testHuffmanEncodedStandard() throws Exception
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "82868441" + "83" + "49509F";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
@ -462,7 +463,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testHuffmanEncodedExtraPadding()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "82868441" + "84" + "49509FFF";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
@ -474,7 +475,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testHuffmanEncodedZeroPadding()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "82868441" + "83" + "495090";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
@ -487,7 +488,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testHuffmanEncodedWithEOS()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "82868441" + "87" + "497FFFFFFF427F";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
@ -499,7 +500,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testHuffmanEncodedOneIncompleteOctet()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "82868441" + "81" + "FE";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
@ -511,7 +512,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testHuffmanEncodedTwoIncompleteOctet()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "82868441" + "82" + "FFFE";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
@ -523,7 +524,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testZeroLengthName()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "00000130";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
@ -534,7 +535,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testZeroLengthValue() throws Exception
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "00016800";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
@ -546,7 +547,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testUpperCaseName()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "0001480130";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
@ -557,7 +558,7 @@ public class HpackDecoderTest
|
|||
@Test
|
||||
public void testWhiteSpaceName()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
|
||||
String encoded = "0001200130";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(StringUtil.fromHexString(encoded));
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.eclipse.jetty.http.MetaData;
|
|||
import org.eclipse.jetty.http.MetaData.Response;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -43,7 +44,7 @@ public class HpackTest
|
|||
public void encodeDecodeResponseTest() throws Exception
|
||||
{
|
||||
HpackEncoder encoder = new HpackEncoder();
|
||||
HpackDecoder decoder = new HpackDecoder(8192);
|
||||
HpackDecoder decoder = new HpackDecoder(8192, NanoTime::now);
|
||||
ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024);
|
||||
|
||||
HttpFields.Mutable fields0 = HttpFields.build()
|
||||
|
@ -98,7 +99,7 @@ public class HpackTest
|
|||
public void encodeDecodeTooLargeTest() throws Exception
|
||||
{
|
||||
HpackEncoder encoder = new HpackEncoder();
|
||||
HpackDecoder decoder = new HpackDecoder(164);
|
||||
HpackDecoder decoder = new HpackDecoder(164, NanoTime::now);
|
||||
ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024);
|
||||
|
||||
HttpFields fields0 = HttpFields.build()
|
||||
|
@ -158,7 +159,7 @@ public class HpackTest
|
|||
@Test
|
||||
public void evictReferencedFieldTest() throws Exception
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(1024);
|
||||
HpackDecoder decoder = new HpackDecoder(1024, NanoTime::now);
|
||||
decoder.setMaxTableCapacity(200);
|
||||
HpackEncoder encoder = new HpackEncoder();
|
||||
encoder.setMaxTableCapacity(decoder.getMaxTableCapacity());
|
||||
|
@ -205,7 +206,7 @@ public class HpackTest
|
|||
public void testHopHeadersAreRemoved() throws Exception
|
||||
{
|
||||
HpackEncoder encoder = new HpackEncoder();
|
||||
HpackDecoder decoder = new HpackDecoder(16384);
|
||||
HpackDecoder decoder = new HpackDecoder(16384, NanoTime::now);
|
||||
|
||||
HttpFields input = HttpFields.build()
|
||||
.add(HttpHeader.ACCEPT, "*")
|
||||
|
@ -232,7 +233,7 @@ public class HpackTest
|
|||
public void testTETrailers() throws Exception
|
||||
{
|
||||
HpackEncoder encoder = new HpackEncoder();
|
||||
HpackDecoder decoder = new HpackDecoder(16384);
|
||||
HpackDecoder decoder = new HpackDecoder(16384, NanoTime::now);
|
||||
|
||||
String teValue = "trailers";
|
||||
String trailerValue = "Custom";
|
||||
|
@ -257,7 +258,7 @@ public class HpackTest
|
|||
public void testColonHeaders() throws Exception
|
||||
{
|
||||
HpackEncoder encoder = new HpackEncoder();
|
||||
HpackDecoder decoder = new HpackDecoder(16384);
|
||||
HpackDecoder decoder = new HpackDecoder(16384, NanoTime::now);
|
||||
|
||||
HttpFields input = HttpFields.build()
|
||||
.add(":status", "200")
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.eclipse.jetty.http3.internal.Grease;
|
|||
import org.eclipse.jetty.http3.internal.HTTP3ErrorCode;
|
||||
import org.eclipse.jetty.http3.qpack.QpackDecoder;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -43,12 +44,15 @@ public class MessageParser
|
|||
private final BooleanSupplier isLast;
|
||||
private BodyParser unknownBodyParser;
|
||||
private State state = State.HEADER;
|
||||
protected boolean dataMode;
|
||||
private boolean dataMode;
|
||||
private long beginNanoTime;
|
||||
private boolean beginNanoTimeStored;
|
||||
|
||||
public MessageParser(ParserListener listener, QpackDecoder decoder, long streamId, BooleanSupplier isLast)
|
||||
{
|
||||
this.listener = listener;
|
||||
this.decoder = decoder;
|
||||
decoder.setBeginNanoTimeSupplier(this::getBeginNanoTime);
|
||||
this.streamId = streamId;
|
||||
this.isLast = isLast;
|
||||
}
|
||||
|
@ -66,6 +70,21 @@ public class MessageParser
|
|||
{
|
||||
headerParser.reset();
|
||||
state = State.HEADER;
|
||||
beginNanoTimeStored = false;
|
||||
}
|
||||
|
||||
private void storeBeginNanoTime()
|
||||
{
|
||||
if (!beginNanoTimeStored)
|
||||
{
|
||||
beginNanoTime = NanoTime.now();
|
||||
beginNanoTimeStored = true;
|
||||
}
|
||||
}
|
||||
|
||||
private long getBeginNanoTime()
|
||||
{
|
||||
return beginNanoTime;
|
||||
}
|
||||
|
||||
public ParserListener getListener()
|
||||
|
@ -101,6 +120,7 @@ public class MessageParser
|
|||
{
|
||||
case HEADER:
|
||||
{
|
||||
storeBeginNanoTime();
|
||||
if (headerParser.parse(buffer))
|
||||
{
|
||||
state = State.BODY;
|
||||
|
|
|
@ -23,9 +23,11 @@ import org.eclipse.jetty.http3.frames.DataFrame;
|
|||
import org.eclipse.jetty.http3.internal.generator.MessageGenerator;
|
||||
import org.eclipse.jetty.http3.internal.parser.MessageParser;
|
||||
import org.eclipse.jetty.http3.internal.parser.ParserListener;
|
||||
import org.eclipse.jetty.http3.qpack.QpackDecoder;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.NullByteBufferPool;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
|
@ -58,6 +60,8 @@ public class DataGenerateParseTest
|
|||
new MessageGenerator(null, true).generate(lease, 0, input, null);
|
||||
|
||||
List<DataFrame> frames = new ArrayList<>();
|
||||
QpackDecoder decoder = new QpackDecoder(instructions -> {});
|
||||
decoder.setBeginNanoTimeSupplier(NanoTime::now);
|
||||
MessageParser parser = new MessageParser(new ParserListener()
|
||||
{
|
||||
@Override
|
||||
|
@ -65,7 +69,7 @@ public class DataGenerateParseTest
|
|||
{
|
||||
frames.add(frame);
|
||||
}
|
||||
}, null, 13, () -> true);
|
||||
}, decoder, 13, () -> true);
|
||||
parser.init(UnaryOperator.identity());
|
||||
for (ByteBuffer buffer : lease.getByteBuffers())
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.eclipse.jetty.http3.qpack.QpackDecoder;
|
|||
import org.eclipse.jetty.http3.qpack.QpackEncoder;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.NullByteBufferPool;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
@ -54,6 +55,7 @@ public class HeadersGenerateParseTest
|
|||
|
||||
QpackDecoder decoder = new QpackDecoder(instructions -> {});
|
||||
decoder.setMaxHeadersSize(4 * 1024);
|
||||
decoder.setBeginNanoTimeSupplier(NanoTime::now);
|
||||
List<HeadersFrame> frames = new ArrayList<>();
|
||||
MessageParser parser = new MessageParser(new ParserListener()
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.LongSupplier;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
|
@ -59,6 +60,7 @@ public class QpackDecoder implements Dumpable
|
|||
private int _maxHeadersSize;
|
||||
private int _maxBlockedStreams;
|
||||
private int _maxTableCapacity;
|
||||
private LongSupplier _beginNanoTimeSupplier;
|
||||
|
||||
private static class MetaDataNotification
|
||||
{
|
||||
|
@ -103,6 +105,11 @@ public class QpackDecoder implements Dumpable
|
|||
return _maxHeadersSize;
|
||||
}
|
||||
|
||||
public void setBeginNanoTimeSupplier(LongSupplier beginNanoTimeSupplier)
|
||||
{
|
||||
_beginNanoTimeSupplier = beginNanoTimeSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxHeadersSize The maximum allowed size of a headers block, expressed as total of all name and value characters, plus 32 per field
|
||||
*/
|
||||
|
@ -180,7 +187,7 @@ public class QpackDecoder implements Dumpable
|
|||
{
|
||||
// Parse the buffer into an Encoded Field Section.
|
||||
int base = signBit ? requiredInsertCount - deltaBase - 1 : requiredInsertCount + deltaBase;
|
||||
EncodedFieldSection encodedFieldSection = new EncodedFieldSection(streamId, handler, requiredInsertCount, base, buffer);
|
||||
EncodedFieldSection encodedFieldSection = new EncodedFieldSection(streamId, handler, requiredInsertCount, base, buffer, _beginNanoTimeSupplier.getAsLong());
|
||||
|
||||
// Decode it straight away if we can, otherwise add it to the list of EncodedFieldSections.
|
||||
if (requiredInsertCount <= insertCount)
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.eclipse.jetty.http.HttpScheme;
|
|||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http3.qpack.QpackException;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
|
||||
import static org.eclipse.jetty.http3.qpack.QpackException.H3_GENERAL_PROTOCOL_ERROR;
|
||||
|
||||
|
@ -40,6 +41,7 @@ public class MetaDataBuilder
|
|||
private QpackException.StreamException _streamException;
|
||||
private boolean _request;
|
||||
private boolean _response;
|
||||
private long _beginNanoTime = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* @param maxHeadersSize The maximum size of the headers, expressed as total name and value characters.
|
||||
|
@ -59,6 +61,13 @@ public class MetaDataBuilder
|
|||
return _maxSize;
|
||||
}
|
||||
|
||||
public void setBeginNanoTime(long beginNanoTime)
|
||||
{
|
||||
if (beginNanoTime == Long.MIN_VALUE)
|
||||
beginNanoTime++;
|
||||
_beginNanoTime = beginNanoTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size.
|
||||
*
|
||||
|
@ -246,10 +255,13 @@ public class MetaDataBuilder
|
|||
if (_path == null)
|
||||
throw new QpackException.StreamException(H3_GENERAL_PROTOCOL_ERROR, "No Path");
|
||||
}
|
||||
long nanoTime = _beginNanoTime == Long.MIN_VALUE ? NanoTime.now() : _beginNanoTime;
|
||||
_beginNanoTime = Long.MIN_VALUE;
|
||||
if (isConnect)
|
||||
return new MetaData.ConnectRequest(_scheme, _authority, _path, fields, _protocol);
|
||||
return new MetaData.ConnectRequest(nanoTime, _scheme, _authority, _path, fields, _protocol);
|
||||
else
|
||||
return new MetaData.Request(
|
||||
nanoTime,
|
||||
_method,
|
||||
_scheme.asString(),
|
||||
_authority,
|
||||
|
|
|
@ -44,13 +44,15 @@ public class EncodedFieldSection
|
|||
private final int _requiredInsertCount;
|
||||
private final int _base;
|
||||
private final QpackDecoder.Handler _handler;
|
||||
private final long _beginNanoTime;
|
||||
|
||||
public EncodedFieldSection(long streamId, QpackDecoder.Handler handler, int requiredInsertCount, int base, ByteBuffer content) throws QpackException
|
||||
public EncodedFieldSection(long streamId, QpackDecoder.Handler handler, int requiredInsertCount, int base, ByteBuffer content, long beginNanoTime) throws QpackException
|
||||
{
|
||||
_streamId = streamId;
|
||||
_requiredInsertCount = requiredInsertCount;
|
||||
_base = base;
|
||||
_handler = handler;
|
||||
_beginNanoTime = beginNanoTime;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -104,6 +106,7 @@ public class EncodedFieldSection
|
|||
HttpField decodedField = encodedField.decode(context);
|
||||
metaDataBuilder.emit(decodedField);
|
||||
}
|
||||
metaDataBuilder.setBeginNanoTime(_beginNanoTime);
|
||||
return metaDataBuilder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.eclipse.jetty.http3.qpack.internal.instruction.LiteralNameEntryInstru
|
|||
import org.eclipse.jetty.http3.qpack.internal.instruction.SectionAcknowledgmentInstruction;
|
||||
import org.eclipse.jetty.http3.qpack.internal.instruction.SetCapacityInstruction;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -56,6 +57,7 @@ public class BlockedStreamsTest
|
|||
_decoderHandler = new TestDecoderHandler();
|
||||
_encoder = new QpackEncoder(_encoderHandler, MAX_BLOCKED_STREAMS);
|
||||
_decoder = new QpackDecoder(_decoderHandler, MAX_HEADER_SIZE);
|
||||
_decoder.setBeginNanoTimeSupplier(NanoTime::now);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.eclipse.jetty.http3.qpack.internal.instruction.SetCapacityInstruction
|
|||
import org.eclipse.jetty.http3.qpack.internal.parser.DecoderInstructionParser;
|
||||
import org.eclipse.jetty.http3.qpack.internal.parser.EncoderInstructionParser;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -65,6 +66,7 @@ public class EncodeDecodeTest
|
|||
}
|
||||
};
|
||||
_decoder = new QpackDecoder(_decoderHandler, MAX_HEADER_SIZE);
|
||||
_decoder.setBeginNanoTimeSupplier(NanoTime::now);
|
||||
|
||||
_encoderInstructionParser = new EncoderInstructionParser(new EncoderParserDebugHandler(_encoder));
|
||||
_decoderInstructionParser = new DecoderInstructionParser(new DecoderParserDebugHandler(_decoder));
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.eclipse.jetty.http.HttpField;
|
|||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -40,6 +41,7 @@ public class EvictionTest
|
|||
_decoder = new QpackDecoder(_decoderHandler);
|
||||
_decoder.setMaxHeadersSize(1024);
|
||||
_decoder.setMaxTableCapacity(4 * 1024);
|
||||
_decoder.setBeginNanoTimeSupplier(NanoTime::now);
|
||||
|
||||
_encoder = new QpackEncoder(_encoderHandler)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.nio.ByteBuffer;
|
|||
import org.eclipse.jetty.http3.qpack.QpackException.SessionException;
|
||||
import org.eclipse.jetty.http3.qpack.internal.instruction.SectionAcknowledgmentInstruction;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -48,6 +49,7 @@ public class SectionAcknowledgmentTest
|
|||
_decoderHandler = new TestDecoderHandler();
|
||||
_encoder = new QpackEncoder(_encoderHandler, MAX_BLOCKED_STREAMS);
|
||||
_decoder = new QpackDecoder(_decoderHandler, MAX_HEADER_SIZE);
|
||||
_decoder.setBeginNanoTimeSupplier(NanoTime::now);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue