Fixed handling of long settings values, so that they do not overflow. Added logging for GREASE cases. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
caddfb5a41
commit
8c94490e18
|
@ -24,6 +24,7 @@ import org.eclipse.jetty.http3.frames.SettingsFrame;
|
|||
import org.eclipse.jetty.http3.internal.ControlFlusher;
|
||||
import org.eclipse.jetty.http3.internal.DecoderStreamConnection;
|
||||
import org.eclipse.jetty.http3.internal.EncoderStreamConnection;
|
||||
import org.eclipse.jetty.http3.internal.Grease;
|
||||
import org.eclipse.jetty.http3.internal.HTTP3ErrorCode;
|
||||
import org.eclipse.jetty.http3.internal.InstructionFlusher;
|
||||
import org.eclipse.jetty.http3.internal.InstructionHandler;
|
||||
|
@ -63,7 +64,7 @@ public class ClientHTTP3Session extends ClientProtocolSession
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("initializing HTTP/3 streams");
|
||||
|
||||
long encoderStreamId = getQuicSession().newStreamId(StreamType.CLIENT_UNIDIRECTIONAL);
|
||||
long encoderStreamId = newStreamId(StreamType.CLIENT_UNIDIRECTIONAL);
|
||||
QuicStreamEndPoint encoderEndPoint = openInstructionEndPoint(encoderStreamId);
|
||||
InstructionFlusher encoderInstructionFlusher = new InstructionFlusher(quicSession, encoderEndPoint, EncoderStreamConnection.STREAM_TYPE);
|
||||
encoder = new QpackEncoder(new InstructionHandler(encoderInstructionFlusher));
|
||||
|
@ -72,7 +73,7 @@ public class ClientHTTP3Session extends ClientProtocolSession
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("created encoder stream #{} on {}", encoderStreamId, encoderEndPoint);
|
||||
|
||||
long decoderStreamId = getQuicSession().newStreamId(StreamType.CLIENT_UNIDIRECTIONAL);
|
||||
long decoderStreamId = newStreamId(StreamType.CLIENT_UNIDIRECTIONAL);
|
||||
QuicStreamEndPoint decoderEndPoint = openInstructionEndPoint(decoderStreamId);
|
||||
InstructionFlusher decoderInstructionFlusher = new InstructionFlusher(quicSession, decoderEndPoint, DecoderStreamConnection.STREAM_TYPE);
|
||||
decoder = new QpackDecoder(new InstructionHandler(decoderInstructionFlusher));
|
||||
|
@ -80,7 +81,7 @@ public class ClientHTTP3Session extends ClientProtocolSession
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("created decoder stream #{} on {}", decoderStreamId, decoderEndPoint);
|
||||
|
||||
long controlStreamId = getQuicSession().newStreamId(StreamType.CLIENT_UNIDIRECTIONAL);
|
||||
long controlStreamId = newStreamId(StreamType.CLIENT_UNIDIRECTIONAL);
|
||||
QuicStreamEndPoint controlEndPoint = openControlEndPoint(controlStreamId);
|
||||
controlFlusher = new ControlFlusher(quicSession, controlEndPoint, true);
|
||||
addBean(controlFlusher);
|
||||
|
@ -106,6 +107,11 @@ public class ClientHTTP3Session extends ClientProtocolSession
|
|||
return session;
|
||||
}
|
||||
|
||||
public long newStreamId(StreamType streamType)
|
||||
{
|
||||
return getQuicSession().newStreamId(streamType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart()
|
||||
{
|
||||
|
@ -171,21 +177,27 @@ public class ClientHTTP3Session extends ClientProtocolSession
|
|||
{
|
||||
if (key == SettingsFrame.MAX_TABLE_CAPACITY)
|
||||
{
|
||||
int maxTableCapacity = value.intValue();
|
||||
int maxTableCapacity = (int)Math.min(value, Integer.MAX_VALUE);
|
||||
encoder.setMaxTableCapacity(maxTableCapacity);
|
||||
encoder.setTableCapacity(Math.min(maxTableCapacity, configuration.getMaxEncoderTableCapacity()));
|
||||
}
|
||||
else if (key == SettingsFrame.MAX_FIELD_SECTION_SIZE)
|
||||
{
|
||||
// Must cap the maxHeaderSize to avoid large allocations.
|
||||
int maxHeadersSize = Math.min(value.intValue(), configuration.getMaxRequestHeadersSize());
|
||||
int maxHeadersSize = (int)Math.min(value, configuration.getMaxResponseHeadersSize());
|
||||
encoder.setMaxHeadersSize(maxHeadersSize);
|
||||
}
|
||||
else if (key == SettingsFrame.MAX_BLOCKED_STREAMS)
|
||||
{
|
||||
int maxBlockedStreams = value.intValue();
|
||||
int maxBlockedStreams = (int)Math.min(value, Integer.MAX_VALUE);
|
||||
encoder.setMaxBlockedStreams(maxBlockedStreams);
|
||||
}
|
||||
else
|
||||
{
|
||||
// SPEC: grease and unknown settings are ignored.
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("ignored {} setting {}={}", Grease.isGreaseValue(key) ? "grease" : "unknown", key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public class HTTP3SessionClient extends HTTP3Session implements Session.Client
|
|||
@Override
|
||||
public CompletableFuture<Stream> newRequest(HeadersFrame frame, Stream.Client.Listener listener)
|
||||
{
|
||||
long streamId = getProtocolSession().getQuicSession().newStreamId(StreamType.CLIENT_BIDIRECTIONAL);
|
||||
long streamId = getProtocolSession().newStreamId(StreamType.CLIENT_BIDIRECTIONAL);
|
||||
return newRequest(streamId, frame, listener);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 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.internal;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* <p>A class to support GREASE (<a href="https://www.rfc-editor.org/rfc/rfc8701.txt">RFC 8701</a>) in HTTP/3.</p>
|
||||
* <p>HTTP/3 GREASE values have the form {@code 0x1F * N + 0x21} with non negative values of {@code N}.</p>
|
||||
*/
|
||||
public class Grease
|
||||
{
|
||||
/**
|
||||
* @param value the value to test
|
||||
* @return whether the value is a GREASE value as defined by HTTP/3
|
||||
*/
|
||||
public static boolean isGreaseValue(long value)
|
||||
{
|
||||
if (value < 0)
|
||||
return false;
|
||||
return (value - 0x21) % 0x1F == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a random grease value as defined by HTTP/3
|
||||
*/
|
||||
public static long generateGreaseValue()
|
||||
{
|
||||
// This constant avoids to overflow VarLenInt.
|
||||
long n = ThreadLocalRandom.current().nextLong(0x210842108421084L);
|
||||
return 0x1F * n + 0x21;
|
||||
}
|
||||
|
||||
private Grease()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.http3.internal;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public enum HTTP3ErrorCode
|
||||
{
|
||||
NO_ERROR(0x100),
|
||||
|
@ -45,9 +43,7 @@ public enum HTTP3ErrorCode
|
|||
public static long randomReservedCode()
|
||||
{
|
||||
// SPEC: reserved errors have the form 0x1F * n + 0x21.
|
||||
// This constant avoids to overflow VarLenInt, which is how an error code is encoded.
|
||||
long n = ThreadLocalRandom.current().nextLong(0x210842108421084L);
|
||||
return 0x1F * n + 0x21;
|
||||
return Grease.generateGreaseValue();
|
||||
}
|
||||
|
||||
public long code()
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.io.IOException;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.http3.frames.FrameType;
|
||||
import org.eclipse.jetty.http3.internal.Grease;
|
||||
import org.eclipse.jetty.http3.internal.HTTP3ErrorCode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -91,8 +92,9 @@ public class ControlParser
|
|||
return;
|
||||
}
|
||||
|
||||
// SPEC: grease and unknown frame types are ignored.
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("ignoring unknown frame type {}", Long.toHexString(frameType));
|
||||
LOG.debug("ignoring {} frame type {}", Grease.isGreaseValue(frameType) ? "grease" : "unknown", Long.toHexString(frameType));
|
||||
|
||||
BodyParser.Result result = unknownBodyParser.parse(buffer);
|
||||
if (result == BodyParser.Result.NO_FRAME)
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.function.BooleanSupplier;
|
|||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http3.frames.FrameType;
|
||||
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;
|
||||
|
@ -128,8 +129,9 @@ public class MessageParser
|
|||
return Result.NO_FRAME;
|
||||
}
|
||||
|
||||
// SPEC: grease and unknown frame types are ignored.
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("ignoring unknown frame type {}", Long.toHexString(frameType));
|
||||
LOG.debug("ignoring {} frame type {}", Grease.isGreaseValue(frameType) ? "grease" : "unknown", Long.toHexString(frameType));
|
||||
|
||||
BodyParser.Result result = unknownBodyParser.parse(buffer);
|
||||
if (result == BodyParser.Result.NO_FRAME)
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.eclipse.jetty.http3.frames.SettingsFrame;
|
|||
import org.eclipse.jetty.http3.internal.ControlFlusher;
|
||||
import org.eclipse.jetty.http3.internal.DecoderStreamConnection;
|
||||
import org.eclipse.jetty.http3.internal.EncoderStreamConnection;
|
||||
import org.eclipse.jetty.http3.internal.Grease;
|
||||
import org.eclipse.jetty.http3.internal.HTTP3ErrorCode;
|
||||
import org.eclipse.jetty.http3.internal.InstructionFlusher;
|
||||
import org.eclipse.jetty.http3.internal.InstructionHandler;
|
||||
|
@ -62,7 +63,7 @@ public class ServerHTTP3Session extends ServerProtocolSession
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("initializing HTTP/3 streams");
|
||||
|
||||
long encoderStreamId = getQuicSession().newStreamId(StreamType.SERVER_UNIDIRECTIONAL);
|
||||
long encoderStreamId = newStreamId(StreamType.SERVER_UNIDIRECTIONAL);
|
||||
QuicStreamEndPoint encoderEndPoint = openInstructionEndPoint(encoderStreamId);
|
||||
InstructionFlusher encoderInstructionFlusher = new InstructionFlusher(quicSession, encoderEndPoint, EncoderStreamConnection.STREAM_TYPE);
|
||||
encoder = new QpackEncoder(new InstructionHandler(encoderInstructionFlusher));
|
||||
|
@ -71,7 +72,7 @@ public class ServerHTTP3Session extends ServerProtocolSession
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("created encoder stream #{} on {}", encoderStreamId, encoderEndPoint);
|
||||
|
||||
long decoderStreamId = getQuicSession().newStreamId(StreamType.SERVER_UNIDIRECTIONAL);
|
||||
long decoderStreamId = newStreamId(StreamType.SERVER_UNIDIRECTIONAL);
|
||||
QuicStreamEndPoint decoderEndPoint = openInstructionEndPoint(decoderStreamId);
|
||||
InstructionFlusher decoderInstructionFlusher = new InstructionFlusher(quicSession, decoderEndPoint, DecoderStreamConnection.STREAM_TYPE);
|
||||
decoder = new QpackDecoder(new InstructionHandler(decoderInstructionFlusher));
|
||||
|
@ -79,7 +80,7 @@ public class ServerHTTP3Session extends ServerProtocolSession
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("created decoder stream #{} on {}", decoderStreamId, decoderEndPoint);
|
||||
|
||||
long controlStreamId = getQuicSession().newStreamId(StreamType.SERVER_UNIDIRECTIONAL);
|
||||
long controlStreamId = newStreamId(StreamType.SERVER_UNIDIRECTIONAL);
|
||||
QuicStreamEndPoint controlEndPoint = openControlEndPoint(controlStreamId);
|
||||
controlFlusher = new ControlFlusher(quicSession, controlEndPoint, configuration.isUseOutputDirectByteBuffers());
|
||||
addBean(controlFlusher);
|
||||
|
@ -105,6 +106,11 @@ public class ServerHTTP3Session extends ServerProtocolSession
|
|||
return session;
|
||||
}
|
||||
|
||||
public long newStreamId(StreamType streamType)
|
||||
{
|
||||
return getQuicSession().newStreamId(streamType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart()
|
||||
{
|
||||
|
@ -170,21 +176,27 @@ public class ServerHTTP3Session extends ServerProtocolSession
|
|||
{
|
||||
if (key == SettingsFrame.MAX_TABLE_CAPACITY)
|
||||
{
|
||||
int maxTableCapacity = value.intValue();
|
||||
int maxTableCapacity = (int)Math.min(value, Integer.MAX_VALUE);
|
||||
encoder.setMaxTableCapacity(maxTableCapacity);
|
||||
encoder.setTableCapacity(Math.min(maxTableCapacity, configuration.getMaxEncoderTableCapacity()));
|
||||
}
|
||||
else if (key == SettingsFrame.MAX_FIELD_SECTION_SIZE)
|
||||
{
|
||||
// Must cap the maxHeaderSize to avoid large allocations.
|
||||
int maxHeadersSize = Math.min(value.intValue(), configuration.getMaxResponseHeadersSize());
|
||||
int maxHeadersSize = (int)Math.min(value, configuration.getMaxResponseHeadersSize());
|
||||
encoder.setMaxHeadersSize(maxHeadersSize);
|
||||
}
|
||||
else if (key == SettingsFrame.MAX_BLOCKED_STREAMS)
|
||||
{
|
||||
int maxBlockedStreams = value.intValue();
|
||||
int maxBlockedStreams = (int)Math.min(value, Integer.MAX_VALUE);
|
||||
encoder.setMaxBlockedStreams(maxBlockedStreams);
|
||||
}
|
||||
else
|
||||
{
|
||||
// SPEC: grease and unknown settings are ignored.
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("ignored {} setting {}={}", Grease.isGreaseValue(key) ? "grease" : "unknown", key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue