module Network.Curl.Download.Lazy (
openLazyURI
, openLazyURIWithOpts
) where
import Network.Curl
import Foreign
import Data.IORef
import qualified Data.ByteString.Lazy.Internal as L
import qualified Data.ByteString.Internal as S
openLazyURI :: String -> IO (Either String L.ByteString)
openLazyURI s = openLazyURIWithOpts [] s
openLazyURIWithOpts :: [CurlOption] -> String -> IO (Either String L.ByteString)
openLazyURIWithOpts opts s = case parseURL s of
Nothing -> return $ Left $ "Malformed url: "++ s
Just url -> do
e <- getFile url opts
return $ case e of
Left err -> Left $ "Failed to connect: " ++ err
Right src -> Right src
newtype URL = URL String
parseURL :: String -> Maybe URL
parseURL s = Just (URL s)
getFile :: URL -> [CurlOption] -> IO (Either String L.ByteString)
getFile (URL url) flags = do
h <- initialize
ref <- newIORef L.Empty
setopt h (CurlFailOnError True)
setDefaultSSLOpts h url
setopt h (CurlURL url)
setopt h (CurlWriteFunction (gather ref))
mapM_ (setopt h) flags
rc <- perform h
chunks <- readIORef ref
return $ if rc /= CurlOK
then Left (show rc)
else Right $! rev'spine chunks
gather :: IORef L.ByteString -> WriteFunction
gather r = writer $ \chunk -> do
chunks <- readIORef r
let chunks' = L.Chunk chunk chunks
writeIORef r $! chunks'
writer :: (S.ByteString -> IO ()) -> WriteFunction
writer f src sz nelems _ = do
let n' = sz * nelems
f =<< (S.create (fromIntegral n') $
\dest -> S.memcpy dest (castPtr src) (fromIntegral n'))
return n'
rev'spine :: L.ByteString -> L.ByteString
rev'spine l = rev l L.Empty
where
rev L.Empty a = a
rev (L.Chunk x xs) a = rev xs (L.Chunk x a)