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); }
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. char[] buffer = null; uint index = 0; string cookieHeader; WinHttpTraceHelper.Trace("WINHTTP_QUERY_SET_COOKIE"); while (WinHttpResponseParser.GetResponseHeader( requestHandle, Interop.WinHttp.WINHTTP_QUERY_SET_COOKIE, ref buffer, ref index, out cookieHeader)) { 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); } } }
// 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 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); } }
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 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("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("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("net_http_io_read", WinHttpException.CreateExceptionUsingLastError())); } } } }, 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("net_http_io_read", WinHttpException.CreateExceptionUsingLastError())); } } return(_state.TcsReadFromResponseStream.Task); }
public void DisposeCtrReadFromResponseStream() { WinHttpTraceHelper.Trace("WinHttpRequestState.DisposeCtrReadFromResponseStream: disposing ctr"); CtrReadFromResponseStream.Dispose(); CtrReadFromResponseStream = default(CancellationTokenRegistration); }
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 { 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 { 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); }