7
7
using System . Threading . Tasks ;
8
8
9
9
using Microsoft . AspNetCore . Http ;
10
- using Microsoft . AspNetCore . Http . Features ;
11
10
using Microsoft . Extensions . Primitives ;
12
11
using Microsoft . Net . Http . Headers ;
13
12
@@ -28,14 +27,14 @@ namespace WebMarkupMin.AspNetCore3
28
27
#endif
29
28
{
30
29
/// <summary>
31
- /// Stream wrapper that apply a markup minification and compression only if necessary
30
+ /// Base class of stream wrapper that apply a markup minification and compression only if necessary
32
31
/// </summary>
33
- internal sealed class BodyWrapperStream : Stream, IHttpBufferingFeature
32
+ internal abstract class BodyWrapperStreamBase : Stream
34
33
{
35
34
/// <summary>
36
35
/// HTTP context
37
36
/// </summary>
38
- private readonly HttpContext _context ;
37
+ protected readonly HttpContext _context ;
39
38
40
39
/// <summary>
41
40
/// Original stream
@@ -55,7 +54,7 @@ internal sealed class BodyWrapperStream : Stream, IHttpBufferingFeature
55
54
/// <summary>
56
55
/// Flag for whether to do automatically flush the compression stream
57
56
/// </summary>
58
- private bool _autoFlushCompressionStream = false ;
57
+ protected bool _autoFlushCompressionStream = false ;
59
58
60
59
/// <summary>
61
60
/// WebMarkupMin configuration
@@ -72,11 +71,6 @@ internal sealed class BodyWrapperStream : Stream, IHttpBufferingFeature
72
71
/// </summary>
73
72
private readonly IHttpCompressionManager _compressionManager ;
74
73
75
- /// <summary>
76
- /// HTTP buffering feature
77
- /// </summary>
78
- private readonly IHttpBufferingFeature _bufferingFeature ;
79
-
80
74
/// <summary>
81
75
/// Flag indicating whether the stream wrapper is initialized
82
76
/// </summary>
@@ -85,12 +79,12 @@ internal sealed class BodyWrapperStream : Stream, IHttpBufferingFeature
85
79
/// <summary>
86
80
/// Flag indicating whether a markup minification is enabled
87
81
/// </summary>
88
- private bool _minificationEnabled = false ;
82
+ protected bool _minificationEnabled = false ;
89
83
90
84
/// <summary>
91
85
/// Flag indicating whether a HTTP compression is enabled
92
86
/// </summary>
93
- private bool _compressionEnabled = false ;
87
+ protected bool _compressionEnabled = false ;
94
88
95
89
/// <summary>
96
90
/// Current URL
@@ -110,7 +104,7 @@ internal sealed class BodyWrapperStream : Stream, IHttpBufferingFeature
110
104
/// <summary>
111
105
/// Current HTTP compressor
112
106
/// </summary>
113
- private ICompressor _currentCompressor ;
107
+ protected ICompressor _currentCompressor ;
114
108
115
109
/// <summary>
116
110
/// Flag indicating whether the current HTTP compressor is initialized
@@ -122,6 +116,11 @@ internal sealed class BodyWrapperStream : Stream, IHttpBufferingFeature
122
116
/// </summary>
123
117
private InterlockedStatedFlag _httpHeadersModifiedForCompressionFlag = new InterlockedStatedFlag ( ) ;
124
118
119
+ /// <summary>
120
+ /// Flag that the stream wrapper is destroyed
121
+ /// </summary>
122
+ private InterlockedStatedFlag _disposedFlag = new InterlockedStatedFlag ( ) ;
123
+
125
124
126
125
/// <summary>
127
126
/// Constructs an instance of the stream wrapper
@@ -131,21 +130,19 @@ internal sealed class BodyWrapperStream : Stream, IHttpBufferingFeature
131
130
/// <param name="options">WebMarkupMin configuration</param>
132
131
/// <param name="minificationManagers">List of markup minification managers</param>
133
132
/// <param name="compressionManager">HTTP compression manager</param>
134
- /// <param name="bufferingFeature">HTTP buffering feature</param>
135
- internal BodyWrapperStream ( HttpContext context, Stream originalStream,
133
+ protected BodyWrapperStreamBase ( HttpContext context, Stream originalStream,
136
134
WebMarkupMinOptions options, IList < IMarkupMinificationManager> minificationManagers,
137
- IHttpCompressionManager compressionManager, IHttpBufferingFeature bufferingFeature )
135
+ IHttpCompressionManager compressionManager)
138
136
{
139
137
_context = context ;
140
138
_originalStream = originalStream ;
141
139
_options = options ;
142
140
_minificationManagers = minificationManagers ;
143
141
_compressionManager = compressionManager ;
144
- _bufferingFeature = bufferingFeature ;
145
142
}
146
143
147
144
148
- private void Initialize ( )
145
+ protected void Initialize ( )
149
146
{
150
147
if ( _wrapperInitializedFlag . Set ( ) )
151
148
{
@@ -235,7 +232,7 @@ private void Initialize()
235
232
}
236
233
}
237
234
238
- private ICompressor InitializeCurrentCompressor ( string acceptEncoding )
235
+ protected ICompressor InitializeCurrentCompressor ( string acceptEncoding )
239
236
{
240
237
if ( _currentCompressorInitializedFlag . Set ( ) )
241
238
{
@@ -258,8 +255,40 @@ private void ModifyHttpHeadersForCompressionOnce()
258
255
responseHeaders . Remove ( HeaderNames . ContentLength ) ;
259
256
}
260
257
}
258
+ #if NET451 || NETSTANDARD2_0 || NETCOREAPP3_0
259
+
260
+ private async void InternalWriteAsync ( byte [ ] buffer , int offset , int count , AsyncCallback callback ,
261
+ TaskCompletionSource < object > tcs )
262
+ {
263
+ try
264
+ {
265
+ await WriteAsync ( buffer , offset , count ) ;
266
+ tcs . TrySetResult ( null ) ;
267
+ }
268
+ catch ( Exception ex )
269
+ {
270
+ tcs . TrySetException ( ex ) ;
271
+ }
272
+
273
+ if ( callback != null )
274
+ {
275
+ // Offload callbacks to avoid stack dives on sync completions
276
+ var ignored = Task . Run ( ( ) =>
277
+ {
278
+ try
279
+ {
280
+ callback ( tcs . Task ) ;
281
+ }
282
+ catch ( Exception )
283
+ {
284
+ // Suppress exceptions on background threads
285
+ }
286
+ } ) ;
287
+ }
288
+ }
289
+ #endif
261
290
262
- public async Task Finish ( )
291
+ protected async Task InternalFinishAsync ( )
263
292
{
264
293
if ( _minificationEnabled )
265
294
{
@@ -345,38 +374,11 @@ public async Task Finish()
345
374
_cachedStream . Clear ( ) ;
346
375
}
347
376
}
348
- #if NET451 || NETSTANDARD2_0 || NETCOREAPP3_0
349
377
350
- private async void InternalWriteAsync ( byte [ ] buffer , int offset , int count , AsyncCallback callback ,
351
- TaskCompletionSource < object > tcs )
378
+ public virtual async Task FinishAsync ( )
352
379
{
353
- try
354
- {
355
- await WriteAsync ( buffer , offset , count ) ;
356
- tcs . TrySetResult ( null ) ;
357
- }
358
- catch ( Exception ex )
359
- {
360
- tcs . TrySetException ( ex ) ;
361
- }
362
-
363
- if ( callback != null )
364
- {
365
- // Offload callbacks to avoid stack dives on sync completions
366
- var ignored = Task . Run ( ( ) =>
367
- {
368
- try
369
- {
370
- callback ( tcs . Task ) ;
371
- }
372
- catch ( Exception )
373
- {
374
- // Suppress exceptions on background threads
375
- }
376
- } ) ;
377
- }
380
+ await Task . Run ( ( ) => throw new NotImplementedException ( ) ) ;
378
381
}
379
- #endif
380
382
381
383
#region Stream overrides
382
384
@@ -527,79 +529,56 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count,
527
529
528
530
protected override void Dispose ( bool disposing )
529
531
{
530
- if ( disposing )
532
+ if ( _disposedFlag . Set ( ) )
531
533
{
532
- if ( _compressionStream != null )
534
+ if ( disposing )
533
535
{
534
- _compressionStream . Dispose ( ) ;
535
- _compressionStream = null ;
536
- }
536
+ if ( _compressionStream != null )
537
+ {
538
+ _compressionStream . Dispose ( ) ;
539
+ _compressionStream = null ;
540
+ }
537
541
538
- _currentCompressor = null ;
542
+ _currentCompressor = null ;
539
543
540
- if ( _cachedStream != null )
541
- {
542
- _cachedStream . Dispose ( ) ;
543
- _cachedStream = null ;
544
+ if ( _cachedStream != null )
545
+ {
546
+ _cachedStream . Dispose ( ) ;
547
+ _cachedStream = null ;
548
+ }
549
+
550
+ _currentMinificationManager = null ;
544
551
}
545
552
546
- _currentMinificationManager = null ;
553
+ base . Dispose ( disposing ) ;
547
554
}
548
-
549
- base . Dispose ( disposing ) ;
550
555
}
551
556
#if NETCOREAPP3_0
552
557
553
558
public override async ValueTask DisposeAsync ( )
554
559
{
555
- if ( _compressionStream != null )
556
- {
557
- await _compressionStream . DisposeAsync ( ) ;
558
- _compressionStream = null ;
559
- }
560
-
561
- _currentCompressor = null ;
562
-
563
- if ( _cachedStream != null )
560
+ if ( _disposedFlag . Set ( ) )
564
561
{
565
- await _cachedStream . DisposeAsync ( ) ;
566
- _cachedStream = null ;
567
- }
568
-
569
- _currentMinificationManager = null ;
570
-
571
- await base . DisposeAsync ( ) ;
572
- }
573
- #endif
574
-
575
- #endregion
562
+ if ( _compressionStream != null )
563
+ {
564
+ await _compressionStream . DisposeAsync ( ) ;
565
+ _compressionStream = null ;
566
+ }
576
567
577
- #region IHttpBufferingFeature implementation
568
+ _currentCompressor = null ;
578
569
579
- public void DisableRequestBuffering ( )
580
- {
581
- _bufferingFeature ? . DisableRequestBuffering ( ) ;
582
- }
570
+ if ( _cachedStream != null )
571
+ {
572
+ await _cachedStream . DisposeAsync ( ) ;
573
+ _cachedStream = null ;
574
+ }
583
575
584
- public void DisableResponseBuffering ( )
585
- {
586
- string acceptEncoding = _context . Request . Headers [ HeaderNames . AcceptEncoding ] ;
587
- ICompressor compressor = InitializeCurrentCompressor ( acceptEncoding ) ;
576
+ _currentMinificationManager = null ;
588
577
589
- if ( compressor ? . SupportsFlush == false )
590
- {
591
- // Some of the compressors don't support flushing which would block real-time
592
- // responses like SignalR.
593
- _compressionEnabled = false ;
594
- _currentCompressor = null ;
578
+ await base . DisposeAsync ( ) ;
595
579
}
596
- else
597
- {
598
- _autoFlushCompressionStream = true ;
599
- }
600
-
601
- _bufferingFeature ? . DisableResponseBuffering ( ) ;
602
580
}
581
+ #endif
603
582
604
583
#endregion
605
584
}
0 commit comments