@@ -44,6 +44,7 @@ public partial class Frame : FrameContext, IFrameControl
44
44
private volatile bool _requestProcessingStopping ; // volatile, see: https://msdn.microsoft.com/en-us/library/x13ttww7.aspx
45
45
private volatile bool _requestAborted ;
46
46
private CancellationTokenSource _abortedCts ;
47
+ private CancellationToken ? _manuallySetRequestAbortToken ;
47
48
48
49
private FrameRequestStream _requestBody ;
49
50
private FrameResponseStream _responseBody ;
@@ -92,8 +93,47 @@ public Frame(ConnectionContext context,
92
93
93
94
public Stream DuplexStream { get ; set ; }
94
95
95
- public CancellationToken RequestAborted { get ; set ; }
96
+ public CancellationToken RequestAborted
97
+ {
98
+ get
99
+ {
100
+ // If a request abort token was previously explicitly set, return it.
101
+ if ( _manuallySetRequestAbortToken . HasValue )
102
+ return _manuallySetRequestAbortToken . Value ;
103
+
104
+ // Otherwise, get the abort CTS. If we have one, which would mean that someone previously
105
+ // asked for the RequestAborted token, simply return its token. If we don't,
106
+ // check to see whether we've already aborted, in which case just return an
107
+ // already canceled token. Finally, force a source into existence if we still
108
+ // don't have one, and return its token.
109
+ var cts = _abortedCts ;
110
+ return
111
+ cts != null ? cts . Token :
112
+ _requestAborted ? new CancellationToken ( true ) :
113
+ RequestAbortedSource . Token ;
114
+ }
115
+ set
116
+ {
117
+ // Set an abort token, overriding one we create internally. This setter and associated
118
+ // field exist purely to support IHttpRequestLifetimeFeature.set_RequestAborted.
119
+ _manuallySetRequestAbortToken = value ;
120
+ }
121
+ }
96
122
123
+ private CancellationTokenSource RequestAbortedSource
124
+ {
125
+ get
126
+ {
127
+ // Get the abort token, lazily-initializing it if necessary.
128
+ // Make sure it's canceled if an abort request already came in.
129
+ var cts = LazyInitializer . EnsureInitialized ( ref _abortedCts , ( ) => new CancellationTokenSource ( ) ) ;
130
+ if ( _requestAborted )
131
+ {
132
+ cts . Cancel ( ) ;
133
+ }
134
+ return cts ;
135
+ }
136
+ }
97
137
public bool HasResponseStarted
98
138
{
99
139
get { return _responseStarted ; }
@@ -145,7 +185,7 @@ public void Reset()
145
185
146
186
_prepareRequest ? . Invoke ( this ) ;
147
187
148
- _abortedCts ? . Dispose ( ) ;
188
+ _manuallySetRequestAbortToken = null ;
149
189
_abortedCts = null ;
150
190
}
151
191
@@ -198,24 +238,14 @@ public void Abort()
198
238
{
199
239
ConnectionControl . End ( ProduceEndType . SocketDisconnect ) ;
200
240
SocketInput . AbortAwaiting ( ) ;
201
-
202
- try
203
- {
204
- _abortedCts ? . Cancel ( ) ;
205
- }
206
- catch ( ObjectDisposedException )
207
- {
208
- // Don't log ODEs thrown from _abortedCts.Cancel()
209
- // If _abortedCts is disposed, the app has already completed.
210
- }
241
+ RequestAbortedSource . Cancel ( ) ;
211
242
}
212
243
catch ( Exception ex )
213
244
{
214
245
Log . LogError ( "Abort" , ex ) ;
215
246
}
216
247
finally
217
248
{
218
- _abortedCts ? . Dispose ( ) ;
219
249
_abortedCts = null ;
220
250
}
221
251
}
@@ -261,8 +291,8 @@ public async Task RequestProcessingAsync()
261
291
ResponseBody = _responseBody ;
262
292
DuplexStream = new FrameDuplexStream ( RequestBody , ResponseBody ) ;
263
293
264
- _abortedCts = new CancellationTokenSource ( ) ;
265
- RequestAborted = _abortedCts . Token ;
294
+ _abortedCts = null ;
295
+ _manuallySetRequestAbortToken = null ;
266
296
267
297
var httpContext = HttpContextFactory . Create ( this ) ;
268
298
try
@@ -315,7 +345,6 @@ public async Task RequestProcessingAsync()
315
345
{
316
346
try
317
347
{
318
- _abortedCts ? . Dispose ( ) ;
319
348
_abortedCts = null ;
320
349
321
350
// If _requestAborted is set, the connection has already been closed.
0 commit comments