Skip to content

Commit bb09451

Browse files
authored
[WinHTTP] remove unnecessary manual decompression (#114778)
* Remove obsoleted manual decompression that existed only for already unsupported Win 8.1- * Remove obsolete unit tests
1 parent a596935 commit bb09451

File tree

5 files changed

+6
-218
lines changed

5 files changed

+6
-218
lines changed

src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ public class WinHttpHandler : HttpMessageHandler
4646
internal static bool CertificateCachingAppContextSwitchEnabled { get; } = AppContext.TryGetSwitch("System.Net.Http.UseWinHttpCertificateCaching", out bool enabled) && enabled;
4747
private static readonly TimeSpan s_maxTimeout = TimeSpan.FromMilliseconds(int.MaxValue);
4848

49-
private static readonly StringWithQualityHeaderValue s_gzipHeaderValue = new StringWithQualityHeaderValue("gzip");
50-
private static readonly StringWithQualityHeaderValue s_deflateHeaderValue = new StringWithQualityHeaderValue("deflate");
5149
private static readonly Lazy<bool> s_supportsTls13 = new Lazy<bool>(CheckTls13Support);
5250
private static readonly TimeSpan s_cleanCachedCertificateTimeout = TimeSpan.FromMilliseconds((int?)AppDomain.CurrentDomain.GetData("System.Net.Http.WinHttpCertificateCachingCleanupTimerInterval") ?? 60_000);
5351
private static readonly long s_staleTimeout = (long)(s_cleanCachedCertificateTimeout.TotalSeconds * Stopwatch.Frequency / 1000);
@@ -56,7 +54,6 @@ public class WinHttpHandler : HttpMessageHandler
5654
private static StringBuilder? t_requestHeadersBuilder;
5755

5856
private readonly object _lockObject = new object();
59-
private bool _doManualDecompressionCheck;
6057
private bool _automaticRedirection = HttpHandlerDefaults.DefaultAutomaticRedirection;
6158
private int _maxAutomaticRedirections = HttpHandlerDefaults.DefaultMaxAutomaticRedirections;
6259
private DecompressionMethods _automaticDecompression = HttpHandlerDefaults.DefaultAutomaticDecompression;
@@ -715,8 +712,7 @@ private static WinHttpChunkMode GetChunkedModeForSend(HttpRequestMessage request
715712
private static void AddRequestHeaders(
716713
SafeWinHttpHandle requestHandle,
717714
HttpRequestMessage requestMessage,
718-
CookieContainer? cookies,
719-
DecompressionMethods manuallyProcessedDecompressionMethods)
715+
CookieContainer? cookies)
720716
{
721717
Debug.Assert(requestMessage.RequestUri != null);
722718

@@ -732,26 +728,6 @@ private static void AddRequestHeaders(
732728
t_requestHeadersBuilder = requestHeadersBuffer = new StringBuilder();
733729
}
734730

735-
// Normally WinHttpHandler will let native WinHTTP add 'Accept-Encoding' request headers
736-
// for gzip and/or default as needed based on whether the handler should do automatic
737-
// decompression of response content. But on Windows 7, WinHTTP doesn't support this feature.
738-
// So, we need to manually add these headers since WinHttpHandler still supports automatic
739-
// decompression (by doing it within the handler).
740-
if (manuallyProcessedDecompressionMethods != DecompressionMethods.None)
741-
{
742-
if ((manuallyProcessedDecompressionMethods & DecompressionMethods.GZip) == DecompressionMethods.GZip &&
743-
!requestMessage.Headers.AcceptEncoding.Contains(s_gzipHeaderValue))
744-
{
745-
requestMessage.Headers.AcceptEncoding.Add(s_gzipHeaderValue);
746-
}
747-
748-
if ((manuallyProcessedDecompressionMethods & DecompressionMethods.Deflate) == DecompressionMethods.Deflate &&
749-
!requestMessage.Headers.AcceptEncoding.Contains(s_deflateHeaderValue))
750-
{
751-
requestMessage.Headers.AcceptEncoding.Add(s_deflateHeaderValue);
752-
}
753-
}
754-
755731
// Manually add cookies.
756732
if (cookies != null && cookies.Count > 0)
757733
{
@@ -941,8 +917,7 @@ private async Task StartRequestAsync(WinHttpRequestState state)
941917
AddRequestHeaders(
942918
state.RequestHandle,
943919
state.RequestMessage,
944-
_cookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer ? _cookieContainer : null,
945-
_doManualDecompressionCheck ? _automaticDecompression : DecompressionMethods.None);
920+
_cookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer ? _cookieContainer : null);
946921

947922
uint proxyAuthScheme = 0;
948923
uint serverAuthScheme = 0;
@@ -1027,8 +1002,7 @@ private async Task StartRequestAsync(WinHttpRequestState state)
10271002
uint optionData = (uint)(int)_receiveDataTimeout.TotalMilliseconds;
10281003
SetWinHttpOption(state.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_RECEIVE_TIMEOUT, ref optionData);
10291004

1030-
HttpResponseMessage responseMessage =
1031-
WinHttpResponseParser.CreateResponseMessage(state, _doManualDecompressionCheck ? _automaticDecompression : DecompressionMethods.None);
1005+
HttpResponseMessage responseMessage = WinHttpResponseParser.CreateResponseMessage(state);
10321006
state.Tcs.TrySetResult(responseMessage);
10331007

10341008
// HttpStatusCode cast is needed for 308 Moved Permenantly, which we support but is not included in NetStandard status codes.
@@ -1372,22 +1346,7 @@ private void SetRequestHandleDecompressionOptions(SafeWinHttpHandle requestHandl
13721346
optionData |= Interop.WinHttp.WINHTTP_DECOMPRESSION_FLAG_DEFLATE;
13731347
}
13741348

1375-
try
1376-
{
1377-
SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_DECOMPRESSION, ref optionData);
1378-
}
1379-
catch (WinHttpException ex)
1380-
{
1381-
if (ex.NativeErrorCode != (int)Interop.WinHttp.ERROR_WINHTTP_INVALID_OPTION)
1382-
{
1383-
throw;
1384-
}
1385-
1386-
// We are running on a platform earlier than Win8.1 for which WINHTTP.DLL
1387-
// doesn't support this option. So, we'll have to do the decompression
1388-
// manually.
1389-
_doManualDecompressionCheck = true;
1390-
}
1349+
SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_DECOMPRESSION, ref optionData);
13911350
}
13921351
}
13931352

