/// <summary> /// Returns the size of the char array buffer. /// </summary> public static unsafe int GetResponseHeaderCharBufferLength(SafeWinHttpHandle requestHandle, bool isTrailingHeaders) { char *buffer = null; int bufferLength = 0; uint index = 0; uint infoLevel = Interop.WinHttp.WINHTTP_QUERY_RAW_HEADERS_CRLF; if (isTrailingHeaders) { infoLevel |= Interop.WinHttp.WINHTTP_QUERY_FLAG_TRAILERS; } if (!QueryHeaders(requestHandle, infoLevel, buffer, ref bufferLength, ref index)) { int lastError = Marshal.GetLastWin32Error(); Debug.Assert(isTrailingHeaders || lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND); if (lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER && (!isTrailingHeaders || lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)) { throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpQueryHeaders)); } } return(bufferLength); }
public static WinHttpException CreateExceptionUsingError(int error, string nameOfCalledFunction, Exception innerException) { var e = new WinHttpException(error, GetErrorMessage(error, nameOfCalledFunction), innerException); ExceptionStackTrace.AddCurrentStack(e); return(e); }
public static WinHttpException CreateExceptionUsingError(int error) { var e = new WinHttpException(error, GetErrorMessage(error)); ExceptionStackTrace.AddCurrentStack(e); return(e); }
private Task <bool> InternalWriteDataAsync(byte[] buffer, int offset, int count, CancellationToken token) { Debug.Assert(count > 0); // TODO (Issue 2505): replace with PinnableBufferCache. if (!_cachedSendPinnedBuffer.IsAllocated || _cachedSendPinnedBuffer.Target != buffer) { if (_cachedSendPinnedBuffer.IsAllocated) { _cachedSendPinnedBuffer.Free(); } _cachedSendPinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); } _state.TcsInternalWriteDataToRequestStream = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); lock (_state.Lock) { if (!Interop.WinHttp.WinHttpWriteData( _state.RequestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)count, IntPtr.Zero)) { _state.TcsInternalWriteDataToRequestStream.TrySetException( new IOException(SR.net_http_io_write, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpWriteData)))); } } // TODO: Issue #2165. Register callback on cancellation token to cancel WinHTTP operation. return(_state.TcsInternalWriteDataToRequestStream.Task); }
private void ThrowOnInvalidHandle(SafeWinHttpHandle handle) { if (handle.IsInvalid) { WinHttpException.ThrowExceptionUsingLastError(); } }
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); } else { var lastError = Marshal.GetLastWin32Error(); if (lastError != Interop.WinHttp.ERROR_FILE_NOT_FOUND) { throw WinHttpException.CreateExceptionUsingError(lastError); } } } finally { // FreeHGlobal already checks for null pointer before freeing the memory. Marshal.FreeHGlobal(proxyConfig.AutoConfigUrl); Marshal.FreeHGlobal(proxyConfig.Proxy); Marshal.FreeHGlobal(proxyConfig.ProxyBypass); } }
/// <summary> /// Fills the buffer with the header value and returns the length, or returns 0 if the header isn't found. /// </summary> private static unsafe int GetResponseHeader(SafeWinHttpHandle requestHandle, uint infoLevel, char[] buffer) { Debug.Assert(buffer != null, "buffer must not be null."); Debug.Assert(buffer.Length > 0, "buffer must not be empty."); int bufferLength = buffer.Length; uint index = 0; fixed(char *pBuffer = &buffer[0]) { if (!QueryHeaders(requestHandle, infoLevel, pBuffer, ref bufferLength, ref index)) { int lastError = Marshal.GetLastWin32Error(); if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND) { return(0); } Debug.Assert(lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER, "buffer must be of sufficient size."); throw WinHttpException.CreateExceptionUsingError(lastError); } } return(bufferLength); }
private void SetWinHttpCredential( SafeWinHttpHandle requestHandle, ICredentials credentials, Uri uri, uint authScheme, uint authTarget) { string userName; string password; Debug.Assert(credentials != null); Debug.Assert(authScheme != 0); Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY || authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER); NetworkCredential networkCredential = credentials.GetCredential(uri, s_authSchemeStringMapping[authScheme]); if (networkCredential == null) { return; } if (networkCredential == CredentialCache.DefaultNetworkCredentials) { // Allow WinHTTP to transmit the default credentials. ChangeDefaultCredentialsPolicy(requestHandle, authTarget, allowDefaultCredentials:true); userName = null; password = null; } else { userName = networkCredential.UserName; password = networkCredential.Password; string domain = networkCredential.Domain; // WinHTTP does not support a blank username. So, we will throw an exception. if (string.IsNullOrEmpty(userName)) { throw new InvalidOperationException(SR.net_http_username_empty_string); } if (!string.IsNullOrEmpty(domain)) { userName = domain + "\\" + userName; } } if (!Interop.WinHttp.WinHttpSetCredentials( requestHandle, authTarget, authScheme, userName, password, IntPtr.Zero)) { WinHttpException.ThrowExceptionUsingLastError(); } }
public static unsafe bool GetResponseHeader( SafeWinHttpHandle requestHandle, uint infoLevel, ref char[] buffer, ref uint index, out string headerValue) { const int StackLimit = 128; Debug.Assert(buffer == null || (buffer != null && buffer.Length > StackLimit)); int bufferLength; uint originalIndex = index; if (buffer == null) { bufferLength = StackLimit; char *pBuffer = stackalloc char[bufferLength]; if (QueryHeaders(requestHandle, infoLevel, pBuffer, ref bufferLength, ref index)) { headerValue = new string(pBuffer, 0, bufferLength); return(true); } } else { bufferLength = buffer.Length; fixed(char *pBuffer = &buffer[0]) { if (QueryHeaders(requestHandle, infoLevel, pBuffer, ref bufferLength, ref index)) { headerValue = new string(pBuffer, 0, bufferLength); return(true); } } } int lastError = Marshal.GetLastWin32Error(); if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND) { headerValue = null; return(false); } if (lastError == Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER) { // WinHttpQueryHeaders may advance the index even when it fails due to insufficient buffer, // so we set the index back to its original value so we can retry retrieving the same // index again with a larger buffer. index = originalIndex; buffer = new char[bufferLength]; return(GetResponseHeader(requestHandle, infoLevel, ref buffer, ref index, out headerValue)); } throw WinHttpException.CreateExceptionUsingError(lastError); }
private async Task CopyToAsyncCore(Stream destination, byte[] buffer, CancellationToken cancellationToken) { _state.PinReceiveBuffer(buffer); CancellationTokenRegistration ctr = cancellationToken.Register(s => ((WinHttpResponseStream)s).CancelPendingResponseStreamReadOperation(), this); _state.AsyncReadInProgress = true; try { // Loop until there's no more data to be read while (true) { // Query for data available lock (_state.Lock) { if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero)) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError()); } } int bytesAvailable = await _state.LifecycleAwaitable; if (bytesAvailable == 0) { break; } Debug.Assert(bytesAvailable > 0); // Read the available data cancellationToken.ThrowIfCancellationRequested(); lock (_state.Lock) { if (!Interop.WinHttp.WinHttpReadData(_requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0), (uint)Math.Min(bytesAvailable, buffer.Length), IntPtr.Zero)) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError()); } } int bytesRead = await _state.LifecycleAwaitable; if (bytesRead == 0) { break; } Debug.Assert(bytesRead > 0); // Write that data out to the output stream await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); } } finally { _state.AsyncReadInProgress = false; ctr.Dispose(); ArrayPool <byte> .Shared.Return(buffer); } // Leaving buffer pinned as it is in ReadAsync. It'll get unpinned when another read // request is made with a different buffer or when the state is cleared. }
private void SetWinHttpOption(SafeWinHttpHandle handle, uint option, ref uint optionData) { if (!Interop.WinHttp.WinHttpSetOption( handle, option, ref optionData)) { WinHttpException.ThrowExceptionUsingLastError(); } }
private void SetWinHttpOption(SafeWinHttpHandle handle, uint option, string optionData) { if (!Interop.WinHttp.WinHttpSetOption( handle, option, optionData, (uint)optionData.Length)) { WinHttpException.ThrowExceptionUsingLastError(); } }
private void SetSessionHandleTimeoutOptions() { if (!Interop.WinHttp.WinHttpSetTimeouts( _sessionHandle, 0, (int)_connectTimeout.TotalMilliseconds, (int)_sendTimeout.TotalMilliseconds, (int)_receiveHeadersTimeout.TotalMilliseconds)) { WinHttpException.ThrowExceptionUsingLastError(); } }
public unsafe static bool GetResponseHeader( SafeWinHttpHandle requestHandle, uint infoLevel, ref char[] buffer, ref uint index, out string headerValue) { const int StackLimit = 128; Debug.Assert(buffer == null || (buffer != null && buffer.Length > StackLimit)); int bufferLength; if (buffer == null) { bufferLength = StackLimit; char *pBuffer = stackalloc char[bufferLength]; if (QueryHeaders(requestHandle, infoLevel, pBuffer, ref bufferLength, ref index)) { headerValue = new string(pBuffer, 0, bufferLength); return(true); } } else { bufferLength = buffer.Length; fixed(char *pBuffer = buffer) { if (QueryHeaders(requestHandle, infoLevel, pBuffer, ref bufferLength, ref index)) { headerValue = new string(pBuffer, 0, bufferLength); return(true); } } } int lastError = Marshal.GetLastWin32Error(); if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND) { headerValue = null; return(false); } if (lastError == Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER) { buffer = new char[bufferLength]; return(GetResponseHeader(requestHandle, infoLevel, ref buffer, ref index, out headerValue)); } throw WinHttpException.CreateExceptionUsingError(lastError); }
private async Task <int> ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken token) { if (count == 0) { return(0); } _state.PinReceiveBuffer(buffer); var ctr = token.Register(s => ((WinHttpResponseStream)s).CancelPendingResponseStreamReadOperation(), this); _state.AsyncReadInProgress = true; try { lock (_state.Lock) { Debug.Assert(!_requestHandle.IsInvalid); if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero)) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryDataAvailable))); } } int bytesAvailable = await _state.LifecycleAwaitable; lock (_state.Lock) { Debug.Assert(!_requestHandle.IsInvalid); if (!Interop.WinHttp.WinHttpReadData( _requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)Math.Min(bytesAvailable, count), IntPtr.Zero)) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReadData))); } } int bytesRead = await _state.LifecycleAwaitable; if (bytesRead == 0) { ReadResponseTrailers(); } return(bytesRead); } finally { _state.AsyncReadInProgress = false; ctr.Dispose(); } }
public static void TraceAsyncError(object thisOrContextObject, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult, [CallerMemberName] string?memberName = null) { Debug.Assert(NetEventSource.Log.IsEnabled()); uint apiIndex = (uint)asyncResult.dwResult.ToInt32(); uint error = asyncResult.dwError; string apiName = GetNameFromApiIndex(apiIndex); NetEventSource.Error( thisOrContextObject, $"api={apiName}, error={GetNameFromError(error)}({error}) \"{WinHttpException.GetErrorMessage((int)error, apiName)}\"", memberName); }
private Task <bool> InternalReceiveResponseHeadersAsync(WinHttpRequestState state) { state.TcsReceiveResponseHeaders = new TaskCompletionSource <bool>(); lock (state.Lock) { if (!Interop.WinHttp.WinHttpReceiveResponse(state.RequestHandle, IntPtr.Zero)) { throw WinHttpException.CreateExceptionUsingLastError(); } } return(state.TcsReceiveResponseHeaders.Task); }
private static void SetWinHttpOption( SafeWinHttpHandle handle, uint option, IntPtr optionData, uint optionSize) { if (!Interop.WinHttp.WinHttpSetOption( handle, option, optionData, optionSize)) { WinHttpException.ThrowExceptionUsingLastError(); } }
private static string GetResponseHeaderStringHelper( SafeWinHttpHandle requestHandle, uint infoLevel, ref uint index) { uint bytesNeeded = 0; bool results = false; // Call WinHttpQueryHeaders once to obtain the size of the buffer needed. The size is returned in // bytes but the API actually returns Unicode characters. if (!Interop.WinHttp.WinHttpQueryHeaders( requestHandle, infoLevel, Interop.WinHttp.WINHTTP_HEADER_NAME_BY_INDEX, null, ref bytesNeeded, ref index)) { int lastError = Marshal.GetLastWin32Error(); if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND) { return(null); } if (lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER) { throw WinHttpException.CreateExceptionUsingError(lastError); } } // Allocate space for the buffer. int charsNeeded = (int)bytesNeeded / sizeof(char); var buffer = new StringBuilder(charsNeeded, charsNeeded); results = Interop.WinHttp.WinHttpQueryHeaders( requestHandle, infoLevel, Interop.WinHttp.WINHTTP_HEADER_NAME_BY_INDEX, buffer, ref bytesNeeded, ref index); if (!results) { WinHttpException.ThrowExceptionUsingLastError(); } return(buffer.ToString()); }
private void WriteData(byte[] buffer, int offset, int count) { uint bytesWritten = 0; GCHandle pinnedHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); bool result = Interop.WinHttp.WinHttpWriteData( _requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)count, out bytesWritten); pinnedHandle.Free(); if (!result) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError()); } }
private static void AddRequestHeaders( SafeWinHttpHandle requestHandle, HttpRequestMessage requestMessage, CookieContainer cookies) { var requestHeadersBuffer = new StringBuilder(); // Manually add cookies. if (cookies != null) { string cookieHeader = GetCookieHeader(requestMessage.RequestUri, cookies); if (!string.IsNullOrEmpty(cookieHeader)) { requestHeadersBuffer.AppendLine(cookieHeader); } } // Serialize general request headers. requestHeadersBuffer.AppendLine(requestMessage.Headers.ToString()); // Serialize entity-body (content) headers. if (requestMessage.Content != null) { // TODO: Content-Length header isn't getting correctly placed using ToString() // This is a bug in HttpContentHeaders that needs to be fixed. if (requestMessage.Content.Headers.ContentLength.HasValue) { long contentLength = requestMessage.Content.Headers.ContentLength.Value; requestMessage.Content.Headers.ContentLength = null; requestMessage.Content.Headers.ContentLength = contentLength; } requestHeadersBuffer.AppendLine(requestMessage.Content.Headers.ToString()); } // Add request headers to WinHTTP request handle. if (!Interop.WinHttp.WinHttpAddRequestHeaders( requestHandle, requestHeadersBuffer, (uint)requestHeadersBuffer.Length, Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD)) { WinHttpException.ThrowExceptionUsingLastError(); } }
/// <summary> /// Returns the first header or throws if the header isn't found. /// </summary> public static uint GetResponseHeaderNumberInfo(SafeWinHttpHandle requestHandle, uint infoLevel) { uint result = 0; uint resultSize = sizeof(uint); if (!Interop.WinHttp.WinHttpQueryHeaders( requestHandle, infoLevel | Interop.WinHttp.WINHTTP_QUERY_FLAG_NUMBER, Interop.WinHttp.WINHTTP_HEADER_NAME_BY_INDEX, ref result, ref resultSize, IntPtr.Zero)) { WinHttpException.ThrowExceptionUsingLastError(); } return(result); }
public static void TraceAsyncError(string message, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult) { if (!IsTraceEnabled()) { return; } uint apiIndex = (uint)asyncResult.dwResult.ToInt32(); uint error = asyncResult.dwError; WriteLine( "{0}: api={1}, error={2}({3}) \"{4}\"", message, GetNameFromApiIndex(apiIndex), GetNameFromError(error), error, WinHttpException.GetErrorMessage((int)error)); }
private static void ResetAuthRequestHeaders(WinHttpRequestState state) { const string AuthHeaderNameWithColon = "Authorization:"; SafeWinHttpHandle requestHandle = state.RequestHandle; // Clear auth headers. if (!Interop.WinHttp.WinHttpAddRequestHeaders( requestHandle, AuthHeaderNameWithColon, (uint)AuthHeaderNameWithColon.Length, Interop.WinHttp.WINHTTP_ADDREQ_FLAG_REPLACE)) { int lastError = Marshal.GetLastWin32Error(); if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND) { throw WinHttpException.CreateExceptionUsingError(lastError, "WINHTTP_CALLBACK_STATUS_REDIRECT/WinHttpAddRequestHeaders"); } } }
private void SetStatusCallback( SafeWinHttpHandle requestHandle, Interop.WinHttp.WINHTTP_STATUS_CALLBACK callback) { IntPtr oldCallback = Interop.WinHttp.WinHttpSetStatusCallback( requestHandle, callback, Interop.WinHttp.WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, IntPtr.Zero); if (oldCallback == new IntPtr(Interop.WinHttp.WINHTTP_INVALID_STATUS_CALLBACK)) { int lastError = Marshal.GetLastWin32Error(); if (lastError != Interop.WinHttp.ERROR_INVALID_HANDLE) // Ignore error if handle was already closed. { throw WinHttpException.CreateExceptionUsingError(lastError); } } }
private Task <bool> InternalWriteEndDataAsync(CancellationToken token) { _state.TcsInternalWriteDataToRequestStream = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); lock (_state.Lock) { if (!Interop.WinHttp.WinHttpWriteData( _requestHandle, IntPtr.Zero, 0, IntPtr.Zero)) { _state.TcsInternalWriteDataToRequestStream.TrySetException( new IOException(SR.net_http_io_write, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpWriteData)))); } } return(_state.TcsInternalWriteDataToRequestStream.Task); }
/// <summary> /// Returns the size of the char array buffer. /// </summary> private static unsafe int GetResponseHeaderCharBufferLength(SafeWinHttpHandle requestHandle, uint infoLevel) { char *buffer = null; int bufferLength = 0; uint index = 0; if (!QueryHeaders(requestHandle, infoLevel, buffer, ref bufferLength, ref index)) { int lastError = Marshal.GetLastWin32Error(); Debug.Assert(lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND); if (lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER) { throw WinHttpException.CreateExceptionUsingError(lastError); } } return(bufferLength); }
private Task <bool> InternalSendRequestAsync(WinHttpRequestState state) { state.TcsSendRequest = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); lock (state.Lock) { if (!Interop.WinHttp.WinHttpSendRequest( state.RequestHandle, null, 0, IntPtr.Zero, 0, 0, state.ToIntPtr())) { WinHttpException.ThrowExceptionUsingLastError(); } } return(state.TcsSendRequest.Task); }
public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if ((long)offset + (long)count > (long)buffer.Length) { throw new ArgumentException("buffer"); } CheckDisposed(); uint bytesRead = 0; GCHandle pinnedHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); bool result = Interop.WinHttp.WinHttpReadData( _requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)count, out bytesRead); pinnedHandle.Free(); if (!result) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError()); } return((int)bytesRead); }
public void ChangeDefaultCredentialsPolicy( SafeWinHttpHandle requestHandle, uint authTarget, bool allowDefaultCredentials) { Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY || authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER); uint optionData = allowDefaultCredentials ? (authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY ? Interop.WinHttp.WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM : Interop.WinHttp.WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW) : Interop.WinHttp.WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH; if (!Interop.WinHttp.WinHttpSetOption( requestHandle, Interop.WinHttp.WINHTTP_OPTION_AUTOLOGON_POLICY, ref optionData)) { WinHttpException.ThrowExceptionUsingLastError(); } }