Skip to content

Commit c794d4d

Browse files
fix: Fix quota project header on retry
1 parent e02d17a commit c794d4d

2 files changed

Lines changed: 24 additions & 16 deletions

File tree

Src/Support/Google.Apis.Auth/OAuth2/AccessTokenWithHeaders.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ limitations under the License.
1515
*/
1616

1717
using Google.Apis.Util;
18+
using System;
1819
using System.Collections.Generic;
1920
using System.Collections.ObjectModel;
21+
using System.Linq;
22+
using System.Net;
2023
using System.Net.Http;
2124
using System.Net.Http.Headers;
2225

@@ -75,10 +78,29 @@ private AccessTokenWithHeaders(string token, string quotaProject = null)
7578
public void AddHeaders(HttpRequestHeaders requestHeaders)
7679
{
7780
requestHeaders.ThrowIfNull(nameof(requestHeaders));
78-
7981
foreach (var header in Headers)
8082
{
81-
requestHeaders.Add(header.Key, header.Value);
83+
// In the case it's a single value header we will not add it if already present, just validate we match
84+
// what's already there.
85+
if (IsSingleValueHeader(header.Key) && requestHeaders.TryGetValues(header.Key, out var existingValue))
86+
{
87+
ValidateMatch(header.Key, existingValue, header.Value);
88+
continue;
89+
}
90+
else
91+
{
92+
requestHeaders.Add(header.Key, header.Value);
93+
}
94+
}
95+
96+
bool IsSingleValueHeader(string key) => key == QuotaProjectHeaderName;
97+
98+
void ValidateMatch(string key, IEnumerable<string> existing, IEnumerable<string> incoming)
99+
{
100+
if (!existing.SequenceEqual(incoming))
101+
{
102+
throw new InvalidOperationException($"The {key} header cannot be overwritten once set.");
103+
}
82104
}
83105
}
84106

Src/Support/Google.Apis.Core/Http/ConfigurableMessageHandler.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ namespace Google.Apis.Http
3838
/// </summary>
3939
public class ConfigurableMessageHandler : DelegatingHandler
4040
{
41-
private const string QuotaProjectHeaderName = "x-goog-user-project";
42-
4341
/// <summary>The class logger.</summary>
4442
private static readonly ILogger Logger = ApplicationContext.Logger.ForType<ConfigurableMessageHandler>();
4543

@@ -464,10 +462,6 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
464462
await interceptor.InterceptAsync(request, cancellationToken).ConfigureAwait(false);
465463
}
466464

467-
// Before having the credential intercept the call, check that quota project hasn't
468-
// been added as a header. Quota project cannot be added except through the credential.
469-
CheckValidAfterInterceptors(request);
470-
471465
await CredentialInterceptAsync(request, cancellationToken).ConfigureAwait(false);
472466

473467
if (loggable)
@@ -657,14 +651,6 @@ bool DisposeAndReturnFalse(IDisposable disposable)
657651
return response;
658652
}
659653

660-
private void CheckValidAfterInterceptors(HttpRequestMessage request)
661-
{
662-
if (request.Headers.Contains(QuotaProjectHeaderName))
663-
{
664-
throw new InvalidOperationException($"{QuotaProjectHeaderName} header can only be added through the credential or through the <Product>ClientBuilder.");
665-
}
666-
}
667-
668654
private async Task CredentialInterceptAsync(HttpRequestMessage request, CancellationToken cancellationToken)
669655
{
670656
var effectiveCredential = GetEffectiveCredential(request);

0 commit comments

Comments
 (0)