2016-06-29 5 views
1

Учитывая общий менеджер HTTP, кажется, что если requestBody имеет тип requestBodySource, и если для тела запроса предоставлена ​​неправильная длина, тогда последующие запросы будут храниться на одном и том же HTTP-адресе менеджер около 20 секунд. Возможно, что-то связано с взаимодействием общего состояния и GivesPopper, что, возможно, вызывает эту проблему. Вот пример кода, который его воспроизводит - мы используем requestb.in для отправки неправильной загрузки по длине, а затем попытаемся прочитать другой действительный URL-адрес на requestb.in.Повреждение общего состояния HTTP-менеджера при отправке неправильной длины для потока

{-# LANGUAGE OverloadedStrings #-} 

import   Data.Conduit.Binary (sourceFile) 
import   Network.HTTP.Conduit 
import   Network.HTTP.Types 
import qualified Data.ByteString.Lazy as LBS 
import System.IO 
import Control.Monad.Trans.Resource (runResourceT) 
import Control.Concurrent.Async (async,waitCatch) 
import Control.Exception (displayException) 

main :: IO() 
main = do 
    {- Set up a ResourceT region with an available HTTP manager. -} 
    httpmgr <- newManager tlsManagerSettings 
    httpmgr2 <- newManager tlsManagerSettings 
    let file ="out" -- some byte contents with length > 1 
    lenb <- System.IO.withFile file ReadMode hFileSize 
    let inbytes = sourceFile file 
    initReq <- parseUrl "http://requestb.in/saxbx3sa" 
    putreq <- async $ runResourceT $ do 
    let req = initReq { method = "POST", 
     -- let us send wrong length in requestBodySource 
     requestBody = (requestBodySource (fromIntegral $ lenb - 1) inbytes)} 
    resp <- httpLbs req httpmgr 
    return (statusCode . responseStatus $ resp) 
    putreqRes <- waitCatch putreq 
    case putreqRes of 
    Left e -> print $ displayException $ e 
    Right r -> print $ r 
    getreq <- async $ runResourceT $ do 
    -- Let us do a GET on a different resource to see if it works 
    initReq <- parseUrl "http://requestb.in/1l15sz21" 
    let req = initReq { method = "GET"} 
    resp <- httpLbs req httpmgr 
    return (statusCode . responseStatus $ resp) 
    getreqRes <- waitCatch getreq 
    case getreqRes of 
    Left e -> print $ displayException $ e 
    Right r -> print $ r 

Выход - первая плохая загрузка проходит в HTTP 200 и последующем GET запрос немедленно вызывает HTTP 400 ошибку:

*Main> main 
    200 
    "StatusCodeException (Status {statusCode = 400, statusMessage = \"Bad Request\"}) 
[(\"Date\",\"Wed, 29 Jun 2016 11:54:59 GMT\"),(\"Content-Type\",\"text/html\"), 
(\"Content-Length\",\"177\"),(\"Connection\",\"close\"),(\"Server\",\"-nginx\"), 
(\"CF-RAY\",\"-\"),(\"X-Response-Body-Start\",\"<html>\\r\\n<head><title>400 Bad 
Request</title></head>\\r\\n<body bgcolor=\\\"white\\\">\\r\\n<center><h1>400 Bad 
Request</h1></center>\\r\\n<hr><center>cloudflare- 
nginx</center>\\r\\n</body>\\r\\n</html>\\r\\n\"),(\"X-Request-URL\",\"GET 
http://requestb.in:80/saxbx3sa\")] (CJ {expose = []})" 

Использование другого менеджера HTTP вместо для GET запроса будет возвращать HTTP 200. Итак, совместное состояние в http-менеджере, похоже, является проблемой здесь.

Кто-нибудь еще его наблюдал? Я просмотрел вопросы github для HTTP Manager, но не видел этого. При неправильной длине потока поведение не должно приводить к повреждению HTTP-менеджера, как это происходит здесь.

Я также смоделировал исходный файл для requestBodySource, где длина верна, но источник прерывается в середине из-за имитируемого сбоя (для имитации сетевых проблем). В этом случае ошибок нет. Таким образом, кажется, что у нас есть только один случай, когда отправка неправильной длины без каких-либо сбоев приведет к тому, что здесь будет испорчено какое-то общее состояние, которое будет выпущено в течение 25 секунд.

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

+0

Вероятно, лучше поможет открыть проблему «http-conduit» – jberryman

+0

Конечно, открылся один ... во время публикации, я не был уверен, что это была ошибка или неправильное использование функции потоковой передачи на моем часть. – Sal

ответ

0

Это проблема с http-clientas reported here. Он оставляет его вызывающему, чтобы убедиться, что длина прошедшего содержимого верна. Это общее соединение с сервером, которое, кажется, находится в плохом состоянии. В зависимости от фактической длины и ожидаемой длины начало следующего запроса может рассматриваться как конец предыдущего тела запроса, в результате чего следующий запрос будет неверно истолкован сервером.

Это было исправлено и слито в багажник через pull request. Решение заключалось в том, чтобы добавить простую проверку длины.

 Смежные вопросы

  • Нет связанных вопросов^_^