Skip to content

Commit

Permalink
Set UserAgent as a default header parameter (#2157)
Browse files Browse the repository at this point in the history
* Set UserAgent as a default header parameter instead of modifying the HttpClient instance.

* Update usage document

---------

Co-authored-by: Peter Breen <PBreen@UNUM.COM>
  • Loading branch information
PetesBreenCoding and peetteer committed Dec 14, 2023
1 parent d99d494 commit f3642c1
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 18 deletions.
2 changes: 1 addition & 1 deletion docs/usage.md
Expand Up @@ -594,7 +594,7 @@ One way of doing it is to use `RestClient` constructors that accept an instance

- `BaseAddress` will be used to set the base address of the `HttpClient` instance if base address is not set there already.
- `MaxTimeout`
- `UserAgent` will be set if the `User-Agent` header is not set on the `HttpClient` instance already.
- `UserAgent` will be added to the `RestClient.DefaultParameters` list as a HTTP header. This will be added to each request made by the `RestClient`, and the `HttpClient` instance will not be modified. This is to allow the `HttpClient` instance to be reused for scenarios where different `User-Agent` headers are required.
- `Expect100Continue`

Another option is to use a simple HTTP client factory as described [above](#simple-factory).
Expand Down
23 changes: 15 additions & 8 deletions src/RestSharp/RestClient.cs
Expand Up @@ -73,6 +73,7 @@ public partial class RestClient : IRestClient {

ConfigureSerializers(configureSerialization);
Options = new ReadOnlyRestClientOptions(options);
DefaultParameters = new DefaultParameters(Options);

if (useClientFactory) {
_disposeHttpClient = false;
Expand All @@ -83,15 +84,14 @@ public partial class RestClient : IRestClient {
HttpClient = GetClient();
}

DefaultParameters = new DefaultParameters(Options);

HttpClient GetClient() {
var handler = new HttpClientHandler();
ConfigureHttpMessageHandler(handler, Options);
var finalHandler = options.ConfigureMessageHandler?.Invoke(handler) ?? handler;

var httpClient = new HttpClient(finalHandler);
ConfigureHttpClient(httpClient, options);
ConfigureDefaultParameters(options);
configureDefaultHeaders?.Invoke(httpClient.DefaultRequestHeaders);
return httpClient;
}
Expand Down Expand Up @@ -181,7 +181,10 @@ public partial class RestClient : IRestClient {
Options = new ReadOnlyRestClientOptions(opt);
DefaultParameters = new DefaultParameters(Options);

if (options != null) ConfigureHttpClient(httpClient, options);
if (options != null) {
ConfigureHttpClient(httpClient, options);
ConfigureDefaultParameters(options);
}
}

/// <summary>
Expand Down Expand Up @@ -218,11 +221,6 @@ public partial class RestClient : IRestClient {
static void ConfigureHttpClient(HttpClient httpClient, RestClientOptions options) {
if (options.MaxTimeout > 0) httpClient.Timeout = TimeSpan.FromMilliseconds(options.MaxTimeout);

if (options.UserAgent != null &&
httpClient.DefaultRequestHeaders.UserAgent.All(x => $"{x.Product?.Name}/{x.Product?.Version}" != options.UserAgent)) {
httpClient.DefaultRequestHeaders.TryAddWithoutValidation(KnownHeaders.UserAgent, options.UserAgent);
}

if (options.Expect100Continue != null) httpClient.DefaultRequestHeaders.ExpectContinue = options.Expect100Continue;
}

Expand Down Expand Up @@ -270,6 +268,15 @@ public partial class RestClient : IRestClient {
AcceptedContentTypes = Serializers.GetAcceptedContentTypes();
}

void ConfigureDefaultParameters(RestClientOptions options) {
if (options.UserAgent != null) {
if (!options.AllowMultipleDefaultParametersWithSameName
&& DefaultParameters.Any(parameter => parameter.Type == ParameterType.HttpHeader && parameter.Name == KnownHeaders.UserAgent))
DefaultParameters.RemoveParameter(KnownHeaders.UserAgent, ParameterType.HttpHeader);
DefaultParameters.AddParameter(Parameter.CreateParameter(KnownHeaders.UserAgent, options.UserAgent, ParameterType.HttpHeader));
}
}

readonly bool _disposeHttpClient;

bool _disposed;
Expand Down
39 changes: 30 additions & 9 deletions test/RestSharp.Tests/RestClientTests.cs
Expand Up @@ -118,20 +118,41 @@ public class RestClientTests {
}

[Fact]
public void ConfigureHttpClient_does_not_duplicate_user_agent_for_same_client() {
public void ConfigureDefaultParameters_sets_user_agent_new_httpClient_instance() {
// arrange
var clientOptions = new RestClientOptions();

// act
var restClient = new RestClient(clientOptions);

//assert
Assert.Single(
restClient.DefaultParameters,
parameter => parameter.Type == ParameterType.HttpHeader &&
parameter.Name == KnownHeaders.UserAgent &&
parameter.Value is string valueAsString &&
valueAsString == clientOptions.UserAgent);

Assert.Empty(restClient.HttpClient.DefaultRequestHeaders.UserAgent);
}

[Fact]
public void ConfigureDefaultParameters_sets_user_agent_given_httpClient_instance() {
// arrange
var httpClient = new HttpClient();
var clientOptions = new RestClientOptions();

// act
var unused = new RestClient(httpClient, clientOptions);
var dummy = new RestClient(httpClient, clientOptions);
var restClient = new RestClient(httpClient, clientOptions);

// assert
Assert.Contains(
httpClient.DefaultRequestHeaders.UserAgent,
agent => $"{agent.Product.Name}/{agent.Product.Version}" == clientOptions.UserAgent
);
Assert.Single(httpClient.DefaultRequestHeaders.UserAgent);
//assert
Assert.Single(
restClient.DefaultParameters,
parameter => parameter.Type == ParameterType.HttpHeader &&
parameter.Name == KnownHeaders.UserAgent &&
parameter.Value is string valueAsString &&
valueAsString == clientOptions.UserAgent);

Assert.Empty(httpClient.DefaultRequestHeaders.UserAgent);
}
}

0 comments on commit f3642c1

Please sign in to comment.