public static void AddResponseCookiesToContainer(WinHttpRequestState state) { HttpRequestMessage request = state.RequestMessage; SafeWinHttpHandle requestHandle = state.RequestHandle; CookieContainer cookieContainer = state.Handler.CookieContainer; Debug.Assert(state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer); Debug.Assert(cookieContainer != null); // Get 'Set-Cookie' headers from response. List <string> cookieHeaders = WinHttpResponseParser.GetResponseHeaders(requestHandle, Interop.WinHttp.WINHTTP_QUERY_SET_COOKIE); WinHttpTraceHelper.Trace("WINHTTP_QUERY_SET_COOKIE"); foreach (string cookieHeader in cookieHeaders) { WinHttpTraceHelper.Trace(cookieHeader); try { cookieContainer.SetCookies(request.RequestUri, cookieHeader); WinHttpTraceHelper.Trace(cookieHeader); } catch (CookieException) { // We ignore malformed cookies in the response. WinHttpTraceHelper.Trace("Ignoring invalid cookie: {0}", cookieHeader); } } }
public static void WinHttpCallback( IntPtr handle, IntPtr context, uint internetStatus, IntPtr statusInformation, uint statusInformationLength) { WinHttpTraceHelper.TraceCallbackStatus("WinHttpCallback", handle, context, internetStatus); if (Environment.HasShutdownStarted) { WinHttpTraceHelper.Trace("WinHttpCallback: Environment.HasShutdownStarted returned True"); return; } if (context == IntPtr.Zero) { return; } WinHttpRequestState state = WinHttpRequestState.FromIntPtr(context); Debug.Assert(state != null, "WinHttpCallback must have a non-null state object"); RequestCallback(handle, state, internetStatus, statusInformation, statusInformationLength); }
private void Dispose(bool disposing) { if (WinHttpTraceHelper.IsTraceEnabled()) { WinHttpTraceHelper.Trace( "WinHttpRequestState.Dispose, GCHandle=0x{0:X}, disposed={1}, disposing={2}", ToIntPtr(), _disposed, disposing); } // Since there is no finalizer and this class is sealed, the disposing parameter should be TRUE. Debug.Assert(disposing, "WinHttpRequestState.Dispose() should have disposing=TRUE"); if (_disposed) { return; } _disposed = true; if (_operationHandle.IsAllocated) { _operationHandle.Free(); } }
// The only way to abort pending async operations in WinHTTP is to close the request handle. // This causes WinHTTP to cancel any pending I/O and accelerating its callbacks on the handle. // This causes our related TaskCompletionSource objects to move to a terminal state. // // We only want to dispose the handle if we are actually waiting for a pending WinHTTP I/O to complete, // meaning that we are await'ing for a Task to complete. While we could simply call dispose without // a pending operation, it would cause random failures in the other threads when we expect a valid handle. private void CancelPendingResponseStreamReadOperation() { WinHttpTraceHelper.Trace("WinHttpResponseStream.CancelPendingResponseStreamReadOperation"); lock (_state.Lock) { if (_state.AsyncReadInProgress) { WinHttpTraceHelper.Trace("WinHttpResponseStream.CancelPendingResponseStreamReadOperation: before dispose"); _requestHandle?.Dispose(); // null check necessary to handle race condition between stream disposal and cancellation WinHttpTraceHelper.Trace("WinHttpResponseStream.CancelPendingResponseStreamReadOperation: after dispose"); } } }
// The only way to abort pending async operations in WinHTTP is to close the request handle. // This causes WinHTTP to cancel any pending I/O and accelerating its callbacks on the handle. // This causes our related TaskCompletionSource objects to move to a terminal state. // // We only want to dispose the handle if we are actually waiting for a pending WinHTTP I/O to complete, // meaning that we are await'ing for a Task to complete. While we could simply call dispose without // a pending operation, it would cause random failures in the other threads when we expect a valid handle. private void CancelPendingResponseStreamReadOperation() { WinHttpTraceHelper.Trace("WinHttpResponseStream.CancelPendingResponseStreamReadOperation"); lock (_state.Lock) { if (_state.AsyncReadInProgress) { Debug.Assert(_requestHandle != null); Debug.Assert(!_requestHandle.IsInvalid); WinHttpTraceHelper.Trace("WinHttpResponseStream.CancelPendingResponseStreamReadOperation: before dispose"); _requestHandle.Dispose(); WinHttpTraceHelper.Trace("WinHttpResponseStream.CancelPendingResponseStreamReadOperation: after dispose"); } } }
// The only way to abort pending async operations in WinHTTP is to close the request handle. // This causes WinHTTP to cancel any pending I/O and accelerating its callbacks on the handle. // This causes our related TaskCompletionSource objects to move to a terminal state. // // We only want to dispose the handle if we are actually waiting for a pending WinHTTP I/O to complete, // meaning that we are await'ing for a Task to complete. While we could simply call dispose without // a pending operation, it would cause random failures in the other threads when we expect a valid handle. private void CancelPendingResponseStreamReadOperation() { WinHttpTraceHelper.Trace("WinHttpResponseStream.CancelPendingResponseStreamReadOperation"); lock (_state.Lock) { WinHttpTraceHelper.Trace( string.Format("WinHttpResponseStream.CancelPendingResponseStreamReadOperation: {0} {1}", (int)_state.TcsQueryDataAvailable.Task.Status, (int)_state.TcsReadFromResponseStream.Task.Status)); if (!_state.TcsQueryDataAvailable.Task.IsCompleted) { Debug.Assert(_requestHandle != null); Debug.Assert(!_requestHandle.IsInvalid); WinHttpTraceHelper.Trace("WinHttpResponseStream.CancelPendingResponseStreamReadOperation: before dispose"); _requestHandle.Dispose(); WinHttpTraceHelper.Trace("WinHttpResponseStream.CancelPendingResponseStreamReadOperation: after dispose"); } } }
private static bool IsResponseHttp2(SafeWinHttpHandle requestHandle) { uint data = 0; uint dataSize = sizeof(uint); if (Interop.WinHttp.WinHttpQueryOption( requestHandle, Interop.WinHttp.WINHTTP_OPTION_HTTP_PROTOCOL_USED, ref data, ref dataSize)) { if ((data & Interop.WinHttp.WINHTTP_PROTOCOL_FLAG_HTTP2) != 0) { WinHttpTraceHelper.Trace("WinHttpHandler.IsResponseHttp2: return true"); return(true); } } return(false); }
private void Dispose(bool disposing) { #if DEBUG Interlocked.Increment(ref s_dbg_callDispose); #endif if (WinHttpTraceHelper.IsTraceEnabled()) { WinHttpTraceHelper.Trace( "WinHttpRequestState.Dispose, GCHandle=0x{0:X}, disposed={1}, disposing={2}", ToIntPtr(), _disposed, disposing); } // Since there is no finalizer and this class is sealed, the disposing parameter should be TRUE. Debug.Assert(disposing, "WinHttpRequestState.Dispose() should have disposing=TRUE"); if (_disposed) { return; } _disposed = true; if (_operationHandle.IsAllocated) { // This method only gets called when the WinHTTP request handle is fully closed and thus all // async operations are done. So, it is safe at this point to unpin the buffers and release // the strong GCHandle for this object. if (_cachedReceivePinnedBuffer.IsAllocated) { _cachedReceivePinnedBuffer.Free(); _cachedReceivePinnedBuffer = default(GCHandle); } #if DEBUG Interlocked.Increment(ref s_dbg_operationHandleFree); #endif _operationHandle.Free(); _operationHandle = default(GCHandle); } }
private const int _recentAutoDetectionInterval = 120_000; // 2 minutes in milliseconds. public WinInetProxyHelper() { var proxyConfig = new Interop.WinHttp.WINHTTP_CURRENT_USER_IE_PROXY_CONFIG(); try { if (Interop.WinHttp.WinHttpGetIEProxyConfigForCurrentUser(out proxyConfig)) { AutoConfigUrl = Marshal.PtrToStringUni(proxyConfig.AutoConfigUrl); AutoDetect = proxyConfig.AutoDetect; Proxy = Marshal.PtrToStringUni(proxyConfig.Proxy); ProxyBypass = Marshal.PtrToStringUni(proxyConfig.ProxyBypass); WinHttpTraceHelper.Trace( "WinInetProxyHelper.ctor: AutoConfigUrl={0}, AutoDetect={1}, Proxy={2}, ProxyBypass={3}", AutoConfigUrl, AutoDetect, Proxy, ProxyBypass); _useProxy = true; } else { // We match behavior of WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY and ignore errors. int lastError = Marshal.GetLastWin32Error(); WinHttpTraceHelper.Trace("WinInetProxyHelper.ctor: error={0}", lastError); } WinHttpTraceHelper.Trace("WinInetProxyHelper.ctor: _useProxy={0}", _useProxy); } finally { // FreeHGlobal already checks for null pointer before freeing the memory. Marshal.FreeHGlobal(proxyConfig.AutoConfigUrl); Marshal.FreeHGlobal(proxyConfig.Proxy); Marshal.FreeHGlobal(proxyConfig.ProxyBypass); } }
public static void WinHttpCallback( IntPtr handle, IntPtr context, uint internetStatus, IntPtr statusInformation, uint statusInformationLength) { bool invokeCallback = false; if (Environment.HasShutdownStarted) { return; } if (context == IntPtr.Zero) { return; } WinHttpRequestState state = WinHttpRequestState.FromIntPtr(context); if (state != null && state.RequestHandle != null && !state.RequestHandle.IsInvalid && state.RequestHandle.DangerousGetHandle() == handle) { invokeCallback = true; } WinHttpTraceHelper.TraceCallbackStatus("WinHttpCallback", handle, invokeCallback, internetStatus); if (invokeCallback) { RequestCallback(handle, state, internetStatus, statusInformation, statusInformationLength); } }
private static void OnRequestError(WinHttpRequestState state, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult) { WinHttpTraceHelper.TraceAsyncError("OnRequestError", asyncResult); Debug.Assert(state != null, "OnRequestError: state is null"); Debug.Assert((unchecked ((int)asyncResult.dwError) != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER && unchecked ((int)asyncResult.dwError) != unchecked ((int)0x80090321)), // SEC_E_BUFFER_TOO_SMALL $"Unexpected async error in WinHttpRequestCallback: {unchecked((int)asyncResult.dwError)}, WinHttp API: {unchecked((uint)asyncResult.dwResult.ToInt32())}"); Exception innerException = WinHttpException.CreateExceptionUsingError(unchecked ((int)asyncResult.dwError)); switch (unchecked ((uint)asyncResult.dwResult.ToInt32())) { case Interop.WinHttp.API_SEND_REQUEST: state.LifecycleAwaitable.SetException(innerException); break; case Interop.WinHttp.API_RECEIVE_RESPONSE: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_RESEND_REQUEST) { state.RetryRequest = true; state.LifecycleAwaitable.SetResult(0); } else if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED) { // WinHttp will automatically drop any client SSL certificates that we // have pre-set into the request handle including the NULL certificate // (which means we have no certs to send). For security reasons, we don't // allow the certificate to be re-applied. But we need to tell WinHttp // explicitly that we don't have any certificate to send. Debug.Assert(state.RequestHandle != null, "OnRequestError: state.RequestHandle is null"); WinHttpHandler.SetNoClientCertificate(state.RequestHandle); state.RetryRequest = true; state.LifecycleAwaitable.SetResult(0); } else if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { state.LifecycleAwaitable.SetCanceled(state.CancellationToken); } else { state.LifecycleAwaitable.SetException(innerException); } break; case Interop.WinHttp.API_QUERY_DATA_AVAILABLE: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { // TODO: Issue #2165. We need to pass in the cancellation token from the // user's ReadAsync() call into the TrySetCanceled(). WinHttpTraceHelper.Trace("RequestCallback: QUERY_DATA_AVAILABLE - ERROR_WINHTTP_OPERATION_CANCELLED"); state.LifecycleAwaitable.SetCanceled(); } else { state.LifecycleAwaitable.SetException( new IOException(SR.net_http_io_read, innerException)); } break; case Interop.WinHttp.API_READ_DATA: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { // TODO: Issue #2165. We need to pass in the cancellation token from the // user's ReadAsync() call into the TrySetCanceled(). WinHttpTraceHelper.Trace("RequestCallback: API_READ_DATA - ERROR_WINHTTP_OPERATION_CANCELLED"); state.LifecycleAwaitable.SetCanceled(); } else { state.LifecycleAwaitable.SetException(new IOException(SR.net_http_io_read, innerException)); } break; case Interop.WinHttp.API_WRITE_DATA: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { // TODO: Issue #2165. We need to pass in the cancellation token from the // user's WriteAsync() call into the TrySetCanceled(). WinHttpTraceHelper.Trace("RequestCallback: API_WRITE_DATA - ERROR_WINHTTP_OPERATION_CANCELLED"); state.TcsInternalWriteDataToRequestStream.TrySetCanceled(); } else { state.TcsInternalWriteDataToRequestStream.TrySetException( new IOException(SR.net_http_io_write, innerException)); } break; default: Debug.Fail( "OnRequestError: Result (" + asyncResult.dwResult + ") is not expected.", "Error code: " + asyncResult.dwError + " (" + innerException.Message + ")"); break; } }
public bool GetProxyForUrl( SafeWinHttpHandle sessionHandle, Uri uri, out Interop.WinHttp.WINHTTP_PROXY_INFO proxyInfo) { proxyInfo.AccessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY; proxyInfo.Proxy = IntPtr.Zero; proxyInfo.ProxyBypass = IntPtr.Zero; if (!_useProxy) { return(false); } bool useProxy = false; Interop.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions; autoProxyOptions.AutoConfigUrl = AutoConfigUrl; autoProxyOptions.AutoDetectFlags = AutoDetect ? (Interop.WinHttp.WINHTTP_AUTO_DETECT_TYPE_DHCP | Interop.WinHttp.WINHTTP_AUTO_DETECT_TYPE_DNS_A) : 0; autoProxyOptions.AutoLoginIfChallenged = false; autoProxyOptions.Flags = (AutoDetect ? Interop.WinHttp.WINHTTP_AUTOPROXY_AUTO_DETECT : 0) | (!string.IsNullOrEmpty(AutoConfigUrl) ? Interop.WinHttp.WINHTTP_AUTOPROXY_CONFIG_URL : 0); autoProxyOptions.Reserved1 = IntPtr.Zero; autoProxyOptions.Reserved2 = 0; // AutoProxy Cache. // http://msdn.microsoft.com/en-us/library/windows/desktop/aa383153(v=vs.85).aspx // If the out-of-process service is active when WinHttpGetProxyForUrl is called, the cached autoproxy // URL and script are available to the whole computer. However, if the out-of-process service is used, // and the fAutoLogonIfChallenged flag in the pAutoProxyOptions structure is true, then the autoproxy // URL and script are not cached. Therefore, calling WinHttpGetProxyForUrl with the fAutoLogonIfChallenged // member set to TRUE results in additional overhead operations that may affect performance. // The following steps can be used to improve performance: // 1. Call WinHttpGetProxyForUrl with the fAutoLogonIfChallenged parameter set to false. The autoproxy // URL and script are cached for future calls to WinHttpGetProxyForUrl. // 2. If Step 1 fails, with ERROR_WINHTTP_LOGIN_FAILURE, then call WinHttpGetProxyForUrl with the // fAutoLogonIfChallenged member set to TRUE. // // We match behavior of WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY and ignore errors. var repeat = false; do { _autoDetectionFailed = false; if (Interop.WinHttp.WinHttpGetProxyForUrl( sessionHandle, uri.AbsoluteUri, ref autoProxyOptions, out proxyInfo)) { WinHttpTraceHelper.Trace("WinInetProxyHelper.GetProxyForUrl: Using autoconfig proxy settings"); useProxy = true; break; } else { var lastError = Marshal.GetLastWin32Error(); WinHttpTraceHelper.Trace("WinInetProxyHelper.GetProxyForUrl: error={0}", lastError); if (lastError == Interop.WinHttp.ERROR_WINHTTP_LOGIN_FAILURE) { if (repeat) { // We don't retry more than once. break; } else { repeat = true; autoProxyOptions.AutoLoginIfChallenged = true; } } else { if (lastError == Interop.WinHttp.ERROR_WINHTTP_AUTODETECTION_FAILED) { _autoDetectionFailed = true; _lastTimeAutoDetectionFailed = Environment.TickCount; } break; } } } while (repeat); // Fall back to manual settings if available. if (!useProxy && !string.IsNullOrEmpty(Proxy)) { proxyInfo.AccessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NAMED_PROXY; proxyInfo.Proxy = Marshal.StringToHGlobalUni(Proxy); proxyInfo.ProxyBypass = string.IsNullOrEmpty(ProxyBypass) ? IntPtr.Zero : Marshal.StringToHGlobalUni(ProxyBypass); WinHttpTraceHelper.Trace( "WinInetProxyHelper.GetProxyForUrl: Fallback to Proxy={0}, ProxyBypass={1}", Proxy, ProxyBypass); useProxy = true; } WinHttpTraceHelper.Trace("WinInetProxyHelper.GetProxyForUrl: useProxy={0}", useProxy); return(useProxy); }
private static void OnRequestSendingRequest(WinHttpRequestState state) { Debug.Assert(state != null, "OnRequestSendingRequest: state is null"); Debug.Assert(state.RequestHandle != null, "OnRequestSendingRequest: state.RequestHandle is null"); if (state.RequestMessage.RequestUri.Scheme != UriScheme.Https) { // Not SSL/TLS. return; } // Grab the channel binding token (CBT) information from the request handle and put it into // the TransportContext object. state.TransportContext.SetChannelBinding(state.RequestHandle); if (state.ServerCertificateValidationCallback != null) { IntPtr certHandle = IntPtr.Zero; uint certHandleSize = (uint)IntPtr.Size; if (!Interop.WinHttp.WinHttpQueryOption( state.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_SERVER_CERT_CONTEXT, ref certHandle, ref certHandleSize)) { int lastError = Marshal.GetLastWin32Error(); WinHttpTraceHelper.Trace( "OnRequestSendingRequest: Error getting WINHTTP_OPTION_SERVER_CERT_CONTEXT, {0}", lastError); if (lastError == Interop.WinHttp.ERROR_WINHTTP_INCORRECT_HANDLE_STATE) { // Not yet an SSL/TLS connection. This occurs while connecting thru a proxy where the // CONNECT verb hasn't yet been processed due to the proxy requiring authentication. // We need to ignore this notification. Another notification will be sent once the final // connection thru the proxy is completed. return; } throw WinHttpException.CreateExceptionUsingError(lastError); } // Get any additional certificates sent from the remote server during the TLS/SSL handshake. X509Certificate2Collection remoteCertificateStore = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(certHandle); // Create a managed wrapper around the certificate handle. Since this results in duplicating // the handle, we will close the original handle after creating the wrapper. var serverCertificate = new X509Certificate2(certHandle); Interop.Crypt32.CertFreeCertificateContext(certHandle); X509Chain chain = null; SslPolicyErrors sslPolicyErrors; bool result = false; try { WinHttpCertificateHelper.BuildChain( serverCertificate, remoteCertificateStore, state.RequestMessage.RequestUri.Host, state.CheckCertificateRevocationList, out chain, out sslPolicyErrors); result = state.ServerCertificateValidationCallback( state.RequestMessage, serverCertificate, chain, sslPolicyErrors); } catch (Exception ex) { throw WinHttpException.CreateExceptionUsingError( (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, ex); } finally { if (chain != null) { chain.Dispose(); } serverCertificate.Dispose(); } if (!result) { throw WinHttpException.CreateExceptionUsingError( (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE); } } }
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken token) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count)); } if (count > buffer.Length - offset) { throw new ArgumentException(SR.net_http_buffer_insufficient_length, nameof(buffer)); } if (token.IsCancellationRequested) { return Task.FromCanceled<int>(token); } CheckDisposed(); if (_state.TcsReadFromResponseStream != null && !_state.TcsReadFromResponseStream.Task.IsCompleted) { throw new InvalidOperationException(SR.net_http_no_concurrent_io_allowed); } _state.PinReceiveBuffer(buffer); _state.TcsReadFromResponseStream = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously); _state.TcsQueryDataAvailable = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously); _state.TcsQueryDataAvailable.Task.ContinueWith((previousTask) => { if (previousTask.IsFaulted) { _state.DisposeCtrReadFromResponseStream(); _state.TcsReadFromResponseStream.TrySetException(previousTask.Exception.InnerException); } else if (previousTask.IsCanceled || token.IsCancellationRequested) { _state.DisposeCtrReadFromResponseStream(); _state.TcsReadFromResponseStream.TrySetCanceled(token); } else { int bytesToRead; int bytesAvailable = previousTask.Result; if (bytesAvailable > count) { bytesToRead = count; } else { bytesToRead = bytesAvailable; } lock (_state.Lock) { Debug.Assert(!_requestHandle.IsInvalid); if (!Interop.WinHttp.WinHttpReadData( _requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)bytesToRead, IntPtr.Zero)) { _state.DisposeCtrReadFromResponseStream(); _state.TcsReadFromResponseStream.TrySetException( new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError().InitializeStackTrace())); } } } }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); // Register callback on cancellation token to cancel any pending WinHTTP operation. if (token.CanBeCanceled) { WinHttpTraceHelper.Trace("WinHttpResponseStream.ReadAsync: registering for cancellation token request"); _state.CtrReadFromResponseStream = token.Register(s => ((WinHttpResponseStream)s).CancelPendingResponseStreamReadOperation(), this); } else { WinHttpTraceHelper.Trace("WinHttpResponseStream.ReadAsync: received no cancellation token"); } lock (_state.Lock) { Debug.Assert(!_requestHandle.IsInvalid); if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero)) { _state.DisposeCtrReadFromResponseStream(); _state.TcsReadFromResponseStream.TrySetException( new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError().InitializeStackTrace())); } } return _state.TcsReadFromResponseStream.Task; }
private static void OnRequestError(WinHttpRequestState state, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult) { Debug.Assert(state != null, "OnRequestError: state is null"); if (NetEventSource.Log.IsEnabled()) { WinHttpTraceHelper.TraceAsyncError(state, asyncResult); } Exception innerException = WinHttpException.CreateExceptionUsingError(unchecked ((int)asyncResult.dwError), "WINHTTP_CALLBACK_STATUS_REQUEST_ERROR"); switch (unchecked ((uint)asyncResult.dwResult.ToInt32())) { case Interop.WinHttp.API_SEND_REQUEST: state.LifecycleAwaitable.SetException(innerException); break; case Interop.WinHttp.API_RECEIVE_RESPONSE: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_RESEND_REQUEST) { state.RetryRequest = true; state.LifecycleAwaitable.SetResult(0); } else if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED) { // WinHttp will automatically drop any client SSL certificates that we // have pre-set into the request handle including the NULL certificate // (which means we have no certs to send). For security reasons, we don't // allow the certificate to be re-applied. But we need to tell WinHttp // explicitly that we don't have any certificate to send. Debug.Assert(state.RequestHandle != null, "OnRequestError: state.RequestHandle is null"); WinHttpHandler.SetNoClientCertificate(state.RequestHandle); state.RetryRequest = true; state.LifecycleAwaitable.SetResult(0); } else if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { state.LifecycleAwaitable.SetCanceled(state.CancellationToken); } else { state.LifecycleAwaitable.SetException(innerException); } break; case Interop.WinHttp.API_QUERY_DATA_AVAILABLE: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(state, "QUERY_DATA_AVAILABLE - ERROR_WINHTTP_OPERATION_CANCELLED"); } state.LifecycleAwaitable.SetCanceled(); } else { state.LifecycleAwaitable.SetException( new IOException(SR.net_http_io_read, innerException)); } break; case Interop.WinHttp.API_READ_DATA: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(state, "API_READ_DATA - ERROR_WINHTTP_OPERATION_CANCELLED"); } state.LifecycleAwaitable.SetCanceled(); } else { state.LifecycleAwaitable.SetException(new IOException(SR.net_http_io_read, innerException)); } break; case Interop.WinHttp.API_WRITE_DATA: Debug.Assert(state.TcsInternalWriteDataToRequestStream != null); if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(state, "API_WRITE_DATA - ERROR_WINHTTP_OPERATION_CANCELLED"); } state.TcsInternalWriteDataToRequestStream.TrySetCanceled(); } else { state.TcsInternalWriteDataToRequestStream.TrySetException( new IOException(SR.net_http_io_write, innerException)); } break; default: Debug.Fail( "OnRequestError: Result (" + asyncResult.dwResult + ") is not expected.", "Error code: " + asyncResult.dwError + " (" + innerException.Message + ")"); break; } }
public void DisposeCtrReadFromResponseStream() { WinHttpTraceHelper.Trace("WinHttpRequestState.DisposeCtrReadFromResponseStream: disposing ctr"); CtrReadFromResponseStream.Dispose(); CtrReadFromResponseStream = default(CancellationTokenRegistration); }
private static void OnRequestError(WinHttpRequestState state, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult) { WinHttpTraceHelper.TraceAsyncError("OnRequestError", asyncResult); Debug.Assert(state != null, "OnRequestError: state is null"); var innerException = WinHttpException.CreateExceptionUsingError((int)asyncResult.dwError).InitializeStackTrace(); switch ((uint)asyncResult.dwResult.ToInt32()) { case Interop.WinHttp.API_SEND_REQUEST: state.TcsSendRequest.TrySetException(innerException); break; case Interop.WinHttp.API_RECEIVE_RESPONSE: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_RESEND_REQUEST) { state.RetryRequest = true; state.TcsReceiveResponseHeaders.TrySetResult(false); } else if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED) { // WinHttp will automatically drop any client SSL certificates that we // have pre-set into the request handle including the NULL certificate // (which means we have no certs to send). For security reasons, we don't // allow the certificate to be re-applied. But we need to tell WinHttp // explicitly that we don't have any certificate to send. Debug.Assert(state.RequestHandle != null, "OnRequestError: state.RequestHandle is null"); WinHttpHandler.SetNoClientCertificate(state.RequestHandle); state.RetryRequest = true; state.TcsReceiveResponseHeaders.TrySetResult(false); } else if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { state.TcsReceiveResponseHeaders.TrySetCanceled(state.CancellationToken); } else { state.TcsReceiveResponseHeaders.TrySetException(innerException); } break; case Interop.WinHttp.API_QUERY_DATA_AVAILABLE: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { // TODO: Issue #2165. We need to pass in the cancellation token from the // user's ReadAsync() call into the TrySetCanceled(). Debug.WriteLine("RequestCallback: QUERY_DATA_AVAILABLE - ERROR_WINHTTP_OPERATION_CANCELLED"); state.TcsQueryDataAvailable.TrySetCanceled(); } else { state.TcsQueryDataAvailable.TrySetException( new IOException(SR.net_http_io_read, innerException)); } break; case Interop.WinHttp.API_READ_DATA: state.DisposeCtrReadFromResponseStream(); if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { // TODO: Issue #2165. We need to pass in the cancellation token from the // user's ReadAsync() call into the TrySetCanceled(). Debug.WriteLine("RequestCallback: API_READ_DATA - ERROR_WINHTTP_OPERATION_CANCELLED"); state.TcsReadFromResponseStream.TrySetCanceled(); } else { state.TcsReadFromResponseStream.TrySetException( new IOException(SR.net_http_io_read, innerException)); } break; case Interop.WinHttp.API_WRITE_DATA: if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { // TODO: Issue #2165. We need to pass in the cancellation token from the // user's WriteAsync() call into the TrySetCanceled(). Debug.WriteLine("RequestCallback: API_WRITE_DATA - ERROR_WINHTTP_OPERATION_CANCELLED"); state.TcsInternalWriteDataToRequestStream.TrySetCanceled(); } else { state.TcsInternalWriteDataToRequestStream.TrySetException( new IOException(SR.net_http_io_write, innerException)); } break; default: Debug.Fail( "OnRequestError: Result (" + asyncResult.dwResult + ") is not expected.", "Error code: " + asyncResult.dwError + " (" + innerException.Message + ")"); break; } }
// TODO: Issue #2165. Merge with similar code used in System.Net.Security move to Common/src//System/Net. public static void BuildChain( X509Certificate2 certificate, X509Certificate2Collection remoteCertificateStore, string hostName, bool checkCertificateRevocationList, out X509Chain chain, out SslPolicyErrors sslPolicyErrors) { chain = null; sslPolicyErrors = SslPolicyErrors.None; // Build the chain. chain = new X509Chain(); chain.ChainPolicy.RevocationMode = checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; // Authenticate the remote party: (e.g. when operating in client mode, authenticate the server). chain.ChainPolicy.ApplicationPolicy.Add(s_serverAuthOid); if (remoteCertificateStore.Count > 0) { if (WinHttpTraceHelper.IsTraceEnabled()) { foreach (X509Certificate cert in remoteCertificateStore) { WinHttpTraceHelper.Trace("WinHttpCertificateHelper.BuildChain: adding cert to ExtraStore: {0}", cert.Subject); } } chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore); } if (!chain.Build(certificate)) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; } // Verify the hostName matches the certificate. unsafe { var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA(); cppStruct.cbSize = (uint)Marshal.SizeOf <Interop.Crypt32.CERT_CHAIN_POLICY_PARA>(); cppStruct.dwFlags = 0; var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA(); eppStruct.cbSize = (uint)Marshal.SizeOf <Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA>(); eppStruct.dwAuthType = Interop.Crypt32.AuthType.AUTHTYPE_SERVER; cppStruct.pvExtraPolicyPara = &eppStruct; fixed(char *namePtr = hostName) { eppStruct.pwszServerName = namePtr; cppStruct.dwFlags = Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG; var status = new Interop.Crypt32.CERT_CHAIN_POLICY_STATUS(); status.cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_STATUS); if (Interop.Crypt32.CertVerifyCertificateChainPolicy( (IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL, chain.SafeHandle, ref cppStruct, ref status)) { if (status.dwError == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } else { // Failure checking the policy. This is a rare error. We will assume the name check failed. // TODO: Issue #2165. Log this error or perhaps throw an exception instead. sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } }