HttpUtility.UrlEncode соответствует спецификации для 'x-www-form-urlencoded'? - PullRequest
9 голосов
/ 09 июля 2010

По MSDN

URLEncode преобразует символы следующим образом:

  • Пробелы () преобразуются в знаки плюс (+).
  • Не алфавитно-цифровые символы переводятся в их шестнадцатеричное представление.

Что похоже, но не точно так же, как W3C

application / x-www-form-urlencoded

Это тип содержимого по умолчанию.Формы, представленные с этим типом содержимого, должны быть закодированы следующим образом:

  1. Имена и значения элементов управления экранируются.Символы пробела заменяются на «+», а затем зарезервированные символы экранируются, как описано в RFC1738 , раздел 2.2: не буквенно-цифровые символы заменяются на «% HH», знак процента и две шестнадцатеричные цифры, представляющиеASCII код персонажа.Разрывы строк представлены в виде пар «CR LF» (т. Е. «% 0D% 0A»).

  2. Имена / значения элементов управления перечислены в порядке их появления в документе.Имя отделяется от значения символом '=', а пары имя / значение отделяются друг от друга знаком '&'.

Мой вопросКто-нибудь проделал работу, чтобы определить, выдает ли URLEncode действительные данные в формате x-www-form-urlencoded?

1 Ответ

6 голосов
/ 16 сентября 2011

Что ж, документация, на которую вы ссылаетесь, относится к 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;
}

Первая часть подпрограммы подсчитывает количество символов, которые необходимо заменить(пробелы и небезопасные символы).Вторая часть подпрограммы выделяет новый буфер и выполняет замены:

  1. Url Safe Символы сохраняются как: a-z A-Z 0-9 ()*-._!
  2. Пробелы преобразуются в знаки плюс
  3. Все остальные символы преобразуются в %HH

RFC1738 состояния (выделено мое):

Таким образом, только буквенно-цифровые символы, специальные символы "$ -_. +! * '(), "и
зарезервированные символы, используемые в зарезервированных целях могут использоваться
без кодировки в URL.

С другой стороны, символы, которые являютсянеобязательно кодировать
(включая буквенно-цифровые символы) может быть закодировано в специфичной для схемы части URL-адреса
, если они не используются для зарезервированной
цели.

Набор безопасных символов URL, разрешенных UrlEncode, является подмножеством специальных символов, определенных в RFC1738.А именно, символы $, отсутствуют и будут закодированы как UrlEncode, даже если спецификация говорит, что они безопасны.Поскольку они могут использоваться в незашифрованном виде (а не must ), они все еще соответствуют спецификации для их кодирования (и во втором абзаце прямо указывается).

В отношениидо разрывов строк, если вход имеет последовательность CR LF, тогда он будет экранирован %0D%0A.Однако, если вход имеет только LF, тогда он будет экранирован %0A (поэтому в этой процедуре нормализация разрывов строк не выполняется).

Итог: Соответствуетспецификацией при дополнительном кодировании $,, и вызывающий абонент отвечает за предоставление соответственно нормализованных разрывов строк на входе.

...