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 {
@@ -270,39 +273,33 @@ internal async Task InnerProcessRequestsAsync<TContext>(IHttpApplication<TContex
270273 stream . Abort ( _abortedException ) ;
271274 }
272275 }
276+ else
277+ {
278+ foreach ( var stream in _streams . Values )
279+ {
280+ stream . OnInputOrOutputCompleted ( ) ;
281+ }
282+ }
283+
284+ _inboundControlStream ? . OnInputOrOutputCompleted ( ) ;
285+ _inboundEncoderStream ? . OnInputOrOutputCompleted ( ) ;
286+ _inboundDecoderStream ? . OnInputOrOutputCompleted ( ) ;
273287 }
274288
275- ControlStream ? . Abort ( new ConnectionAbortedException ( "Connection is shutting down." ) ) ;
276- EncoderStream ? . Abort ( new ConnectionAbortedException ( "Connection is shutting down." ) ) ;
277- DecoderStream ? . Abort ( new ConnectionAbortedException ( "Connection is shutting down." ) ) ;
289+ OutboundControlStream ? . Abort ( new ConnectionAbortedException ( "Connection is shutting down." ) ) ;
278290
279291 await controlTask ;
280- await encoderTask ;
281- await decoderTask ;
282292 }
283293 }
284294
285295 private async ValueTask CreateControlStream < TContext > ( IHttpApplication < TContext > application ) where TContext : notnull
286296 {
287297 var stream = await CreateNewUnidirectionalStreamAsync ( application ) ;
288- ControlStream = stream ;
298+ OutboundControlStream = stream ;
289299 await stream . SendStreamIdAsync ( id : 0 ) ;
290300 await stream . SendSettingsFrameAsync ( ) ;
291301 }
292302
293- private async ValueTask CreateEncoderStream < TContext > ( IHttpApplication < TContext > application ) where TContext : notnull
294- {
295- var stream = await CreateNewUnidirectionalStreamAsync ( application ) ;
296- EncoderStream = stream ;
297- await stream . SendStreamIdAsync ( id : 2 ) ;
298- }
299-
300- private async ValueTask CreateDecoderStream < TContext > ( IHttpApplication < TContext > application ) where TContext : notnull
301- {
302- var stream = await CreateNewUnidirectionalStreamAsync ( application ) ;
303- DecoderStream = stream ;
304- await stream . SendStreamIdAsync ( id : 3 ) ;
305- }
306303
307304 private async ValueTask < Http3ControlStream > CreateNewUnidirectionalStreamAsync < TContext > ( IHttpApplication < TContext > application ) where TContext : notnull
308305 {
@@ -349,10 +346,10 @@ private void InnerAbort(ConnectionAbortedException ex)
349346
350347 lock ( _sync )
351348 {
352- if ( ControlStream != null )
349+ if ( OutboundControlStream != null )
353350 {
354351 // TODO need to await this somewhere or allow this to be called elsewhere?
355- ControlStream . SendGoAway ( _highestOpenedStreamId ) . GetAwaiter ( ) . GetResult ( ) ;
352+ OutboundControlStream . SendGoAway ( _highestOpenedStreamId ) . GetAwaiter ( ) . GetResult ( ) ;
356353 }
357354
358355 _haveSentGoAway = true ;
@@ -382,5 +379,44 @@ internal void RemoveStream(long streamId)
382379 _streams . Remove ( streamId ) ;
383380 }
384381 }
382+
383+ public bool SetInboundControlStream ( Http3ControlStream stream )
384+ {
385+ lock ( _sync )
386+ {
387+ if ( _inboundControlStream == null )
388+ {
389+ _inboundControlStream = stream ;
390+ return true ;
391+ }
392+ return false ;
393+ }
394+ }
395+
396+ public bool SetInboundEncoderStream ( Http3ControlStream stream )
397+ {
398+ lock ( _sync )
399+ {
400+ if ( _inboundEncoderStream == null )
401+ {
402+ _inboundEncoderStream = stream ;
403+ return true ;
404+ }
405+ return false ;
406+ }
407+ }
408+
409+ public bool SetInboundDecoderStream ( Http3ControlStream stream )
410+ {
411+ lock ( _sync )
412+ {
413+ if ( _inboundDecoderStream == null )
414+ {
415+ _inboundDecoderStream = stream ;
416+ return true ;
417+ }
418+ return false ;
419+ }
420+ }
385421 }
386422}
0 commit comments