packages feed

http-client 0.3.2.1 → 0.3.2.2

raw patch · 7 files changed

+76/−111 lines, 7 files

Files

Network/HTTP/Client.hs view
@@ -43,7 +43,7 @@ -- A note on exceptions: for the most part, all actions that perform I/O should -- be assumed to throw an @HttpException@ in the event of some problem, and all -- pure functions will be total. For example, @withResponse@, @httpLbs@, and--- @brRead@ can all throw exceptions. Functions like @responseStatus@ and+-- @BodyReader@ can all throw exceptions. Functions like @responseStatus@ and -- @applyBasicAuth@ are guaranteed to be total (or there\'s a bug in the -- library). --
Network/HTTP/Client/Body.hs view
@@ -9,6 +9,7 @@     , brEmpty     , brAddCleanup     , brReadSome+    , brRead     ) where  import Network.HTTP.Client.Connection@@ -21,8 +22,15 @@ import Control.Monad (unless, when) import qualified Data.Streaming.Zlib as Z +-- ^ Get a single chunk of data from the response body, or an empty+-- bytestring if no more data is available.+--+-- Since 0.1.0+brRead :: BodyReader -> IO S.ByteString+brRead = id+ brReadSome :: BodyReader -> Int -> IO L.ByteString-brReadSome BodyReader {..} =+brReadSome brRead =     loop id   where     loop front rem@@ -34,35 +42,29 @@                 else loop (front . (bs:)) (rem - S.length bs)  brEmpty :: BodyReader-brEmpty = BodyReader-    { brRead = return S.empty-    , brComplete = return True-    }+brEmpty = return S.empty  brAddCleanup :: IO () -> BodyReader -> BodyReader-brAddCleanup cleanup br = BodyReader-    { brRead = do-        bs <- brRead br-        when (S.null bs) cleanup-        return bs-    , brComplete = brComplete br-    }+brAddCleanup cleanup brRead = do+    bs <- brRead+    when (S.null bs) cleanup+    return bs  -- | Strictly consume all remaining chunks of data from the stream. -- -- Since 0.1.0 brConsume :: BodyReader -> IO [S.ByteString]-brConsume f =+brConsume brRead =     go id   where     go front = do-        x <- brRead f+        x <- brRead         if S.null x             then return $ front []             else go (front . (x:))  makeGzipReader :: BodyReader -> IO BodyReader-makeGzipReader br = do+makeGzipReader brRead = do     inf <- Z.initInflate $ Z.WindowBits 31     istate <- newIORef Nothing     let goPopper popper = do@@ -80,69 +82,55 @@                             return bs                 Z.PRError e -> throwIO $ HttpZlibException e         start = do-            bs <- brRead br+            bs <- brRead             if S.null bs                 then return S.empty                 else do                     popper <- Z.feedInflate inf bs                     goPopper popper-    return BodyReader-        { brRead = do-            state <- readIORef istate-            case state of-                Nothing -> start-                Just popper -> goPopper popper-        , brComplete = brComplete br-        }+    return $ do+        state <- readIORef istate+        case state of+            Nothing -> start+            Just popper -> goPopper popper  makeUnlimitedReader :: Connection -> IO BodyReader makeUnlimitedReader Connection {..} = do     icomplete <- newIORef False-    return $! BodyReader-        { brRead = do-            bs <- connectionRead-            when (S.null bs) $ writeIORef icomplete True-            return bs-        , brComplete = readIORef icomplete-        }+    return $ do+        bs <- connectionRead+        when (S.null bs) $ writeIORef icomplete True+        return bs  makeLengthReader :: Int -> Connection -> IO BodyReader makeLengthReader count0 Connection {..} = do     icount <- newIORef count0-    return $! BodyReader-        { brRead = do-            count <- readIORef icount-            if count <= 0-                then return empty-                else do-                    bs <- connectionRead-                    when (S.null bs) $ throwIO $ ResponseBodyTooShort (fromIntegral count0) (fromIntegral $ count0 - count)-                    case compare count $ S.length bs of-                        LT -> do-                            let (x, y) = S.splitAt count bs-                            connectionUnread y-                            writeIORef icount (-1)-                            return x-                        EQ -> do-                            writeIORef icount (-1)-                            return bs-                        GT -> do-                            writeIORef icount (count - S.length bs)-                            return bs-        , brComplete = fmap (== -1) $ readIORef icount-        }+    return $ do+        count <- readIORef icount+        if count <= 0+            then return empty+            else do+                bs <- connectionRead+                when (S.null bs) $ throwIO $ ResponseBodyTooShort (fromIntegral count0) (fromIntegral $ count0 - count)+                case compare count $ S.length bs of+                    LT -> do+                        let (x, y) = S.splitAt count bs+                        connectionUnread y+                        writeIORef icount (-1)+                        return x+                    EQ -> do+                        writeIORef icount (-1)+                        return bs+                    GT -> do+                        writeIORef icount (count - S.length bs)+                        return bs  makeChunkedReader :: Bool -- ^ raw                   -> Connection                   -> IO BodyReader makeChunkedReader raw conn@Connection {..} = do     icount <- newIORef 0-    return $! BodyReader-        { brRead = go icount-        , brComplete = do-            count <- readIORef icount-            return $! count == -1-        }+    return $ go icount   where     go icount = do         count0 <- readIORef icount
Network/HTTP/Client/Response.hs view
@@ -8,17 +8,13 @@     , lbsResponse     ) where -import Control.Arrow (first)-import Control.Monad (liftM, (>=>))+import Control.Monad ((>=>))  import Control.Exception (throwIO) -import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Lazy as L -import qualified Data.CaseInsensitive as CI- import Data.Default.Class (def)  import qualified Network.HTTP.Types as W@@ -26,12 +22,10 @@  import Network.HTTP.Client.Types -import Network.HTTP.Client.Manager import Network.HTTP.Client.Request import Network.HTTP.Client.Util import Network.HTTP.Client.Body import Network.HTTP.Client.Headers-import Network.HTTP.Client.Connection  import System.Timeout (timeout) @@ -96,7 +90,7 @@     let timeout' =             case timeout'' of                 Nothing -> id-                Just t -> timeout t >=> maybe responseTimeout return+                Just t -> timeout t >=> maybe (throwIO ResponseTimeout) return     StatusHeaders s version hs <- timeout' $ parseStatusHeaders conn     let mcl = lookup "content-length" hs >>= readDec . S8.unpack @@ -132,5 +126,3 @@         , responseCookieJar = def         , responseClose' = ResponseClose (cleanup False)         }-  where-    responseTimeout = throwIO ResponseTimeout
Network/HTTP/Client/Types.hs view
@@ -4,7 +4,7 @@ {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE RankNTypes #-} module Network.HTTP.Client.Types-    ( BodyReader (..)+    ( BodyReader     , Connection (..)     , StatusHeaders (..)     , HttpException (..)@@ -50,19 +50,15 @@ import Data.Text (Text) import Data.Streaming.Zlib (ZlibException) --- | An abstraction for representing an incoming response body coming from the--- server. Data provided by this abstraction has already been gunzipped and+-- | An @IO@ action that represents an incoming response body coming from the+-- server. Data provided by this action has already been gunzipped and -- de-chunked, and respects any content-length headers present. ----- Since 0.1.0-data BodyReader = BodyReader-    { brRead :: !(IO S.ByteString)-    -- ^ Get a single chunk of data from the response body, or an empty-    -- bytestring if no more data is available.-    ---    -- Since 0.1.0-    , brComplete :: !(IO Bool)-    }+-- The action gets a single chunk of data from the response body, or an empty+-- bytestring if no more data is available.+--+-- Since 0.4.0+type BodyReader = IO S.ByteString  data Connection = Connection     { connectionRead :: !(IO S.ByteString)
http-client.cabal view
@@ -1,5 +1,5 @@ name:                http-client-version:             0.3.2.1+version:             0.3.2.2 synopsis:            An HTTP client engine, intended as a base layer for more user-friendly packages. description:         This codebase has been refactored from http-conduit. homepage:            https://github.com/snoyberg/http-client
test/Network/HTTP/Client/BodySpec.hs view
@@ -11,6 +11,11 @@ main :: IO () main = hspec spec +brComplete :: BodyReader -> IO Bool+brComplete brRead = do+  xs <- brRead+  return (xs == "")+ spec :: Spec spec = describe "BodySpec" $ do     it "chunked, single" $ do@@ -18,89 +23,72 @@             [ "5\r\nhello\r\n6\r\n world\r\n0\r\nnot consumed"             ]         reader <- makeChunkedReader False conn-        complete1 <- brComplete reader-        complete1 `shouldBe` False         body <- brConsume reader         S.concat body `shouldBe` "hello world"         input' <- input         S.concat input' `shouldBe` "not consumed"-        complete2 <- brComplete reader-        complete2 `shouldBe` True+        brComplete reader `shouldReturn` True+     it "chunked, pieces" $ do         (conn, _, input) <- dummyConnection $ map S.singleton $ S.unpack             "5\r\nhello\r\n6\r\n world\r\n0\r\nnot consumed"         reader <- makeChunkedReader False conn-        complete1 <- brComplete reader-        complete1 `shouldBe` False         body <- brConsume reader         S.concat body `shouldBe` "hello world"         input' <- input         S.concat input' `shouldBe` "not consumed"-        complete2 <- brComplete reader-        complete2 `shouldBe` True+        brComplete reader `shouldReturn` True+     it "chunked, raw" $ do         (conn, _, input) <- dummyConnection             [ "5\r\nhello\r\n6\r\n world\r\n0\r\nnot consumed"             ]         reader <- makeChunkedReader True conn-        complete1 <- brComplete reader-        complete1 `shouldBe` False         body <- brConsume reader         S.concat body `shouldBe` "5\r\nhello\r\n6\r\n world\r\n0\r\n"         input' <- input         S.concat input' `shouldBe` "not consumed"-        complete2 <- brComplete reader-        complete2 `shouldBe` True+        brComplete reader `shouldReturn` True      it "chunked, pieces, raw" $ do         (conn, _, input) <- dummyConnection $ map S.singleton $ S.unpack             "5\r\nhello\r\n6\r\n world\r\n0\r\nnot consumed"         reader <- makeChunkedReader True conn-        complete1 <- brComplete reader-        complete1 `shouldBe` False         body <- brConsume reader         S.concat body `shouldBe` "5\r\nhello\r\n6\r\n world\r\n0\r\n"         input' <- input         S.concat input' `shouldBe` "not consumed"-        complete2 <- brComplete reader-        complete2 `shouldBe` True+        brComplete reader `shouldReturn` True      it "length, single" $ do         (conn, _, input) <- dummyConnection             [ "hello world done"             ]         reader <- makeLengthReader 11 conn-        complete1 <- brComplete reader-        complete1 `shouldBe` False         body <- brConsume reader         S.concat body `shouldBe` "hello world"         input' <- input         S.concat input' `shouldBe` " done"-        complete2 <- brComplete reader-        complete2 `shouldBe` True+        brComplete reader `shouldReturn` True+     it "length, pieces" $ do         (conn, _, input) <- dummyConnection $ map S.singleton $ S.unpack             "hello world done"         reader <- makeLengthReader 11 conn-        complete1 <- brComplete reader-        complete1 `shouldBe` False         body <- brConsume reader         S.concat body `shouldBe` "hello world"         input' <- input         S.concat input' `shouldBe` " done"-        complete2 <- brComplete reader-        complete2 `shouldBe` True+        brComplete reader `shouldReturn` True+     it "gzip" $ do         let orig = L.fromChunks $ replicate 5000 "Hello world!"             origZ = compress orig         (conn, _, input) <- dummyConnection $ L.toChunks origZ ++ ["ignored"]         reader' <- makeLengthReader (fromIntegral $ L.length origZ) conn         reader <- makeGzipReader reader'-        complete1 <- brComplete reader-        complete1 `shouldBe` False         body <- brConsume reader         L.fromChunks body `shouldBe` orig         input' <- input         S.concat input' `shouldBe` "ignored"-        complete2 <- brComplete reader-        complete2 `shouldBe` True+        brComplete reader `shouldReturn` True
test/Network/HTTP/ClientSpec.hs view
@@ -13,6 +13,7 @@ import           Test.Hspec import qualified Data.Streaming.Network    as N import qualified Data.ByteString           as S+import           Data.ByteString.Lazy.Char8 () -- orphan instance  main :: IO () main = hspec spec