Skip to content

Commit

Permalink
Implement "AddOrUpdateHeader(s)" methods (#1576)
Browse files Browse the repository at this point in the history
Issue #1569
  • Loading branch information
Lramelot committed Jul 15, 2021
1 parent 56c3098 commit fd470c0
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 17 deletions.
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);
}
}
}

0 comments on commit fd470c0

Please sign in to comment.