|
4 | 4 | using System;
|
5 | 5 | using System.Buffers;
|
6 | 6 | using System.Collections.Generic;
|
7 |
| -using System.Diagnostics; |
8 | 7 | using System.IO;
|
9 | 8 | using System.IO.Pipelines;
|
10 | 9 | using System.Security.Claims;
|
@@ -213,69 +212,13 @@ private async Task ExecuteAsync(HttpContext context, ConnectionDelegate connecti
|
213 | 212 | }
|
214 | 213 | }
|
215 | 214 |
|
216 |
| - // Mark the connection as active |
217 |
| - var oldState = connection.TryChangeState(HttpConnectionStatus.Inactive, HttpConnectionStatus.Active); |
218 |
| - |
219 |
| - if (oldState == HttpConnectionStatus.Disposed) |
220 |
| - { |
221 |
| - Log.ConnectionDisposed(_logger, connection.ConnectionId); |
222 |
| - |
223 |
| - // The connection was disposed |
224 |
| - context.Response.StatusCode = StatusCodes.Status404NotFound; |
225 |
| - context.Response.ContentType = "text/plain"; |
226 |
| - return; |
227 |
| - } |
228 |
| - |
229 |
| - if (oldState == HttpConnectionStatus.Active) |
| 215 | + if (!connection.TryActivateLongPollingConnection( |
| 216 | + connectionDelegate, context, options.LongPolling.PollTimeout, |
| 217 | + currentRequestTcs.Task, _loggerFactory, _logger)) |
230 | 218 | {
|
231 |
| - var existing = connection.GetHttpContext(); |
232 |
| - Log.ConnectionAlreadyActive(_logger, connection.ConnectionId, existing.TraceIdentifier); |
233 |
| - context.Response.StatusCode = StatusCodes.Status409Conflict; |
234 |
| - context.Response.ContentType = "text/plain"; |
235 | 219 | return;
|
236 | 220 | }
|
237 | 221 |
|
238 |
| - connection.PreviousPollTask = currentRequestTcs.Task; |
239 |
| - |
240 |
| - // Raise OnConnected for new connections only since polls happen all the time |
241 |
| - if (connection.ApplicationTask == null) |
242 |
| - { |
243 |
| - Log.EstablishedConnection(_logger); |
244 |
| - |
245 |
| - connection.ApplicationTask = ExecuteApplication(connectionDelegate, connection); |
246 |
| - |
247 |
| - context.Response.ContentType = "application/octet-stream"; |
248 |
| - |
249 |
| - // This request has no content |
250 |
| - context.Response.ContentLength = 0; |
251 |
| - |
252 |
| - // On the first poll, we flush the response immediately to mark the poll as "initialized" so future |
253 |
| - // requests can be made safely |
254 |
| - connection.TransportTask = context.Response.Body.FlushAsync(); |
255 |
| - } |
256 |
| - else |
257 |
| - { |
258 |
| - Log.ResumingConnection(_logger); |
259 |
| - |
260 |
| - // REVIEW: Performance of this isn't great as this does a bunch of per request allocations |
261 |
| - connection.Cancellation = new CancellationTokenSource(); |
262 |
| - |
263 |
| - var timeoutSource = new CancellationTokenSource(); |
264 |
| - var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(connection.Cancellation.Token, context.RequestAborted, timeoutSource.Token); |
265 |
| - |
266 |
| - // Dispose these tokens when the request is over |
267 |
| - context.Response.RegisterForDispose(timeoutSource); |
268 |
| - context.Response.RegisterForDispose(tokenSource); |
269 |
| - |
270 |
| - var longPolling = new LongPollingTransport(timeoutSource.Token, connection.Application.Input, _loggerFactory); |
271 |
| - |
272 |
| - // Start the transport |
273 |
| - connection.TransportTask = longPolling.ProcessRequestAsync(context, tokenSource.Token); |
274 |
| - |
275 |
| - // Start the timeout after we return from creating the transport task |
276 |
| - timeoutSource.CancelAfter(options.LongPolling.PollTimeout); |
277 |
| - } |
278 |
| - |
279 | 222 | var resultTask = await Task.WhenAny(connection.ApplicationTask, connection.TransportTask);
|
280 | 223 |
|
281 | 224 | try
|
@@ -340,51 +283,13 @@ private async Task DoPersistentConnection(ConnectionDelegate connectionDelegate,
|
340 | 283 | HttpContext context,
|
341 | 284 | HttpConnectionContext connection)
|
342 | 285 | {
|
343 |
| - // Mark the connection as active |
344 |
| - var oldState = connection.TryChangeState(HttpConnectionStatus.Inactive, HttpConnectionStatus.Active); |
345 |
| - |
346 |
| - if (oldState == HttpConnectionStatus.Disposed) |
347 |
| - { |
348 |
| - Log.ConnectionDisposed(_logger, connection.ConnectionId); |
349 |
| - |
350 |
| - // Connection was disposed |
351 |
| - context.Response.StatusCode = StatusCodes.Status404NotFound; |
352 |
| - return; |
353 |
| - } |
354 |
| - |
355 |
| - // There's already an active request |
356 |
| - if (oldState == HttpConnectionStatus.Active) |
| 286 | + if (connection.TryActivatePersistentConnection(connectionDelegate, transport, _logger)) |
357 | 287 | {
|
358 |
| - Log.ConnectionAlreadyActive(_logger, connection.ConnectionId, connection.GetHttpContext().TraceIdentifier); |
| 288 | + // Wait for any of them to end |
| 289 | + await Task.WhenAny(connection.ApplicationTask, connection.TransportTask); |
359 | 290 |
|
360 |
| - // Reject the request with a 409 conflict |
361 |
| - context.Response.StatusCode = StatusCodes.Status409Conflict; |
362 |
| - return; |
| 291 | + await _manager.DisposeAndRemoveAsync(connection, closeGracefully: true); |
363 | 292 | }
|
364 |
| - |
365 |
| - // Call into the end point passing the connection |
366 |
| - connection.ApplicationTask = ExecuteApplication(connectionDelegate, connection); |
367 |
| - |
368 |
| - // Start the transport |
369 |
| - connection.TransportTask = transport.ProcessRequestAsync(context, context.RequestAborted); |
370 |
| - |
371 |
| - // Wait for any of them to end |
372 |
| - await Task.WhenAny(connection.ApplicationTask, connection.TransportTask); |
373 |
| - |
374 |
| - await _manager.DisposeAndRemoveAsync(connection, closeGracefully: true); |
375 |
| - } |
376 |
| - |
377 |
| - private async Task ExecuteApplication(ConnectionDelegate connectionDelegate, HttpConnectionContext connection) |
378 |
| - { |
379 |
| - // Verify some initialization invariants |
380 |
| - Debug.Assert(connection.TransportType != HttpTransportType.None, "Transport has not been initialized yet"); |
381 |
| - |
382 |
| - // Jump onto the thread pool thread so blocking user code doesn't block the setup of the |
383 |
| - // connection and transport |
384 |
| - await AwaitableThreadPool.Yield(); |
385 |
| - |
386 |
| - // Running this in an async method turns sync exceptions into async ones |
387 |
| - await connectionDelegate(connection); |
388 | 293 | }
|
389 | 294 |
|
390 | 295 | private async Task ProcessNegotiate(HttpContext context, HttpConnectionDispatcherOptions options, ConnectionLogScope logScope)
|
|
0 commit comments