File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -15,8 +15,11 @@ limitations under the License.
1515*/
1616
1717using Google . Apis . Util ;
18+ using System ;
1819using System . Collections . Generic ;
1920using System . Collections . ObjectModel ;
21+ using System . Linq ;
22+ using System . Net ;
2023using System . Net . Http ;
2124using 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
Original file line number Diff line number Diff 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 ) ;
You can’t perform that action at this time.
0 commit comments