Skip to content

Commit 75a7a3d

Browse files
committed
fix #1634 PUrify broke GetHashCode() on mono
1 parent 87a2c0a commit 75a7a3d

File tree

2 files changed

+81
-81
lines changed

2 files changed

+81
-81
lines changed

src/Elasticsearch.DNX.sln

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
Microsoft Visual Studio Solution File, Format Version 12.00
22
# Visual Studio 14
3-
VisualStudioVersion = 14.0.23107.0
3+
VisualStudioVersion = 14.0.24720.0
44
MinimumVisualStudioVersion = 10.0.40219.1
55
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Elasticsearch.Net", "Elasticsearch.Net\Elasticsearch.Net.xproj", "{C837B88B-1395-424C-8A6D-BFB5B47B8B8E}"
66
EndProject
77
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{87237912-4EFF-49B1-AE76-CD46D97A8DA1}"
88
ProjectSection(SolutionItems) = preProject
9+
..\build.bat = ..\build.bat
910
global.json = global.json
1011
..\nuget.config = ..\nuget.config
1112
EndProjectSection

src/Elasticsearch.Net/Purify/Purify.cs

Lines changed: 79 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,26 @@ public static class Purifier
1111
public static Uri Purify(this Uri uri) => uri;
1212
}
1313
#else
14-
/// <summary>
15-
/// The Uri classes in .NET prior to 4.5 and Mono scrub through your Uris and modify them in order to prevent vulnerabilities, for
16-
/// example escaped slashes are unescaped. This scrubbing however prevents Uris that are inline with RFC 3986. Beyond that it prevents
17-
/// using .NET's HTTP clients (HttpClient and WebClient) to talk to APIs that require accessing resources using escaped
18-
/// slashes unless you are using .NET 4.5.
19-
/// <pre>
20-
/// This static class allows you to purify a Uri instance so that it remains untouched across all .NET runtime versions
21-
/// </pre>
22-
/// </summary>
14+
/// <summary>
15+
/// The Uri classes in .NET prior to 4.5 and Mono scrub through your Uris and modify them in order to prevent vulnerabilities, for
16+
/// example escaped slashes are unescaped. This scrubbing however prevents Uris that are inline with RFC 3986. Beyond that it prevents
17+
/// using .NET's HTTP clients (HttpClient and WebClient) to talk to APIs that require accessing resources using escaped
18+
/// slashes unless you are using .NET 4.5.
19+
/// <pre>
20+
/// This static class allows you to purify a Uri instance so that it remains untouched across all .NET runtime versions
21+
/// </pre>
22+
/// </summary>
2323
public static class Purifier
2424
{
25-
private static readonly bool HasBrokenDotNetUri;
2625

27-
private static readonly bool IsMono;
26+
private static readonly bool hasBrokenDotNetUri;
27+
28+
private static readonly bool isMono;
2829

2930
static Purifier()
3031
{
31-
IsMono = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic) == null;
32-
if (IsMono)
32+
isMono = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic) == null;
33+
if (isMono)
3334
return;
3435

3536
//ShouldUseLegacyV2Quirks was introduced in .net 4.5
@@ -38,7 +39,7 @@ static Purifier()
3839
var legacyV2Quirks = typeof(UriParser).GetProperty("ShouldUseLegacyV2Quirks", BindingFlags.Static | BindingFlags.NonPublic);
3940
if (legacyV2Quirks == null)
4041
{
41-
HasBrokenDotNetUri = true; //neither 4.0 or 4.5
42+
hasBrokenDotNetUri = true; //neither 4.0 or 4.5
4243
return;
4344
}
4445
var isBrokenUri = (bool)legacyV2Quirks.GetValue(null, null);
@@ -61,23 +62,23 @@ static Purifier()
6162
//
6263
// so instead of using reflection perform a one off functional test.
6364

64-
HasBrokenDotNetUri = !new Uri("http://google.com/%2F")
65+
hasBrokenDotNetUri = !new Uri("http://google.com/%2F")
6566
.ToString()
6667
.EndsWith("%2F", StringComparison.InvariantCulture);
6768
}
6869

