2016-06-29 21 views
1

Angesichts eines freigegebenen HTTP-Manager scheint es, wenn die requestBody vom Typ requestBodySource ist und wenn falsche Länge für den Anfragetext angegeben wird, dann nachfolgende Anfragen auf demselben HTTP Mist Manager für etwa 20 Sekunden. Es scheint etwas über die Interaktion von Shared State und GivesPopper zu sein, das dieses Problem verursacht. Hier ist ein Beispielcode, der es reproduziert - wir verwenden requestb.in für den Upload falscher Länge und versuchen dann, eine andere gültige URL auf requestb.in zu lesen.Beschädigte HTTP-Manager-Status beim Senden falsche Länge für Stream

{-# 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 

Ausgang - erster schlechter Upload geht als HTTP 200 durch und nachfolgenden GET Anfrage verursacht sofort HTTP 400 Fehler:

*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 = []})" 

einen anderen HTTP-Manager wird stattdessen für GET Anfrage HTTP 200 zurückzukehren. Also, Shared-Status im HTTP-Manager scheint hier das Problem zu sein.

Hat jemand anderes es beobachtet? Ich ging durch github Probleme für HTTP Manager, aber habe nicht gesehen, dass dies gemeldet wurde. Bei falscher Streaming-Länge sollte das Verhalten nicht dazu führen, den HTTP-Manager zu beschädigen, wie es hier scheint.

Ich habe auch eine Quelldatei für requestBodySource simuliert, bei der die Länge korrekt ist, aber die Quelle aufgrund eines simulierten Fehlers in der Mitte abbricht (um Netzwerkprobleme zu simulieren). In diesem Fall gibt es keine Fehler. Es scheint also nur einen Fall zu geben, in dem das Senden einer falschen Länge ohne Fehler dazu führt, dass eine Art gemeinsamer Status hier beschädigt wird, der innerhalb von 25 Sekunden freigegeben wird.

Wenn jemand irgendwelche Einsichten darüber hat, was hier vor sich geht, wird es sehr hilfreich sein. Ich habe einen Workaround zur Durchsetzung der richtigen Streaming-Länge. Ich werde jedoch gerne verstehen, was vor sich geht, damit ich in der Produktion nicht in diese Situation geraten kann.

+0

Wahrscheinlich würde bessere Hilfe beim Öffnen eines 'http-Conduit'-Problems bekommen – jberryman

+0

Sicher, geöffnet ... zum Zeitpunkt des Postings war ich nicht sicher, ob es ein Bug oder eine falsche Verwendung der Streaming-Funktion auf meinem war Teil. – Sal

Antwort

0

Dies ist ein Problem mit http-clientas reported here. Es überlässt dem Aufrufer, dass die übergebene Inhaltslänge korrekt ist. Es ist die freigegebene Verbindung zu dem Server, die in dem fehlerhaften Zustand zu sein scheint. Abhängig von der tatsächlichen Länge und der erwarteten Länge wird der Beginn der nächsten Anfrage möglicherweise als das Ende des vorherigen Anfragekörpers behandelt, wodurch die nächste Anfrage vom Server falsch interpretiert wird.

Dies wurde behoben und durch eine pull request in den Kofferraum zusammengeführt. Die Lösung bestand darin, eine einfache Längenvalidierung hinzuzufügen.