private async void StartRequest(WinHttpRequestState state) { if (state.CancellationToken.IsCancellationRequested) { state.Tcs.TrySetCanceled(state.CancellationToken); state.ClearSendRequestState(); return; } SafeWinHttpHandle connectHandle = null; try { EnsureSessionHandleExists(state); // Specify an HTTP server. connectHandle = Interop.WinHttp.WinHttpConnect( _sessionHandle, state.RequestMessage.RequestUri.Host, (ushort)state.RequestMessage.RequestUri.Port, 0); ThrowOnInvalidHandle(connectHandle); connectHandle.SetParentHandle(_sessionHandle); // Try to use the requested version if a known/supported version was explicitly requested. // Otherwise, we simply use winhttp's default. string httpVersion = null; if (state.RequestMessage.Version == HttpVersionInternal.Version10) { httpVersion = "HTTP/1.0"; } else if (state.RequestMessage.Version == HttpVersionInternal.Version11) { httpVersion = "HTTP/1.1"; } // Turn off additional URI reserved character escaping (percent-encoding). This matches // .NET Framework behavior. System.Uri establishes the baseline rules for percent-encoding // of reserved characters. uint flags = Interop.WinHttp.WINHTTP_FLAG_ESCAPE_DISABLE; if (state.RequestMessage.RequestUri.Scheme == UriScheme.Https) { flags |= Interop.WinHttp.WINHTTP_FLAG_SECURE; } // Create an HTTP request handle. state.RequestHandle = Interop.WinHttp.WinHttpOpenRequest( connectHandle, state.RequestMessage.Method.Method, state.RequestMessage.RequestUri.PathAndQuery, httpVersion, Interop.WinHttp.WINHTTP_NO_REFERER, Interop.WinHttp.WINHTTP_DEFAULT_ACCEPT_TYPES, flags); ThrowOnInvalidHandle(state.RequestHandle); state.RequestHandle.SetParentHandle(connectHandle); // Set callback function. SetStatusCallback(state.RequestHandle, WinHttpRequestCallback.StaticCallbackDelegate); // Set needed options on the request handle. SetRequestHandleOptions(state); bool chunkedModeForSend = IsChunkedModeForSend(state.RequestMessage); AddRequestHeaders( state.RequestHandle, state.RequestMessage, _cookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer ? _cookieContainer : null); uint proxyAuthScheme = 0; uint serverAuthScheme = 0; state.RetryRequest = false; // The only way to abort pending async operations in WinHTTP is to close the WinHTTP handle. // We will detect a cancellation request on the cancellation token by registering a callback. // If the callback is invoked, then we begin the abort process by disposing the handle. This // will have the side-effect of WinHTTP cancelling any pending I/O and accelerating its callbacks // on the handle and thus releasing the awaiting tasks in the loop below. This helps to provide // a more timely, cooperative, cancellation pattern. using (state.CancellationToken.Register(s => ((WinHttpRequestState)s).RequestHandle.Dispose(), state)) { do { _authHelper.PreAuthenticateRequest(state, proxyAuthScheme); await InternalSendRequestAsync(state); if (state.RequestMessage.Content != null) { await InternalSendRequestBodyAsync(state, chunkedModeForSend).ConfigureAwait(false); } bool receivedResponse = await InternalReceiveResponseHeadersAsync(state) != 0; if (receivedResponse) { // If we're manually handling cookies, we need to add them to the container after // each response has been received. if (state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer) { WinHttpCookieContainerAdapter.AddResponseCookiesToContainer(state); } _authHelper.CheckResponseForAuthentication( state, ref proxyAuthScheme, ref serverAuthScheme); } } while (state.RetryRequest); } state.CancellationToken.ThrowIfCancellationRequested(); // Since the headers have been read, set the "receive" timeout to be based on each read // call of the response body data. WINHTTP_OPTION_RECEIVE_TIMEOUT sets a timeout on each // lower layer winsock read. uint optionData = (uint)_receiveDataTimeout.TotalMilliseconds; SetWinHttpOption(state.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_RECEIVE_TIMEOUT, ref optionData); HttpResponseMessage responseMessage = WinHttpResponseParser.CreateResponseMessage(state, _doManualDecompressionCheck); state.Tcs.TrySetResult(responseMessage); } catch (Exception ex) { HandleAsyncException(state, state.SavedException ?? ex); } finally { SafeWinHttpHandle.DisposeAndClearHandle(ref connectHandle); state.ClearSendRequestState(); } }