diff --git a/Network/Curl/Download.hs b/Network/Curl/Download.hs
--- a/Network/Curl/Download.hs
+++ b/Network/Curl/Download.hs
@@ -123,15 +123,15 @@
 
     let start = 1024
     buf  <- mallocBytes start
-    ref  <- newIORef (buf, 0)
+    ref  <- newIORef (P buf 0)
 
     setopt h (CurlFailOnError True)
     setDefaultSSLOpts h url
     setopt h (CurlURL url)
     setopt h (CurlWriteFunction (gather ref))
     mapM_ (setopt h) flags
-    rc         <- perform h
-    (buf', sz) <- readIORef ref
+    rc        <- perform h
+    P buf' sz <- readIORef ref
 
     if rc /= CurlOK
         then do
@@ -141,12 +141,14 @@
             fp <- newForeignPtr finalizerFree buf'
             return (Right $! S.fromForeignPtr fp 0 (fromIntegral sz))
 
-gather :: IORef (Ptr Word8, Int) -> WriteFunction
+data P = P !(Ptr Word8) !Int
+
+gather :: IORef P -> WriteFunction
 gather r = writer $ \(src, m) -> do
-    (dest, n) <- readIORef r
+    P dest n <- readIORef r
     dest' <- reallocBytes dest (n + m)
     S.memcpy (dest' `plusPtr` n) src (fromIntegral m)
-    writeIORef r (dest', n + m)
+    writeIORef r (P dest' (n + m))
 
 -- memcpy chunks of data into our bytestring.
 writer :: ((Ptr Word8, Int) -> IO ()) -> WriteFunction
diff --git a/Network/Curl/Download/Lazy.hs b/Network/Curl/Download/Lazy.hs
new file mode 100644
--- /dev/null
+++ b/Network/Curl/Download/Lazy.hs
@@ -0,0 +1,109 @@
+
+--------------------------------------------------------------------
+-- |
+-- Module    : Network.Curl.Download.Lazy
+-- Copyright : (c) Don Stewart
+-- License   : BSD3
+--
+-- Maintainer:  Don Stewart <dons@galois.com>
+-- Stability :  provisional
+-- Portability: posix
+--
+-- A binding to curl, an efficient, high level library for
+-- retrieving files using Uniform Resource Locators (URLs).
+--
+-- Content may be retrieved as a lazy "ByteString".
+--
+-- Error handling is encapsulated in the "Either" type.
+--
+--------------------------------------------------------------------
+
+module Network.Curl.Download.Lazy (
+
+        -- * The basic lazy interface to network content
+          openLazyURI
+
+    ) where
+
+import Network.Curl
+import Foreign
+
+import Data.IORef
+import Control.Monad
+import Control.Monad.Instances
+import System.IO
+
+import qualified Data.ByteString.Lazy.Internal as L
+import qualified Data.ByteString.Internal      as S
+
+------------------------------------------------------------------------
+
+-- | Download content specified by a url using curl, returning the
+-- content as a lazy "ByteString".
+--
+-- If an error occurs, "Left" is returned, with a
+-- protocol-specific error string.
+--
+-- Examples:
+--
+-- > openURI "http://haskell.org"
+--
+openLazyURI :: String -> IO (Either String L.ByteString)
+openLazyURI s = case parseURL s of
+     Nothing  -> return $ Left $ "Malformed url: "++ s
+     Just url -> do
+        e <- getFile url []
+        return $ case e of
+             Left err   -> Left $ "Failed to connect: " ++ err
+             Right src  -> Right src
+
+------------------------------------------------------------------------
+-- Internal:
+--
+
+newtype URL = URL String
+
+parseURL :: String -> Maybe URL
+parseURL s = Just (URL s) -- no parsing
+
+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
+
+--          fp <- newForeignPtr finalizerFree buf'
+--          return (Right $! S.fromForeignPtr fp 0 (fromIntegral sz))
+
+gather :: IORef L.ByteString -> WriteFunction
+gather r = writer $ \chunk -> do
+    chunks <- readIORef r
+    let chunks' = L.Chunk chunk chunks
+    writeIORef r $! chunks'
+
+-- memcpy chunks of data into our bytestring.
+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'
+
+
+-- reverse just the spine of a lazy bytestring
+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)
diff --git a/download-curl.cabal b/download-curl.cabal
--- a/download-curl.cabal
+++ b/download-curl.cabal
@@ -1,11 +1,11 @@
 name:            download-curl
-version:         0.0
+version:         0.1
 homepage:        http://code.haskell.org/~dons/code/download-curl
 synopsis:        High-level file download based on URLs
 description:     High-level file download based on URLs
  .
- Download web content as strict bytestring, strings, HTML tags, XML, RSS
- or Atom feeds or JSON, using the curl network library.
+ Download web content as strict or lazy bytestringrs, strings, HTML
+ tags, XML, RSS or Atom feeds or JSON, using the curl network library.
  .
  Importing the library:
  .                 
@@ -49,6 +49,7 @@
 
 library
     exposed-modules: Network.Curl.Download
+                     Network.Curl.Download.Lazy
     ghc-options:     -Wall
 
     if flag(small_base)
