1

共有 HTTP マネージャーを指定すると、requestBodyがタイプrequestBodySourceであり、要求本文に間違った長さが指定されている場合、後続の要求は同じ HTTP マネージャーで約 20 秒間失敗するようです。共有状態の相互作用について何かがあるようで、GivesPopperおそらくそれがこの問題を引き起こしています。これを再現するサンプル コードを次に示します。requestb.in を使用して間違った長さのアップロードを送信し、requestb.in で別の有効な URL を読み取ろうとします。

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

GETリクエストの代わりに別の http マネージャを使用すると、が返されHTTP 200ます。したがって、ここでは http マネージャーでの共有状態が問題のようです。

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

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

ここで何が起こっているのかについて誰かが洞察を持っているなら、それは非常に役に立ちます。適切なストリーミングの長さを強制する回避策があります。ただし、本番環境でこのような状況に陥らないように、何が起こっているのかを理解したいと思います。

4

1 に答える 1