@@ -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