module Network.HTTP.Semantics.ReadN (
ReadN,
defaultReadN,
)
where
import qualified Data.ByteString as B
import Data.IORef
import Network.Socket
import qualified Network.Socket.ByteString as N
type ReadN = Int -> IO B.ByteString
defaultReadN :: Socket -> IORef (Maybe B.ByteString) -> ReadN
defaultReadN :: Socket -> IORef (Maybe ByteString) -> ReadN
defaultReadN Socket
_ IORef (Maybe ByteString)
_ Int
0 = ByteString -> IO ByteString
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
B.empty
defaultReadN Socket
s IORef (Maybe ByteString)
ref Int
n = do
mbs <- IORef (Maybe ByteString) -> IO (Maybe ByteString)
forall a. IORef a -> IO a
readIORef IORef (Maybe ByteString)
ref
writeIORef ref Nothing
case mbs of
Maybe ByteString
Nothing -> do
bs <- Socket -> ReadN
N.recv Socket
s Int
n
if B.null bs
then return B.empty
else
if B.length bs == n
then return bs
else loop bs
Just ByteString
bs
| ByteString -> Int
B.length ByteString
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
n -> ByteString -> IO ByteString
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
bs
| ByteString -> Int
B.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
n -> do
let (ByteString
bs0, ByteString
bs1) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
n ByteString
bs
IORef (Maybe ByteString) -> Maybe ByteString -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Maybe ByteString)
ref (ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
bs1)
ByteString -> IO ByteString
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
bs0
| Bool
otherwise -> ByteString -> IO ByteString
loop ByteString
bs
where
loop :: ByteString -> IO ByteString
loop ByteString
bs = do
let n' :: Int
n' = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
bs
bs1 <- Socket -> ReadN
N.recv Socket
s Int
n'
if B.null bs1
then return B.empty
else do
let bs2 = ByteString
bs ByteString -> ByteString -> ByteString
`B.append` ByteString
bs1
if B.length bs2 == n
then return bs2
else loop bs2