Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

Commit e4afd78

Browse files
committed
Add strong and weak ETag comparisons
1 parent e2a0e88 commit e4afd78

File tree

2 files changed

+127
-1
lines changed

2 files changed

+127
-1
lines changed

src/Microsoft.Net.Http.Headers/EntityTagHeaderValue.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ public override string ToString()
9393
return _tag;
9494
}
9595

96+
/// <summary>
97+
/// Check against another <see cref="EntityTagHeaderValue"/> for equality.
98+
/// This equality check should not be used to determine if two values match under the RFC specifications (https://tools.ietf.org/html/rfc7232#section-2.3.2).
99+
/// </summary>
100+
/// <param name="obj">The other value to check against for equality.</param>
101+
/// <returns>
102+
/// <c>true</c> if the strength and tag of the two values match,
103+
/// <c>false</c> if the other value is null, is not an <see cref="EntityTagHeaderValue"/>, or if there is a mismatch of strength or tag between the two values.
104+
/// </returns>
96105
public override bool Equals(object obj)
97106
{
98107
var other = obj as EntityTagHeaderValue;
@@ -103,7 +112,7 @@ public override bool Equals(object obj)
103112
}
104113

105114
// Since the tag is a quoted-string we treat it case-sensitive.
106-
return ((_isWeak == other._isWeak) && (string.CompareOrdinal(_tag, other._tag) == 0));
115+
return _isWeak == other._isWeak && string.Equals(_tag, other._tag, StringComparison.Ordinal);
107116
}
108117

109118
public override int GetHashCode()
@@ -112,6 +121,32 @@ public override int GetHashCode()
112121
return _tag.GetHashCode() ^ _isWeak.GetHashCode();
113122
}
114123

124+
/// <summary>
125+
/// Compares against another <see cref="EntityTagHeaderValue"/> to see if they match under the RFC specifications (https://tools.ietf.org/html/rfc7232#section-2.3.2).
126+
/// </summary>
127+
/// <param name="other">The other <see cref="EntityTagHeaderValue"/> to compare against.</param>
128+
/// <param name="useStrongComparison"><c>true</c> to use a strong comparison, <c>false</c> to use a weak comparison</param>
129+
/// <returns>
130+
/// <c>true</c> if the <see cref="EntityTagHeaderValue"/> match for the given comparison type,
131+
/// <c>false</c> if the other value is null or the comparison failed.
132+
/// </returns>
133+
public bool Compare(EntityTagHeaderValue other, bool useStrongComparison)
134+
{
135+
if (other == null)
136+
{
137+
return false;
138+
}
139+
140+
if (useStrongComparison)
141+
{
142+
return !IsWeak && !other.IsWeak && string.Equals(Tag, other.Tag, StringComparison.Ordinal);
143+
}
144+
else
145+
{
146+
return string.Equals(Tag, other.Tag, StringComparison.Ordinal);
147+
}
148+
}
149+
115150
public static EntityTagHeaderValue Parse(string input)
116151
{
117152
var index = 0;

test/Microsoft.Net.Http.Headers.Tests/EntityTagHeaderValueTest.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,97 @@ public void Equals_UseSameAndDifferentETags_EqualOrNotEqualNoExceptions()
9999
Assert.True(etag1.Equals(etag5), "tag vs. tag..");
100100
}
101101

102+
[Fact]
103+
public void Compare_WithNull_ReturnsFalse()
104+
{
105+
Assert.False(EntityTagHeaderValue.Any.Compare(null, useStrongComparison: true));
106+
Assert.False(EntityTagHeaderValue.Any.Compare(null, useStrongComparison: false));
107+
}
108+
109+
public static TheoryData<EntityTagHeaderValue, EntityTagHeaderValue> NotEquivalentUnderStrongComparison
110+
{
111+
get
112+
{
113+
return new TheoryData<EntityTagHeaderValue, EntityTagHeaderValue>
114+
{
115+
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"TAG\"") },
116+
{ new EntityTagHeaderValue("\"tag\"", true), new EntityTagHeaderValue("\"tag\"", true) },
117+
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag\"", true) },
118+
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag1\"") },
119+
{ new EntityTagHeaderValue("\"tag\""), EntityTagHeaderValue.Any },
120+
};
121+
}
122+
}
123+
124+
[Theory]
125+
[MemberData(nameof(NotEquivalentUnderStrongComparison))]
126+
public void CompareUsingStrongComparison_NonEquivalentPairs_ReturnFalse(EntityTagHeaderValue left, EntityTagHeaderValue right)
127+
{
128+
Assert.False(left.Compare(right, useStrongComparison: true));
129+
Assert.False(right.Compare(left, useStrongComparison: true));
130+
}
131+
132+
public static TheoryData<EntityTagHeaderValue, EntityTagHeaderValue> EquivalentUnderStrongComparison
133+
{
134+
get
135+
{
136+
return new TheoryData<EntityTagHeaderValue, EntityTagHeaderValue>
137+
{
138+
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag\"") },
139+
};
140+
}
141+
}
142+
143+
[Theory]
144+
[MemberData(nameof(EquivalentUnderStrongComparison))]
145+
public void CompareUsingStrongComparison_EquivalentPairs_ReturnTrue(EntityTagHeaderValue left, EntityTagHeaderValue right)
146+
{
147+
Assert.True(left.Compare(right, useStrongComparison: true));
148+
Assert.True(right.Compare(left, useStrongComparison: true));
149+
}
150+
151+
public static TheoryData<EntityTagHeaderValue, EntityTagHeaderValue> NotEquivalentUnderWeakComparison
152+
{
153+
get
154+
{
155+
return new TheoryData<EntityTagHeaderValue, EntityTagHeaderValue>
156+
{
157+
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"TAG\"") },
158+
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag1\"") },
159+
{ new EntityTagHeaderValue("\"tag\""), EntityTagHeaderValue.Any },
160+
};
161+
}
162+
}
163+
164+
[Theory]
165+
[MemberData(nameof(NotEquivalentUnderWeakComparison))]
166+
public void CompareUsingWeakComparison_NonEquivalentPairs_ReturnFalse(EntityTagHeaderValue left, EntityTagHeaderValue right)
167+
{
168+
Assert.False(left.Compare(right, useStrongComparison: false));
169+
Assert.False(right.Compare(left, useStrongComparison: false));
170+
}
171+
172+
public static TheoryData<EntityTagHeaderValue, EntityTagHeaderValue> EquivalentUnderWeakComparison
173+
{
174+
get
175+
{
176+
return new TheoryData<EntityTagHeaderValue, EntityTagHeaderValue>
177+
{
178+
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag\"") },
179+
{ new EntityTagHeaderValue("\"tag\"", true), new EntityTagHeaderValue("\"tag\"", true) },
180+
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag\"", true) },
181+
};
182+
}
183+
}
184+
185+
[Theory]
186+
[MemberData(nameof(EquivalentUnderWeakComparison))]
187+
public void CompareUsingWeakComparison_EquivalentPairs_ReturnTrue(EntityTagHeaderValue left, EntityTagHeaderValue right)
188+
{
189+
Assert.True(left.Compare(right, useStrongComparison: false));
190+
Assert.True(right.Compare(left, useStrongComparison: false));
191+
}
192+
102193
[Fact]
103194
public void Parse_SetOfValidValueStrings_ParsedCorrectly()
104195
{

0 commit comments

Comments
 (0)