Imported Upstream version 5.16.0.100

Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-08-07 15:19:03 +00:00
parent 0a9828183b
commit 7d7f676260
4419 changed files with 170950 additions and 90273 deletions

View File

@ -121,6 +121,9 @@
<data name="net_http_content_stream_already_read" xml:space="preserve">
<value>The stream was already consumed. It cannot be read again.</value>
</data>
<data name="net_http_winhttp_error" xml:space="preserve">
<value>Error {0} calling {1}, '{2}'.</value>
</data>
<data name="PlatformNotSupported_WinHttpHandler" xml:space="preserve">
<value>WinHttpHandler is only supported on .NET Framework and .NET Core runtimes on Windows. It is not supported for Windows Store Applications (UWP) or Unix platforms.</value>
</data>

View File

@ -10,6 +10,7 @@
<!-- Although we have a NS configuration, the actual UWP implementation is a shim over WinRT: so just validate against OneCore -->
<UWPCompatible>false</UWPCompatible>
<IncludeDllSafeSearchPathAttribute>true</IncludeDllSafeSearchPathAttribute>
<ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
@ -42,6 +43,7 @@
<ItemGroup>
<Reference Include="System.Buffers" />
<Reference Include="System.Diagnostics.DiagnosticSource" />
<Reference Include="System.Memory" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'net46' OR '$(TargetGroup)' == 'netfx'">
<Reference Include="mscorlib" />

View File

@ -23,7 +23,6 @@
<CompileItem Include="$(CommonPath)\System\Net\UriScheme.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\HttpHandlerDefaults.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\NoWriteNoSeekStreamContent.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\WinHttpException.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Security\CertificateHelper.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Security\CertificateHelper.Windows.cs" />
<CompileItem Include="$(CommonPath)\System\Runtime\ExceptionServices\ExceptionStackTrace.cs" />
@ -33,6 +32,7 @@
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpCertificateHelper.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpChannelBinding.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpCookieContainerAdapter.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpException.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpHandler.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpRequestCallback.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpRequestState.cs" />

View File

@ -102,7 +102,7 @@ namespace System.Net.Http
// But we can validate with assert.
Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);
serverAuthScheme = ChooseAuthScheme(supportedSchemes);
serverAuthScheme = ChooseAuthScheme(supportedSchemes, state.RequestMessage.RequestUri, state.ServerCredentials);
if (serverAuthScheme != 0)
{
if (SetWinHttpCredential(
@ -155,7 +155,7 @@ namespace System.Net.Http
// But we can validate with assert.
Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY);
proxyAuthScheme = ChooseAuthScheme(supportedSchemes);
proxyAuthScheme = ChooseAuthScheme(supportedSchemes, state.Proxy.GetProxy(state.RequestMessage.RequestUri), proxyCreds);
state.RetryRequest = true;
break;
@ -296,7 +296,7 @@ namespace System.Net.Http
Interop.WinHttp.WINHTTP_OPTION_AUTOLOGON_POLICY,
ref optionData))
{
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@ -365,17 +365,22 @@ namespace System.Net.Http
password,
IntPtr.Zero))
{
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetCredentials));
}
return true;
}
private static uint ChooseAuthScheme(uint supportedSchemes)
private static uint ChooseAuthScheme(uint supportedSchemes, Uri uri, ICredentials credentials)
{
if (credentials == null)
{
return 0;
}
foreach (uint authScheme in s_authSchemePriorityOrder)
{
if ((supportedSchemes & authScheme) != 0)
if ((supportedSchemes & authScheme) != 0 && credentials.GetCredential(uri, s_authSchemeStringMapping[authScheme]) != null)
{
return authScheme;
}

View File

@ -55,11 +55,11 @@ namespace System.Net.Http
unsafe
{
var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA();
cppStruct.cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.CERT_CHAIN_POLICY_PARA>();
cppStruct.cbSize = (uint)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.cbSize = (uint)sizeof(Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA);
eppStruct.dwAuthType = Interop.Crypt32.AuthType.AUTHTYPE_SERVER;
cppStruct.pvExtraPolicyPara = &eppStruct;

View File

@ -61,7 +61,7 @@ namespace System.Net.Http
int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
{
throw WinHttpException.CreateExceptionUsingError(lastError);
throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
}
}
@ -76,7 +76,7 @@ namespace System.Net.Http
(uint)cookieHeader.Length,
Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
{
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
}
}
}

