给定一个共享的 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
输出 - 第一次错误上传通过 as 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 秒内被释放。
如果有人对这里发生的事情有任何见解,那将非常有帮助。我有一个强制执行正确流长度的解决方法。但是,我想了解发生了什么,这样我就可以避免在生产中遇到这种情况。