Skip to content
This repository has been archived by the owner on Jul 9, 2024. It is now read-only.

Commit

Permalink
- further linting
Browse files Browse the repository at this point in the history
  • Loading branch information
baywet committed Oct 20, 2023
1 parent b99525c commit 8ba8490
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ private async Task DelayTestWithMessage(HttpResponseMessage response, int count,
Message = message;
await Task.Run(async () =>
{
await this._retryHandler.Delay(response, count, delay, out _, new CancellationToken());
await RetryHandler.Delay(response, count, delay, out _, new CancellationToken());
Message += " Work " + count;
});
}
Expand Down
8 changes: 7 additions & 1 deletion src/Extensions/HttpRequestMessageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Abstractions.Extensions;
Expand Down Expand Up @@ -40,11 +41,12 @@ public static class HttpRequestMessageExtensions
/// Create a new HTTP request by copying previous HTTP request's headers and properties from response's request message.
/// </summary>
/// <param name="originalRequest">The previous <see cref="HttpRequestMessage"/> needs to be copy.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the request.</param>
/// <returns>The <see cref="HttpRequestMessage"/>.</returns>
/// <remarks>
/// Re-issue a new HTTP request with the previous request's headers and properties
/// </remarks>
internal static async Task<HttpRequestMessage> CloneAsync(this HttpRequestMessage originalRequest)
internal static async Task<HttpRequestMessage> CloneAsync(this HttpRequestMessage originalRequest, CancellationToken cancellationToken = default)
{
var newRequest = new HttpRequestMessage(originalRequest.Method, originalRequest.RequestUri);

Expand All @@ -68,7 +70,11 @@ internal static async Task<HttpRequestMessage> CloneAsync(this HttpRequestMessag
if(originalRequest.Content != null)
{
// HttpClient doesn't rewind streams and we have to explicitly do so.
#if NET5_0_OR_GREATER
var contentStream = await originalRequest.Content.ReadAsStreamAsync(cancellationToken);
#else
var contentStream = await originalRequest.Content.ReadAsStreamAsync();
#endif

if(contentStream.CanSeek)
contentStream.Seek(0, SeekOrigin.Begin);
Expand Down
20 changes: 15 additions & 5 deletions src/Middleware/CompressionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,20 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage

ActivitySource? activitySource;
Activity? activity;
if (request.GetRequestOption<ObservabilityOptions>() is ObservabilityOptions obsOptions) {
if(request.GetRequestOption<ObservabilityOptions>() is ObservabilityOptions obsOptions)
{
activitySource = new ActivitySource(obsOptions.TracerInstrumentationName);
activity = activitySource?.StartActivity($"{nameof(CompressionHandler)}_{nameof(SendAsync)}");

Check warning on line 39 in src/Middleware/CompressionHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Change this expression which always evaluates to the same result. (https://rules.sonarsource.com/csharp/RSPEC-2589)
activity?.SetTag("com.microsoft.kiota.handler.compression.enable", true);
} else {
}
else
{
activity = null;
activitySource = null;
}

try {
try
{

StringWithQualityHeaderValue gzipQHeaderValue = new StringWithQualityHeaderValue(GZip);

Expand All @@ -57,7 +61,11 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
// Decompress response content when Content-Encoding: gzip header is present.
if(ShouldDecompressContent(response))
{
StreamContent streamContent = new StreamContent(new GZipStream(await response.Content.ReadAsStreamAsync(), CompressionMode.Decompress));
#if NET5_0_OR_GREATER
StreamContent streamContent = new StreamContent(new GZipStream(await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false), CompressionMode.Decompress));
#else
StreamContent streamContent = new StreamContent(new GZipStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), CompressionMode.Decompress));
#endif
// Copy Content Headers to the destination stream content
foreach(var httpContentHeader in response.Content.Headers)
{
Expand All @@ -67,7 +75,9 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
}

return response;
} finally {
}
finally
{
activity?.Dispose();
activitySource?.Dispose();
}
Expand Down
26 changes: 18 additions & 8 deletions src/Middleware/RedirectHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Microsoft.Kiota.Http.HttpClientLibrary.Middleware
/// <summary>
/// A <see cref="DelegatingHandler"/> implementation for handling redirection of requests.
/// </summary>
public class RedirectHandler: DelegatingHandler
public class RedirectHandler : DelegatingHandler
{
/// <summary>
/// Constructs a new <see cref="RedirectHandler"/>
Expand Down Expand Up @@ -49,15 +49,19 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage

ActivitySource? activitySource;
Activity? activity;
if (request.GetRequestOption<ObservabilityOptions>() is ObservabilityOptions obsOptions) {
if(request.GetRequestOption<ObservabilityOptions>() is ObservabilityOptions obsOptions)
{
activitySource = new ActivitySource(obsOptions.TracerInstrumentationName);
activity = activitySource?.StartActivity($"{nameof(RedirectHandler)}_{nameof(SendAsync)}");
activity?.SetTag("com.microsoft.kiota.handler.redirect.enable", true);
} else {
}
else
{
activity = null;
activitySource = null;
}
try {
try
{

// send request first time to get response
var response = await base.SendAsync(request, cancellationToken);
Expand All @@ -82,16 +86,20 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
// Drain response content to free responses.
if(response.Content != null)
{
await response.Content.ReadAsByteArrayAsync();
#if NET5_0_OR_GREATER
await response.Content.ReadAsByteArrayAsync(cancellationToken).ConfigureAwait(false);
#else
await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
#endif
}

// general clone request with internal CloneAsync (see CloneAsync for details) extension method
var originalRequest = response.RequestMessage;
if (originalRequest == null)
if(originalRequest == null)
{
return response;// We can't clone the original request to replay it.
}
var newRequest = await originalRequest.CloneAsync();
var newRequest = await originalRequest.CloneAsync(cancellationToken);

// status code == 303: change request method from post to get and content to be null
if(response.StatusCode == HttpStatusCode.SeeOther)
Expand Down Expand Up @@ -145,7 +153,9 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
new Exception($"Max redirects exceeded. Redirect count : {redirectCount}"));
}
return response;
} finally {
}
finally
{
activity?.Dispose();
activitySource?.Dispose();
}
Expand Down
46 changes: 30 additions & 16 deletions src/Middleware/RetryHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,27 +55,33 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
var retryOption = request.GetRequestOption<RetryHandlerOption>() ?? RetryOption;
ActivitySource? activitySource;
Activity? activity;
if (request.GetRequestOption<ObservabilityOptions>() is ObservabilityOptions obsOptions) {
if(request.GetRequestOption<ObservabilityOptions>() is ObservabilityOptions obsOptions)
{
activitySource = new ActivitySource(obsOptions.TracerInstrumentationName);
activity = activitySource?.StartActivity($"{nameof(RetryHandler)}_{nameof(SendAsync)}");

Check warning on line 61 in src/Middleware/RetryHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Change this expression which always evaluates to the same result. (https://rules.sonarsource.com/csharp/RSPEC-2589)
activity?.SetTag("com.microsoft.kiota.handler.retry.enable", true);
} else {
}
else
{
activity = null;
activitySource = null;
}

try {
try
{

var response = await base.SendAsync(request, cancellationToken);
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Check whether retries are permitted and that the MaxRetry value is a non - negative, non - zero value
if(request.IsBuffered() && retryOption.MaxRetry > 0 && (ShouldRetry(response.StatusCode) || retryOption.ShouldRetry(retryOption.Delay, 0, response)))
{
response = await SendRetryAsync(response, retryOption, cancellationToken, activitySource);
response = await SendRetryAsync(response, retryOption, cancellationToken, activitySource).ConfigureAwait(false);
}

return response;
} finally {
}
finally
{
activity?.Dispose();
activitySource?.Dispose();
}
Expand All @@ -89,7 +95,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the retry.</param>
/// <param name="activitySource">The <see cref="ActivitySource"/> for the retry.</param>
/// <returns></returns>
private async Task<HttpResponseMessage> SendRetryAsync(HttpResponseMessage response,RetryHandlerOption retryOption, CancellationToken cancellationToken, ActivitySource? activitySource)
private async Task<HttpResponseMessage> SendRetryAsync(HttpResponseMessage response, RetryHandlerOption retryOption, CancellationToken cancellationToken, ActivitySource? activitySource)
{
int retryCount = 0;
TimeSpan cumulativeDelay = TimeSpan.Zero;
Expand All @@ -103,11 +109,15 @@ private async Task<HttpResponseMessage> SendRetryAsync(HttpResponseMessage respo
// before retry attempt and before the TooManyRetries ServiceException.
if(response.Content != null)
{
await response.Content.ReadAsByteArrayAsync();
#if NET5_0_OR_GREATER
await response.Content.ReadAsByteArrayAsync(cancellationToken).ConfigureAwait(false);
#else
await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
#endif
}

// Call Delay method to get delay time from response's Retry-After header or by exponential backoff
Task delay = Delay(response, retryCount, retryOption.Delay, out double delayInSeconds, cancellationToken);
Task delay = RetryHandler.Delay(response, retryCount, retryOption.Delay, out double delayInSeconds, cancellationToken);

// If client specified a retries time limit, let's honor it
if(retryOption.RetriesTimeLimit > TimeSpan.Zero)
Expand All @@ -128,7 +138,7 @@ private async Task<HttpResponseMessage> SendRetryAsync(HttpResponseMessage respo
{
return response;// We can't clone the original request to replay it.
}
var request = await originalRequest.CloneAsync();
var request = await originalRequest.CloneAsync(cancellationToken).ConfigureAwait(false);

// Increase retryCount and then update Retry-Attempt in request header
retryCount++;
Expand All @@ -138,7 +148,7 @@ private async Task<HttpResponseMessage> SendRetryAsync(HttpResponseMessage respo
await delay;

// Call base.SendAsync to send the request
response = await base.SendAsync(request, cancellationToken);
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);

if(!(request.IsBuffered() && (ShouldRetry(response.StatusCode) || retryOption.ShouldRetry(retryOption.Delay, retryCount, response))))
{
Expand All @@ -150,7 +160,11 @@ private async Task<HttpResponseMessage> SendRetryAsync(HttpResponseMessage respo
// before retry attempt and before the TooManyRetries ServiceException.
if(response.Content != null)
{
await response.Content.ReadAsByteArrayAsync();
#if NET5_0_OR_GREATER
await response.Content.ReadAsByteArrayAsync(cancellationToken).ConfigureAwait(false);
#else
await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
#endif
}

throw new InvalidOperationException(
Expand Down Expand Up @@ -181,22 +195,22 @@ private static void AddOrUpdateRetryAttempt(HttpRequestMessage request, int retr
/// <param name="delayInSeconds"></param>
/// <param name="cancellationToken">The cancellationToken for the Http request</param>
/// <returns>The <see cref="Task"/> for delay operation.</returns>
internal Task Delay(HttpResponseMessage response, int retryCount, int delay, out double delayInSeconds, CancellationToken cancellationToken)
internal static Task Delay(HttpResponseMessage response, int retryCount, int delay, out double delayInSeconds, CancellationToken cancellationToken)
{
delayInSeconds = delay;
if(response.Headers.TryGetValues(RetryAfter, out IEnumerable<string>? values))
{
string retryAfter = values.First();
// the delay could be in the form of a seconds or a http date. See https://httpwg.org/specs/rfc7231.html#header.retry-after
if(Int32.TryParse(retryAfter, out int delaySeconds))
if(int.TryParse(retryAfter, out int delaySeconds))
{
delayInSeconds = delaySeconds;
}
else if(DateTime.TryParseExact(retryAfter, CultureInfo.InvariantCulture.DateTimeFormat.RFC1123Pattern, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime))
{
var timeSpan = dateTime - DateTime.Now;
// ensure the delay is a positive span otherwise use the exponential back-off
delayInSeconds = timeSpan.Seconds > 0 ? timeSpan.Seconds: CalculateExponentialDelay(retryCount, delay);
delayInSeconds = timeSpan.Seconds > 0 ? timeSpan.Seconds : CalculateExponentialDelay(retryCount, delay);
}
}
else
Expand All @@ -205,7 +219,7 @@ internal Task Delay(HttpResponseMessage response, int retryCount, int delay, out
}

TimeSpan delayTimeSpan = TimeSpan.FromSeconds(Math.Min(delayInSeconds, RetryHandlerOption.MaxDelay));
delayInSeconds=delayTimeSpan.TotalSeconds;
delayInSeconds = delayTimeSpan.TotalSeconds;
return Task.Delay(delayTimeSpan, cancellationToken);
}

Expand Down

0 comments on commit 8ba8490

Please sign in to comment.