#9900: simplify and add test

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2023-11-21 17:05:36 +01:00
parent 52e182486d
commit 382638b84d
2 changed files with 111 additions and 6 deletions

View File

@ -66,7 +66,7 @@ public class Parser
{
this.bufferPool = bufferPool;
this.headerParser = new HeaderParser(rateControl == null ? RateControl.NO_RATE_CONTROL : rateControl);
this.hpackDecoder = new HpackDecoder(maxHeaderSize, this::loadAndClearBeginNanoTime);
this.hpackDecoder = new HpackDecoder(maxHeaderSize, this::getBeginNanoTime);
this.bodyParsers = new BodyParser[FrameType.values().length];
}
@ -104,16 +104,18 @@ public class Parser
{
headerParser.reset();
state = State.HEADER;
nanoTimeStored = false;
}
private long loadAndClearBeginNanoTime()
public long getBeginNanoTime()
{
long beginNanoTime = this.beginNanoTime;
nanoTimeStored = false;
return beginNanoTime;
}
private void clearBeginNanoTime()
{
nanoTimeStored = false;
}
private void storeBeginNanoTime()
{
if (!nanoTimeStored)
@ -140,11 +142,11 @@ public class Parser
{
while (true)
{
storeBeginNanoTime();
switch (state)
{
case HEADER:
{
storeBeginNanoTime();
if (!parseHeader(buffer))
return;
break;
@ -153,6 +155,8 @@ public class Parser
{
if (!parseBody(buffer))
return;
if (!continuation)
clearBeginNanoTime();
break;
}
default:

View File

@ -161,6 +161,107 @@ public class ContinuationParseTest
}
}
@Test
public void testBeginNanoTime() throws Exception
{
ArrayByteBufferPool.Tracking bufferPool = new ArrayByteBufferPool.Tracking();
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(bufferPool), new HpackEncoder());
final List<HeadersFrame> frames = new ArrayList<>();
Parser parser = new Parser(bufferPool, 8192);
parser.init(new Parser.Listener()
{
@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.Accumulator accumulator = new ByteBufferPool.Accumulator();
generator.generateHeaders(accumulator, streamId, metaData, null, true);
List<ByteBuffer> byteBuffers = accumulator.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());
byteBuffers = accumulator.getByteBuffers();
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));
accumulator.release();
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.getHttpURI(), request.getHttpURI());
for (int j = 0; j < fields.size(); ++j)
{
HttpField field = fields.getField(j);
assertTrue(request.getHttpFields().contains(field));
}
PriorityFrame priority = frame.getPriority();
assertNull(priority);
assertEquals(beginNanoTime, request.getBeginNanoTime());
assertEquals(0, bufferPool.getLeaks().size(), bufferPool.dumpLeaks());
}
@Test
public void testLargeHeadersBlock() throws Exception
{