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

Implement "AddOrUpdateHeader(s)" methods #1576

Merged
merged 1 commit into from Jul 15, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/RestSharp/IRestRequest.cs
Expand Up @@ -374,16 +374,32 @@ public interface IRestRequest
/// </summary>
/// <param name="name">Name of the header to add</param>
/// <param name="value">Value of the header to add</param>
/// <returns></returns>
/// <returns>This request</returns>
IRestRequest AddHeader(string name, string value);

/// <summary>
/// Shortcut to AddOrUpdateParameter(name, value, HttpHeader) overload
/// </summary>
/// <param name="name">Name of the header to add or update</param>
/// <param name="value">Value of the header to add or update</param>
/// <returns>This request</returns>
IRestRequest AddOrUpdateHeader(string name, string value);

/// <summary>
/// Uses AddHeader(name, value) in a convenient way to pass
/// in multiple headers at once.
/// </summary>
/// <param name="headers">Key/Value pairs containing the name: value of the headers</param>
/// <returns>This request</returns>
IRestRequest AddHeaders(ICollection<KeyValuePair<string, string>> headers);

/// <summary>
/// Uses AddOrUpdateHeader(name, value) in a convenient way to pass
/// in multiple headers at once.
/// </summary>
/// <param name="headers">Key/Value pairs containing the name: value of the headers</param>
/// <returns>This request</returns>
IRestRequest AddOrUpdateHeaders(ICollection<KeyValuePair<string, string>> headers);