View File

@ -0,0 +1,80 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
namespace System.Net.Http
{
internal class WinHttpException : Win32Exception
{
public WinHttpException(int error, string message) : base(error, message)
{
this.HResult = ConvertErrorCodeToHR(error);
}
public WinHttpException(int error, string message, Exception innerException) : base(message, innerException)
{
this.HResult = ConvertErrorCodeToHR(error);
}
public static int ConvertErrorCodeToHR(int error)
{
// This method allows common error detection code to be used by consumers
// of HttpClient. This method converts the ErrorCode returned by WinHTTP
// to the same HRESULT value as is provided in the .Net Native implementation
// of HttpClient under the same error conditions. Clients would access
// HttpRequestException.InnerException.HRESULT to discover what caused
// the exception.
switch (unchecked((uint)error))
{
case Interop.WinHttp.ERROR_WINHTTP_CONNECTION_ERROR:
return unchecked((int)Interop.WinHttp.WININET_E_CONNECTION_RESET);
default:
// Marshal.GetHRForLastWin32Error can't be used as not all error codes originate from native
// code.
return Interop.HRESULT_FROM_WIN32(error);
}
}
public static void ThrowExceptionUsingLastError(string nameOfCalledFunction)
{
throw CreateExceptionUsingLastError(nameOfCalledFunction);
}
public static WinHttpException CreateExceptionUsingLastError(string nameOfCalledFunction)
{
int lastError = Marshal.GetLastWin32Error();
return CreateExceptionUsingError(lastError, nameOfCalledFunction);
}
public static WinHttpException CreateExceptionUsingError(int error, string nameOfCalledFunction)
{
var e = new WinHttpException(error, GetErrorMessage(error, nameOfCalledFunction));
ExceptionStackTrace.AddCurrentStack(e);
return e;
}
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 string GetErrorMessage(int error, string nameOfCalledFunction)
{
Debug.Assert(!string.IsNullOrEmpty(nameOfCalledFunction));
// Look up specific error message in WINHTTP.DLL since it is not listed in default system resources
// and thus can't be found by default .Net interop.
IntPtr moduleHandle = Interop.Kernel32.GetModuleHandle(Interop.Libraries.WinHttp);
string httpError = Interop.Kernel32.GetMessage(moduleHandle, error);
return SR.Format(SR.net_http_winhttp_error, error, nameOfCalledFunction, httpError);
}
}
}

View File

