The 2011 answer above by Simon Mourier no longer works on recent versions of .NET. This is because it uses reflection to look up a field inside the UriParser
class, and update its value. This field is no longer named m_Flags
, but just _flags
now. It's not particularly surprising that this field name would have changed in the past 12 years across many versions of .NET.
Here is an alternative that works for .NET 7 (I haven't tried any other versions). Call this function at the start of your program, and adjust the list of schemes to fit your use case:
public static void DoNotSimplifyUris()
{
const int CanonicalizeAsFilePath = 0x01000000;
const int ConvertPathSlashes = 0x00400000;
const int CompressPath = 0x00800000;
var getSyntaxMethod = typeof (UriParser).GetMethod("GetSyntax", BindingFlags.Static | BindingFlags.NonPublic);
if (getSyntaxMethod == null)
{
throw new MissingMethodException("UriParser", "GetSyntax");
}
foreach (var scheme in new[] { "http", "https" })
{
// call with "http" and "https" to update both UriParser objects (see UriParser class for all instances)
var uriParser = getSyntaxMethod.Invoke(null, new object[] { scheme });
if (uriParser == null)
{
throw new ArgumentNullException($"Unexpected: UriParser.getSyntax({scheme}) returned null");
}
// get reference to UriParser._flags field
var flagsFieldInfo = typeof(UriParser).GetField("_flags",
BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance);
if (flagsFieldInfo == null)
{
throw new MissingFieldException("UriParser", "_flags");
}
// get value of that field on the UriParser object we're looking at (either the http or https instance)
var flagsValue = flagsFieldInfo.GetValue(uriParser);
if (flagsValue == null)
{
throw new Exception($"Could not extract the value of UriParser._flags for the {scheme} instance");
}
// convert to the underlying int representation to unset some flags
var flags = (int) flagsValue;
flags &= ~CanonicalizeAsFilePath;
flags &= ~ConvertPathSlashes;
flags &= ~CompressPath;
// save the modified value on the UriParser instance
flagsFieldInfo.SetValue(uriParser, flags);
}
}
This should also work with other changes made by UriParser
to URIs. For example, by default it simplifies /./
to simply /
as if all URIs represented a file path.
I tried sending a request to /foo/./bar
without calling this method, and the server received a GET /foo/bar
. When calling it first, it receives GET /foo/./bar
.