/// <summary>
/// Shortcut to AddParameter(name, value, Cookie) overload
Expand Down
55 changes: 42 additions & 13 deletions src/RestSharp/RestRequest.cs
Expand Up @@ -384,25 +384,21 @@ public IRestRequest AddOrUpdateParameter(string name, object value, string conte
/// <inheritdoc />
public IRestRequest AddHeader(string name, string value)
{
static bool InvalidHost(string host) => Uri.CheckHostName(PortSplitRegex.Split(host)[0]) == UriHostNameType.Unknown;

if (name == "Host" && InvalidHost(value))
throw new ArgumentException("The specified value is not a valid Host header string.", nameof(value));

CheckAndThrowsForInvalidHost(name, value);
return AddParameter(name, value, ParameterType.HttpHeader);
}

/// <inheritdoc />
public IRestRequest AddHeaders(ICollection<KeyValuePair<string, string>> headers)
public IRestRequest AddOrUpdateHeader(string name, string value)
{
var duplicateKeys = headers
.GroupBy(pair => pair.Key.ToUpperInvariant())
.Where(group => group.Count() > 1)
.Select(group => group.Key)
.ToList();
CheckAndThrowsForInvalidHost(name, value);
return AddOrUpdateParameter(name, value, ParameterType.HttpHeader);
}

if (duplicateKeys.Any())
throw new ArgumentException($"Duplicate header names exist: {string.Join(", ", duplicateKeys)}");
/// <inheritdoc />
public IRestRequest AddHeaders(ICollection<KeyValuePair<string, string>> headers)
{
CheckAndThrowsDuplicateKeys(headers);

foreach (var pair in headers)
{
Expand All @@ -412,6 +408,19 @@ public IRestRequest AddHeaders(ICollection<KeyValuePair<string, string>> headers
return this;
}

/// <inheritdoc />
public IRestRequest AddOrUpdateHeaders(ICollection<KeyValuePair<string, string>> headers)
{
CheckAndThrowsDuplicateKeys(headers);

foreach (var pair in headers)
{
AddOrUpdateHeader(pair.Key, pair.Value);
}

return this;
}

/// <inheritdoc />
public IRestRequest AddCookie(string name, string value) => AddParameter(name, value, ParameterType.Cookie);

Expand Down Expand Up @@ -486,5 +495,25 @@ public IRestRequest AddDecompressionMethod(DecompressionMethods decompressionMet
public IRestRequest AddUrlSegment(string name, object value) => AddParameter(name, value, ParameterType.UrlSegment);

IRestRequest AddFile(FileParameter file) => this.With(x => x.Files.Add(file));

private static void CheckAndThrowsForInvalidHost(string name, string value)
{
static bool InvalidHost(string host) => Uri.CheckHostName(PortSplitRegex.Split(host)[0]) == UriHostNameType.Unknown;

if (name == "Host" && InvalidHost(value))
throw new ArgumentException("The specified value is not a valid Host header string.", nameof(value));
}

private static void CheckAndThrowsDuplicateKeys(ICollection<KeyValuePair<string, string>> headers)
{
var duplicateKeys = headers
.GroupBy(pair => pair.Key.ToUpperInvariant())
.Where(group => group.Count() > 1)
.Select(group => group.Key)
.ToList();

if (duplicateKeys.Any())
throw new ArgumentException($"Duplicate header names exist: {string.Join(", ", duplicateKeys)}");
}
}
}
123 changes: 120 additions & 3 deletions test/RestSharp.Tests/RequestHeaderTests.cs
Expand Up @@ -29,7 +29,7 @@ public void AddHeaders_SameCaseDuplicatesExist_ThrowsException()
[Test]
public void AddHeaders_DifferentCaseDuplicatesExist_ThrowsException()
{
var headers = new List<KeyValuePair<string, string>>()
var headers = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("Accept", "application/json"),
new KeyValuePair<string, string>("Accept-Language", "en-us,en;q=0.5"),
Expand All @@ -46,7 +46,7 @@ public void AddHeaders_DifferentCaseDuplicatesExist_ThrowsException()
[Test]
public void AddHeaders_NoDuplicatesExist_Has3Headers()
{
var headers = new List<KeyValuePair<string, string>>()
var headers = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("Accept", "application/json"),
new KeyValuePair<string, string>("Accept-Language", "en-us,en;q=0.5"),
Expand All @@ -64,7 +64,7 @@ public void AddHeaders_NoDuplicatesExist_Has3Headers()
[Test]
public void AddHeaders_NoDuplicatesExistUsingDictionary_Has3Headers()
{
var headers = new Dictionary<string, string>()
var headers = new Dictionary<string, string>
{
{ "Accept", "application/json" },
{ "Accept-Language", "en-us,en;q=0.5" },
Expand All @@ -78,5 +78,122 @@ public void AddHeaders_NoDuplicatesExistUsingDictionary_Has3Headers()

Assert.AreEqual(3, httpParameters.Count());
}

[Test]
public void AddOrUpdateHeader_ShouldUpdateExistingHeader_WhenHeaderExist()
{
// Arrange
var request = new RestRequest();
request.AddHeader("Accept", "application/xml");

// Act
request.AddOrUpdateHeader("Accept", "application/json");

// Assert
var headers = request.Parameters.Where(parameter => parameter.Type == ParameterType.HttpHeader).ToArray();

Assert.AreEqual("application/json", headers.First(parameter => parameter.Name == "Accept").Value);
Assert.AreEqual(1, headers.Length);
}

[Test]
public void AddOrUpdateHeader_ShouldUpdateExistingHeader_WhenHeaderDoesNotExist()
{
// Arrange
var request = new RestRequest();

// Act
request.AddOrUpdateHeader("Accept", "application/json");

// Assert
var headers = request.Parameters.Where(parameter => parameter.Type == ParameterType.HttpHeader).ToArray();

Assert.AreEqual("application/json", headers.First(parameter => parameter.Name == "Accept").Value);
Assert.AreEqual(1, headers.Length);
}

[Test]
public void AddOrUpdateHeaders_ShouldAddHeaders_WhenNoneExists()
{
// Arrange
var headers = new Dictionary<string, string>
{
{ "Accept", "application/json" },
{ "Accept-Language", "en-us,en;q=0.5" },
{ "Keep-Alive", "300" }
};

var request = new RestRequest();

// Act
request.AddOrUpdateHeaders(headers);

// Assert
var requestHeaders = request.Parameters.Where(parameter => parameter.Type == ParameterType.HttpHeader).ToArray();

Assert.AreEqual("application/json", requestHeaders.First(parameter => parameter.Name == "Accept").Value);
Assert.AreEqual("en-us,en;q=0.5", requestHeaders.First(parameter => parameter.Name == "Accept-Language").Value);
Assert.AreEqual("300", requestHeaders.First(parameter => parameter.Name == "Keep-Alive").Value);
Assert.AreEqual(3, requestHeaders.Length);
}

[Test]
public void AddOrUpdateHeaders_ShouldUpdateHeaders_WhenAllExists()
{
// Arrange
var headers = new Dictionary<string, string>
{
{ "Accept", "application/json" },
{ "Keep-Alive", "300" }
};
var updatedHeaders = new Dictionary<string, string>
{
{ "Accept", "application/xml" },
{ "Keep-Alive", "400" }
};

var request = new RestRequest();
request.AddHeaders(headers);

// Act
request.AddOrUpdateHeaders(updatedHeaders);

// Assert
var requestHeaders = request.Parameters.Where(parameter => parameter.Type == ParameterType.HttpHeader).ToArray();

Assert.AreEqual("application/xml", requestHeaders.First(parameter => parameter.Name == "Accept").Value);
Assert.AreEqual("400", requestHeaders.First(parameter => parameter.Name == "Keep-Alive").Value);
Assert.AreEqual(2, requestHeaders.Length);
}

[Test]
public void AddOrUpdateHeaders_ShouldAddAndUpdateHeaders_WhenSomeExists()
{
// Arrange
var headers = new Dictionary<string, string>
{
{ "Accept", "application/json" },
{ "Keep-Alive", "300" }
};
var updatedHeaders = new Dictionary<string, string>
{
{ "Accept", "application/xml" },
{ "Accept-Language", "en-us,en;q=0.5" }
};

var request = new RestRequest();
request.AddHeaders(headers);

// Act
request.AddOrUpdateHeaders(updatedHeaders);

// Assert
var requestHeaders = request.Parameters.Where(parameter => parameter.Type == ParameterType.HttpHeader).ToArray();

Assert.AreEqual("application/xml", requestHeaders.First(parameter => parameter.Name == "Accept").Value);
Assert.AreEqual("en-us,en;q=0.5", requestHeaders.First(parameter => parameter.Name == "Accept-Language").Value);
Assert.AreEqual("300", requestHeaders.First(parameter => parameter.Name == "Keep-Alive").Value);
Assert.AreEqual(3, requestHeaders.Length);
}
}
}