ПОЛУЧЕНИЕ URL-адреса с косой чертой в кодировке URL

Я хочу отправить HTTP GET http://example.com/%2F, Моим первым предположением будет что-то вроде этого:

using (WebClient webClient = new WebClient())
{
  webClient.DownloadData("http://example.com/%2F");
}

К сожалению, я вижу, что на самом деле отправляется по проводам:

GET // HTTP/1.1
Host: example.com
Connection: Keep-Alive

Таким образом, http://example.com/%2F переводится на http://example.com// перед его передачей.

Есть ли способ на самом деле отправить этот GET-запрос?

Протокол OCSP предписывает отправлять url-кодировку base-64-кодировки при использовании OCSP по HTTP/GET, поэтому необходимо отправить фактический% 2F, а не '/', чтобы быть совместимым.

РЕДАКТИРОВАТЬ:

Вот соответствующая часть стандарта протокола OCSP ( RFC 2560, Приложение A.1.1):

Запрос OCSP с использованием метода GET строится следующим образом:

GET {url} / {url-кодировка кодировки base-64 кодировки DER для OCSPRequest}

Я очень открыт для других прочтений этого, но я не могу понять, что еще можно сказать.

4 ответа

Решение

По умолчанию Uri класс не позволит сбежать / персонаж (%2f) в URI (хотя это кажется законным в моем чтении RFC 3986).

Uri uri = new Uri("http://example.com/%2F");
Console.WriteLine(uri.AbsoluteUri); // prints: http://example.com//

(Примечание: не используйте Uri.ToString для печати URI.)

Согласно отчету об ошибке для этой проблемы в Microsoft Connect, такое поведение является заданным, но вы можете обойти это, добавив следующее в файл app.config или web.config:

<uri>
  <schemeSettings>
    <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
  </schemeSettings>
</uri>

(Перепечатано с /questions/934549/c-webrequestgetresponse-400-nevernyij-zapros/934555#934555 потому что это "официальный" способ избежать этой ошибки без использования отражения для изменения приватных полей.)

Изменить: отчет об ошибке подключения больше не отображается, но документация для <schemeSettings> рекомендует этот подход, чтобы разрешить сбежал / символы в URI. Обратите внимание (согласно этой статье), что могут быть последствия для безопасности компонентов, которые неправильно обрабатывают экранированные косые черты.

Это ужасный хак, неизбежно несовместимый с будущими версиями фреймворка и так далее.

Но это работает!

(на моей машине...)

Uri uri = new Uri("http://example.com/%2F");
ForceCanonicalPathAndQuery(uri);
using (WebClient webClient = new WebClient())
{
  webClient.DownloadData(uri);
}

void ForceCanonicalPathAndQuery(Uri uri){
  string paq = uri.PathAndQuery; // need to access PathAndQuery
  FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
  ulong flags = (ulong) flagsFieldInfo.GetValue(uri);
  flags &= ~((ulong) 0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
  flagsFieldInfo.SetValue(uri, flags);
}

Обновление: похоже, поведение класса Uri по умолчанию было действительно изменено в.NET 4.5, и теперь вы можете использовать экранированные косые черты, и они не будут затронуты.

Я запустил следующий код в.NET 3.5, .NET 4.0, .NET 4.5/4.5.1

static void Main(string[] args)
{
    var uri = new Uri("http://www.yahooo.com/%2F");
    var client = new WebClient();
    client.DownloadString(uri);
}

В.NET 3.5/4.0 трассировка показывает, что%2F фактически был неэкранированным, как ожидалось.

След скрипача

Тем не менее, в.NET 4.5 / 4.5.1 вы можете видеть, что%2F не был неэкранированным (обратите внимание на GET /%2F)

След скрипача

Теперь вы можете даже использовать ToString() в Uri, и вы получите тот же результат.

Итак, в заключение, кажется, что если вы используете.NET >= .NET 4.5, то все будет вести себя так, как должно соответствовать RFC.

Я только что попытался использовать тот же подход, работая с Mono. Я отправил свой вопрос о подходе здесь: Получение Uri с экранированными косыми чертами на моно

Как упоминалось в моем комментарии к ответу, опубликованному Рамусом, для.Net Standard (и, возможно, более поздних версий.Net Framework) требуется следующее, чтобы этот хак работал:

Uri uri = new Uri("http://example.com/%2F");
ForceCanonicalPathAndQuery(uri);
using (WebClient webClient = new WebClient())
{
  webClient.DownloadData(uri);
}

void ForceCanonicalPathAndQuery(Uri uri){
  string paq = uri.PathAndQuery; // need to access PathAndQuery
  FieldInfo flagsFieldInfo = typeof(Uri).GetField("_flags", BindingFlags.Instance | BindingFlags.NonPublic);
  ulong flags = (ulong) flagsFieldInfo.GetValue(uri);
  flags &= ~((ulong) 0xC30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
  flagsFieldInfo.SetValue(uri, flags);
}

Двойное кодирование: % 252F

Но также, если вы используете HttpWebRequest, вы можете запретить кодировать URL-адрес, так как он должен работать.

Кроме того, если WebClient принимает URI, вы можете создать новый URI и установить его, чтобы он не кодировался.

Другие вопросы по тегам