2016-06-29 6 views
1

共有HTTPマネージャを指定すると、requestBodySourcerequestBodyで、長さが間違っていると、後続の要求が同じHTTPマネージャーに約20秒間。おそらくこの問題の原因となっている共有状態とGivesPopperの相互作用についての何かがあるようです。ここでは、それを再現するサンプルコードです - 私たちは間違った長さのアップロードを送信するためにrequestb.inを使用し、次にrequestb.inで別の有効なURLを読み取ろうとします。ストリームに間違った長さを送信すると、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エラーが発生します。GET要求のための代わりに別のHTTP Managerを使用して

*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 200を返します。だから、httpマネージャの共有状態がここで問題になっているようです。

他の誰もそれを観察しましたか?私はHTTP Managerのgithubの問題を調べましたが、これは報告されていません。ストリーミングの長さが間違っていると、ここで発生しているようにHTTPマネージャが破損してはいけません。

また、長さが正しいrequestBodySourceのソースファイルをシミュレートしましたが、シミュレートされたエラー(ネットワークの問題をシミュレートするため)が原因で途中で終了します。その場合、エラーはありません。だから、間違った長さで何の失敗もせずに送信すると、何らかの種類の共有状態がここで破損し、25秒以内に解放されるケースが1つしかないようです。

ここで何が起こっているかについて誰かが洞察を持っているなら、非常に役に立ちます。私は右ストリーミングの長さを強制する回避策があります。しかし、私は何が起きているのか理解したいので、生産現場でこのような状況に陥るのを避けることができます。

+0

「http-conduit」の問題を開くのに役立つだろう – jberryman

+0

投稿時に、バグだったのか、私のストリーミング機能の使い方が間違っているのか分かりませんでした部。 – Sal

答えて

0

これはhttp-clientas reported hereの問題です。渡されたコンテンツの長さが正しいことを確認するために、呼び出し側にそれを渡します。これは、悪い状態にあると思われるサーバーへの共有接続です。実際の長さと予想される長さに応じて、次の要求の開始が前の要求本体の終わりとして扱われ、次の要求がサーバーによって誤って解釈される可能性があります。

これは修正され、pull requestによってトランクにマージされました。解決策は、簡単な長さの検証を追加することでした。

関連する問題