@ -194,8 +194,6 @@ namespace System.Net.Http
set
{
SecurityProtocol.ThrowOnNotAllowed(value, allowNone: true);
CheckDisposedOrStarted();
_sslProtocols = value;
}
@ -661,7 +659,7 @@ namespace System.Net.Http
(uint)requestHeadersBuffer.Length,
Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
{
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
}
}
@ -728,7 +726,7 @@ namespace System.Net.Http
WinHttpTraceHelper.Trace("WinHttpHandler.EnsureSessionHandleExists: error={0}", lastError);
if (lastError != Interop.WinHttp.ERROR_INVALID_PARAMETER)
{
ThrowOnInvalidHandle(sessionHandle);
ThrowOnInvalidHandle(sessionHandle, nameof(Interop.WinHttp.WinHttpOpen));
}
// We must be running on a platform earlier than Win8.1/Win2K12R2 which doesn't support
@ -741,7 +739,7 @@ namespace System.Net.Http
_proxyHelper.ManualSettingsOnly ? _proxyHelper.Proxy : Interop.WinHttp.WINHTTP_NO_PROXY_NAME,
_proxyHelper.ManualSettingsOnly ? _proxyHelper.ProxyBypass : Interop.WinHttp.WINHTTP_NO_PROXY_BYPASS,
(int)Interop.WinHttp.WINHTTP_FLAG_ASYNC);
ThrowOnInvalidHandle(sessionHandle);
ThrowOnInvalidHandle(sessionHandle, nameof(Interop.WinHttp.WinHttpOpen));
}
uint optionAssuredNonBlockingTrue = 1; // TRUE
@ -757,7 +755,7 @@ namespace System.Net.Http
int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.WinHttp.ERROR_WINHTTP_INVALID_OPTION)
{
throw WinHttpException.CreateExceptionUsingError(lastError);
throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@ -788,7 +786,7 @@ namespace System.Net.Http
state.RequestMessage.RequestUri.Host,
(ushort)state.RequestMessage.RequestUri.Port,
0);
ThrowOnInvalidHandle(connectHandle);
ThrowOnInvalidHandle(connectHandle, nameof(Interop.WinHttp.WinHttpConnect));
connectHandle.SetParentHandle(_sessionHandle);
// Try to use the requested version if a known/supported version was explicitly requested.
@ -821,7 +819,7 @@ namespace System.Net.Http
Interop.WinHttp.WINHTTP_NO_REFERER,
Interop.WinHttp.WINHTTP_DEFAULT_ACCEPT_TYPES,
flags);
ThrowOnInvalidHandle(state.RequestHandle);
ThrowOnInvalidHandle(state.RequestHandle, nameof(Interop.WinHttp.WinHttpOpenRequest));
state.RequestHandle.SetParentHandle(connectHandle);
// Set callback function.
@ -888,6 +886,16 @@ namespace System.Net.Http
HttpResponseMessage responseMessage = WinHttpResponseParser.CreateResponseMessage(state, _doManualDecompressionCheck);
state.Tcs.TrySetResult(responseMessage);
// HttpStatusCode cast is needed for 308 Moved Permenantly, which we support but is not included in NetStandard status codes.
if (WinHttpTraceHelper.IsTraceEnabled() &&
((responseMessage.StatusCode >= HttpStatusCode.MultipleChoices && responseMessage.StatusCode <= HttpStatusCode.SeeOther) ||
(responseMessage.StatusCode >= HttpStatusCode.RedirectKeepVerb && responseMessage.StatusCode <= (HttpStatusCode)308)) &&
state.RequestMessage.RequestUri.Scheme == Uri.UriSchemeHttps && responseMessage.Headers.Location?.Scheme == Uri.UriSchemeHttp)
{
WinHttpTraceHelper.Trace("WinHttpHandler.SendAsync: Insecure https to http redirect from {0} to {1} blocked.",
state.RequestMessage.RequestUri.ToString(), responseMessage.Headers.Location.ToString());
}
}
catch (Exception ex)
{
@ -919,6 +927,18 @@ namespace System.Net.Http
uint optionData = 0;
SslProtocols sslProtocols =
(_sslProtocols == SslProtocols.None) ? SecurityProtocol.DefaultSecurityProtocols : _sslProtocols;
#pragma warning disable 0618 // SSL2/SSL3 are deprecated
if ((sslProtocols & SslProtocols.Ssl2) != 0)
{
optionData |= Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_SSL2;
}
if ((sslProtocols & SslProtocols.Ssl3) != 0)
{
optionData |= Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_SSL3;
}
#pragma warning restore 0618
if ((sslProtocols & SslProtocols.Tls) != 0)
{
@ -947,7 +967,7 @@ namespace System.Net.Http
(int)_sendTimeout.TotalMilliseconds,
(int)_receiveHeadersTimeout.TotalMilliseconds))
{
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetTimeouts));
}
}
@ -1204,7 +1224,7 @@ namespace System.Net.Http
option,
ref optionData))
{
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@ -1217,7 +1237,7 @@ namespace System.Net.Http
optionData,
(uint)optionData.Length))
{
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@ -1234,7 +1254,7 @@ namespace System.Net.Http
optionData,
optionSize))
{
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@ -1304,18 +1324,18 @@ namespace System.Net.Http
int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.WinHttp.ERROR_INVALID_HANDLE) // Ignore error if handle was already closed.
{
throw WinHttpException.CreateExceptionUsingError(lastError);
throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpSetStatusCallback));
}
}
}
private void ThrowOnInvalidHandle(SafeWinHttpHandle handle)
private void ThrowOnInvalidHandle(SafeWinHttpHandle handle, string nameOfCalledFunction)
{
if (handle.IsInvalid)
{
int lastError = Marshal.GetLastWin32Error();
WinHttpTraceHelper.Trace("WinHttpHandler.ThrowOnInvalidHandle: error={0}", lastError);
throw WinHttpException.CreateExceptionUsingError(lastError);
throw WinHttpException.CreateExceptionUsingError(lastError, nameOfCalledFunction);
}
}
@ -1333,11 +1353,13 @@ namespace System.Net.Http
0,
state.ToIntPtr()))
{
// Dispose (which will unpin) the state object. Since this failed, WinHTTP won't associate
// our context value (state object) to the request handle. And thus we won't get HANDLE_CLOSING
// notifications which would normally cause the state object to be unpinned and disposed.
// WinHTTP doesn't always associate our context value (state object) to the request handle.
// And thus we might not get a HANDLE_CLOSING notification which would normally cause the
// state object to be unpinned and disposed. So, we manually dispose the request handle and
// state object here.
state.RequestHandle.Dispose();
state.Dispose();
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSendRequest));
}
}
@ -1361,7 +1383,7 @@ namespace System.Net.Http
{
if (!Interop.WinHttp.WinHttpReceiveResponse(state.RequestHandle, IntPtr.Zero))
{
throw WinHttpException.CreateExceptionUsingLastError();
throw WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReceiveResponse));
}
}

