Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set UserAgent as a default header parameter #2157

Merged
merged 2 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/usage.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public RestClient(

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

if (useClientFactory) {
_disposeHttpClient = false;
Expand All @@ -83,15 +84,14 @@ public RestClient(
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 RestClient(
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 RestClient(
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 @@ void ConfigureSerializers(ConfigureSerialization? configureSerialization) {
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
Original file line number Diff line number Diff line change
Expand Up @@ -118,20 +118,41 @@ public void Should_use_new_httpClient_instance() {
}

[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);
}
}