如何创建使用GenericUriParserOptions.DontCompressPath解析的Uri实例

时间:2010-03-25 13:39:25

标签: c# .net http uri

当.NET System.Uri类解析字符串时,它会对输入执行一些规范化操作,例如对方案和主机名进行较低的设置。它还会修剪每个路径段的尾随时段。后一个特性对OpenID应用程序来说是致命的,因为一些OpenID(如雅虎发布的那些)包括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。

我很高兴任何解决方案:

  1. Uri.Path
  2. 中的路径段中保留尾随句点
  3. 在传出的HTTP请求中包含这些句点。
  4. 理想情况下适用于ASP.NET中等信任(但不是绝对必要)。

4 个答案:

答案 0 :(得分:5)

微软称它将在.NET 4.0中修复(尽管从评论中可以看出它还没有修复)

https://connect.microsoft.com/VisualStudio/feedback/details/386695/system-uri-incorrectly-strips-trailing-dots?wa=wsignin1.0#tabs

然而,该页面上有一种解决方法。它涉及使用反射来改变选项,因此它可能不符合中等信任要求。只需滚动到底部,然后单击“解决方法”选项卡。

感谢jxdavis和Google的回答:

http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/5206beca-071f-485d-a2bd-657d635239c9

答案 1 :(得分:2)

我很好奇,如果问题的一部分是你只考虑“不压缩路径”,而不是基本HTTP解析器的所有默认值:(包括UnEscapeDotsAndSlashes)

  private const UriSyntaxFlags HttpSyntaxFlags = (UriSyntaxFlags.AllowIriParsing | UriSyntaxFlags.AllowIdn | UriSyntaxFlags.UnEscapeDotsAndSlashes | UriSyntaxFlags.CanonicalizeAsFilePath | UriSyntaxFlags.CompressPath | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.PathIsRooted | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MustHaveAuthority);

这与有标志的新闻相反(例如):

 private const UriSyntaxFlags NewsSyntaxFlags = (UriSyntaxFlags.AllowIriParsing | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHavePath);

Dang,Brandon Black在打字的时候打败了我......

这可能有助于代码可读性:

namespace System 
{
    [Flags]
    internal enum UriSyntaxFlags
    {
        AllowAnInternetHost = 0xe00,
        AllowAnyOtherHost = 0x1000,
        AllowDnsHost = 0x200,
        AllowDOSPath = 0x100000,
        AllowEmptyHost = 0x80,
        AllowIdn = 0x4000000,
        AllowIPv4Host = 0x400,
        AllowIPv6Host = 0x800,
        AllowIriParsing = 0x10000000,
        AllowUncHost = 0x100,
        BuiltInSyntax = 0x40000,
        CanonicalizeAsFilePath = 0x1000000,
        CompressPath = 0x800000,
        ConvertPathSlashes = 0x400000,
        FileLikeUri = 0x2000,
        MailToLikeUri = 0x4000,
        MayHaveFragment = 0x40,
        MayHavePath = 0x10,
        MayHavePort = 8,
        MayHaveQuery = 0x20,
        MayHaveUserInfo = 4,
        MustHaveAuthority = 1,
        OptionalAuthority = 2,
        ParserSchemeOnly = 0x80000,
        PathIsRooted = 0x200000,
        SimpleUserSyntax = 0x20000,
        UnEscapeDotsAndSlashes = 0x2000000,
        V1_UnknownUri = 0x10000
    }
}

答案 2 :(得分:1)

你应该能够逃脱'。'使用'%2E',但这是廉价而肮脏的出路。

您可能会尝试使用 dontEscape 选项,这可能会改变Uri处理这些字符的方式。

更多信息: http://msdn.microsoft.com/en-us/library/system.uri.aspx

另请参阅以下内容(请参阅DontUnescapePathDotsAndSlashes): http:// msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx

答案 3 :(得分:1)

这有用吗?

public class MyUriParser : UriParser
{
private string actualScheme;

public MyUriParser(string actualScheme)
{
    Type type = this.GetType();
    FieldInfo fInfo = type.BaseType.GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
    fInfo.SetValue(this, 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;
}}