diff --git a/src/libraries/System.Net.Quic/ref/System.Net.Quic.cs b/src/libraries/System.Net.Quic/ref/System.Net.Quic.cs
index a0c1f488e04785..d8dbf635bef66d 100644
--- a/src/libraries/System.Net.Quic/ref/System.Net.Quic.cs
+++ b/src/libraries/System.Net.Quic/ref/System.Net.Quic.cs
@@ -114,6 +114,7 @@ public QuicServerConnectionOptions() { }
public sealed partial class QuicStream : System.IO.Stream
{
internal QuicStream() { }
+ public const byte DefaultPriority = (byte)127;
public override bool CanRead { get { throw null; } }
public override bool CanSeek { get { throw null; } }
public override bool CanTimeout { get { throw null; } }
@@ -121,6 +122,7 @@ internal QuicStream() { }
public long Id { get { throw null; } }
public override long Length { get { throw null; } }
public override long Position { get { throw null; } set { } }
+ public byte Priority { get { throw null; } set { } }
public System.Threading.Tasks.Task ReadsClosed { get { throw null; } }
public override int ReadTimeout { get { throw null; } set { } }
public System.Net.Quic.QuicStreamType Type { get { throw null; } }
diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs
index 91d84e6ebf525d..b9a9b8df071951 100644
--- a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs
+++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs
@@ -120,6 +120,7 @@ public sealed partial class QuicStream
private long _id = -1;
private readonly QuicStreamType _type;
+ private byte _priority = DefaultPriority;
///
/// Provided via from so that can decrement its available stream count field.
@@ -127,6 +128,14 @@ public sealed partial class QuicStream
///
private Action? _decrementStreamCapacity;
+ ///
+ /// The default value of , which is the middle of the range.
+ ///
+ ///
+ /// represents the lowest priority and represents the highest priority.
+ ///
+ public const byte DefaultPriority = 0x7F;
+
///
/// Stream id, see .
///
@@ -137,6 +146,27 @@ public sealed partial class QuicStream
///
public QuicStreamType Type => _type;
+ ///
+ /// Gets or sets the stream priority, see RFC 9000: Stream Prioritization.
+ ///
+ ///
+ /// Priority only affects the order of data sent on the wire relative to other streams on the same connection.
+ /// represents the lowest priority and represents the highest.
+ /// The default value is .
+ ///
+ /// The priority level for this stream. The default value is .
+ public byte Priority
+ {
+ get => _priority;
+ set
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+
+ SetMsQuicParameter(_handle, QUIC_PARAM_STREAM_PRIORITY, (ushort)((value << 8) | 0xFF));
+ _priority = value;
+ }
+ }
+
///
/// A that will get completed once reading side has been closed.
/// Which might be by reading till end of stream ( will return 0),
diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs
index 1996c97831bc3c..dbf4861bdb862e 100644
--- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs
+++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs
@@ -1553,5 +1553,96 @@ async ValueTask WaitingSide(QuicStream stream, Task task, bool server)
}
}
}
+
+ [Fact]
+ public async Task Priority_DefaultValue()
+ {
+ await RunClientServer(
+ serverFunction: async connection =>
+ {
+ await using QuicStream stream = await connection.AcceptInboundStreamAsync();
+ Assert.Equal(QuicStream.DefaultPriority, stream.Priority);
+ },
+ clientFunction: async connection =>
+ {
+ await using QuicStream stream = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
+ Assert.Equal(QuicStream.DefaultPriority, stream.Priority);
+ stream.CompleteWrites();
+ }
+ );
+ }
+
+ [Theory]
+ [InlineData(byte.MinValue)]
+ [InlineData(1)]
+ [InlineData(QuicStream.DefaultPriority)]
+ [InlineData(byte.MaxValue)]
+ public async Task Priority_SetGet(byte priority)
+ {
+ await RunClientServer(
+ serverFunction: async connection =>
+ {
+ await using QuicStream stream = await connection.AcceptInboundStreamAsync();
+ byte[] buffer = new byte[1];
+ await ReadAll(stream, buffer);
+ },
+ clientFunction: async connection =>
+ {
+ await using QuicStream stream = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
+ stream.Priority = priority;
+ Assert.Equal(priority, stream.Priority);
+ await stream.WriteAsync(new byte[] { 42 }, completeWrites: true);
+ }
+ );
+ }
+
+ [Fact]
+ public async Task Priority_SetMultipleTimes()
+ {
+ await RunClientServer(
+ serverFunction: async connection =>
+ {
+ await using QuicStream stream = await connection.AcceptInboundStreamAsync();
+ byte[] buffer = new byte[1];
+ await ReadAll(stream, buffer);
+ },
+ clientFunction: async connection =>
+ {
+ await using QuicStream stream = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
+
+ stream.Priority = byte.MaxValue;
+ Assert.Equal(byte.MaxValue, stream.Priority);
+
+ stream.Priority = byte.MinValue;
+ Assert.Equal(byte.MinValue, stream.Priority);
+
+ stream.Priority = QuicStream.DefaultPriority;
+ Assert.Equal(QuicStream.DefaultPriority, stream.Priority);
+
+ await stream.WriteAsync(new byte[] { 42 }, completeWrites: true);
+ }
+ );
+ }
+
+ [Fact]
+ public async Task Priority_ThrowsAfterDispose()
+ {
+ await RunClientServer(
+ serverFunction: async connection =>
+ {
+ await using QuicStream stream = await connection.AcceptInboundStreamAsync();
+ byte[] buffer = new byte[1];
+ await ReadAll(stream, buffer);
+ },
+ clientFunction: async connection =>
+ {
+ QuicStream stream = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
+ await stream.WriteAsync(new byte[] { 42 }, completeWrites: true);
+ await stream.DisposeAsync();
+
+ Assert.Throws(() => stream.Priority = byte.MaxValue);
+ }
+ );
+ }
}
}