packages feed

simple-sendfile-0.0.0: Network/Sendfile/Fallback.hs

module Network.Sendfile.Fallback (sendfile) where

import Control.Monad
import Control.Monad.IO.Class
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.Enumerator
import Data.Enumerator.Binary as EB
import Data.Enumerator.List as EL
import Network.Sendfile.Types
import Network.Socket
import qualified Network.Socket.ByteString as SB

{-|
   Sendfile emulation using enumerator.

   - Used system calls: open(), stat(), read(), send() and close().
-}
sendfile :: Socket -> FilePath -> FileRange -> IO ()
sendfile s fp EntireFile =
    run_ $ enumFile fp $$ sendIter s
sendfile s fp (PartOfFile off len) =
    run_ $ EB.enumFileRange fp (Just off) (Just len) $$ sendIter s

sendIter :: Socket -> Iteratee ByteString IO ()
sendIter s = do
    mb <- EL.head
    case mb of
        Nothing -> return ()
        Just bs -> do
            liftIO $ sendLoop s bs (BS.length bs)
            sendIter s

sendLoop :: Socket -> ByteString -> Int -> IO ()
sendLoop s bs len = do
    bytes <- SB.send s bs
    when (bytes /= len) $ sendLoop s (BS.drop bytes bs) (len - bytes)