Skip to content

Commit b488cef

Browse files
authored
Merge branch 'release/7.0.3xx' => 'main' (#31511)
2 parents 326fa05 + e1cd792 commit b488cef

File tree

120 files changed

+12702
-17
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+12702
-17
lines changed

.vsts-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ stages:
146146
name: $(DncEngInternalBuildPool)
147147
demands: ImageOverride -equals 1es-ubuntu-2204
148148
${{ if eq(variables['System.TeamProject'], 'public') }}:
149-
helixTargetQueue: 'ubuntu.2204.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-amd64'
149+
helixTargetQueue: ubuntu.2204.amd64.open
150150
${{ if ne(variables['System.TeamProject'], 'public') }}:
151151
helixTargetQueue: Ubuntu.2204.Amd64
152152
strategy:

CODEOWNERS

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,18 @@
7777

7878
# ApiCompat tools owned by runtime team
7979
# Area-ApiCompat
80-
/src/ApiCompat/ @dotnet/area-infrastructure-libraries
81-
/src/Tests/Microsoft.DotNet.ApiCompatibility*/ @dotnet/area-infrastructure-libraries
82-
/src/Tests/Microsoft.DotNet.ApiCompat*/ @dotnet/area-infrastructure-libraries
83-
/src/Tests/Microsoft.DotNet.PackageValidation*/ @dotnet/area-infrastructure-libraries
80+
/src/ApiCompat/ @ericstj @dotnet/area-infrastructure-libraries @joperezr
81+
/src/Tests/Microsoft.DotNet.ApiCompatibility*/ @ericstj @dotnet/area-infrastructure-libraries @joperezr
82+
/src/Tests/Microsoft.DotNet.ApiCompat*/ @ericstj @dotnet/area-infrastructure-libraries @joperezr
83+
/src/Tests/Microsoft.DotNet.PackageValidation*/ @ericstj @dotnet/area-infrastructure-libraries @joperezr
8484

8585
# Area-GenAPI
8686
/src/GenAPI/ @andriipatsula @dotnet/area-infrastructure-libraries
8787
/src/Tests/Microsoft.DotNet.GenAPI/ @andriipatsula @dotnet/area-infrastructure-libraries
8888
/src/Microsoft.DotNet.ApiSymbolExtensions/ @andriipatsula @dotnet/area-infrastructure-libraries
89+
90+
# Area: dotnet containers
91+
/src/Cli/Containers @dotnet/sdk-container-builds-maintainers
92+
/src/Tests/containerize.UnitTests @dotnet/sdk-container-builds-maintainers
93+
/src/Tests/Microsoft.NET.Build.Containers.IntegrationTests @dotnet/sdk-container-builds-maintainers
94+
/src/Tests/Microsoft.NET.Build.Containers.UnitTests @dotnet/sdk-container-builds-maintainers

containers.slnf

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"solution": {
3+
"path": "sdk.sln",
4+
"projects": [
5+
"src\\Cli\\Microsoft.DotNet.Cli.Utils\\Microsoft.DotNet.Cli.Utils.csproj",
6+
"src\\Cli\\Microsoft.DotNet.InternalAbstractions\\Microsoft.DotNet.InternalAbstractions.csproj",
7+
"src\\Containers\\Microsoft.NET.Build.Containers\\Microsoft.NET.Build.Containers.csproj",
8+
"src\\Containers\\containerize\\containerize.csproj",
9+
"src\\Containers\\packaging\\package.csproj",
10+
"src\\Tests\\Microsoft.NET.Build.Containers.IntegrationTests\\Microsoft.NET.Build.Containers.IntegrationTests.csproj",
11+
"src\\Tests\\Microsoft.NET.Build.Containers.UnitTests\\Microsoft.NET.Build.Containers.UnitTests.csproj",
12+
"src\\Tests\\Microsoft.NET.TestFramework\\Microsoft.NET.TestFramework.csproj",
13+
"src\\Tests\\containerize.UnitTests\\containerize.UnitTests.csproj"
14+
]
15+
}
16+
}

eng/Signing.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
<FileSignInfo Include="xunit.performance.core.dll" CertificateName="3PartySHA2" />
5252
<FileSignInfo Include="xunit.performance.execution.dll" CertificateName="3PartySHA2" />
5353
<FileSignInfo Include="xunit.performance.metrics.dll" CertificateName="3PartySHA2" />
54+
<FileSignInfo Include="Valleysoft.DockerCredsProvider.dll" CertificateName="3PartySHA2" />
5455
</ItemGroup>
5556

