HttpUtility.UrlEncode是否符合'x-www-form-urlencoded'的规范?

时间:2010-07-08 22:45:52

标签: .net urlencode standards-compliance

Per MSDN

  

URLEncode按如下方式转换字符:

     
      
  • Spaces()转换为加号(+)。
  •   
  • 非字母数字字符转义为十六进制表示。
  •   

W3C

相似但不完全相同
  

应用程序/ x-WWW窗体-urlencoded

     

这是默认内容类型。使用此内容类型提交的表单必须按如下方式编码:

     
      
  1. 转义控件名称和值。空格字符被替换   用'+',然后保留字符   按照RFC1738中的描述进行转义,   第2.2节:非字母数字   字符被'%HH'替换,a   百分号和两个十六进制   表示ASCII码的数字   人物。换行符是   表示为“CR LF”对(即,   '%0D 0A%')。

  2.   
  3. 控件名称/值按其出现的顺序列出   文献。名称与。分开   '='和名称/值对的值   通过'&'分开。

  4.   

我的问题是,是否有人完成了确定URLEncode是否生成有效的x-www-form-urlencoded数据的工作?

1 个答案:

答案 0 :(得分:6)

嗯,您链接到的文档是针对IIS 6 Server.UrlEncode的,但您的标题似乎询问了.NET System.Web.HttpUtility.UrlEncode。使用像Reflector这样的工具,我们可以看到后者的实现,并确定它是否符合W3C规范。

这是最终调用的编码例程(注意,它是为一个字节数组定义的,其他重载使得字符串最终将这些字符串转换为字节数组并调用此方法)。您可以为每个控件名称和值调用此方法(以避免转义用作分隔符的保留字符= &。)

protected internal virtual byte[] UrlEncode(byte[] bytes, int offset, int count)
{
    if (!ValidateUrlEncodingParameters(bytes, offset, count))
    {
        return null;
    }
    int num = 0;
    int num2 = 0;
    for (int i = 0; i < count; i++)
    {
        char ch = (char) bytes[offset + i];
        if (ch == ' ')
        {
            num++;
        }
        else if (!HttpEncoderUtility.IsUrlSafeChar(ch))
        {
            num2++;
        }
    }
    if ((num == 0) && (num2 == 0))
    {
        return bytes;
    }
    byte[] buffer = new byte[count + (num2 * 2)];
    int num4 = 0;
    for (int j = 0; j < count; j++)
    {
        byte num6 = bytes[offset + j];
        char ch2 = (char) num6;
        if (HttpEncoderUtility.IsUrlSafeChar(ch2))
        {
            buffer[num4++] = num6;
        }
        else if (ch2 == ' ')
        {
            buffer[num4++] = 0x2b;
        }
        else
        {
            buffer[num4++] = 0x25;
            buffer[num4++] = (byte) HttpEncoderUtility.IntToHex((num6 >> 4) & 15);
            buffer[num4++] = (byte) HttpEncoderUtility.IntToHex(num6 & 15);
        }
    }
    return buffer;
}

public static bool IsUrlSafeChar(char ch)
{
    if ((((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))) || ((ch >= '0') && (ch <= '9')))
    {
        return true;
    }
    switch (ch)
    {
        case '(':
        case ')':
        case '*':
        case '-':
        case '.':
        case '_':
        case '!':
            return true;
    }
    return false;
}

例程的第一部分计算需要替换的字符数(空格和非URL安全字符)。例程的第二部分分配一个新的缓冲区并执行替换:

  1. Url安全字符保持原样:a-z A-Z 0-9 ()*-._!
  2. 空格转换为加号
  3. 所有其他字符都转换为%HH
  4. RFC1738声明(强调我的):

      

    因此,只有字母数字,特殊字符“$ -_。+!*'(),”和
      用于保留目的的保留字符可能可以使用
      在URL中未编码。

         

    另一方面,不需要编码的字符
      (包括字母数字)可以在特定方案中编码   URL的一部分,只要它们不用于保留的   目的

    UrlEncode允许的一组Url安全字符是RFC1738中定义的特殊字符的子集。也就是说,字符$,缺失,即使规范说它们是安全的,也会被UrlEncode编码。由于可能使用未编码(而不是必须),因此它仍然符合编码它们的规范(第二段明确说明)。

    关于换行符,如果输入具有CR LF序列,那么将对其进行转义%0D%0A。但是,如果输入只有LF,那么它将被转义%0A(因此在此例程中没有规范化换行符。)

    底线:它符合规范,同时另外编码$,,并且调用者负责在输入中提供适当规范化的换行符。