Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: automatic decompression of response content #857

Merged
merged 2 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project does adheres to [Semantic Versioning](https://semver.org/spec/v

## [Unreleased]

## [3.1.14] - 2024-07-23

### Changed

- Obsoletes custom decompression handler in favor of native client capabilities at https://github.com/microsoft/kiota-dotnet/pull/303

## [3.1.12] - 2024-07-03

### Changed
Expand Down
20 changes: 10 additions & 10 deletions src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<AssemblyOriginatorKeyFile>35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<!-- x-release-please-start-version -->
<VersionPrefix>3.1.13</VersionPrefix>
<VersionPrefix>3.1.14</VersionPrefix>
<!-- x-release-please-end -->
<!-- VersionPrefix minor version should not be set when the change comes from the generator. It will be updated automatically. -->
<!-- VersionPrefix minor version must be manually set when making manual changes to code. -->
Expand All @@ -38,7 +38,7 @@
<EnableNETAnalyzers>True</EnableNETAnalyzers>
<PackageReadmeFile>README.md</PackageReadmeFile>
<NoWarn>NU5048;NETSDK1202</NoWarn>
<IsTrimmable>true</IsTrimmable>
<IsTrimmable Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)','net5.0'))">true</IsTrimmable>
</PropertyGroup>
<!-- https://github.com/clairernovotny/DeterministicBuilds#deterministic-builds -->
<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
Expand All @@ -62,15 +62,15 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="7.6.2" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.0.1" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.Kiota.Abstractions" Version="[1.9.6, 2.0.0)" />
<PackageReference Include="Microsoft.Kiota.Authentication.Azure" Version="[1.1.7, 2.0.0)" />
<PackageReference Include="Microsoft.Kiota.Serialization.Json" Version="[1.3.3, 2.0.0)" />
<PackageReference Include="Microsoft.Kiota.Serialization.Text" Version="[1.2.2, 2.0.0)" />
<PackageReference Include="Microsoft.Kiota.Serialization.Form" Version="[1.2.5, 2.0.0)" />
<PackageReference Include="Microsoft.Kiota.Http.HttpClientLibrary" Version="[1.4.3, 2.0.0)" />
<PackageReference Include="Microsoft.Kiota.Serialization.Multipart" Version="[1.1.5, 2.0.0)" />
<PackageReference Include="Microsoft.Kiota.Abstractions" Version="1.9.11" />
<PackageReference Include="Microsoft.Kiota.Authentication.Azure" Version="1.9.11" />
<PackageReference Include="Microsoft.Kiota.Serialization.Json" Version="1.9.11" />
<PackageReference Include="Microsoft.Kiota.Serialization.Text" Version="1.9.11" />
<PackageReference Include="Microsoft.Kiota.Serialization.Form" Version="1.9.11" />
<PackageReference Include="Microsoft.Kiota.Http.HttpClientLibrary" Version="1.9.11" />
<PackageReference Include="Microsoft.Kiota.Serialization.Multipart" Version="1.9.11" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net462' ">
<PackageReference Include="System.Net.Http.WinHttpHandler" Version="[6.0,9.0)" />
Expand Down
43 changes: 14 additions & 29 deletions src/Microsoft.Graph.Core/Requests/GraphClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,6 @@ public static IList<DelegatingHandler> CreateDefaultHandlers(GraphClientOptions
var handlers = KiotaClientFactory.CreateDefaultHandlers();
handlers.Add(new GraphTelemetryHandler(graphClientOptions));// add the telemetry handler last.

// TODO remove this once https://github.com/microsoft/kiota/issues/598 is closed.
handlers.Insert(0, new CompressionHandler());

return handlers;
}

Expand Down Expand Up @@ -173,20 +170,6 @@ internal static (HttpMessageHandler Pipeline, FeatureFlag FeatureFlags) CreatePi
throw new ArgumentNullException(nameof(handlers), "DelegatingHandler array contains null item.");
}

#if IOS || MACOS || MACCATALYST
#if IOS || MACCATALYST
// Skip CompressionHandler since NSUrlSessionHandler automatically handles decompression on iOS and macOS and it can't be turned off.
// See issue https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/481 for more details.
if (finalHandler.GetType().Equals(typeof(NSUrlSessionHandler)) && handler.GetType().Equals(typeof(CompressionHandler)))
#elif MACOS
if (finalHandler.GetType().Equals(typeof(Foundation.NSUrlSessionHandler)) && handler.GetType().Equals(typeof(CompressionHandler)))
#endif
{
// Skip chaining of CompressionHandler.
continue;
}
#endif