View File

@ -110,8 +110,19 @@ namespace System.Net.Http
}
catch (Exception ex)
{
Interop.WinHttp.WinHttpCloseHandle(handle);
state.SavedException = ex;
if (state.RequestHandle != null)
{
// Since we got a fatal error processing the request callback,
// we need to close the WinHttp request handle in order to
// abort the currently executing WinHttp async operation.
//
// We must always call Dispose() against the SafeWinHttpHandle
// wrapper and never close directly the raw WinHttp handle.
// The SafeWinHttpHandle wrapper is thread-safe and guarantees
// calling the underlying WinHttpCloseHandle() function only once.
state.RequestHandle.Dispose();
}
}
}
@ -214,6 +225,10 @@ namespace System.Net.Http
{
state.ServerCredentials = null;
}
// Similarly, we need to clear any Auth headers that were added to the request manually or
// through the default headers.
ResetAuthRequestHeaders(state);
}
private static void OnRequestSendingRequest(WinHttpRequestState state)
@ -256,7 +271,7 @@ namespace System.Net.Http
return;
}
throw WinHttpException.CreateExceptionUsingError(lastError);
throw WinHttpException.CreateExceptionUsingError(lastError, "WINHTTP_CALLBACK_STATUS_SENDING_REQUEST/WinHttpQueryOption");
}
// Get any additional certificates sent from the remote server during the TLS/SSL handshake.
@ -291,7 +306,7 @@ namespace System.Net.Http
catch (Exception ex)
{
throw WinHttpException.CreateExceptionUsingError(
(int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, ex);
(int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, "X509Chain.Build", ex);
}
finally
{
@ -306,7 +321,7 @@ namespace System.Net.Http
if (!result)
{
throw WinHttpException.CreateExceptionUsingError(
(int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE);
(int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, "ServerCertificateValidationCallback");
}
}
}
@ -317,7 +332,7 @@ namespace System.Net.Http
Debug.Assert(state != null, "OnRequestError: state is null");
Exception innerException = WinHttpException.CreateExceptionUsingError(unchecked((int)asyncResult.dwError));
Exception innerException = WinHttpException.CreateExceptionUsingError(unchecked((int)asyncResult.dwError), "WINHTTP_CALLBACK_STATUS_REQUEST_ERROR");
switch (unchecked((uint)asyncResult.dwResult.ToInt32()))
{
@ -404,5 +419,25 @@ namespace System.Net.Http
break;
}
}
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");
}
}
}
}
}

View File

@ -249,7 +249,7 @@ namespace System.Net.Http
IntPtr.Zero))
{
_state.TcsInternalWriteDataToRequestStream.TrySetException(
new IOException(SR.net_http_io_write, WinHttpException.CreateExceptionUsingLastError()));
new IOException(SR.net_http_io_write, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpWriteData))));
}
}

View File

