我想使用Snap服务器实现大数据流(双向)。为了探索可能性,我创建了一个具有两个端点的示例程序 - 读取和写入。有一个非常简单的内部缓冲区,其中包含一个ByteString
,写入端点的任何内容都会出现在读取端点中。 (目前没有办法如何终止流,但这对于此目的来说没问题。)
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import Control.Concurrent.MVar.Lifted
import Control.Monad
import Data.ByteString (ByteString)
import Blaze.ByteString.Builder (Builder, fromByteString)
import Data.Enumerator
import qualified Data.Enumerator.List as E
import Data.Enumerator.Binary (enumFile, iterHandle)
import Snap.Core
import Snap.Http.Server
main :: IO ()
main = do
buf <- newEmptyMVar
quickHttpServe (site buf)
site :: MVar ByteString -> Snap ()
site buf =
route [ ("read", modifyResponse (setBufferingMode False
. setResponseBody (fromBuf buf)))
, ("write", runRequestBody (toBuf buf))
]
fromBuf :: MVar ByteString -> Enumerator Builder IO a
fromBuf buf = E.repeatM (liftM fromByteString $ takeMVar buf)
toBuf :: MVar ByteString -> Iteratee ByteString IO ()
toBuf buf = E.mapM_ (putMVar buf)
然后我在不同的终端运行
curl http://localhost:8000/read >/dev/nul
和
dd if=/dev/zero bs=1M count=100 | \
curl --data-binary @- http://localhost:8000/write
但写入部分失败,异常转义为顶层:读取的字节数太多。这显然是TooManyBytesReadException
的一个实例,但我无法找到抛出的位置。写入少量数据(如1MB)可以按预期工作。
我的问题是:
答案 0 :(得分:2)
如果您向"application/x-www-form-urlencoded"
添加不是/write
的任何内容类型,它将会有效,例如:
dd if=/dev/zero bs=1M count=100 | \
curl -H "Content-Type: application/json" --data-binary @- http://localhost:8000/write
Snap中的This bit做了类似
的事情if contentType == Just "application/x-www-form-urlencoded" then readData maximumPOSTBodySize
where
maximumPOSTBodySize = 10*1024*1024
和x-www-form-urlencoded
是curl的默认设置。
答案 1 :(得分:2)
要跟进上一个答案:因为application/x-www-form-urlencoded
类型的表单非常常见,因为Snap会为您自动解码它们并将它们放入请求中的参数映射中。该想法在精神上类似于例如来自PHP的$_POST
。
然而,由于这些映射被读入RAM,天真地解码这些数据的无限量将允许攻击者通过向其发送任意数量的此输入直到堆耗尽来简单地DoS服务器。出于这个原因,snap-server
限制了它愿意以这种方式阅读的数据量。