Имитация неправильных заголовков длины контента для HTTP в C#

StackOverflow https://stackoverflow.com/questions/1329317

Вопрос

Мы создаем комплексную среду интеграционного тестирования на C# для нашего приложения, которая существует поверх HTTP, используя IIS7 для размещения наших приложений.

В рамках наших интеграционных тестов мы хотим протестировать входящие запросы, которые приведут к EndOfStreamExceptions («Невозможно прочитать за пределами конца потока»), которые возникают, когда клиент отправляет HTTP-заголовок, указывающий больший размер тела, чем он фактически передает как часть тело.Мы хотим протестировать наш код восстановления ошибок для этого условия, поэтому нам нужно смоделировать такого рода запросы.

Я ищу библиотеку сокетов на основе .NET Fx или специальную замену HttpWebRequest, которая позволяет разработчикам моделировать такие условия и добавлять их в наш набор интеграционных тестов.Кто-нибудь знает такие библиотеки?Сценарное решение также будет работать.

Это было полезно?

Решение

Установите свойство ContentLength перед вызовом GetRequestStream (или BeginGetRequestStream), а затем запишите в этот поток меньше байтов.ContentLength выдаст ошибку, если вы попытаетесь установить ее после получения потока запросов.Если вы не установили ContentLength, HttpWebRequest будет буферизовать заголовки до тех пор, пока поток не будет закрыт, чтобы он мог установить ContentLength соответствующим образом (альтернативно вы можете использовать SendChunked, но здесь это вам не подойдет).Если вы хотите получить максимальный контроль над этим, создайте один или два неправильных запроса вручную, а затем откройте сокет к порту 80 на сервере и запишите запрос в поток TCP, а затем прочитайте ответ и проверьте соединение, чтобы увидеть, было ли оно закрыто. .

ОДНАКО:Я не думаю, что этот тест – хорошая идея.Вот проблема:

Клиент отправляет запрос на сервер.Он утверждает, что содержимое будет иметь размер 100 байт.Затем он отправляет 90 байт, а затем просто прекращает отправку, оставляя соединение открытым.Сервер читает 90 байт, затем ждет оставшуюся часть, так как клиент сказал, что будут отправлены 100 байт.Теперь Клиент отправляет второй запрос.Что сервер будет делать с первыми 10 байтами нового запроса?

Ответ заключается в том, что сервер предположит, что эти байты были частью предыдущего запроса, и воспримет их как таковые, а затем начнет читать «новый» запрос через 10 байт после его запуска, что, очевидно, приведет к искажению заголовков.Серверу это не понравится, поэтому он отправит ошибку 4xx, а затем закроет соединение.Причина, по которой он закрывает соединение, заключается в том, что теперь у него нет возможности узнать, что означают отправляемые ему данные, и нет возможности восстановить его.Кроме того, закрытие соединения не будет корректным, оно будет внезапным, и HttpWebRequest на другом конце, отправляющем второй запрос (или третий или четвертый, если они поставлены в очередь), выдаст WebException, говорящий, что базовое соединение было закрыто, и вам придется гадать, почему.

Это же поведение приводит к закрытию соединения с заголовком Expect 100-continue, а сервер возвращает 100-continue, за которым следует 4xx, например, когда требуется аутентификация.Несмотря на то, что он отклонил запрос, он все равно ДОЛЖЕН предполагать, что следующие байты являются частью того же запроса, поскольку он обязался получить эти байты, отправив 100-continue.Если он не будет обслуживать этот запрос или если клиент хочет отменить запрос и отправить новый (предположительно с учетными данными аутентификации), ему придется закрыть соединение и открыть новое.

Наконец, тестирование EndOfStreamException в сетевом потоке с использованием TCP не имеет для меня никакого смысла.TCP не отмечает «конец» потока, он просто продолжает отправлять данные по мере их записи в сокет.Для него нет «EOF» и нет способа определить, все ли данные были переданы, если вы не знаете, какой объем данных ожидать.На самом деле TCP не имеет «конца» своего потока, если соединение не закрыто, и в этом случае вы получите исключение WebException или исключение SocketException в зависимости от того, в каком месте стека вы работаете.Любые ошибки передачи в протоколе обрабатываются в winsock.Если данные больше не отправляются, один конец соединения в конечном итоге отправит подтверждение активности другому, чтобы убедиться, что соединение все еще действительно открыто и один хост не просто разорвал его.Если время ожидания активности истечет, соединение будет закрыто, и вы можете получить WebException при следующей попытке чтения из него.Учитывая, как все это работает, я просто не понимаю, какую пользу вы сможете извлечь из этого теста.Гораздо лучше просто отправлять некорректные запросы и гарантировать, что ошибки обрабатываются соответствующим образом, а соответствующее сообщение 4xx отправляется обратно клиенту и соединение закрывается должным образом.

Другие советы

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

Просто получите весь веб-запрос, обрежьте его настолько, насколько захотите, а затем перешлите его дальше.Возможно, вам придется создать новую копию WebRequest в процессе, а не усекать его на месте, но это все равно должно быть простым.

Не могли бы вы просто установить HttpWebRequest.ContentLength свойство на клиентах на меньшее или большее значение, чем фактический размер данных?

Если вы хотите смоделировать подобные вещи, когда вы нарушаете протокол HTTP, вам придется написать для этого собственный код.HttpWebRequest не позволяет вам делать подобные вещи.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top