@ -92,7 +92,7 @@ namespace System.Net.Http
}
}
response.Content = new NoWriteNoSeekStreamContent(decompressedStream, state.CancellationToken);
response.Content = new NoWriteNoSeekStreamContent(decompressedStream);
response.RequestMessage = request;
// Parse raw response headers and place them into response message.
@ -127,7 +127,7 @@ namespace System.Net.Http
ref resultSize,
IntPtr.Zero))
{
WinHttpException.ThrowExceptionUsingLastError();
WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
return result;
@ -189,7 +189,7 @@ namespace System.Net.Http
return GetResponseHeader(requestHandle, infoLevel, ref buffer, ref index, out headerValue);
}
throw WinHttpException.CreateExceptionUsingError(lastError);
throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
/// <summary>
@ -216,7 +216,7 @@ namespace System.Net.Http
Debug.Assert(lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER, "buffer must be of sufficient size.");
throw WinHttpException.CreateExceptionUsingError(lastError);
throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
}
@ -240,7 +240,7 @@ namespace System.Net.Http
if (lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER)
{
throw WinHttpException.CreateExceptionUsingError(lastError);
throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
}

View File

@ -121,7 +121,7 @@ namespace System.Net.Http
{
if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero))
{
throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError());
throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryDataAvailable)));
}
}
int bytesAvailable = await _state.LifecycleAwaitable;
@ -137,7 +137,7 @@ namespace System.Net.Http
{
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());
throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReadData)));
}
}
int bytesRead = await _state.LifecycleAwaitable;
@ -222,7 +222,7 @@ namespace System.Net.Http
Debug.Assert(!_requestHandle.IsInvalid);
if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero))
{
throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError());
throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryDataAvailable)));
}
}
@ -237,7 +237,7 @@ namespace System.Net.Http
(uint)Math.Min(bytesAvailable, count),
IntPtr.Zero))
{
throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError());
throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReadData)));
}
}

View File

@ -138,14 +138,14 @@ namespace System.Net.Http
uint apiIndex = (uint)asyncResult.dwResult.ToInt32();
uint error = asyncResult.dwError;
string apiName = GetNameFromApiIndex(apiIndex);
WriteLine(
"{0}: api={1}, error={2}({3}) \"{4}\"",
message,
GetNameFromApiIndex(apiIndex),
apiName,
GetNameFromError(error),
error,
WinHttpException.GetErrorMessage((int)error));
WinHttpException.GetErrorMessage((int)error, apiName));
}
private static void WriteLine(string message)

View File