// Check for duplicate handler by type.
if (!existingHandlerTypes.Add(handler.GetType()))
{
Expand Down Expand Up @@ -220,17 +203,17 @@ internal static HttpMessageHandler GetNativePlatformHttpHandler(IWebProxy proxy
#elif MACOS
return new Foundation.NSUrlSessionHandler { AllowAutoRedirect = false };
#elif ANDROID
return new Xamarin.Android.Net.AndroidMessageHandler { Proxy = proxy, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.None };
return new Xamarin.Android.Net.AndroidMessageHandler { Proxy = proxy, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.All };
#elif NETFRAMEWORK
// If custom proxy is passed, the WindowsProxyUsePolicy will need updating
// https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs#L575
var proxyPolicy = proxy != null ? WindowsProxyUsePolicy.UseCustomProxy : WindowsProxyUsePolicy.UseWinHttpProxy;
return new WinHttpHandler { Proxy = proxy, AutomaticDecompression = DecompressionMethods.None , WindowsProxyUsePolicy = proxyPolicy, SendTimeout = Timeout.InfiniteTimeSpan, ReceiveDataTimeout = Timeout.InfiniteTimeSpan, ReceiveHeadersTimeout = Timeout.InfiniteTimeSpan };
return new WinHttpHandler { Proxy = proxy, AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate , WindowsProxyUsePolicy = proxyPolicy, SendTimeout = Timeout.InfiniteTimeSpan, ReceiveDataTimeout = Timeout.InfiniteTimeSpan, ReceiveHeadersTimeout = Timeout.InfiniteTimeSpan };
#elif NET6_0_OR_GREATER
//use resilient configs when we can https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0#alternatives-to-ihttpclientfactory-1
return new SocketsHttpHandler { Proxy = proxy, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.None, PooledConnectionLifetime = TimeSpan.FromMinutes(1)};
return new SocketsHttpHandler { Proxy = proxy, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.All, PooledConnectionLifetime = TimeSpan.FromMinutes(1)};
#else
return new HttpClientHandler { Proxy = proxy, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.None };
return new HttpClientHandler { Proxy = proxy, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate };
#endif
}

Expand All @@ -241,14 +224,16 @@ internal static HttpMessageHandler GetNativePlatformHttpHandler(IWebProxy proxy
/// <returns>Delegating handler feature flag.</returns>
private static FeatureFlag GetHandlerFeatureFlag(DelegatingHandler delegatingHandler)
{
if (delegatingHandler is CompressionHandler)
return FeatureFlag.CompressionHandler;
else if (delegatingHandler is RetryHandler)
return FeatureFlag.RetryHandler;
else if (delegatingHandler is RedirectHandler)
return FeatureFlag.RedirectHandler;
else
return FeatureFlag.None;
return delegatingHandler switch
{
// Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
CompressionHandler => FeatureFlag.CompressionHandler,
#pragma warning restore CS0618 // Type or member is obsolete
RetryHandler => FeatureFlag.RetryHandler,
RedirectHandler => FeatureFlag.RedirectHandler,
_ => FeatureFlag.None
};
}

private static Uri DetermineBaseAddress(string nationalCloud, string version)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ public void Should_CreatePipeline_Without_CompressionHandler()
[Fact]
public void Should_CreatePipeline_Without_HttpMessageHandlerInput()
{
using CompressionHandler compressionHandler = (CompressionHandler)GraphClientFactory.CreatePipeline(handlers, new MockRedirectHandler());
using UriReplacementHandler<UriReplacementHandlerOption> uriReplacementHandler = (UriReplacementHandler<UriReplacementHandlerOption>)compressionHandler.InnerHandler;
using UriReplacementHandler<UriReplacementHandlerOption> uriReplacementHandler = (UriReplacementHandler<UriReplacementHandlerOption>)GraphClientFactory.CreatePipeline(handlers, new MockRedirectHandler());
using RetryHandler retryHandler = (RetryHandler)uriReplacementHandler.InnerHandler;
using RedirectHandler redirectHandler = (RedirectHandler)retryHandler.InnerHandler;
using ParametersNameDecodingHandler odataQueryHandler = (ParametersNameDecodingHandler)redirectHandler.InnerHandler;
Expand All @@ -83,14 +82,12 @@ public void Should_CreatePipeline_Without_HttpMessageHandlerInput()
Assert.NotNull(userAgentHandler);
Assert.NotNull(headersInspectionHandler);
Assert.NotNull(odataQueryHandler);
Assert.NotNull(compressionHandler);
Assert.NotNull(retryHandler);
Assert.NotNull(redirectHandler);
Assert.NotNull(innerMost);
Assert.IsType<GraphTelemetryHandler>(telemetryHandler);
Assert.IsType<ParametersNameDecodingHandler>(odataQueryHandler);
Assert.IsType<HeadersInspectionHandler>(headersInspectionHandler);
Assert.IsType<CompressionHandler>(compressionHandler);
Assert.IsType<UserAgentHandler>(userAgentHandler);
Assert.IsType<RetryHandler>(retryHandler);
Assert.IsType<RedirectHandler>(redirectHandler);
Expand All @@ -101,8 +98,7 @@ public void Should_CreatePipeline_Without_HttpMessageHandlerInput()
[Fact]
public void CreatePipelineWithHttpMessageHandlerInput()
{
using CompressionHandler compressionHandler = (CompressionHandler)GraphClientFactory.CreatePipeline(handlers, new MockRedirectHandler());
using UriReplacementHandler<UriReplacementHandlerOption> uriReplacementHandler = (UriReplacementHandler<UriReplacementHandlerOption>)compressionHandler.InnerHandler;
using UriReplacementHandler<UriReplacementHandlerOption> uriReplacementHandler = (UriReplacementHandler<UriReplacementHandlerOption>)GraphClientFactory.CreatePipeline(handlers, new MockRedirectHandler());
using RetryHandler retryHandler = (RetryHandler)uriReplacementHandler.InnerHandler;
using RedirectHandler redirectHandler = (RedirectHandler)retryHandler.InnerHandler;
using ParametersNameDecodingHandler odataQueryHandler = (ParametersNameDecodingHandler)redirectHandler.InnerHandler;
Expand All @@ -115,14 +111,12 @@ public void CreatePipelineWithHttpMessageHandlerInput()
Assert.NotNull(userAgentHandler);
Assert.NotNull(headersInspectionHandler);
Assert.NotNull(odataQueryHandler);
Assert.NotNull(compressionHandler);
Assert.NotNull(retryHandler);
Assert.NotNull(redirectHandler);
Assert.NotNull(innerMost);
Assert.IsType<GraphTelemetryHandler>(telemetryHandler);
Assert.IsType<ParametersNameDecodingHandler>(odataQueryHandler);
Assert.IsType<HeadersInspectionHandler>(headersInspectionHandler);
Assert.IsType<CompressionHandler>(compressionHandler);
Assert.IsType<RetryHandler>(retryHandler);
Assert.IsType<UserAgentHandler>(userAgentHandler);
Assert.IsType<RedirectHandler>(redirectHandler);
Expand All @@ -143,11 +137,11 @@ public void CreatePipelineWithoutPipeline()
public void CreatePipeline_Should_Throw_Exception_With_Duplicate_Handlers()
{
var handlers = GraphClientFactory.CreateDefaultHandlers();
handlers.Add(new CompressionHandler());
handlers.Add(new GraphTelemetryHandler());

ArgumentException exception = Assert.Throws<ArgumentException>(() => GraphClientFactory.CreatePipeline(handlers));

Assert.Contains($"{typeof(CompressionHandler)} has a duplicate handler.", exception.Message);
Assert.Contains($"{typeof(GraphTelemetryHandler)} has a duplicate handler.", exception.Message);
}

[Fact]
Expand Down Expand Up @@ -281,7 +275,7 @@ public void CreateClient_WithInnerHandlerReference()
[Fact]
public void CreatePipelineWithFeatureFlags_Should_Set_FeatureFlag_For_Default_Handlers()
{
FeatureFlag expectedFlag = FeatureFlag.CompressionHandler | FeatureFlag.RetryHandler | FeatureFlag.RedirectHandler;
FeatureFlag expectedFlag = FeatureFlag.RetryHandler | FeatureFlag.RedirectHandler;
string expectedFlagHeaderValue = Enum.Format(typeof(FeatureFlag), expectedFlag, "x");
var handlers = GraphClientFactory.CreateDefaultHandlers();
var pipelineWithHandlers = GraphClientFactory.CreatePipelineWithFeatureFlags(handlers);
Expand All @@ -293,7 +287,7 @@ public void CreatePipelineWithFeatureFlags_Should_Set_FeatureFlag_For_Default_Ha
[Fact]
public void CreatePipelineWithFeatureFlags_Should_Set_FeatureFlag_For_Speficied_Handlers()
{
FeatureFlag expectedFlag = FeatureFlag.CompressionHandler | FeatureFlag.RetryHandler;
FeatureFlag expectedFlag = FeatureFlag.RetryHandler;
var handlers = GraphClientFactory.CreateDefaultHandlers();
//Exclude the redirect handler for this test
handlers = handlers.Where(handler => !handler.GetType().Equals(typeof(RedirectHandler))).ToList();
Expand Down