A puzzle for today: what will this code get?
Console.WriteLine(uri.OriginalString);
Console.WriteLine(uri.AbsoluteUri);
The right answer is “it depends”. Let’s sort it out.
So, what will it get?
The result depends on the .NET version
http://localhost/%2F1
http://localhost//1
// .NET 4.5
http://localhost/%2F1
http://localhost/%2F1
Why is that?
Unfortunately, before .NET 4.0 there was an unpleasant bug with escaping slashes (aka %2F). In .NET 4.5 they decided to fix this bug to address RFC 3986. It seems they did the right thing, but they created some more headaches for developers who don’t know about this tiny nuance: now escaping mechanism depends on the .NET version. It would be better to use the right mechanism from .NET 4.5. But what if you don’t have .NET 4.5? There is a way to fix the behavior in .NET 4.0. You just need to add the following magic lines to the .config file of your project:
<uri>
<schemeSettings>
<add name="http"
genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
</schemeSettings>
</uri>
</configuration>
This trick works starting from .NET 4.0 beta 2. In other words it won’t work in .NET 3.5. You will have to look for the other options. For example, you can find the following magic “hack” on the Internet:
{
string paq = uri.PathAndQuery; // need to access PathAndQuery
FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags",
BindingFlags.Instance | BindingFlags.NonPublic);
ulong flags = (ulong) flagsFieldInfo.GetValue(uri);
flags &= ~((ulong) 0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
flagsFieldInfo.SetValue(uri, flags);
}
And what will happen in Mono?
In Mono, they have the very same bug. The fix became available in Mono 3.10.0 in October 2014. If you have the latest version, everything should be ok for you. How the rest of developers would switch between the old and new behavior? System.Uri class has the IriParsing property for this purpose. Let’s review the code:
internal static bool IriParsing {
get { return s_IriParsing; }
set { s_IriParsing = value; }
}
The property is set in the following way:
{
#if NET_4_5
IriParsing = true;
#endif
var iriparsingVar =
Environment.GetEnvironmentVariable ("MONO_URI_IRIPARSING");
if (iriparsingVar == "true")
IriParsing = true;
else if (iriparsingVar == "false")
IriParsing = false;
}
In other words, the easiest way to do it is the MONO_URI_IRIPARSING environment variable.
Summary
The bug is very unpleasant and might cost you many hours of peace of mind, if you accidentally face it. That is why I decided to write this article to make more people aware of this issue. Remember about the ambiguity of escaping of some URI and write stable code.
Related links:
- Mono Bug 16960
- StackOverflow: Getting a Uri with escaped slashes on mono
- StackOverflow: GETting a URL with an url-encoded slash
- Mono 3.10.0 release notes
- Mike Hadlow: How to stop System.Uri un-escaping forward slash characters
- Arnout’s Eclectica: URL-encoded slashes in System.Uri