-
Notifications
You must be signed in to change notification settings - Fork 9.8k
/
MediaTypeHeaderValueComparer.cs
135 lines (124 loc) · 4.8 KB
/
MediaTypeHeaderValueComparer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace Microsoft.Net.Http.Headers;
/// <summary>
/// Implementation of <see cref="IComparer{T}"/> that can compare accept media type header fields
/// based on their quality values (a.k.a q-values).
/// </summary>
public class MediaTypeHeaderValueComparer : IComparer<MediaTypeHeaderValue>
{
private MediaTypeHeaderValueComparer()
{
}
/// <summary>
/// Gets the <see cref="MediaTypeHeaderValueComparer"/> instance.
/// </summary>
public static MediaTypeHeaderValueComparer QualityComparer { get; } = new MediaTypeHeaderValueComparer();
/// <inheritdoc />
/// <remarks>
/// Performs comparisons based on the arguments' quality values
/// (aka their "q-value"). Values with identical q-values are considered equal (i.e. the result is 0)
/// with the exception that suffixed subtype wildcards are considered less than subtype wildcards, subtype wildcards
/// are considered less than specific media types and full wildcards are considered less than
/// subtype wildcards. This allows callers to sort a sequence of <see cref="MediaTypeHeaderValue"/> following
/// their q-values in the order of specific media types, subtype wildcards, and last any full wildcards.
/// </remarks>
/// <example>
/// If we had a list of media types (comma separated): { text/*;q=0.8, text/*+json;q=0.8, */*;q=1, */*;q=0.8, text/plain;q=0.8 }
/// Sorting them using Compare would return: { */*;q=0.8, text/*;q=0.8, text/*+json;q=0.8, text/plain;q=0.8, */*;q=1 }
/// </example>
public int Compare(MediaTypeHeaderValue? mediaType1, MediaTypeHeaderValue? mediaType2)
{
if (object.ReferenceEquals(mediaType1, mediaType2))
{
return 0;
}
if (mediaType1 is null)
{
return -1;
}
if (mediaType2 is null)
{
return 1;
}
var returnValue = CompareBasedOnQualityFactor(mediaType1, mediaType2);
if (returnValue == 0)
{
if (!mediaType1.Type.Equals(mediaType2.Type, StringComparison.OrdinalIgnoreCase))
{
if (mediaType1.MatchesAllTypes)
{
return -1;
}
else if (mediaType2.MatchesAllTypes)
{
return 1;
}
else if (mediaType1.MatchesAllSubTypes && !mediaType2.MatchesAllSubTypes)
{
return -1;
}
else if (!mediaType1.MatchesAllSubTypes && mediaType2.MatchesAllSubTypes)
{
return 1;
}
else if (mediaType1.MatchesAllSubTypesWithoutSuffix && !mediaType2.MatchesAllSubTypesWithoutSuffix)
{
return -1;
}
else if (!mediaType1.MatchesAllSubTypesWithoutSuffix && mediaType2.MatchesAllSubTypesWithoutSuffix)
{
return 1;
}
}
else if (!mediaType1.SubType.Equals(mediaType2.SubType, StringComparison.OrdinalIgnoreCase))
{
if (mediaType1.MatchesAllSubTypes)
{
return -1;
}
else if (mediaType2.MatchesAllSubTypes)
{
return 1;
}
else if (mediaType1.MatchesAllSubTypesWithoutSuffix && !mediaType2.MatchesAllSubTypesWithoutSuffix)
{
return -1;
}
else if (!mediaType1.MatchesAllSubTypesWithoutSuffix && mediaType2.MatchesAllSubTypesWithoutSuffix)
{
return 1;
}
}
else if (!mediaType1.Suffix.Equals(mediaType2.Suffix, StringComparison.OrdinalIgnoreCase))
{
if (mediaType1.MatchesAllSubTypesWithoutSuffix)
{
return -1;
}
else if (mediaType2.MatchesAllSubTypesWithoutSuffix)
{
return 1;
}
}
}
return returnValue;
}
private static int CompareBasedOnQualityFactor(
MediaTypeHeaderValue mediaType1,
MediaTypeHeaderValue mediaType2)
{
var mediaType1Quality = mediaType1.Quality ?? HeaderQuality.Match;
var mediaType2Quality = mediaType2.Quality ?? HeaderQuality.Match;
var qualityDifference = mediaType1Quality - mediaType2Quality;
if (qualityDifference < 0)
{
return -1;
}
else if (qualityDifference > 0)
{
return 1;
}
return 0;
}
}