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

Use RawHttpMessageHandler and VssHttpRetryMessageHandler in ResultsHttpClient #2908

Merged
merged 5 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
25 changes: 23 additions & 2 deletions src/Runner.Common/ResultsServer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.WebSockets;
using System.Security;
Expand Down Expand Up @@ -52,8 +53,8 @@ public sealed class ResultServer : RunnerService, IResultsServer

public void InitializeResultsClient(Uri uri, string liveConsoleFeedUrl, string token)
{
var httpMessageHandler = HostContext.CreateHttpClientHandler();
this._resultsClient = new ResultsHttpClient(uri, httpMessageHandler, token, disposeHandler: true);
this._resultsClient = CreateHttpClient(uri, token);
yacaovsnc marked this conversation as resolved.
Show resolved Hide resolved

_token = token;
if (!string.IsNullOrEmpty(liveConsoleFeedUrl))
{
Expand All @@ -62,6 +63,26 @@ public void InitializeResultsClient(Uri uri, string liveConsoleFeedUrl, string t
}
}

public ResultsHttpClient CreateHttpClient(Uri uri, string token)
{
// Using default 100 timeout
RawClientHttpRequestSettings settings = VssUtil.GetHttpRequestSettings(null);

// Create retry handler
IEnumerable<DelegatingHandler> delegatingHandlers = new List<DelegatingHandler>();
if (settings.MaxRetryRequest > 0)
{
delegatingHandlers = new DelegatingHandler[] { new VssHttpRetryMessageHandler(settings.MaxRetryRequest) };
}

// Setup RawHttpMessageHandler without credentials
var httpMessageHandler = new RawHttpMessageHandler(new NoOpCredentials(null), settings);

var pipeline = HttpClientFactory.CreatePipeline(httpMessageHandler, delegatingHandlers);

return new ResultsHttpClient(uri, pipeline, token, disposeHandler: true);
}

public Task CreateResultsStepSummaryAsync(string planId, string jobId, Guid stepId, string file,
CancellationToken cancellationToken)
{
Expand Down
54 changes: 30 additions & 24 deletions src/Runner.Sdk/Util/VssUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,35 @@ public static RawConnection CreateRawConnection(
VssCredentials credentials,
IEnumerable<DelegatingHandler> additionalDelegatingHandler = null,
TimeSpan? timeout = null)
{
yacaovsnc marked this conversation as resolved.
Show resolved Hide resolved
RawClientHttpRequestSettings settings = GetHttpRequestSettings(timeout);
RawConnection connection = new(serverUri, new RawHttpMessageHandler(credentials.Federated, settings), additionalDelegatingHandler);
return connection;
}

public static VssCredentials GetVssCredential(ServiceEndpoint serviceEndpoint)
{
ArgUtil.NotNull(serviceEndpoint, nameof(serviceEndpoint));
ArgUtil.NotNull(serviceEndpoint.Authorization, nameof(serviceEndpoint.Authorization));
ArgUtil.NotNullOrEmpty(serviceEndpoint.Authorization.Scheme, nameof(serviceEndpoint.Authorization.Scheme));

if (serviceEndpoint.Authorization.Parameters.Count == 0)
{
throw new ArgumentOutOfRangeException(nameof(serviceEndpoint));
}

VssCredentials credentials = null;
string accessToken;
if (serviceEndpoint.Authorization.Scheme == EndpointAuthorizationSchemes.OAuth &&
serviceEndpoint.Authorization.Parameters.TryGetValue(EndpointAuthorizationParameters.AccessToken, out accessToken))
{
credentials = new VssCredentials(new VssOAuthAccessTokenCredential(accessToken), CredentialPromptType.DoNotPrompt);
}

return credentials;
}

public static RawClientHttpRequestSettings GetHttpRequestSettings(TimeSpan? timeout = null)
{
RawClientHttpRequestSettings settings = RawClientHttpRequestSettings.Default.Clone();

Expand Down Expand Up @@ -116,30 +145,7 @@ public static RawConnection CreateRawConnection(
// settings are applied to an HttpRequestMessage.
settings.AcceptLanguages.Remove(CultureInfo.InvariantCulture);

RawConnection connection = new(serverUri, new RawHttpMessageHandler(credentials.Federated, settings), additionalDelegatingHandler);
return connection;
}

public static VssCredentials GetVssCredential(ServiceEndpoint serviceEndpoint)
{
ArgUtil.NotNull(serviceEndpoint, nameof(serviceEndpoint));
ArgUtil.NotNull(serviceEndpoint.Authorization, nameof(serviceEndpoint.Authorization));
ArgUtil.NotNullOrEmpty(serviceEndpoint.Authorization.Scheme, nameof(serviceEndpoint.Authorization.Scheme));

if (serviceEndpoint.Authorization.Parameters.Count == 0)
{
throw new ArgumentOutOfRangeException(nameof(serviceEndpoint));
}

VssCredentials credentials = null;
string accessToken;
if (serviceEndpoint.Authorization.Scheme == EndpointAuthorizationSchemes.OAuth &&
serviceEndpoint.Authorization.Parameters.TryGetValue(EndpointAuthorizationParameters.AccessToken, out accessToken))
{
credentials = new VssCredentials(new VssOAuthAccessTokenCredential(accessToken), CredentialPromptType.DoNotPrompt);
}

return credentials;
return settings;
}
}
}
22 changes: 22 additions & 0 deletions src/Sdk/Common/Common/Authentication/NoOpCredentials.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace GitHub.Services.Common
{
// Set of classes used to bypass token operations
// Results Service and External services follow a different auth model but
// we are required to pass in a credentials object to create a RawHttpMessageHandler
public class NoOpCredentials : FederatedCredential
yacaovsnc marked this conversation as resolved.
Show resolved Hide resolved
{
public NoOpCredentials(IssuedToken initialToken) : base(initialToken)
{
}

public override VssCredentialsType CredentialType { get; }
protected override IssuedTokenProvider OnCreateTokenProvider(Uri serverUrl, IHttpResponse response)
{
return null;
}
}
}
13 changes: 9 additions & 4 deletions src/Sdk/Common/Common/RawHttpMessageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ protected override async Task<HttpResponseMessage> SendAsync(
lock (m_thisLock)
{
// Ensure that we attempt to use the most appropriate authentication mechanism by default.
if (m_tokenProvider == null)
if (m_tokenProvider == null && !(this.Credentials is NoOpCredentials))
{
m_tokenProvider = this.Credentials.CreateTokenProvider(request.RequestUri, null, null);
}
Expand All @@ -121,7 +121,8 @@ protected override async Task<HttpResponseMessage> SendAsync(
HttpResponseMessageWrapper responseWrapper;

Boolean lastResponseDemandedProxyAuth = false;
Int32 retries = m_maxAuthRetries;
// do not retry if we cannot recreate tokens
Int32 retries = this.Credentials is NoOpCredentials ? 0 : m_maxAuthRetries;
try
{
tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
Expand All @@ -138,8 +139,12 @@ protected override async Task<HttpResponseMessage> SendAsync(
}

// Let's start with sending a token
IssuedToken token = await m_tokenProvider.GetTokenAsync(null, tokenSource.Token).ConfigureAwait(false);
ApplyToken(request, token, applyICredentialsToWebProxy: lastResponseDemandedProxyAuth);
IssuedToken token = null;
if (m_tokenProvider != null)
{
token = await m_tokenProvider.GetTokenAsync(null, tokenSource.Token).ConfigureAwait(false);
ApplyToken(request, token, applyICredentialsToWebProxy: lastResponseDemandedProxyAuth);
}

// The WinHttpHandler will chunk any content that does not have a computed length which is
// not what we want. By loading into a buffer up-front we bypass this behavior and there is
Expand Down
2 changes: 1 addition & 1 deletion src/Sdk/WebApi/WebApi/ResultsHttpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public ResultsHttpClient(
HttpMessageHandler pipeline,
string token,
bool disposeHandler)
: base(baseUrl, pipeline, disposeHandler)
: base(baseUrl, pipeline,disposeHandler)
{
m_token = token;
m_resultsServiceUrl = baseUrl;
Expand Down