--- 'input' returns a 'Lazy.ByteString' but it's not really lazy:
--- reading from the socket just happens at the computation of 'input',
--- not at the evaluation of the 'Lazy.ByteString'. The same goes for
--- 'inputChunk'.
-input ∷ Int → Resource Lazy.ByteString
-input limit
- = do driftTo GettingBody
- itr ← getInteraction
- chunk ← if reqHasBody $ fromJust $ itrRequest itr then
- askForInput itr
- else
- do driftTo DecidingHeader
- return (∅)
- return chunk
- where
- askForInput ∷ Interaction → Resource Lazy.ByteString
- askForInput (Interaction {..})
- = do let confLimit = cnfMaxEntityLength itrConfig
- actualLimit = if limit ≤ 0 then
- confLimit
- else
- limit
- when (actualLimit ≤ 0)
- $ fail ("inputLBS: limit must be positive: " ⧺ show actualLimit)
- -- Reader にリクエスト
- liftIO $ atomically
- $ writeTVar itrReqBodyWanted actualLimit
- -- 應答を待つ。トランザクションを分けなければ當然デッドロックする。
- chunk ← liftIO $ atomically
- $ do chunkLen ← readTVar itrReceivedBodyLen
- chunkIsOver ← readTVar itrReqChunkIsOver
- if chunkLen < actualLimit then
- -- 要求された量に滿たなくて、まだ殘りが
- -- あるなら再試行。
- unless chunkIsOver
- $ retry
- else
- -- 制限値一杯まで讀むやうに指示したのに
- -- まだ殘ってゐるなら、それは多過ぎる。
- unless chunkIsOver
- $ tooLarge actualLimit
- -- 成功。itr 内にチャンクを置いたままにする
- -- とメモリの無駄になるので除去。
- chunk ← seqToLBS <$> readTVar itrReceivedBody
- writeTVar itrReceivedBody (∅)
- writeTVar itrReceivedBodyLen 0
- return chunk
-
- driftTo DecidingHeader
- return chunk
-
- tooLarge ∷ Int → STM ()
- tooLarge lim = abortSTM RequestEntityTooLarge []
- (Just $ "Request body must be smaller than "
- ⊕ T.pack (show lim) ⊕ " bytes.")
-
-seqToLBS ∷ Seq ByteString → Lazy.ByteString
-{-# INLINE seqToLBS #-}
-seqToLBS = Lazy.fromChunks ∘ toList
-
--- | Computation of @'inputChunk' limit@ attempts to read a part of
--- request body up to @limit@ bytes. You can read any large request by
--- repeating computation of this action. When you've read all the
--- request body, 'inputChunk' returns an empty string and then make
--- the 'Resource' transit to /Deciding Header/ state.
---
--- @limit@ may be less than or equal to zero. In this case, the
--- default limitation value ('cnfMaxEntityLength') is used. See
--- 'defaultLimit'.
---
--- Note that 'inputChunkLBS' is more efficient than 'inputChunk' so you
--- should use it whenever possible.
-inputChunk ∷ Int → Resource Lazy.ByteString
-inputChunk limit
- = do driftTo GettingBody
- itr ← getInteraction
- chunk ← if reqHasBody $ fromJust $ itrRequest itr then
- askForInput itr
- else
- do driftTo DecidingHeader
- return (∅)
- return chunk
+-- 'getChunks' returns a lazy 'Lazy.ByteString' but it's not really
+-- lazy: reading from the socket just happens at the computation of
+-- 'getChunks', not at the evaluation of the 'Lazy.ByteString'.
+getChunks ∷ Maybe Int → Resource Lazy.ByteString
+getChunks (Just n)
+ | n < 0 = fail ("getChunks: limit must not be negative: " ⧺ show n)
+ | n ≡ 0 = return (∅)
+ | otherwise = getChunks' n
+getChunks Nothing
+ = getConfig ≫= getChunks ∘ Just ∘ cnfMaxEntityLength
+
+getChunks' ∷ Int → Resource Lazy.ByteString
+getChunks' limit = go limit (∅)