Skip to content

Commit 732b944

Browse files
committed
WIP
1 parent 7d2c493 commit 732b944

File tree

16 files changed

+726
-485
lines changed

16 files changed

+726
-485
lines changed

src/libraries/Common/src/System/Net/StreamBuffer.cs

+16
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ internal sealed class StreamBuffer : IDisposable
1818
private bool _readAborted;
1919
private readonly ResettableValueTaskSource _readTaskSource;
2020
private readonly ResettableValueTaskSource _writeTaskSource;
21+
private readonly TaskCompletionSource _shutdownTaskSource;
2122

2223
public const int DefaultInitialBufferSize = 4 * 1024;
2324
public const int DefaultMaxBufferSize = 32 * 1024;
@@ -28,10 +29,13 @@ public StreamBuffer(int initialBufferSize = DefaultInitialBufferSize, int maxBuf
2829
_maxBufferSize = maxBufferSize;
2930
_readTaskSource = new ResettableValueTaskSource();
3031
_writeTaskSource = new ResettableValueTaskSource();
32+
_shutdownTaskSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
3133
}
3234

3335
private object SyncObject => _readTaskSource;
3436

37+
public Task Completed => _shutdownTaskSource.Task;
38+
3539
public bool IsComplete
3640
{
3741
get
@@ -187,6 +191,11 @@ public void EndWrite()
187191
_writeEnded = true;
188192

189193
_readTaskSource.SignalWaiter();
194+
195+
if (_buffer.IsEmpty)
196+
{
197+
_shutdownTaskSource.TrySetResult();
198+
}
190199
}
191200
}
192201

@@ -210,10 +219,16 @@ public void EndWrite()
210219

211220
_writeTaskSource.SignalWaiter();
212221

222+
if (_buffer.IsEmpty && _writeEnded)
223+
{
224+
_shutdownTaskSource.TrySetResult();
225+
}
226+
213227
return (false, bytesRead);
214228
}
215229
else if (_writeEnded)
216230
{
231+
_shutdownTaskSource.TrySetResult();
217232
return (false, 0);
218233
}
219234

@@ -280,6 +295,7 @@ public void AbortRead()
280295

281296
_readTaskSource.SignalWaiter();
282297
_writeTaskSource.SignalWaiter();
298+
_shutdownTaskSource.TrySetResult();
283299
}
284300
}
285301

src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public async Task SendFrameAsync(long frameType, ReadOnlyMemory<byte> framePaylo
118118

119119
public async Task ShutdownSendAsync()
120120
{
121-
_stream.Shutdown();
121+
await _stream.CompleteWritesAsync().ConfigureAwait(false);
122122
await _stream.ShutdownWriteCompleted().ConfigureAwait(false);
123123
}
124124

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ private async Task ProcessServerStreamAsync(QuicStream stream)
614614
NetEventSource.Info(this, $"Ignoring server-initiated stream of unknown type {unknownStreamType}.");
615615
}
616616

617-
stream.AbortWrite((long)Http3ErrorCode.StreamCreationError);
617+
stream.Abort((long)Http3ErrorCode.StreamCreationError, QuicAbortDirection.Read);
618618
return;
619619
}
620620
}

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public async Task<HttpResponseMessage> SendAsync(CancellationToken cancellationT
152152
}
153153
else
154154
{
155-
_stream.Shutdown();
155+
_stream.CompleteWrites();
156156
}
157157
}
158158

