【问题标题】:How to implement data streaming with the Snap framework?如何使用 Snap 框架实现数据流式传输?
【发布时间】:2015-01-15 10:39:40
【问题描述】:

我想使用 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 之类的较小数据量可以按预期工作。

我的问题是:

  1. 在哪里/如何修复阅读限制?
  2. 这种流式传输数据,无需在内存中加载整个 POST 请求吗?如果不是,如何解决?

【问题讨论】:

    标签: haskell streaming haskell-snap-framework


    【解决方案1】:

    如果您将任何不是 "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
    

    This bit 在 Snap 中执行类似的操作

    if contentType == Just "application/x-www-form-urlencoded" then readData maximumPOSTBodySize
      where
        maximumPOSTBodySize = 10*1024*1024
    

    x-www-form-urlencoded 是 curl 的默认值。

    【讨论】:

    • application/octet-stream 可能是更合适的内容类型。
    【解决方案2】:

    跟进上一个答案:因为application/x-www-form-urlencoded 类型的表单非常常见,为方便起见,Snap 会为您自动解码它们并将它们放入请求中的参数映射中。这个想法在精神上类似于例如$_POST 来自 PHP。

    但是,由于这些映射被读取到 RAM 中,天真地解码无限量的此类数据将允许攻击者通过向服务器发送任意数量的此输入直到堆耗尽来轻而易举地对服务器进行 DoS。出于这个原因,snap-server 限制了它愿意以这种方式读取的数据量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-15
      • 1970-01-01
      • 2010-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多