How to get Uri.EscapeDataString to comply with RFC 3986

后端 未结 5 1425
死守一世寂寞
死守一世寂寞 2020-11-30 04:07

The Uri class defaults to RFC 2396. For OpenID and OAuth, I need Uri escaping consistent with RFC 3986.

From the System.Uri class documentation:

5条回答
  •  一向
    一向 (楼主)
    2020-11-30 04:34

    Having not been able to get Uri.EscapeDataString to take on RFC 3986 behavior, I wrote my own RFC 3986 compliant escaping method. It leverages Uri.EscapeDataString, and then 'upgrades' the escaping to RFC 3986 compliance.

    /// 
    /// The set of characters that are unreserved in RFC 2396 but are NOT unreserved in RFC 3986.
    /// 
    private static readonly string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" };
    
    /// 
    /// Escapes a string according to the URI data string rules given in RFC 3986.
    /// 
    /// The value to escape.
    /// The escaped value.
    /// 
    /// The  method is supposed to take on
    /// RFC 3986 behavior if certain elements are present in a .config file.  Even if this
    /// actually worked (which in my experiments it doesn't), we can't rely on every
    /// host actually having this configuration element present.
    /// 
    internal static string EscapeUriDataStringRfc3986(string value) {
        // Start with RFC 2396 escaping by calling the .NET method to do the work.
        // This MAY sometimes exhibit RFC 3986 behavior (according to the documentation).
        // If it does, the escaping we do that follows it will be a no-op since the
        // characters we search for to replace can't possibly exist in the string.
        StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value));
    
        // Upgrade the escaping to RFC 3986, if necessary.
        for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) {
            escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
        }
    
        // Return the fully-RFC3986-escaped string.
        return escaped.ToString();
    }
    

提交回复
热议问题