@@ -263,7 +263,7 @@ public async Task<HttpResponseMessage> SendAsync(CancellationToken cancellationT
263263

264264
if (cancellationToken.IsCancellationRequested)
265265
{
266-
_stream.AbortWrite((long)Http3ErrorCode.RequestCancelled);
266+
_stream.Abort((long)Http3ErrorCode.RequestCancelled);
267267
throw new OperationCanceledException(ex.Message, ex, cancellationToken);
268268
}
269269
else
@@ -280,7 +280,7 @@ public async Task<HttpResponseMessage> SendAsync(CancellationToken cancellationT
280280
}
281281
catch (Exception ex)
282282
{
283-
_stream.AbortWrite((long)Http3ErrorCode.InternalError);
283+
_stream.Abort((long)Http3ErrorCode.InternalError);
284284
if (ex is HttpRequestException)
285285
{
286286
throw;
@@ -372,7 +372,7 @@ private async Task SendContentAsync(HttpContent content, CancellationToken cance
372372
_sendBuffer.Discard(_sendBuffer.ActiveLength);
373373
}
374374

375-
_stream.Shutdown();
375+
_stream.CompleteWrites();
376376
}
377377

378378
private async ValueTask WriteRequestContentAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
@@ -777,7 +777,7 @@ private async ValueTask ReadHeadersAsync(long headersLength, CancellationToken c
777777
// https://tools.ietf.org/html/draft-ietf-quic-http-24#section-4.1.1
778778
if (headersLength > _headerBudgetRemaining)
779779
{
780-
_stream.AbortWrite((long)Http3ErrorCode.ExcessiveLoad);
780+
_stream.Abort((long)Http3ErrorCode.ExcessiveLoad);
781781
throw new HttpRequestException(SR.Format(SR.net_http_response_headers_exceeded_length, _connection.Pool.Settings._maxResponseHeadersLength * 1024L));
782782
}
783783

@@ -1114,11 +1114,11 @@ private void HandleReadResponseContentException(Exception ex, CancellationToken
11141114
_connection.Abort(ex);
11151115
throw new IOException(SR.net_http_client_execution_error, new HttpRequestException(SR.net_http_client_execution_error, ex));
11161116
case OperationCanceledException oce when oce.CancellationToken == cancellationToken:
1117-
_stream.AbortWrite((long)Http3ErrorCode.RequestCancelled);
1117+
_stream.Abort((long)Http3ErrorCode.RequestCancelled);
11181118
ExceptionDispatchInfo.Throw(ex); // Rethrow.
11191119
return; // Never reached.
11201120
default:
1121-
_stream.AbortWrite((long)Http3ErrorCode.InternalError);
1121+
_stream.Abort((long)Http3ErrorCode.InternalError);
11221122
throw new IOException(SR.net_http_client_execution_error, new HttpRequestException(SR.net_http_client_execution_error, ex));
11231123
}
11241124
}

src/libraries/System.Net.Quic/System.Net.Quic.sln

+23-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
Microsoft Visual Studio Solution File, Format Version 12.00
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.31220.234
5+
MinimumVisualStudioVersion = 10.0.40219.1
26
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{55C933AA-2735-4B38-A1DD-01A27467AB18}"
37
EndProject
48
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Win32.Registry", "..\Microsoft.Win32.Registry\ref\Microsoft.Win32.Registry.csproj", "{69CDCFD5-AA35-40D8-A437-ED1C06E9CA95}"
@@ -23,18 +27,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{4BABFE90-C81
2327
EndProject
2428
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DAC0D00A-6EB0-4A72-94BB-EB90B3EE72A9}"
2529
EndProject
30+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreamConformanceTests", "..\Common\tests\StreamConformanceTests\StreamConformanceTests.csproj", "{CCE2D0B0-BDBE-4750-B215-2517286510EB}"
31+
EndProject
2632
Global
27-
GlobalSection(NestedProjects) = preSolution
28-
{55C933AA-2735-4B38-A1DD-01A27467AB18} = {BDA10542-BE94-4A73-9B5B-6BE5CE57F883}
29-
{E8E7DD3A-EC3F-4472-9F70-B515A3D11038} = {BDA10542-BE94-4A73-9B5B-6BE5CE57F883}
30-
{69CDCFD5-AA35-40D8-A437-ED1C06E9CA95} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
31-
{D7A52855-C6DE-4FD0-9CAF-E55F292C69E5} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
32-
{7BB8C50D-4770-42CB-BE15-76AD623A5AE8} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
33-
{833418C5-FEC9-482F-A0D6-69DFC332C1B6} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
34-
{E1CABA2F-48AD-49FA-B872-BEED78C51980} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
35-
{4F87758B-D1AF-4DE3-A9A2-68B1558C02B7} = {DAC0D00A-6EB0-4A72-94BB-EB90B3EE72A9}
36-
{9D56BA9E-1B0D-4320-9FE9-A2D326A32BE0} = {DAC0D00A-6EB0-4A72-94BB-EB90B3EE72A9}
37-
EndGlobalSection
3833
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3934
Debug|Any CPU = Debug|Any CPU
4035
Release|Any CPU = Release|Any CPU
@@ -76,10 +71,26 @@ Global
7671
{E1CABA2F-48AD-49FA-B872-BEED78C51980}.Debug|Any CPU.Build.0 = Debug|Any CPU
7772
{E1CABA2F-48AD-49FA-B872-BEED78C51980}.Release|Any CPU.ActiveCfg = Release|Any CPU
7873
{E1CABA2F-48AD-49FA-B872-BEED78C51980}.Release|Any CPU.Build.0 = Release|Any CPU
74+
{CCE2D0B0-BDBE-4750-B215-2517286510EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
75+
{CCE2D0B0-BDBE-4750-B215-2517286510EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
76+
{CCE2D0B0-BDBE-4750-B215-2517286510EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
77+
{CCE2D0B0-BDBE-4750-B215-2517286510EB}.Release|Any CPU.Build.0 = Release|Any CPU
7978
EndGlobalSection
8079
GlobalSection(SolutionProperties) = preSolution
8180
HideSolutionNode = FALSE
8281
EndGlobalSection
82+
GlobalSection(NestedProjects) = preSolution
83+
{55C933AA-2735-4B38-A1DD-01A27467AB18} = {BDA10542-BE94-4A73-9B5B-6BE5CE57F883}
84+
{69CDCFD5-AA35-40D8-A437-ED1C06E9CA95} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
85+
{D7A52855-C6DE-4FD0-9CAF-E55F292C69E5} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
86+
{4F87758B-D1AF-4DE3-A9A2-68B1558C02B7} = {DAC0D00A-6EB0-4A72-94BB-EB90B3EE72A9}
87+
{E8E7DD3A-EC3F-4472-9F70-B515A3D11038} = {BDA10542-BE94-4A73-9B5B-6BE5CE57F883}
88+
{7BB8C50D-4770-42CB-BE15-76AD623A5AE8} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
89+
{9D56BA9E-1B0D-4320-9FE9-A2D326A32BE0} = {DAC0D00A-6EB0-4A72-94BB-EB90B3EE72A9}
90+
{833418C5-FEC9-482F-A0D6-69DFC332C1B6} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
91+
{E1CABA2F-48AD-49FA-B872-BEED78C51980} = {4BABFE90-C818-4772-9D2E-B92F69E1FCDF}
92+
{CCE2D0B0-BDBE-4750-B215-2517286510EB} = {BDA10542-BE94-4A73-9B5B-6BE5CE57F883}
93+
EndGlobalSection
8394
GlobalSection(ExtensibilityGlobals) = postSolution
8495
SolutionGuid = {4B59ACCA-7F0C-4062-AA79-B3D75EFACCCD}
8596
EndGlobalSection

src/libraries/System.Net.Quic/ref/System.Net.Quic.cs

+11-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66

77
namespace System.Net.Quic
88
{
9+
[System.FlagsAttribute]
10+
public enum QuicAbortDirection
11+
{
12+
Read = 1,
13+
Write = 2,
14+
Both = 3,
15+
}
916
public partial class QuicClientConnectionOptions : System.Net.Quic.QuicOptions
1017
{
1118
public QuicClientConnectionOptions() { }
@@ -85,11 +92,13 @@ internal QuicStream() { }
8592
public override long Length { get { throw null; } }
8693
public override long Position { get { throw null; } set { } }
8794
public long StreamId { get { throw null; } }
88-
public void AbortRead(long errorCode) { }
89-
public void AbortWrite(long errorCode) { }
95+
public void Abort(long errorCode, System.Net.Quic.QuicAbortDirection abortDirection = System.Net.Quic.QuicAbortDirection.Both) { }
9096
public override System.IAsyncResult BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback? callback, object? state) { throw null; }
9197
public override System.IAsyncResult BeginWrite(byte[] buffer, int offset, int count, System.AsyncCallback? callback, object? state) { throw null; }
98+
public System.Threading.Tasks.ValueTask CloseAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
99+
public void CompleteWrites() { }
92100
protected override void Dispose(bool disposing) { }
101+
public override System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }
93102
public override int EndRead(System.IAsyncResult asyncResult) { throw null; }
94103
public override void EndWrite(System.IAsyncResult asyncResult) { }
95104
public override void Flush() { }
@@ -100,9 +109,6 @@ public override void Flush() { }
100109
public override System.Threading.Tasks.ValueTask<int> ReadAsync(System.Memory<byte> buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
101110
public override long Seek(long offset, System.IO.SeekOrigin origin) { throw null; }
102111
public override void SetLength(long value) { }
103-
public void Shutdown() { }
104-
public System.Threading.Tasks.ValueTask ShutdownWriteCompleted(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
105-
public System.Threading.Tasks.ValueTask ShutdownCompleted(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
106112
public override void Write(byte[] buffer, int offset, int count) { }
107113
public override void Write(System.ReadOnlySpan<byte> buffer) { }
108114
public System.Threading.Tasks.ValueTask WriteAsync(System.Buffers.ReadOnlySequence<byte> buffers, bool endStream, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }

src/libraries/System.Net.Quic/src/Resources/Strings.resx

+28-29
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<root>
3-
<!--
4-
Microsoft ResX Schema
5-
3+
<!--
4+
Microsoft ResX Schema
5+
66
Version 2.0
7-
8-
The primary goals of this format is to allow a simple XML format
9-
that is mostly human readable. The generation and parsing of the
10-
various data types are done through the TypeConverter classes
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
1111
associated with the data types.
12-
12+
1313
Example:
14-
14+
1515
... ado.net/XML headers & schema ...
1616
<resheader name="resmimetype">text/microsoft-resx</resheader>
1717
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
2626
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
2727
<comment>This is a comment</comment>
2828
</data>
29-
30-
There are any number of "resheader" rows that contain simple
29+
30+
There are any number of "resheader" rows that contain simple
3131
name/value pairs.
32-
33-
Each data row contains a name, and value. The row also contains a
34-
type or mimetype. Type corresponds to a .NET class that support
35-
text/value conversion through the TypeConverter architecture.
36-
Classes that don't support this are serialized and stored with the
32+
33+
Each data row contains a name, and value. The row also contains a
34+
type or mimetype. Type corresponds to a .NET class that support
35+
text/value conversion through the TypeConverter architecture.
36+
Classes that don't support this are serialized and stored with the
3737
mimetype set.
38-
39-
The mimetype is used for serialized objects, and tells the
40-
ResXResourceReader how to depersist the object. This is currently not
38+
39+
The mimetype is used for serialized objects, and tells the
40+
ResXResourceReader how to depersist the object. This is currently not
4141
extensible. For a given mimetype the value must be set accordingly:
42-
43-
Note - application/x-microsoft.net.object.binary.base64 is the format
44-
that the ResXResourceWriter will generate, however the reader can
42+
43+
Note - application/x-microsoft.net.object.binary.base64 is the format
44+
that the ResXResourceWriter will generate, however the reader can
4545
read any of the formats listed below.
46-
46+
4747
mimetype: application/x-microsoft.net.object.binary.base64
48-
value : The object must be serialized with
48+
value : The object must be serialized with
4949
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
5050
: and then encoded with base64 encoding.
51-
51+
5252
mimetype: application/x-microsoft.net.object.soap.base64
53-
value : The object must be serialized with
53+
value : The object must be serialized with
5454
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
5555
: and then encoded with base64 encoding.
5656
5757
mimetype: application/x-microsoft.net.object.bytearray.base64
58-
value : The object must be serialized into a byte array
58+
value : The object must be serialized into a byte array
5959
: using a System.ComponentModel.TypeConverter
6060
: and then encoded with base64 encoding.
6161
-->
@@ -150,5 +150,4 @@
150150
<data name="net_quic_writing_notallowed" xml:space="preserve">
151151
<value>Writing is not allowed on stream.</value>
152152
</data>
153-
</root>
154-
153+
</root>

0 commit comments

Comments
 (0)