When the .NET System.Uri class parses strings it performs some normalization on the input, such as lower-casing the scheme and hostname. It also trims trailing periods from each path segment. This latter feature is fatal to OpenID applications because some OpenIDs (like those issued from Yahoo) include base64 encoded path segments which may end with a period.
How can I disable this period-trimming behavior of the Uri class?
Registering my own scheme using UriParser.Register with a parser initialized with GenericUriParserOptions.DontCompressPath avoids the period trimming, and some other operations that are also undesirable for OpenID. But I cannot register a new parser for existing schemes like HTTP and HTTPS, which I must do for OpenIDs.
Another approach I tried was registering my own new scheme, and programming the custom parser to change the scheme back to the standard HTTP(s) schemes as part of parsing:
public class MyUriParser : GenericUriParser
{
private string actualScheme;
public MyUriParser(string actualScheme)
: base(GenericUriParserOptions.DontCompressPath)
{
this.actualScheme = actualScheme.ToLowerInvariant();
}
protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
{
string result = base.GetComponents(uri, components, format);
// Substitute our actual desired scheme in the string if it's in there.
if ((components & UriComponents.Scheme) != 0)
{
string registeredScheme = base.GetComponents(uri, UriComponents.Scheme, format);
result = this.actualScheme + result.Substring(registeredScheme.Length);
}
return result;
}
}
class Program
{
static void Main(string[] args)
{
UriParser.Register(new MyUriParser("http"), "httpx", 80);
UriParser.Register(new MyUriParser("https"), "httpsx", 443);
Uri z = new Uri("httpsx://me.yahoo.com/b./c.#adf");
var req = (HttpWebRequest)WebRequest.Create(z);
req.GetResponse();
}
}
This actually almost works. The Uri instance reports https instead of httpsx everywhere -- except the Uri.Scheme property itself. That's a problem when you pass this Uri instance to the HttpWebRequest to send a request to this address. Apparently it checks the Scheme property and doesn't recognize it as 'https' because it just sends plaintext to the 443 port instead of SSL.
I'm happy for any solution that:
Preserves trailing periods in path segments in Uri.Path
Includes these periods in outgoing HTTP requests.
Ideally works with under ASP.NET medium trust (but not absolutely necessary).