diff --git a/src/System.Net.Http.WinHttpHandler/src/Resources/Strings.resx b/src/System.Net.Http.WinHttpHandler/src/Resources/Strings.resx
index 846190e58dcf..5ce718aaab7a 100644
--- a/src/System.Net.Http.WinHttpHandler/src/Resources/Strings.resx
+++ b/src/System.Net.Http.WinHttpHandler/src/Resources/Strings.resx
@@ -121,6 +121,9 @@
The stream was already consumed. It cannot be read again.
+
+ Error {0} calling {1}, '{2}'.
+
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.
diff --git a/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.msbuild b/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.msbuild
index eca0378858dd..043e9c4bd873 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.msbuild
+++ b/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.msbuild
@@ -23,7 +23,6 @@
-
@@ -33,6 +32,7 @@
+
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs
index d985c46f3eac..ab716d47ad2d 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs
@@ -296,7 +296,7 @@ public void ChangeDefaultCredentialsPolicy(
Interop.WinHttp.WINHTTP_OPTION_AUTOLOGON_POLICY,
ref optionData))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@@ -365,7 +365,7 @@ private bool SetWinHttpCredential(
password,
IntPtr.Zero))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetCredentials));
}
return true;
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs
index 824d9cc776d2..5455255a4954 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs
@@ -61,7 +61,7 @@ public static void ResetCookieRequestHeaders(WinHttpRequestState state, Uri redi
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 @@ public static void ResetCookieRequestHeaders(WinHttpRequestState state, Uri redi
(uint)cookieHeader.Length,
Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
}
}
}
diff --git a/src/Common/src/System/Net/Http/WinHttpException.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpException.cs
similarity index 76%
rename from src/Common/src/System/Net/Http/WinHttpException.cs
rename to src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpException.cs
index d77e3471351f..bb7956762f62 100644
--- a/src/Common/src/System/Net/Http/WinHttpException.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpException.cs
@@ -3,6 +3,7 @@
// 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;
@@ -39,37 +40,41 @@ public static int ConvertErrorCodeToHR(int error)
}
}
- public static void ThrowExceptionUsingLastError()
+ public static void ThrowExceptionUsingLastError(string nameOfCalledFunction)
{
- throw CreateExceptionUsingLastError();
+ throw CreateExceptionUsingLastError(nameOfCalledFunction);
}
- public static WinHttpException CreateExceptionUsingLastError()
+ public static WinHttpException CreateExceptionUsingLastError(string nameOfCalledFunction)
{
int lastError = Marshal.GetLastWin32Error();
- return CreateExceptionUsingError(lastError);
+ return CreateExceptionUsingError(lastError, nameOfCalledFunction);
}
- public static WinHttpException CreateExceptionUsingError(int error)
+ public static WinHttpException CreateExceptionUsingError(int error, string nameOfCalledFunction)
{
- var e = new WinHttpException(error, GetErrorMessage(error));
+ var e = new WinHttpException(error, GetErrorMessage(error, nameOfCalledFunction));
ExceptionStackTrace.AddCurrentStack(e);
return e;
}
- public static WinHttpException CreateExceptionUsingError(int error, Exception innerException)
+ public static WinHttpException CreateExceptionUsingError(int error, string nameOfCalledFunction, Exception innerException)
{
- var e = new WinHttpException(error, GetErrorMessage(error), innerException);
+ var e = new WinHttpException(error, GetErrorMessage(error, nameOfCalledFunction), innerException);
ExceptionStackTrace.AddCurrentStack(e);
return e;
}
- public static string GetErrorMessage(int error)
+ 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);
- return Interop.Kernel32.GetMessage(moduleHandle, error);
+ string httpError = Interop.Kernel32.GetMessage(moduleHandle, error);
+
+ return SR.Format(SR.net_http_winhttp_error, error, nameOfCalledFunction, httpError);
}
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
index 4b6447aa3efc..65ae9c528a9c 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
@@ -661,7 +661,7 @@ private static void AddRequestHeaders(
(uint)requestHeadersBuffer.Length,
Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
}
}
@@ -728,7 +728,7 @@ private void EnsureSessionHandleExists(WinHttpRequestState state)
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 +741,7 @@ private void EnsureSessionHandleExists(WinHttpRequestState state)
_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 +757,7 @@ private void EnsureSessionHandleExists(WinHttpRequestState state)
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 +788,7 @@ private async void StartRequest(WinHttpRequestState state)
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 +821,7 @@ private async void StartRequest(WinHttpRequestState state)
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.
@@ -957,7 +957,7 @@ private void SetSessionHandleTimeoutOptions(SafeWinHttpHandle sessionHandle)
(int)_sendTimeout.TotalMilliseconds,
(int)_receiveHeadersTimeout.TotalMilliseconds))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetTimeouts));
}
}
@@ -1214,7 +1214,7 @@ private void SetWinHttpOption(SafeWinHttpHandle handle, uint option, ref uint op
option,
ref optionData))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@@ -1227,7 +1227,7 @@ private void SetWinHttpOption(SafeWinHttpHandle handle, uint option, string opti
optionData,
(uint)optionData.Length))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@@ -1244,7 +1244,7 @@ private static void SetWinHttpOption(
optionData,
optionSize))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@@ -1314,18 +1314,18 @@ private void SetStatusCallback(
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);
}
}
@@ -1343,11 +1343,13 @@ private RendezvousAwaitable InternalSendRequestAsync(WinHttpRequestState st
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));
}
}
@@ -1371,7 +1373,7 @@ private RendezvousAwaitable InternalReceiveResponseHeadersAsync(WinHttpRequ
{
if (!Interop.WinHttp.WinHttpReceiveResponse(state.RequestHandle, IntPtr.Zero))
{
- throw WinHttpException.CreateExceptionUsingLastError();
+ throw WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReceiveResponse));
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
index ca3cf65d6ca1..4d2a9896670a 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
@@ -110,8 +110,19 @@ private static void RequestCallback(
}
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();
+ }
}
}
@@ -260,7 +271,7 @@ private static void OnRequestSendingRequest(WinHttpRequestState state)
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.
@@ -295,7 +306,7 @@ private static void OnRequestSendingRequest(WinHttpRequestState state)
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
{
@@ -310,7 +321,7 @@ private static void OnRequestSendingRequest(WinHttpRequestState state)
if (!result)
{
throw WinHttpException.CreateExceptionUsingError(
- (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE);
+ (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, "ServerCertificateValidationCallback");
}
}
}
@@ -321,7 +332,7 @@ private static void OnRequestError(WinHttpRequestState state, Interop.WinHttp.WI
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()))
{
@@ -424,7 +435,7 @@ private static void ResetAuthRequestHeaders(WinHttpRequestState state)
int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
{
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, "WINHTTP_CALLBACK_STATUS_REDIRECT/WinHttpAddRequestHeaders");
}
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs
index a1fc3aef658a..034fc564274d 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs
@@ -249,7 +249,7 @@ private Task InternalWriteDataAsync(byte[] buffer, int offset, int count,
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))));
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs
index bc6ff3f10353..18e655f06bd3 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs
@@ -127,7 +127,7 @@ public static uint GetResponseHeaderNumberInfo(SafeWinHttpHandle requestHandle,
ref resultSize,
IntPtr.Zero))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
return result;
@@ -189,7 +189,7 @@ public static unsafe bool GetResponseHeader(
return GetResponseHeader(requestHandle, infoLevel, ref buffer, ref index, out headerValue);
}
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
///
@@ -216,7 +216,7 @@ private static unsafe int GetResponseHeader(SafeWinHttpHandle requestHandle, uin
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 @@ private static unsafe int GetResponseHeaderCharBufferLength(SafeWinHttpHandle re
if (lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER)
{
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs
index 2c3af3458ca1..a6aa8e444865 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs
@@ -121,7 +121,7 @@ private async Task CopyToAsyncCore(Stream destination, byte[] buffer, Cancellati
{
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 @@ private async Task CopyToAsyncCore(Stream destination, byte[] buffer, Cancellati
{
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 @@ private async Task ReadAsyncCore(byte[] buffer, int offset, int count, Canc
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 @@ private async Task ReadAsyncCore(byte[] buffer, int offset, int count, Canc
(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)));
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs
index 07aaa39f8422..5e2ff60b43b6 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs
@@ -138,14 +138,14 @@ public static void TraceAsyncError(string message, Interop.WinHttp.WINHTTP_ASYNC
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)
diff --git a/src/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs b/src/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
index c15e68938663..cf5812a1d709 100644
--- a/src/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
+++ b/src/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
@@ -16,6 +16,8 @@
// 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 @@ public void SendAsync_SlowServerRespondsAfterDefaultReceiveTimeout_ThrowsHttpReq
}
}
+ [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(() => 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.
diff --git a/src/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj b/src/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj
index 871e66692ea7..31adaf06e11b 100644
--- a/src/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj
+++ b/src/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj
@@ -73,9 +73,6 @@
Common\System\Net\Http\NoWriteNoSeekStreamContent.cs
-
- Common\System\Net\Http\WinHttpException.cs
-
Common\System\Net\Security\CertificateHelper.cs
@@ -103,6 +100,9 @@
ProductionCode\WinHttpCookieContainerAdapter.cs
+
+ ProductionCode\WinHttpException.cs
+
ProductionCode\WinHttpHandler.cs
diff --git a/src/System.Net.Http/src/Resources/Strings.resx b/src/System.Net.Http/src/Resources/Strings.resx
index c75d0a9adef6..b8cdb1d8a1d5 100644
--- a/src/System.Net.Http/src/Resources/Strings.resx
+++ b/src/System.Net.Http/src/Resources/Strings.resx
@@ -399,6 +399,9 @@
CONNECT request must contain Host header.
+
+ Error {0} calling {1}, '{2}'.
+
This method is not implemented by this class.
diff --git a/src/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj
index 33dc3a78fdfa..cd2b2c90c225 100644
--- a/src/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj
+++ b/src/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj
@@ -373,6 +373,9 @@
ProductionCode\System\Net\Http\HttpSystemProxy.cs
+
+ ProductionCode\System\Net\Http\WinHttpException.cs
+
ProductionCode\System\Net\Http\WinInetProxyHelper.cs
@@ -394,9 +397,6 @@
Common\Interop\Windows\winhttp\Interop.SafeWinHttpHandle.cs
-
- Common\System\Net\Http\WinHttpException.cs
-
Common\System\Runtime\ExceptionServices\ExceptionStackTrace.cs