src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,7 @@ namespace System.Net.Http
1515
{
1616
internal static class WinHttpResponseParser
1717
{
18-
private const string EncodingNameDeflate = "DEFLATE";
19-
private const string EncodingNameGzip = "GZIP";
20-
21-
public static HttpResponseMessage CreateResponseMessage(
22-
WinHttpRequestState state,
23-
DecompressionMethods manuallyProcessedDecompressionMethods)
18+
public static HttpResponseMessage CreateResponseMessage(WinHttpRequestState state)
2419
{
2520
HttpRequestMessage? request = state.RequestMessage;
2621
SafeWinHttpHandle? requestHandle = state.RequestHandle;
@@ -65,35 +60,7 @@ public static HttpResponseMessage CreateResponseMessage(
6560
// Create response stream and wrap it in a StreamContent object.
6661
var responseStream = new WinHttpResponseStream(requestHandle, state, response);
6762
state.RequestHandle = null; // ownership successfully transferred to WinHttpResponseStream.
68-
Stream decompressedStream = responseStream;
69-
70-
if (manuallyProcessedDecompressionMethods != DecompressionMethods.None)
71-
{
72-
int contentEncodingStartIndex = 0;
73-
int contentEncodingLength = GetResponseHeader(
74-
requestHandle,
75-
Interop.WinHttp.WINHTTP_QUERY_CONTENT_ENCODING,
76-
buffer);
77-
78-
ReadOnlySpan<char> value = new ReadOnlySpan<char>(buffer, contentEncodingStartIndex, contentEncodingLength).Trim();
79-
if (!value.IsEmpty)
80-
{
81-
if ((manuallyProcessedDecompressionMethods & DecompressionMethods.GZip) == DecompressionMethods.GZip &&
82-
value.Equals(EncodingNameGzip.AsSpan(), StringComparison.OrdinalIgnoreCase))
83-
{
84-
decompressedStream = new GZipStream(responseStream, CompressionMode.Decompress);
85-
stripEncodingHeaders = true;
86-
}
87-
else if ((manuallyProcessedDecompressionMethods & DecompressionMethods.Deflate) == DecompressionMethods.Deflate &&
88-
value.Equals(EncodingNameDeflate.AsSpan(), StringComparison.OrdinalIgnoreCase))
89-
{
90-
decompressedStream = new DeflateStream(responseStream, CompressionMode.Decompress);
91-
stripEncodingHeaders = true;
92-
}
93-
}
94-
}
95-
96-
response.Content = new NoWriteNoSeekStreamContent(decompressedStream);
63+
response.Content = new NoWriteNoSeekStreamContent(responseStream);
9764
response.RequestMessage = request;
9865

9966
// Parse raw response headers and place them into response message.

src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/FakeInterop.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -474,12 +474,6 @@ public static bool WinHttpSetOption(
474474
ref uint optionData,
475475
uint optionLength = sizeof(uint))
476476
{
477-
if (option == Interop.WinHttp.WINHTTP_OPTION_DECOMPRESSION & !TestControl.WinHttpDecompressionSupport)
478-
{
479-
TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_WINHTTP_INVALID_OPTION;
480-
return false;
481-
}
482-
483477
if (option == Interop.WinHttp.WINHTTP_OPTION_DISABLE_FEATURE &&
484478
optionData == Interop.WinHttp.WINHTTP_DISABLE_COOKIES)
485479
{

src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/TestControl.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ public static class TestControl
1717

1818
public static int LastWin32Error { get; set; }
1919

20-
public static bool WinHttpDecompressionSupport { get; set; }
21-
2220
public static bool PACFileNotDetectedOnNetwork { get; set; }
2321

2422
public static X509Certificate2Collection CurrentUserCertificateStore{ get; set; }
@@ -31,8 +29,6 @@ public static void Reset()
3129
WinHttpReceiveResponse = new ApiControl();
3230
WinHttpWriteData = new ApiControl();
3331

34-
WinHttpDecompressionSupport = true;
35-
3632
LastWin32Error = 0;
3733

3834
PACFileNotDetectedOnNetwork = false;

src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs

Lines changed: 0 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -687,100 +687,6 @@ public async Task SendAsync_PostNoContentObjectWithChunkedEncodingHeader_ExpectH
687687
}
688688
}
689689

690-
[Fact]
691-
public async Task SendAsync_NoWinHttpDecompressionSupportAndResponseBodyIsDeflateCompressed_ExpectedResponse()
692-
{
693-
TestControl.WinHttpDecompressionSupport = false;
694-
var handler = new WinHttpHandler();
695-
696-
using (HttpResponseMessage response = SendRequestHelper.Send(
697-
handler,
698-
delegate
699-
{
700-
handler.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
701-
TestServer.SetResponse(DecompressionMethods.Deflate, TestServer.ExpectedResponseBody);
702-
}))
703-
{
704-
await VerifyResponseContent(
705-
TestServer.ExpectedResponseBodyBytes,
706-
response.Content,
707-
responseContentWasOriginallyCompressed: true,
708-
responseContentWasAutoDecompressed: true);
709-
}
710-
}
711-
712-
[Fact]
713-
public async Task SendAsync_NoWinHttpDecompressionSupportAndResponseBodyIsGZipCompressed_ExpectedResponse()
714-
{
715-
TestControl.WinHttpDecompressionSupport = false;
716-
var handler = new WinHttpHandler();
717-
718-
using (HttpResponseMessage response = SendRequestHelper.Send(
719-
handler,
720-
delegate
721-
{
722-
handler.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
723-
TestServer.SetResponse(DecompressionMethods.GZip, TestServer.ExpectedResponseBody);
724-
}))
725-
{
726-
await VerifyResponseContent(
727-
TestServer.ExpectedResponseBodyBytes,
728-
response.Content,
729-
responseContentWasOriginallyCompressed: true,
730-
responseContentWasAutoDecompressed: true);
731-
}
732-
}
733-
734-
[Fact]
735-
public async Task SendAsync_NoWinHttpDecompressionSupportAndResponseBodyIsNotCompressed_ExpectedResponse()
736-
{
737-
TestControl.WinHttpDecompressionSupport = false;
738-
var handler = new WinHttpHandler();
739-
740-
using (HttpResponseMessage response = SendRequestHelper.Send(
741-
handler,
742-
delegate
743-
{
744-
handler.WindowsProxyUsePolicy = WindowsProxyUsePolicy.UseWinInetProxy;
745-
}))
746-
{
747-
await VerifyResponseContent(
748-
TestServer.ExpectedResponseBodyBytes,
749-
response.Content,
750-
responseContentWasOriginallyCompressed: false,
751-
responseContentWasAutoDecompressed: false);
752-
753-
}
754-
}
755-
756-
[Theory]
757-
[InlineData(false)]
758-
[InlineData(true)]
759-
public async Task SendAsync_NoWinHttpDecompressionSupport_AutoDecompressionSettingDiffers_ResponseIsNotDecompressed(bool responseIsGZip)
760-
{
761-
DecompressionMethods decompressionMethods = responseIsGZip ? DecompressionMethods.Deflate : DecompressionMethods.GZip;
762-
_output.WriteLine("DecompressionMethods = {0}", decompressionMethods.ToString());
763-
764-
TestControl.WinHttpDecompressionSupport = false;
765-
var handler = new WinHttpHandler();
766-
767-
using (HttpResponseMessage response = SendRequestHelper.Send(
768-
handler,
769-
delegate
770-
{
771-
handler.AutomaticDecompression = decompressionMethods;
772-
TestServer.SetResponse(responseIsGZip ? DecompressionMethods.GZip : DecompressionMethods.Deflate, TestServer.ExpectedResponseBody);
773-
}))
774-
{
775-
await VerifyResponseContent(
776-
TestServer.CompressBytes(TestServer.ExpectedResponseBodyBytes, useGZip: responseIsGZip),
777-
response.Content,
778-
responseContentWasOriginallyCompressed: true,
779-
responseContentWasAutoDecompressed: false);
780-
781-
}
782-
}
783-
784690
[Fact]
785691
public void SendAsync_AutomaticProxySupportAndUseWinInetSettings_ExpectedWinHttpSessionProxySettings()
786692
{
@@ -931,40 +837,6 @@ public void SendAsync_MultipleCallsWithDispose_NoHandleLeaksManuallyVerifiedUsin
931837
}
932838
}
933839

934-
private async Task VerifyResponseContent(
935-
byte[] expectedResponseBodyBytes,
936-
HttpContent responseContent,
937-
bool responseContentWasOriginallyCompressed,
938-
bool responseContentWasAutoDecompressed)
939-
{
940-
Nullable<long> contentLength = responseContent.Headers.ContentLength;
941-
ICollection<string> contentEncoding = responseContent.Headers.ContentEncoding;
942-
943-
_output.WriteLine("Response Content.Headers.ContentLength = {0}", contentLength.HasValue ? contentLength.Value.ToString() : "(null)");
944-
_output.WriteLine("Response Content.Headers.ContentEncoding = {0}", contentEncoding.Count > 0 ? contentEncoding.ToString() : "(null)");
945-
byte[] responseBodyBytes = await responseContent.ReadAsByteArrayAsync();
946-
_output.WriteLine($"Response Body = {BitConverter.ToString(responseBodyBytes)}");
947-
_output.WriteLine($"Expected Response Body = {BitConverter.ToString(expectedResponseBodyBytes)}");
948-
949-
if (!responseContentWasOriginallyCompressed)
950-
{
951-
Assert.True(contentLength > 0);
952-
}
953-
else if (responseContentWasAutoDecompressed)
954-
{
955-
956-
Assert.Null(contentLength);
957-
Assert.Equal(0, contentEncoding.Count);
958-
}
959-
else
960-
{
961-
Assert.True(contentLength > 0);
962-
Assert.True(contentEncoding.Count > 0);
963-
}
964-
965-
Assert.Equal<byte>(expectedResponseBodyBytes, responseBodyBytes);
966-
}
967-
968840
// Commented out as the test relies on finalizer for cleanup and only has value as written
969841
// when run on its own and manual analysis is done of logs.
970842
//[Fact]

0 commit comments

Comments
 (0)