69-
/// <summary>
70-
/// Will purify the <param name="uri"></param> to the unscrubed version.
71-
/// <pre>Calling this will be a NOOP on .NET 4.5 and up.</pre>
72-
/// </summary>
73-
/// <param name="uri">The uri to be purified</param>
74-
/// <returns>The purified uri</returns>
70+
/// <summary>
71+
/// Will purify the <param name="uri"></param> to the unscrubed version.
72+
/// <pre>Calling this will be a NOOP on .NET 4.5 and up.</pre>
73+
/// </summary>
74+
/// <param name="uri">The uri to be purified</param>
75+
/// <returns>The purified uri</returns>
7576
public static Uri Purify(this Uri uri)
7677
{
7778
IPurifier purifier = null;
78-
if (IsMono)
79+
if (isMono)
7980
purifier = new PurifierMono();
80-
else if (HasBrokenDotNetUri)
81+
else if (hasBrokenDotNetUri)
8182
purifier = new PurifierDotNet();
8283
else return uri;
8384

@@ -86,98 +87,96 @@ public static Uri Purify(this Uri uri)
8687

8788
private interface IPurifier
8889
{
89-
/// <summary>
90-
/// purifies and returns the passed <param name="uri"></param>
91-
/// </summary>
90+
/// <summary>
91+
/// purifies and returns the passed <param name="uri"></param>
92+
/// </summary>
9293
Uri Purify(Uri uri);
9394
}
9495

9596
private class PurifierDotNet : IPurifier
9697
{
97-
private static readonly FieldInfo FlagsField;
98-
private static readonly FieldInfo InfoField;
99-
private static readonly FieldInfo StringField;
100-
private static readonly FieldInfo InfoStringField;
101-
private static readonly FieldInfo MoreInfoField;
102-
private static readonly FieldInfo MoreInfoAbsoluteUri;
103-
private static readonly FieldInfo MoreInfoPath;
104-
private static readonly FieldInfo MoreInfoQuery;
98+
private static FieldInfo flagsField;
99+
private static FieldInfo infoField;
100+
private static FieldInfo stringField;
101+
private static FieldInfo infoStringField;
102+
private static FieldInfo moreInfoField;
103+
private static FieldInfo moreInfoAbsoluteUri;
104+
private static FieldInfo moreInfoPath;
105+
private static FieldInfo moreInfoQuery;
105106

106107
static PurifierDotNet()
107108
{
108109
var uriType = typeof(Uri);
109-
FlagsField = uriType.GetField("m_Flags", BindingFlags.NonPublic | BindingFlags.Instance);
110-
StringField = uriType.GetField("m_String", BindingFlags.NonPublic | BindingFlags.Instance);
111-
InfoField = uriType.GetField("m_Info", BindingFlags.NonPublic | BindingFlags.Instance);
112-
var infoFieldType = InfoField.FieldType;
113-
InfoStringField = infoFieldType.GetField("String", BindingFlags.Public | BindingFlags.Instance);
114-
MoreInfoField = infoFieldType.GetField("MoreInfo", BindingFlags.Public | BindingFlags.Instance);
115-
var moreInfoType = MoreInfoField.FieldType;
116-
MoreInfoAbsoluteUri = moreInfoType.GetField("AbsoluteUri", BindingFlags.Public | BindingFlags.Instance);
117-
MoreInfoQuery = moreInfoType.GetField("Query", BindingFlags.Public | BindingFlags.Instance);
118-
MoreInfoPath = moreInfoType.GetField("Path", BindingFlags.Public | BindingFlags.Instance);
110+
flagsField = uriType.GetField("m_Flags", BindingFlags.NonPublic | BindingFlags.Instance);
111+
stringField = uriType.GetField("m_String", BindingFlags.NonPublic | BindingFlags.Instance);
112+
infoField = uriType.GetField("m_Info", BindingFlags.NonPublic | BindingFlags.Instance);
113+
var infoFieldType = infoField.FieldType;
114+
infoStringField = infoFieldType.GetField("String", BindingFlags.Public | BindingFlags.Instance);
115+
moreInfoField = infoFieldType.GetField("MoreInfo", BindingFlags.Public | BindingFlags.Instance);
116+
var moreInfoType = moreInfoField.FieldType;
117+
moreInfoAbsoluteUri = moreInfoType.GetField("AbsoluteUri", BindingFlags.Public | BindingFlags.Instance);
118+
moreInfoQuery = moreInfoType.GetField("Query", BindingFlags.Public | BindingFlags.Instance);
119+
moreInfoPath = moreInfoType.GetField("Path", BindingFlags.Public | BindingFlags.Instance);
119120
}
120121

121122
//Code inspired by Rasmus Faber's solution in this post: http://stackoverflow.com/questions/781205/getting-a-url-with-an-url-encoded-slash
122123
public Uri Purify(Uri uri)
123124
{
124-
// ReSharper disable once UnusedVariable
125125
string paq = uri.PathAndQuery; // need to access PathAndQuery
126-
// ReSharper disable once UnusedVariable
127126
var abs = uri.AbsoluteUri; //need to access this as well the MoreInfo prop is initialized.
128-
ulong flags = (ulong)FlagsField.GetValue(uri);
127+
ulong flags = (ulong)flagsField.GetValue(uri);
129128
flags &= ~((ulong)0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
130-
FlagsField.SetValue(uri, flags);
131-
object info = InfoField.GetValue(uri);
132-
var source = (string)StringField.GetValue(uri);
133-
InfoStringField.SetValue(info, source);
134-
object moreInfo = MoreInfoField.GetValue(info);
135-
MoreInfoAbsoluteUri.SetValue(moreInfo, source);
129+
flagsField.SetValue(uri, flags);
130+
object info = infoField.GetValue(uri);
131+
var source = (string)stringField.GetValue(uri);
132+
infoStringField.SetValue(info, source);
133+
object moreInfo = moreInfoField.GetValue(info);
134+
moreInfoAbsoluteUri.SetValue(moreInfo, source);
136135
var uriInfo = new UriInfo(uri, source);
137-
MoreInfoPath.SetValue(moreInfo, uriInfo.Path);
138-
MoreInfoQuery.SetValue(moreInfo, uriInfo.Query);
136+
moreInfoPath.SetValue(moreInfo, uriInfo.Path);
137+
moreInfoQuery.SetValue(moreInfo, uriInfo.Query);
139138
return uri;
140139
}
141140
}
142141

143142
private class PurifierMono : IPurifier
144143
{
145-
private static readonly Type UriType = typeof(Uri);
146-
private static readonly FieldInfo MonoSourceField;
147-
private static readonly FieldInfo MonoQueryField;
148-
private static readonly FieldInfo MonoPathField;
149-
private static readonly FieldInfo MonoCachedToStringField;
150-
private static readonly FieldInfo MonoCachedAbsoluteUriField;
144+
private static Type uriType = typeof(Uri);
145+
private static FieldInfo mono_sourceField;
146+
private static FieldInfo mono_queryField;
147+
private static FieldInfo mono_pathField;
148+
private static FieldInfo mono_cachedToStringField;
149+
private static FieldInfo mono_cachedAbsoluteUriField;
151150

152151
static PurifierMono()
153152
{
154-
MonoSourceField = UriType.GetField("source", BindingFlags.NonPublic | BindingFlags.Instance);
155-
MonoQueryField = UriType.GetField("query", BindingFlags.NonPublic | BindingFlags.Instance);
156-
MonoPathField = UriType.GetField("path", BindingFlags.NonPublic | BindingFlags.Instance);
157-
MonoCachedToStringField = UriType.GetField("cachedToString", BindingFlags.NonPublic | BindingFlags.Instance);
158-
MonoCachedAbsoluteUriField = UriType.GetField("cachedAbsoluteUri",
153+
mono_sourceField = uriType.GetField("source", BindingFlags.NonPublic | BindingFlags.Instance);
154+
mono_queryField = uriType.GetField("query", BindingFlags.NonPublic | BindingFlags.Instance);
155+
mono_pathField = uriType.GetField("path", BindingFlags.NonPublic | BindingFlags.Instance);
156+
mono_cachedToStringField = uriType.GetField("cachedToString", BindingFlags.NonPublic | BindingFlags.Instance);
157+
mono_cachedAbsoluteUriField = uriType.GetField("cachedAbsoluteUri",
159158
BindingFlags.NonPublic | BindingFlags.Instance);
160159
}
161160

162161
public Uri Purify(Uri uri)
163162
{
164-
var source = (string)MonoSourceField.GetValue(uri);
165-
MonoCachedToStringField.SetValue(uri, source);
166-
MonoCachedAbsoluteUriField.SetValue(uri, source);
163+
var source = (string)mono_sourceField.GetValue(uri);
164+
mono_cachedToStringField.SetValue(uri, source ?? string.Empty);
165+
mono_cachedAbsoluteUriField.SetValue(uri, source ?? string.Empty);
167166
var uriInfo = new UriInfo(uri, source);
168-
MonoPathField.SetValue(uri, uriInfo.Path);
169-
MonoQueryField.SetValue(uri, uriInfo.Query);
167+
mono_pathField.SetValue(uri, uriInfo.Path ?? string.Empty);
168+
mono_queryField.SetValue(uri, uriInfo.Query ?? string.Empty);
170169
return uri;
171170
}
172171
}
173172

174-
/// <summary>
175-
/// Class that breaks a Uri into path and query components given its orignal source
176-
/// </summary>
173+
/// <summary>
174+
/// Class that breaks a Uri into path and query components given its orignal source
175+
/// </summary>
177176
private class UriInfo
178177
{
179-
public string Path { get; }
180-
public string Query { get; }
178+
public string Path { get; private set; }
179+
public string Query { get; private set; }
181180

182181
public UriInfo(Uri uri, string source)
183182
{
@@ -190,19 +189,19 @@ public UriInfo(Uri uri, string source)
190189

191190
if (start < pathEnd - 1 && source[start] == ':')
192191
{
193-
var portLength = uri.Port.ToString(CultureInfo.InvariantCulture).Length;
192+
var portLength = uri.Port.ToString().Length;
194193
start += portLength + 1;
195194
}
196195

197196
Path = queryPos > -1 ? source.Substring(start, pathEnd - start) : source.Substring(start);
198-
199197
Query = fragPos > -1
200198
? source.Substring(queryPos, fragPos - queryPos)
201199
: queryPos > -1
202200
? source.Substring(queryPos, (source.Length - queryPos))
203201
: null;
204202
}
205203
}
206-
}
207-
#endif
204+
}
205+
206+
#endif
208207
}

0 commit comments

Comments
 (0)