6
6
using System . Collections . Concurrent ;
7
7
using System . Collections . Generic ;
8
8
using System . Diagnostics ;
9
+ using System . Globalization ;
9
10
using System . IO ;
10
11
using System . IO . Pipelines ;
11
12
using System . Linq ;
12
13
using System . Net . Http ;
13
14
using System . Net . Http . QPack ;
14
15
using System . Reflection ;
16
+ using System . Text ;
15
17
using System . Threading ;
16
18
using System . Threading . Channels ;
17
19
using System . Threading . Tasks ;
@@ -38,6 +40,8 @@ public abstract class Http3TestBase : TestApplicationErrorLoggerLoggedTest, IDis
38
40
{
39
41
protected static readonly int MaxRequestHeaderFieldSize = 16 * 1024 ;
40
42
protected static readonly string _4kHeaderValue = new string ( 'a' , 4096 ) ;
43
+ protected static readonly byte [ ] _helloWorldBytes = Encoding . ASCII . GetBytes ( "hello, world" ) ;
44
+ protected static readonly byte [ ] _maxData = Encoding . ASCII . GetBytes ( new string ( 'a' , 16 * 1024 ) ) ;
41
45
42
46
internal TestServiceContext _serviceContext ;
43
47
internal readonly TimeoutControl _timeoutControl ;
@@ -49,16 +53,37 @@ public abstract class Http3TestBase : TestApplicationErrorLoggerLoggedTest, IDis
49
53
protected readonly TaskCompletionSource _closedStateReached = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
50
54
51
55
internal readonly ConcurrentDictionary < long , Http3StreamBase > _runningStreams = new ConcurrentDictionary < long , Http3StreamBase > ( ) ;
52
-
53
56
protected readonly RequestDelegate _noopApplication ;
54
57
protected readonly RequestDelegate _echoApplication ;
58
+ protected readonly RequestDelegate _readRateApplication ;
55
59
protected readonly RequestDelegate _echoMethod ;
56
60
protected readonly RequestDelegate _echoPath ;
57
61
protected readonly RequestDelegate _echoHost ;
58
62
59
63
private Http3ControlStream _inboundControlStream ;
60
64
private long _currentStreamId ;
61
65
66
+ protected static readonly IEnumerable < KeyValuePair < string , string > > _browserRequestHeaders = new [ ]
67
+ {
68
+ new KeyValuePair < string , string > ( HeaderNames . Method , "GET" ) ,
69
+ new KeyValuePair < string , string > ( HeaderNames . Path , "/" ) ,
70
+ new KeyValuePair < string , string > ( HeaderNames . Scheme , "http" ) ,
71
+ new KeyValuePair < string , string > ( HeaderNames . Authority , "localhost:80" ) ,
72
+ new KeyValuePair < string , string > ( "user-agent" , "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0" ) ,
73
+ new KeyValuePair < string , string > ( "accept" , "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" ) ,
74
+ new KeyValuePair < string , string > ( "accept-language" , "en-US,en;q=0.5" ) ,
75
+ new KeyValuePair < string , string > ( "accept-encoding" , "gzip, deflate, br" ) ,
76
+ new KeyValuePair < string , string > ( "upgrade-insecure-requests" , "1" ) ,
77
+ } ;
78
+
79
+ protected static IEnumerable < KeyValuePair < string , string > > ReadRateRequestHeaders ( int expectedBytes ) => new [ ]
80
+ {
81
+ new KeyValuePair < string , string > ( HeaderNames . Method , "POST" ) ,
82
+ new KeyValuePair < string , string > ( HeaderNames . Path , "/" + expectedBytes ) ,
83
+ new KeyValuePair < string , string > ( HeaderNames . Scheme , "http" ) ,
84
+ new KeyValuePair < string , string > ( HeaderNames . Authority , "localhost:80" ) ,
85
+ } ;
86
+
62
87
public Http3TestBase ( )
63
88
{
64
89
_timeoutControl = new TimeoutControl ( _mockTimeoutHandler . Object ) ;
@@ -83,6 +108,26 @@ public Http3TestBase()
83
108
}
84
109
} ;
85
110
111
+ _readRateApplication = async context =>
112
+ {
113
+ var expectedBytes = int . Parse ( context . Request . Path . Value . Substring ( 1 ) , CultureInfo . InvariantCulture ) ;
114
+
115
+ var buffer = new byte [ 16 * 1024 ] ;
116
+ var received = 0 ;
117
+
118
+ while ( received < expectedBytes )
119
+ {
120
+ received += await context . Request . Body . ReadAsync ( buffer , 0 , buffer . Length ) ;
121
+ }
122
+
123
+ var stalledReadTask = context . Request . Body . ReadAsync ( buffer , 0 , buffer . Length ) ;
124
+
125
+ // Write to the response so the test knows the app started the stalled read.
126
+ await context . Response . Body . WriteAsync ( new byte [ 1 ] , 0 , 1 ) ;
127
+
128
+ await stalledReadTask ;
129
+ } ;
130
+
86
131
_echoMethod = context =>
87
132
{
88
133
context . Response . Headers [ "Method" ] = context . Request . Method ;
@@ -151,7 +196,17 @@ internal async ValueTask<Http3ControlStream> GetInboundControlStream()
151
196
return _inboundControlStream ;
152
197
}
153
198
154
- internal async Task WaitForConnectionErrorAsync < TException > ( bool ignoreNonGoAwayFrames , long expectedLastStreamId , Http3ErrorCode expectedErrorCode , params string [ ] expectedErrorMessage )
199
+ internal void CloseConnectionGracefully ( )
200
+ {
201
+ MultiplexedConnectionContext . ConnectionClosingCts . Cancel ( ) ;
202
+ }
203
+
204
+ internal Task WaitForConnectionStopAsync ( long expectedLastStreamId , bool ignoreNonGoAwayFrames , Http3ErrorCode ? expectedErrorCode = null )
205
+ {
206
+ return WaitForConnectionErrorAsync < Exception > ( ignoreNonGoAwayFrames , expectedLastStreamId , expectedErrorCode : expectedErrorCode ?? 0 , expectedErrorMessage : null ) ;
207
+ }
208
+
209
+ internal async Task WaitForConnectionErrorAsync < TException > ( bool ignoreNonGoAwayFrames , long ? expectedLastStreamId , Http3ErrorCode expectedErrorCode , params string [ ] expectedErrorMessage )
155
210
where TException : Exception
156
211
{
157
212
var frame = await _inboundControlStream . ReceiveFrameAsync ( ) ;
@@ -164,7 +219,10 @@ internal async Task WaitForConnectionErrorAsync<TException>(bool ignoreNonGoAway
164
219
}
165
220
}
166
221
167
- VerifyGoAway ( frame , expectedLastStreamId ) ;
222
+ if ( expectedLastStreamId != null )
223
+ {
224
+ VerifyGoAway ( frame , expectedLastStreamId . GetValueOrDefault ( ) ) ;
225
+ }
168
226
169
227
Assert . Equal ( ( Http3ErrorCode ) expectedErrorCode , ( Http3ErrorCode ) MultiplexedConnectionContext . Error ) ;
170
228
@@ -216,8 +274,6 @@ protected async Task InitializeConnectionAsync(RequestDelegate application)
216
274
_connectionTask = Connection . ProcessStreamsAsync ( new DummyApplication ( application ) ) ;
217
275
218
276
await GetInboundControlStream ( ) ;
219
-
220
- await Task . CompletedTask ;
221
277
}
222
278
223
279
internal async ValueTask < Http3RequestStream > InitializeConnectionAndStreamsAsync ( RequestDelegate application )
@@ -394,7 +450,7 @@ public class Http3StreamBase : IProtocolErrorCodeFeature
394
450
internal DuplexPipe . DuplexPipePair _pair ;
395
451
internal Http3TestBase _testBase ;
396
452
internal Http3Connection _connection ;
397
- private long _bytesReceived ;
453
+ public long BytesReceived { get ; private set ; }
398
454
public long Error { get ; set ; }
399
455
400
456
public Task OnStreamCreatedTask => _onStreamCreatedTcs . Task ;
@@ -412,6 +468,12 @@ protected static async Task FlushAsync(PipeWriter writableBuffer)
412
468
await writableBuffer . FlushAsync ( ) . AsTask ( ) . DefaultTimeout ( ) ;
413
469
}
414
470
471
+ internal async Task ReceiveEndAsync ( )
472
+ {
473
+ var result = await _pair . Application . Input . ReadAsync ( ) . AsTask ( ) . DefaultTimeout ( ) ;
474
+ Assert . True ( result . IsCompleted ) ;
475
+ }
476
+
415
477
internal async Task < Http3FrameWithPayload > ReceiveFrameAsync ( )
416
478
{
417
479
var frame = new Http3FrameWithPayload ( ) ;
@@ -446,7 +508,7 @@ internal async Task<Http3FrameWithPayload> ReceiveFrameAsync()
446
508
}
447
509
finally
448
510
{
449
- _bytesReceived += copyBuffer . Slice ( copyBuffer . Start , consumed ) . Length ;
511
+ BytesReceived += copyBuffer . Slice ( copyBuffer . Start , consumed ) . Length ;
450
512
_pair . Application . Input . AdvanceTo ( consumed , examined ) ;
451
513
}
452
514
}
@@ -655,6 +717,17 @@ void WriteSpan(PipeWriter pw)
655
717
await FlushAsync ( writableBuffer ) ;
656
718
}
657
719
720
+ internal async Task SendGoAwayAsync ( long streamId , bool endStream = false )
721
+ {
722
+ var frame = new Http3RawFrame ( ) ;
723
+ frame . PrepareGoAway ( ) ;
724
+
725
+ var data = new byte [ VariableLengthIntegerHelper . GetByteCount ( streamId ) ] ;
726
+ VariableLengthIntegerHelper . WriteInteger ( data , streamId ) ;
727
+
728
+ await SendFrameAsync ( frame , data , endStream ) ;
729
+ }
730
+
658
731
internal async Task SendSettingsAsync ( List < Http3PeerSetting > settings , bool endStream = false )
659
732
{
660
733
var frame = new Http3RawFrame ( ) ;
@@ -738,6 +811,7 @@ public class TestMultiplexedConnectionContext : MultiplexedConnectionContext, IC
738
811
} ) ;
739
812
740
813
private readonly Http3TestBase _testBase ;
814
+ private long _error ;
741
815
742
816
public TestMultiplexedConnectionContext ( Http3TestBase testBase )
743
817
{
@@ -759,7 +833,11 @@ public TestMultiplexedConnectionContext(Http3TestBase testBase)
759
833
760
834
public CancellationTokenSource ConnectionClosingCts { get ; set ; } = new CancellationTokenSource ( ) ;
761
835
762
- public long Error { get ; set ; }
836
+ public long Error
837
+ {
838
+ get => _error ;
839
+ set => _error = value ;
840
+ }
763
841
764
842
public override void Abort ( )
765
843
{
0 commit comments