/// <summary> /// Start processing the request. /// </summary> /// <returns></returns> internal Task <HttpContext> SendAsync(CancellationToken cancellationToken) { var registration = cancellationToken.Register(ClientInitiatedAbort); // Everything inside this function happens in the SERVER's execution context (unless PreserveExecutionContext is true) async Task RunRequestAsync() { // HTTP/2 specific features must be added after the request has been configured. if (HttpProtocol.IsHttp2(_httpContext.Request.Protocol)) { _httpContext.Features.Set <IHttpResetFeature>(this); } // This will configure IHttpContextAccessor so it needs to happen INSIDE this function, // since we are now inside the Server's execution context. If it happens outside this cont // it will be lost when we abandon the execution context. _testContext = _application.CreateContext(_httpContext.Features); try { await _application.ProcessRequestAsync(_testContext); // Determine whether request body was complete when the delegate exited. // This could throw an error if there was a pending server read. Needs to // happen before completing the response so the response returns the error. var requestBodyInProgress = RequestBodyReadInProgress(); // Matches Kestrel server: response is completed before request is drained await CompleteResponseAsync(); await CompleteRequestAsync(requestBodyInProgress); _application.DisposeContext(_testContext, exception: null); } catch (Exception ex) { Abort(ex); _application.DisposeContext(_testContext, ex); } finally { registration.Dispose(); } } // Async offload, don't let the test code block the caller. if (_preserveExecutionContext) { _ = Task.Factory.StartNew(RunRequestAsync); } else { ThreadPool.UnsafeQueueUserWorkItem(_ => { _ = RunRequestAsync(); }, null); } return(_responseTcs.Task); }
/// <summary> /// Start processing the request. /// </summary> /// <returns></returns> internal Task <HttpContext> SendAsync(CancellationToken cancellationToken) { var registration = cancellationToken.Register(ClientInitiatedAbort); // Everything inside this function happens in the SERVER's execution context (unless PreserveExecutionContext is true) async Task RunRequestAsync() { // HTTP/2 specific features must be added after the request has been configured. if (string.Equals("HTTP/2", _httpContext.Request.Protocol, StringComparison.OrdinalIgnoreCase)) { _httpContext.Features.Set <IHttpResetFeature>(this); } // This will configure IHttpContextAccessor so it needs to happen INSIDE this function, // since we are now inside the Server's execution context. If it happens outside this cont // it will be lost when we abandon the execution context. _testContext = _application.CreateContext(_httpContext.Features); try { await _application.ProcessRequestAsync(_testContext); await CompleteRequestAsync(); await CompleteResponseAsync(); _application.DisposeContext(_testContext, exception: null); } catch (Exception ex) { Abort(ex); _application.DisposeContext(_testContext, ex); } finally { registration.Dispose(); } } // Async offload, don't let the test code block the caller. if (_preserveExecutionContext) { _ = Task.Factory.StartNew(RunRequestAsync); } else { ThreadPool.UnsafeQueueUserWorkItem(_ => { _ = RunRequestAsync(); }, null); } return(_responseTcs.Task); }
/// <summary> /// Start processing the request. /// </summary> /// <returns></returns> internal Task <HttpContext> SendAsync(CancellationToken cancellationToken) { var registration = cancellationToken.Register(AbortRequest); // Everything inside this function happens in the SERVER's execution context (unless PreserveExecutionContext is true) async Task RunRequestAsync() { // This will configure IHttpContextAccessor so it needs to happen INSIDE this function, // since we are now inside the Server's execution context. If it happens outside this cont // it will be lost when we abandon the execution context. _testContext = _application.CreateContext(_httpContext.Features); try { await _application.ProcessRequestAsync(_testContext); await CompleteResponseAsync(); _application.DisposeContext(_testContext, exception: null); } catch (Exception ex) { Abort(ex); _application.DisposeContext(_testContext, ex); } finally { registration.Dispose(); } } // Async offload, don't let the test code block the caller. if (_preserveExecutionContext) { _ = Task.Factory.StartNew(RunRequestAsync); } else { ThreadPool.UnsafeQueueUserWorkItem(_ => { _ = RunRequestAsync(); }, null); } return(_responseTcs.Task); }
/// <summary> /// Start processing the request. /// </summary> /// <returns></returns> internal Task <HttpContext> SendAsync(CancellationToken cancellationToken) { var registration = cancellationToken.Register(ClientInitiatedAbort); // Everything inside this function happens in the SERVER's execution context (unless PreserveExecutionContext is true) async Task RunRequestAsync() { // HTTP/2 specific features must be added after the request has been configured. if (HttpProtocol.IsHttp2(_httpContext.Request.Protocol)) { _httpContext.Features.Set <IHttpResetFeature>(this); } // This will configure IHttpContextAccessor so it needs to happen INSIDE this function, // since we are now inside the Server's execution context. If it happens outside this cont // it will be lost when we abandon the execution context. _testContext = _application.CreateContext(_httpContext.Features); try { await _application.ProcessRequestAsync(_testContext); // Determine whether request body was complete when the delegate exited. // This could throw an error if there was a pending server read. Needs to // happen before completing the response so the response returns the error. var requestBodyInProgress = RequestBodyReadInProgress(); if (requestBodyInProgress) { // If request is still in progress then abort it. CancelRequestBody(); } // Matches Kestrel server: response is completed before request is drained await CompleteResponseAsync(); if (!requestBodyInProgress) { // Writer was already completed in send request callback. await _requestPipe.Reader.CompleteAsync(); // Don't wait for request to drain. It could block indefinitely. In a real server // we would wait for a timeout and then kill the socket. // Potential future improvement: add logging that the request timed out } _application.DisposeContext(_testContext, exception: null); } catch (Exception ex) { Abort(ex); _application.DisposeContext(_testContext, ex); } finally { registration.Dispose(); } } // Async offload, don't let the test code block the caller. if (_preserveExecutionContext) { _ = Task.Factory.StartNew(RunRequestAsync, default, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);