diff --git a/src/RestClient/Authenticators/OAuth/src/OAuthAuthenticator.cs b/src/RestClient/Authenticators/OAuth/src/OAuthAuthenticator.cs index 68b5e88..44ecfcd 100644 --- a/src/RestClient/Authenticators/OAuth/src/OAuthAuthenticator.cs +++ b/src/RestClient/Authenticators/OAuth/src/OAuthAuthenticator.cs @@ -1,4 +1,4 @@ -namespace ClickView.Extensions.RestClient.Authenticators.OAuth; +namespace ClickView.Extensions.RestClient.Authenticators.OAuth; using System; using System.Collections.Generic; @@ -56,7 +56,7 @@ public virtual async Task AuthenticateAsync(IClientRequest request, Cancellation return; } - request.AddHeader("Authorization", "Bearer " + oAuthToken); + request.AddOrUpdateHeader("Authorization", "Bearer " + oAuthToken); } protected void AddTokenSource(ITokenSource tokenSource) @@ -116,4 +116,4 @@ protected IAuthenticatorEndpointFactory CreateEndpointFactory(string endpoint) return new DefaultEndpointFactory(Options.Endpoints); } -} \ No newline at end of file +} diff --git a/src/RestClient/RestClient/src/Authentication/BasicAccessAuthenticator.cs b/src/RestClient/RestClient/src/Authentication/BasicAccessAuthenticator.cs index b9664c4..e69409c 100644 --- a/src/RestClient/RestClient/src/Authentication/BasicAccessAuthenticator.cs +++ b/src/RestClient/RestClient/src/Authentication/BasicAccessAuthenticator.cs @@ -1,4 +1,4 @@ -namespace ClickView.Extensions.RestClient.Authentication; +namespace ClickView.Extensions.RestClient.Authentication; using System; using System.Text; @@ -24,7 +24,7 @@ public BasicAccessAuthenticator(string userId, string password) public Task AuthenticateAsync(IClientRequest request, CancellationToken token = default) { - request.AddHeader("Authorization", $"Basic {_encoded}"); + request.AddOrUpdateHeader("Authorization", $"Basic {_encoded}"); return Task.CompletedTask; } @@ -33,4 +33,4 @@ private static string ToBase64(string s) var bytes = Encoding.UTF8.GetBytes(s); return Convert.ToBase64String(bytes); } -} \ No newline at end of file +} diff --git a/src/RestClient/RestClient/src/Authentication/HeaderAuthenticator.cs b/src/RestClient/RestClient/src/Authentication/HeaderAuthenticator.cs index 0fb99ab..9eeeaca 100644 --- a/src/RestClient/RestClient/src/Authentication/HeaderAuthenticator.cs +++ b/src/RestClient/RestClient/src/Authentication/HeaderAuthenticator.cs @@ -1,4 +1,4 @@ -namespace ClickView.Extensions.RestClient.Authentication; +namespace ClickView.Extensions.RestClient.Authentication; using System.Threading; using System.Threading.Tasks; @@ -20,8 +20,8 @@ public HeaderAuthenticator(string key, string value) public Task AuthenticateAsync(IClientRequest request, CancellationToken token = default) { - request.AddHeader(_key, _value); + request.AddOrUpdateHeader(_key, _value); return Task.CompletedTask; } -} \ No newline at end of file +} diff --git a/src/RestClient/RestClient/src/Requests/BaseRestClientRequest.cs b/src/RestClient/RestClient/src/Requests/BaseRestClientRequest.cs index 835a10a..535667f 100644 --- a/src/RestClient/RestClient/src/Requests/BaseRestClientRequest.cs +++ b/src/RestClient/RestClient/src/Requests/BaseRestClientRequest.cs @@ -45,6 +45,18 @@ public void AddHeader(string key, IEnumerable values) _headers.Add(key, values); } + public void AddOrUpdateHeader(string key, string value) + { + _headers.Remove(key); // no-op if it does not exist + _headers.Add(key, value); + } + + public void AddOrUpdateHeader(string key, IEnumerable values) + { + _headers.Remove(key); // no-op if it does not exist + _headers.Add(key, values); + } + public void AddBody(object body) { if (!MethodSupportsBody(Method)) @@ -53,7 +65,7 @@ public void AddBody(object body) _content = body; return; - bool MethodSupportsBody(HttpMethod method) + static bool MethodSupportsBody(HttpMethod method) { return method == HttpMethod.Post || #if NETCOREAPP2_1_OR_GREATER diff --git a/src/RestClient/RestClient/src/Requests/IClientRequest.cs b/src/RestClient/RestClient/src/Requests/IClientRequest.cs index 23e262e..416ffc2 100644 --- a/src/RestClient/RestClient/src/Requests/IClientRequest.cs +++ b/src/RestClient/RestClient/src/Requests/IClientRequest.cs @@ -11,5 +11,7 @@ public interface IClientRequest void AddHeader(string key, string value); void AddHeader(string key, IEnumerable values); + void AddOrUpdateHeader(string key, string value); + void AddOrUpdateHeader(string key, IEnumerable values); void AddBody(object body); -} \ No newline at end of file +} diff --git a/src/RestClient/RestClient/src/RestClient.cs b/src/RestClient/RestClient/src/RestClient.cs index 69c05c8..7a1539f 100644 --- a/src/RestClient/RestClient/src/RestClient.cs +++ b/src/RestClient/RestClient/src/RestClient.cs @@ -162,7 +162,6 @@ private static HttpClient CreateClient(RestClientOptions options) PrepareHttpClient(httpClient, options); - return httpClient; } diff --git a/src/RestClient/RestClient/test/RestClientRequestTests.cs b/src/RestClient/RestClient/test/RestClientRequestTests.cs index 5cc7474..054d6b3 100644 --- a/src/RestClient/RestClient/test/RestClientRequestTests.cs +++ b/src/RestClient/RestClient/test/RestClientRequestTests.cs @@ -73,6 +73,32 @@ public void AddBody_GetRequest_ThrowsException() Assert.Equal("Cannot add body to GET", ex.Message); } + [Fact] + public void AddOrUpdateHeader_SingleValue_SameHeaderTwice_DoesNotThrow() + { + const string key = "X-Test-Header"; + const string value = "TestValue"; + + var request = new RestClientRequest(HttpMethod.Post, "test"); + request.AddOrUpdateHeader(key, value); + request.AddOrUpdateHeader(key, value); + + Assert.Single(request.Headers); + } + + [Fact] + public void AddOrUpdateHeader_MultipleValues_SameHeaderTwice_DoesNotThrow() + { + const string key = "X-Test-Header"; + string[] values = ["TestValue1", "TestValue2"]; + + var request = new RestClientRequest(HttpMethod.Post, "test"); + request.AddOrUpdateHeader(key, values); + request.AddOrUpdateHeader(key, values); + + Assert.Single(request.Headers); + } + private class TestSerializer : ISerializer { public string Format => "test"; diff --git a/src/RestClient/RestClient/test/RestClientTests.cs b/src/RestClient/RestClient/test/RestClientTests.cs index 5cc8acc..0e08139 100644 --- a/src/RestClient/RestClient/test/RestClientTests.cs +++ b/src/RestClient/RestClient/test/RestClientTests.cs @@ -214,7 +214,7 @@ public async Task ExecuteAsync_DefaultUserAgentSet_RequestContainsDefaultUserAge ItExpr.IsAny(), ItExpr.IsAny() ) - .Callback((request, token) => + .Callback((request, _) => { userAgentHeader = request.Headers.UserAgent.ToString(); }) @@ -244,4 +244,4 @@ protected override async ValueTask> ParseResponseAsyn return new RestClientResponse(message, await message.Content.ReadAsStringAsync()); } } -} \ No newline at end of file +}