【发布时间】:2011-01-31 17:43:19
【问题描述】:
当 .NET System.Uri 类解析字符串时,它会对输入执行一些规范化,例如将方案和主机名小写。它还修剪每个路径段的尾随周期。后一种特性对 OpenID 应用程序来说是致命的,因为一些 OpenID(例如从 Yahoo 发布的那些)包含可能以句点结尾的 base64 编码路径段。
如何禁用 Uri 类的这种周期修剪行为?
使用UriParser.Register 注册我自己的方案并使用GenericUriParserOptions.DontCompressPath 初始化的解析器避免了句点修整以及其他一些对于OpenID 来说也是不可取的操作。但是我无法为现有的方案(如 HTTP 和 HTTPS)注册新的解析器,而我必须为 OpenID 做这些。
我尝试的另一种方法是注册我自己的新方案,并编写自定义解析器以将方案更改回标准 HTTP(s) 方案作为解析的一部分:
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();
}
}
这实际上几乎有效。 Uri 实例到处报告 https 而不是 httpsx —— 除了 Uri.Scheme 属性本身。当您将此Uri 实例传递给HttpWebRequest 以向该地址发送请求时,这是一个问题。显然它检查了 Scheme 属性并且不将其识别为“https”,因为它只是将纯文本发送到 443 端口而不是 SSL。
我很高兴有任何解决方案:
- 在
Uri.Path的路径段中保留尾随句点 - 在传出的 HTTP 请求中包含这些句点。
- 在 ASP.NET 中等信任下理想地工作(但不是绝对必要的)。
【问题讨论】:
-
如果您的示例代码是一个失败的单元测试来说明问题所在会更容易。
-
单元测试必须设置一个 HTTPS Web 服务器来证明失败。 :(
-
你有没有成功解决过这个问题?您还需要这方面的帮助吗?
-
是的,当完全信任不可用时,通过反射(当完全信任可用时)和其他魔法的复杂混合。 github.com/AArnott/dotnetopenid/blob/v3.4/src/DotNetOpenAuth/… 中的大部分代码都致力于发挥所有必要的技巧来获得 99% 的正确行为。