@ -14,6 +14,9 @@ namespace System.Net.Http
internal class WinInetProxyHelper
{
private bool _useProxy = false;
private bool _autoDetectionFailed;
private int _lastTimeAutoDetectionFailed; // Environment.TickCount units (milliseconds).
private const int _recentAutoDetectionInterval = 120_000; // 2 minutes in milliseconds.
public WinInetProxyHelper()
{
@ -79,6 +82,10 @@ namespace System.Net.Http
public string ProxyBypass { get; set; }
public bool RecentAutoDetectionFailure =>
_autoDetectionFailed &&
Environment.TickCount - _lastTimeAutoDetectionFailed <= _recentAutoDetectionInterval;
public bool GetProxyForUrl(
SafeWinHttpHandle sessionHandle,
Uri uri,
@ -123,6 +130,7 @@ namespace System.Net.Http
var repeat = false;
do
{
_autoDetectionFailed = false;
if (Interop.WinHttp.WinHttpGetProxyForUrl(
sessionHandle,
uri.AbsoluteUri,
@ -131,7 +139,7 @@ namespace System.Net.Http
{
WinHttpTraceHelper.Trace("WinInetProxyHelper.GetProxyForUrl: Using autoconfig proxy settings");
useProxy = true;
break;
}
else
@ -154,6 +162,12 @@ namespace System.Net.Http
}
else
{
if (lastError == Interop.WinHttp.ERROR_WINHTTP_AUTODETECTION_FAILED)
{
_autoDetectionFailed = true;
_lastTimeAutoDetectionFailed = Environment.TickCount;
}
break;
}
}

View File

@ -16,6 +16,8 @@ using Xunit.Abstractions;
// WinHttpHandler is a class and not a namespace and can't be part of namespace paths.
namespace System.Net.Http.WinHttpHandlerFunctional.Tests
{
using Configuration = System.Net.Test.Common.Configuration;
// Note: Disposing the HttpClient object automatically disposes the handler within. So, it is not necessary
// to separately Dispose (or have a 'using' statement) for the handler.
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "WinHttpHandler not supported on UAP")]
@ -113,6 +115,25 @@ namespace System.Net.Http.WinHttpHandlerFunctional.Tests
}
}
[Fact]
public async Task SendAsync_GetUsingChunkedEncoding_ThrowsHttpRequestException()
{
// WinHTTP doesn't support GET requests with a request body that uses
// chunked encoding. This test pins this behavior and verifies that the
// error handling is working correctly.
var server = new Uri("http://www.microsoft.com"); // No network I/O actually happens.
var request = new HttpRequestMessage(HttpMethod.Get, server);
request.Content = new StringContent("Request body");
request.Headers.TransferEncodingChunked = true;
var handler = new WinHttpHandler();
using (HttpClient client = new HttpClient(handler))
{
HttpRequestException ex = await Assert.ThrowsAsync<HttpRequestException>(() => client.SendAsync(request));
_output.WriteLine(ex.ToString());
}
}
public static bool JsonMessageContainsKeyValue(string message, string key, string value)
{
// TODO: Merge with System.Net.Http TestHelper class as part of GitHub Issue #4989.

View File

@ -73,9 +73,6 @@
<Compile Include="$(CommonPath)\System\Net\Http\NoWriteNoSeekStreamContent.cs">
<Link>Common\System\Net\Http\NoWriteNoSeekStreamContent.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\Http\WinHttpException.cs">
<Link>Common\System\Net\Http\WinHttpException.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\Security\CertificateHelper.cs">
<Link>Common\System\Net\Security\CertificateHelper.cs</Link>
</Compile>
@ -103,6 +100,9 @@
<Compile Include="..\..\src\System\Net\Http\WinHttpCookieContainerAdapter.cs">
<Link>ProductionCode\WinHttpCookieContainerAdapter.cs</Link>
</Compile>
<Compile Include="..\..\src\System\Net\Http\WinHttpException.cs">
<Link>ProductionCode\WinHttpException.cs</Link>
</Compile>
<Compile Include="..\..\src\System\Net\Http\WinHttpHandler.cs">
<Link>ProductionCode\WinHttpHandler.cs</Link>
</Compile>

View File

@ -435,15 +435,6 @@ namespace System.Net.Http.WinHttpHandlerUnitTests
handler.ReceiveHeadersTimeout = Timeout.InfiniteTimeSpan;
}
[Theory]
[ClassData(typeof(SslProtocolSupport.UnsupportedSslProtocolsTestData))]
public void SslProtocols_SetUsingUnsupported_Throws(SslProtocols protocol)
{
var handler = new WinHttpHandler();
Assert.Throws<NotSupportedException>(() => { handler.SslProtocols = protocol; });
}
[Theory]
[ClassData(typeof(SslProtocolSupport.SupportedSslProtocolsTestData))]
public void SslProtocols_SetUsingSupported_Success(SslProtocols protocol)
@ -460,33 +451,27 @@ namespace System.Net.Http.WinHttpHandlerUnitTests
handler.SslProtocols = SslProtocols.None;
}
[Fact]
public void SslProtocols_SetUsingInvalidEnum_Throws()
{
var handler = new WinHttpHandler();
Assert.Throws<NotSupportedException>(() => { handler.SslProtocols = (SslProtocols)4096; });
}
[Fact]
public void SslProtocols_SetUsingValidEnums_ExpectedWinHttpHandleSettings()
[Theory]
[InlineData(
SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12,
Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2)]
#pragma warning disable 0618
[InlineData(
SslProtocols.Ssl2 | SslProtocols.Ssl3,
Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 |
Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_SSL3)]
#pragma warning restore 0618
public void SslProtocols_SetUsingValidEnums_ExpectedWinHttpHandleSettings(
SslProtocols specified, uint expectedProtocols)
{
var handler = new WinHttpHandler();
SendRequestHelper.Send(
handler,
delegate
{
handler.SslProtocols =
SslProtocols.Tls |
SslProtocols.Tls11 |
SslProtocols.Tls12;
});
delegate { handler.SslProtocols = specified; });
uint expectedProtocols =
Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
Assert.Equal(expectedProtocols, APICallHistory.WinHttpOptionSecureProtocols);
}