5657
<!-- Filter out any test packages from ItemsToSign -->

sdk.sln

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tasks", "Tasks", "{F720D695
452452
EndProject
453453
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.WebAssembly.Tasks", "src\WasmSdk\Tasks\Microsoft.NET.Sdk.WebAssembly.Tasks.csproj", "{754C18B9-AEDB-4455-BAF4-844C6CEEF8F7}"
454454
EndProject
455+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Containers", "Containers", "{EC4A66C5-E2E2-4201-9E8D-BAC6B630D12A}"
456+
EndProject
457+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "containerize", "src\Containers\containerize\containerize.csproj", "{ECCDB04A-A365-4656-989D-4E258D286AE4}"
458+
EndProject
459+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Build.Containers", "src\Containers\Microsoft.NET.Build.Containers\Microsoft.NET.Build.Containers.csproj", "{9E8C7C3B-B8B3-490C-BA11-E1F60ED4E21D}"
460+
EndProject
461+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "package", "src\Containers\packaging\package.csproj", "{DEA8FE40-0AE9-4CE6-9430-089C985217CA}"
462+
EndProject
463+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "containerize.UnitTests", "src\Tests\containerize.UnitTests\containerize.UnitTests.csproj", "{F04DB812-7278-47F2-913E-225CE2EF150C}"
464+
EndProject
465+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Build.Containers.IntegrationTests", "src\Tests\Microsoft.NET.Build.Containers.IntegrationTests\Microsoft.NET.Build.Containers.IntegrationTests.csproj", "{7DCA2BEC-B1E1-4F2B-952A-A26B5110FDA5}"
466+
EndProject
467+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Build.Containers.UnitTests", "src\Tests\Microsoft.NET.Build.Containers.UnitTests\Microsoft.NET.Build.Containers.UnitTests.csproj", "{E54506B8-0B81-4FC4-99B5-5C67E19D4B09}"
468+
EndProject
455469
Global
456470
GlobalSection(SolutionConfigurationPlatforms) = preSolution
457471
Debug|Any CPU = Debug|Any CPU
@@ -846,6 +860,30 @@ Global
846860
{754C18B9-AEDB-4455-BAF4-844C6CEEF8F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
847861
{754C18B9-AEDB-4455-BAF4-844C6CEEF8F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
848862
{754C18B9-AEDB-4455-BAF4-844C6CEEF8F7}.Release|Any CPU.Build.0 = Release|Any CPU
863+
{ECCDB04A-A365-4656-989D-4E258D286AE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
864+
{ECCDB04A-A365-4656-989D-4E258D286AE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
865+
{ECCDB04A-A365-4656-989D-4E258D286AE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
866+
{ECCDB04A-A365-4656-989D-4E258D286AE4}.Release|Any CPU.Build.0 = Release|Any CPU
867+
{9E8C7C3B-B8B3-490C-BA11-E1F60ED4E21D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
868+
{9E8C7C3B-B8B3-490C-BA11-E1F60ED4E21D}.Debug|Any CPU.Build.0 = Debug|Any CPU
869+
{9E8C7C3B-B8B3-490C-BA11-E1F60ED4E21D}.Release|Any CPU.ActiveCfg = Release|Any CPU
870+
{9E8C7C3B-B8B3-490C-BA11-E1F60ED4E21D}.Release|Any CPU.Build.0 = Release|Any CPU
871+
{DEA8FE40-0AE9-4CE6-9430-089C985217CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
872+
{DEA8FE40-0AE9-4CE6-9430-089C985217CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
873+
{DEA8FE40-0AE9-4CE6-9430-089C985217CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
874+
{DEA8FE40-0AE9-4CE6-9430-089C985217CA}.Release|Any CPU.Build.0 = Release|Any CPU
875+
{F04DB812-7278-47F2-913E-225CE2EF150C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
876+
{F04DB812-7278-47F2-913E-225CE2EF150C}.Debug|Any CPU.Build.0 = Debug|Any CPU
877+
{F04DB812-7278-47F2-913E-225CE2EF150C}.Release|Any CPU.ActiveCfg = Release|Any CPU
878+
{F04DB812-7278-47F2-913E-225CE2EF150C}.Release|Any CPU.Build.0 = Release|Any CPU
879+
{7DCA2BEC-B1E1-4F2B-952A-A26B5110FDA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
880+
{7DCA2BEC-B1E1-4F2B-952A-A26B5110FDA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
881+
{7DCA2BEC-B1E1-4F2B-952A-A26B5110FDA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
882+
{7DCA2BEC-B1E1-4F2B-952A-A26B5110FDA5}.Release|Any CPU.Build.0 = Release|Any CPU
883+
{E54506B8-0B81-4FC4-99B5-5C67E19D4B09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
884+
{E54506B8-0B81-4FC4-99B5-5C67E19D4B09}.Debug|Any CPU.Build.0 = Debug|Any CPU
885+
{E54506B8-0B81-4FC4-99B5-5C67E19D4B09}.Release|Any CPU.ActiveCfg = Release|Any CPU
886+
{E54506B8-0B81-4FC4-99B5-5C67E19D4B09}.Release|Any CPU.Build.0 = Release|Any CPU
849887
EndGlobalSection
850888
GlobalSection(SolutionProperties) = preSolution
851889
HideSolutionNode = FALSE
@@ -1001,6 +1039,13 @@ Global
10011039
{B2CE3F28-8FEC-4715-B483-5B442E3136CE} = {21835A9E-D667-4761-8675-B2BC105CC2FE}
10021040
{F720D695-F35A-4700-9463-C359163D14EE} = {21835A9E-D667-4761-8675-B2BC105CC2FE}
10031041
{754C18B9-AEDB-4455-BAF4-844C6CEEF8F7} = {F720D695-F35A-4700-9463-C359163D14EE}
1042+
{EC4A66C5-E2E2-4201-9E8D-BAC6B630D12A} = {22AB674F-ED91-4FBC-BFEE-8A1E82F9F05E}
1043+
{ECCDB04A-A365-4656-989D-4E258D286AE4} = {EC4A66C5-E2E2-4201-9E8D-BAC6B630D12A}
1044+
{9E8C7C3B-B8B3-490C-BA11-E1F60ED4E21D} = {EC4A66C5-E2E2-4201-9E8D-BAC6B630D12A}
1045+
{DEA8FE40-0AE9-4CE6-9430-089C985217CA} = {EC4A66C5-E2E2-4201-9E8D-BAC6B630D12A}
1046+
{F04DB812-7278-47F2-913E-225CE2EF150C} = {580D1AE7-AA8F-4912-8B76-105594E00B3B}
1047+
{7DCA2BEC-B1E1-4F2B-952A-A26B5110FDA5} = {580D1AE7-AA8F-4912-8B76-105594E00B3B}
1048+
{E54506B8-0B81-4FC4-99B5-5C67E19D4B09} = {580D1AE7-AA8F-4912-8B76-105594E00B3B}
10041049
EndGlobalSection
10051050
GlobalSection(ExtensibilityGlobals) = postSolution
10061051
SolutionGuid = {FB8F26CE-4DE6-433F-B32A-79183020BBD6}

source-build.slnf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
"src\\Cli\\Microsoft.DotNet.InternalAbstractions\\Microsoft.DotNet.InternalAbstractions.csproj",
2020
"src\\Cli\\Microsoft.TemplateEngine.Cli\\Microsoft.TemplateEngine.Cli.csproj",
2121
"src\\Cli\\dotnet\\dotnet.csproj",
22+
"src\\Containers\\Microsoft.NET.Build.Containers\\Microsoft.NET.Build.Containers.csproj",
23+
"src\\Containers\\containerize\\containerize.csproj",
24+
"src\\Containers\\packaging\\package.csproj",
2225
"src\\Layout\\redist\\redist.csproj",
2326
"src\\Layout\\tool_fsharp\\tool_fsc.csproj",
2427
"src\\Layout\\tool_msbuild\\tool_msbuild.csproj",
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.NET.Build.Containers.Resources;
5+
6+
namespace Microsoft.NET.Build.Containers;
7+
8+
/// <summary>
9+
/// A delegating handler that handles the special error handling needed for Amazon ECR.
10+
///
11+
/// When pushing images to ECR if the target container repository does not exist ECR ends
12+
/// the connection causing an IOException with a generic "The response ended prematurely."
13+
/// error message. The handler catches the generic error and provides a more informed error
14+
/// message to let the user know they need to create the repository.
15+
/// </summary>
16+
internal sealed class AmazonECRMessageHandler : DelegatingHandler
17+
{
18+
public AmazonECRMessageHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
19+
20+
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
21+
{
22+
try
23+
{
24+
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
25+
}
26+
catch (HttpRequestException e) when (e.InnerException is IOException ioe && ioe.Message.Equals("The response ended prematurely.", StringComparison.OrdinalIgnoreCase))
27+
{
28+
string message = Resource.GetString(nameof(Strings.AmazonRegistryFailed));
29+
throw new ContainerHttpException(message, request.RequestUri?.ToString(), null);
30+
}
31+
catch
32+
{
33+
throw;
34+
}
35+
}
36+
}
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics.CodeAnalysis;
5+
using System.Net;
6+
using System.Net.Http.Headers;
7+
using System.Text;
8+
using System.Text.Json;
9+
using System.Text.RegularExpressions;
10+
11+
using Valleysoft.DockerCredsProvider;
12+
13+
using Microsoft.NET.Build.Containers.Credentials;
14+
using System.Net.Sockets;
15+
using Microsoft.NET.Build.Containers.Resources;
16+
17+
namespace Microsoft.NET.Build.Containers;
18+
19+
/// <summary>
20+
/// A delegating handler that performs the Docker auth handshake as described <see href="https://docs.docker.com/registry/spec/auth/token/">in their docs</see> if a request isn't authenticated
21+
/// </summary>
22+
internal sealed partial class AuthHandshakeMessageHandler : DelegatingHandler
23+
{
24+
private const int MaxRequestRetries = 5; // Arbitrary but seems to work ok for chunked uploads to ghcr.io
25+
26+
private sealed record AuthInfo(Uri Realm, string Service, string? Scope);
27+
28+
/// <summary>
29+
/// the www-authenticate header must have realm, service, and scope information, so this method parses it into that shape if present
30+
/// </summary>
31+
/// <param name="msg"></param>
32+
/// <param name="authInfo"></param>
33+
/// <returns></returns>
34+
private static bool TryParseAuthenticationInfo(HttpResponseMessage msg, [NotNullWhen(true)] out string? scheme, [NotNullWhen(true)] out AuthInfo? authInfo)
35+
{
36+
authInfo = null;
37+
scheme = null;
38+
39+
var authenticateHeader = msg.Headers.WwwAuthenticate;
40+
if (!authenticateHeader.Any())
41+
{
42+
return false;
43+
}
44+
45+
AuthenticationHeaderValue header = authenticateHeader.First();
46+
if (header is { Scheme: "Bearer" or "Basic", Parameter: string bearerArgs })
47+
{
48+
scheme = header.Scheme;
49+
Dictionary<string, string> keyValues = new();
50+
foreach (Match match in BearerParameterSplitter().Matches(bearerArgs))
51+
{
52+
keyValues.Add(match.Groups["key"].Value, match.Groups["value"].Value);
53+
}
54+
55+
if (keyValues.TryGetValue("realm", out string? realm) && keyValues.TryGetValue("service", out string? service))
56+
{
57+
string? scope = null;
58+
keyValues.TryGetValue("scope", out scope);
59+
authInfo = new AuthInfo(new Uri(realm), service, scope);
60+
return true;
61+
}
62+
}
63+
64+
return false;
65+
}
66+
67+
public AuthHandshakeMessageHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
68+
69+
/// <summary>
70+
/// Response to a request to get a token using some auth.
71+
/// </summary>
72+
/// <remarks>
73+
/// <see href="https://docs.docker.com/registry/spec/auth/token/#token-response-fields"/>
74+
/// </remarks>
75+
private sealed record TokenResponse(string? token, string? access_token, int? expires_in, DateTimeOffset? issued_at)
76+
{
77+
public string ResolvedToken => token ?? access_token ?? throw new ArgumentException(Resource.GetString(nameof(Strings.InvalidTokenResponse)));
78+
}
79+
80+
/// <summary>
81+
/// Uses the authentication information from a 401 response to perform the authentication dance for a given registry.
82+
/// Credentials for the request are retrieved from the credential provider, then used to acquire a token.
83+
/// That token is cached for some duration on a per-host basis.
84+
/// </summary>
85+
/// <param name="uri"></param>
86+
/// <param name="service"></param>
87+
/// <param name="scope"></param>
88+
/// <param name="cancellationToken"></param>
89+
/// <returns></returns>
90+
private async Task<AuthenticationHeaderValue?> GetAuthenticationAsync(string registry, string scheme, Uri realm, string service, string? scope, CancellationToken cancellationToken)
91+
{
92+
// Allow overrides for auth via environment variables
93+
string? credU = Environment.GetEnvironmentVariable(ContainerHelpers.HostObjectUser);
94+
string? credP = Environment.GetEnvironmentVariable(ContainerHelpers.HostObjectPass);
95+
96+
// fetch creds for the host
97+
DockerCredentials? privateRepoCreds;
98+
99+
if (!string.IsNullOrEmpty(credU) && !string.IsNullOrEmpty(credP))
100+
{
101+
privateRepoCreds = new DockerCredentials(credU, credP);
102+
}
103+
else
104+
{
105+
try
106+
{
107+
privateRepoCreds = await CredsProvider.GetCredentialsAsync(registry).ConfigureAwait(false);
108+
}
109+
catch (Exception e)
110+
{
111+
throw new CredentialRetrievalException(registry, e);
112+
}
113+
}
114+
115+
if (scheme is "Basic")
116+
{
117+
var basicAuth = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{privateRepoCreds.Username}:{privateRepoCreds.Password}")));
118+
return AuthHeaderCache.AddOrUpdate(realm, basicAuth);
119+
}
120+
else if (scheme is "Bearer")
121+
{
122+
// use those creds when calling the token provider
123+
var header = privateRepoCreds.Username == "<token>"
124+
? new AuthenticationHeaderValue("Bearer", privateRepoCreds.Password)
125+
: new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{privateRepoCreds.Username}:{privateRepoCreds.Password}")));
126+
var builder = new UriBuilder(realm);
127+
var queryDict = System.Web.HttpUtility.ParseQueryString("");
128+
queryDict["service"] = service;
129+
if (scope is string s)
130+
{
131+
queryDict["scope"] = s;
132+
}
133+
builder.Query = queryDict.ToString();
134+
var message = new HttpRequestMessage(HttpMethod.Get, builder.ToString());
135+
message.Headers.Authorization = header;
136+
137+
var tokenResponse = await base.SendAsync(message, cancellationToken).ConfigureAwait(false);
138+
tokenResponse.EnsureSuccessStatusCode();
139+
140+
TokenResponse? token = JsonSerializer.Deserialize<TokenResponse>(tokenResponse.Content.ReadAsStream(cancellationToken));
141+
if (token is null)
142+
{
143+
throw new ArgumentException(Resource.GetString(nameof(Strings.CouldntDeserializeJsonToken)));
144+
}
145+
146+
// save the retrieved token in the cache
147+
var bearerAuth = new AuthenticationHeaderValue("Bearer", token.ResolvedToken);
148+
return AuthHeaderCache.AddOrUpdate(realm, bearerAuth);
149+
}
150+
else
151+
{
152+
return null;
153+
}
154+
}
155+
156+
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
157+
{
158+
if (request.RequestUri is null)
159+
{
160+
throw new ArgumentException(Resource.GetString(nameof(Strings.NoRequestUriSpecified)), nameof(request));
161+
}
162+
163+
// attempt to use cached token for the request if available
164+
if (AuthHeaderCache.TryGet(request.RequestUri, out AuthenticationHeaderValue? cachedAuthentication))
165+
{
166+
request.Headers.Authorization = cachedAuthentication;
167+
}
168+
169+
int retryCount = 0;
170+
171+
while (retryCount < MaxRequestRetries)
172+
{
173+
try
174+
{
175+
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
176+
if (response is { StatusCode: HttpStatusCode.OK })
177+
{
178+
return response;
179+
}
180+
else if (response is { StatusCode: HttpStatusCode.Unauthorized } && TryParseAuthenticationInfo(response, out string? scheme, out AuthInfo? authInfo))
181+
{
182+
if (await GetAuthenticationAsync(request.RequestUri.Host, scheme, authInfo.Realm, authInfo.Service, authInfo.Scope, cancellationToken).ConfigureAwait(false) is AuthenticationHeaderValue authentication)
183+
{
184+
request.Headers.Authorization = AuthHeaderCache.AddOrUpdate(request.RequestUri, authentication);
185+
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
186+
}
187+
return response;
188+
}
189+
else
190+
{
191+
return response;
192+
}
193+
}
194+
catch (HttpRequestException e) when (e.InnerException is IOException ioe && ioe.InnerException is SocketException se)
195+
{
196+
retryCount += 1;
197+
198+
// TODO: log in a way that is MSBuild-friendly
199+
Console.WriteLine($"Encountered a SocketException with message \"{se.Message}\". Pausing before retry.");
200+
201+
await Task.Delay(TimeSpan.FromSeconds(1.0 * Math.Pow(2, retryCount)), cancellationToken).ConfigureAwait(false);
202+
203+
// retry
204+
continue;
205+
}
206+
}
207+
208+
throw new ApplicationException(Resource.GetString(nameof(Strings.TooManyRetries)));
209+
}
210+
211+
[GeneratedRegex("(?<key>\\w+)=\"(?<value>[^\"]*)\"(?:,|$)")]
212+
private static partial Regex BearerParameterSplitter();
213+
}

0 commit comments

Comments
 (0)