Имитация неправильных заголовков длины содержимого для HTTP в C # - PullRequest
1 голос
/ 25 августа 2009

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

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

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

Ответы [ 4 ]

4 голосов
/ 28 августа 2009

Установите свойство 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, например, когда требуется Auth. Несмотря на то, что он отклонил запрос, он все равно ДОЛЖЕН предположить, что следующие байты являются частью того же запроса, так как он принял на себя обязательство получить эти байты, отправив продолжение 100. Если он не будет обслуживать этот запрос или если клиент захочет отменить запрос и отправить новый (предположительно с учетными данными аутентификации), он должен закрыть соединение и открыть новое.

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

0 голосов
/ 14 сентября 2009

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

0 голосов
/ 28 августа 2009

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

0 голосов
/ 25 августа 2009

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

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

...