55using System . Collections . Generic ;
66using System . Diagnostics ;
77using System . Net ;
8- using System . Net . Http ;
98using System . Threading ;
109using System . Threading . Tasks ;
1110using Microsoft . AspNetCore . Connections ;
1211using Microsoft . AspNetCore . Connections . Experimental ;
1312using Microsoft . AspNetCore . Connections . Features ;
1413using Microsoft . AspNetCore . Hosting . Server ;
1514using Microsoft . AspNetCore . Http . Features ;
16- using Microsoft . AspNetCore . Server . Kestrel . Core . Internal . Http3 . QPack ;
1715using Microsoft . AspNetCore . Server . Kestrel . Core . Internal . Infrastructure ;
1816using Microsoft . Extensions . Logging ;
1917
2018namespace Microsoft . AspNetCore . Server . Kestrel . Core . Internal . Http3
2119{
2220 internal class Http3Connection : ITimeoutHandler
2321 {
24- public DynamicTable DynamicTable { get ; set ; }
22+ public Http3ControlStream OutboundControlStream { get ; set ; }
2523
2624 public Http3ControlStream ? ControlStream { get ; set ; }
2725 public Http3ControlStream ? EncoderStream { get ; set ; }
@@ -47,7 +45,6 @@ public Http3Connection(Http3ConnectionContext context)
4745 {
4846 _multiplexedContext = context . ConnectionContext ;
4947 _context = context ;
50- DynamicTable = new DynamicTable ( 0 ) ;
5148 _systemClock = context . ServiceContext . SystemClock ;
5249 _timeoutControl = new TimeoutControl ( this ) ;
5350 _context . TimeoutControl ??= _timeoutControl ;
@@ -198,10 +195,16 @@ public void OnTimeout(TimeoutReason reason)
198195
199196 internal async Task InnerProcessRequestsAsync < TContext > ( IHttpApplication < TContext > application ) where TContext : notnull
200197 {
201- // Start other three unidirectional streams here.
198+ // An endpoint MAY avoid creating an encoder stream if it's not going to
199+ // be used(for example if its encoder doesn't wish to use the dynamic
200+ // table, or if the maximum size of the dynamic table permitted by the
201+ // peer is zero).
202+
203+ // An endpoint MAY avoid creating a decoder stream if its decoder sets
204+ // the maximum capacity of the dynamic table to zero.
205+
206+ // Don't create Encoder and Decoder as they aren't used now.
202207 var controlTask = CreateControlStream ( application ) ;
203- var encoderTask = CreateEncoderStream ( application ) ;
204- var decoderTask = CreateDecoderStream ( application ) ;
205208
206209 try
207210 {
@@ -271,39 +274,33 @@ internal async Task InnerProcessRequestsAsync<TContext>(IHttpApplication<TContex
271274 stream . Abort ( _abortedException ) ;
272275 }
273276 }
277+ else
278+ {
279+ foreach ( var stream in _streams . Values )
280+ {
281+ stream . OnInputOrOutputCompleted ( ) ;
282+ }
283+ }
284+
285+ _inboundControlStream ? . OnInputOrOutputCompleted ( ) ;
286+ _inboundEncoderStream ? . OnInputOrOutputCompleted ( ) ;
287+ _inboundDecoderStream ? . OnInputOrOutputCompleted ( ) ;
274288 }
275289
276- ControlStream ? . Abort ( new ConnectionAbortedException ( "Connection is shutting down." ) ) ;
277- EncoderStream ? . Abort ( new ConnectionAbortedException ( "Connection is shutting down." ) ) ;
278- DecoderStream ? . Abort ( new ConnectionAbortedException ( "Connection is shutting down." ) ) ;
290+ OutboundControlStream ? . Abort ( new ConnectionAbortedException ( "Connection is shutting down." ) ) ;
279291
280292 await controlTask ;
281- await encoderTask ;
282- await decoderTask ;
283293 }
284294 }
285295
286296 private async ValueTask CreateControlStream < TContext > ( IHttpApplication < TContext > application ) where TContext : notnull
287297 {
288298 var stream = await CreateNewUnidirectionalStreamAsync ( application ) ;
289- ControlStream = stream ;
299+ OutboundControlStream = stream ;
290300 await stream . SendStreamIdAsync ( id : 0 ) ;
291301 await stream . SendSettingsFrameAsync ( ) ;
292302 }
293303
294- private async ValueTask CreateEncoderStream < TContext > ( IHttpApplication < TContext > application ) where TContext : notnull
295- {
296- var stream = await CreateNewUnidirectionalStreamAsync ( application ) ;
297- EncoderStream = stream ;
298- await stream . SendStreamIdAsync ( id : 2 ) ;
299- }
300-
301- private async ValueTask CreateDecoderStream < TContext > ( IHttpApplication < TContext > application ) where TContext : notnull
302- {
303- var stream = await CreateNewUnidirectionalStreamAsync ( application ) ;
304- DecoderStream = stream ;
305- await stream . SendStreamIdAsync ( id : 3 ) ;
306- }
307304
308305 private async ValueTask < Http3ControlStream > CreateNewUnidirectionalStreamAsync < TContext > ( IHttpApplication < TContext > application ) where TContext : notnull
309306 {
@@ -350,10 +347,10 @@ private void InnerAbort(ConnectionAbortedException ex)
350347
351348 lock ( _sync )
352349 {
353- if ( ControlStream != null )
350+ if ( OutboundControlStream != null )
354351 {
355352 // TODO need to await this somewhere or allow this to be called elsewhere?
356- ControlStream . SendGoAway ( _highestOpenedStreamId ) . GetAwaiter ( ) . GetResult ( ) ;
353+ OutboundControlStream . SendGoAway ( _highestOpenedStreamId ) . GetAwaiter ( ) . GetResult ( ) ;
357354 }
358355
359356 _haveSentGoAway = true ;
@@ -383,5 +380,44 @@ internal void RemoveStream(long streamId)
383380 _streams . Remove ( streamId ) ;
384381 }
385382 }
383+
384+ public bool SetInboundControlStream ( Http3ControlStream stream )
385+ {
386+ lock ( _sync )
387+ {
388+ if ( _inboundControlStream == null )
389+ {
390+ _inboundControlStream = stream ;
391+ return true ;
392+ }
393+ return false ;
394+ }
395+ }
396+
397+ public bool SetInboundEncoderStream ( Http3ControlStream stream )
398+ {
399+ lock ( _sync )
400+ {
401+ if ( _inboundEncoderStream == null )
402+ {
403+ _inboundEncoderStream = stream ;
404+ return true ;
405+ }
406+ return false ;
407+ }
408+ }
409+
410+ public bool SetInboundDecoderStream ( Http3ControlStream stream )
411+ {
412+ lock ( _sync )
413+ {
414+ if ( _inboundDecoderStream == null )
415+ {
416+ _inboundDecoderStream = stream ;
417+ return true ;
418+ }
419+ return false ;
420+ }
421+ }
386422 }
387423}
0 commit comments