http-enumerator 0.7.1.2 → 0.7.1.3
raw patch · 2 files changed
+74/−32 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Network/HTTP/Enumerator.hs +73/−31
- http-enumerator.cabal +1/−1
Network/HTTP/Enumerator.hs view
@@ -110,6 +110,7 @@ ( Iteratee (..), Stream (..), catchError, throwError , yield, Step (..), Enumeratee, ($$), joinI, Enumerator, run_ , returnI, (>==>), (>>==), continue, checkDone, enumEOF+ , (=$) ) import qualified Data.Enumerator.List as EL import Network.HTTP.Enumerator.HttpParser@@ -140,6 +141,7 @@ import Blaze.ByteString.Builder (toByteString) import Data.Maybe (fromMaybe) import Data.Default (Default (def))+import Numeric (showHex) #if !MIN_VERSION_base(4,3,0) import GHC.IO.Handle.Types import System.IO (hWaitForInput, hIsEOF)@@ -400,8 +402,8 @@ -> (W.Status -> W.ResponseHeaders -> Iteratee S.ByteString m a) -> Manager -> Iteratee S.ByteString m a-http Request {..} bodyStep m = do- withConn m connhost connport requestEnum $$ go+http req@(Request {..}) bodyStep m =+ withConn m connhost connport requestEnum $$ getResponse req bodyStep where (useProxy, connhost, connport) = case proxy of@@ -455,36 +457,54 @@ `mappend` Blaze.fromByteString "\r\n") `mappend` Blaze.fromByteString "\r\n" requestEnum = enumSingle requestHeaders' >==> bodyEnum- go = do- ((_, sc, sm), hs) <- iterHeaders- let s = W.Status sc sm- let hs' = map (first CI.mk) hs- let mcl = lookup "content-length" hs'- let body' x =- if not rawBody && ("transfer-encoding", "chunked") `elem` hs'- then joinI $ chunkedEnumeratee $$ x- else case mcl >>= readMay . S8.unpack of- Just len -> joinI $ takeLBS len $$ x- Nothing -> x- let decompresser x =- if not rawBody- && ("content-encoding", "gzip") `elem` hs'- && decompress (fromMaybe "" $ lookup "content-type" hs')- then joinI $ Z.ungzip x- else returnI x- -- RFC 2616 section 4.4_1 defines responses that must not include a body- res <-- if method == "HEAD" || sc == 204 -- No Content- || sc == 304 -- Not Modified- || (sc < 200 && sc >= 100)- then enumEOF $$ bodyStep s hs'- else body' $ decompresser $$ do- x <- bodyStep s hs'- flushStream- return x- let toPut = Just "close" /= lookup "connection" hs'- return (toPut, res) +getResponse :: MonadIO m+ => Request m+ -> (W.Status -> [W.Header] -> Iteratee S8.ByteString m a)+ -> Iteratee S8.ByteString m (Bool, a)+getResponse Request {..} bodyStep = do+ ((_, sc, sm), hs) <- iterHeaders+ let s = W.Status sc sm+ let hs' = map (first CI.mk) hs+ let mcl = lookup "content-length" hs'+ let body' =+ case (rawBody, ("transfer-encoding", "chunked") `elem` hs') of+ (False, True) -> (chunkedEnumeratee =$)+ (True , True) -> (chunkedTerminator =$)+ (_ , False) -> case mcl >>= readMay . S8.unpack of+ Just len -> (takeLBS len =$)+ Nothing -> id+ let decompresser =+ if needsGunzip hs'+ then (Z.ungzip =$)+ else id+ -- RFC 2616 section 4.4_1 defines responses that must not include a body+ res <-+ if hasNoBody method sc+ then enumEOF $$ bodyStep s hs'+ else body' $ decompresser $ do+ x <- bodyStep s hs'+ flushStream+ return x++ -- should we put this connection back into the connection manager?+ let toPut = Just "close" /= lookup "connection" hs'+ return (toPut, res)+ where+ hasNoBody :: S8.ByteString -- ^ request method+ -> Int -- ^ status code+ -> Bool+ hasNoBody "HEAD" _ = True+ hasNoBody _ 204 = True+ hasNoBody _ 304 = True+ hasNoBody _ i = 100 <= i && i < 200++ needsGunzip :: [W.Header] -> Bool+ needsGunzip hs' =+ not rawBody+ && ("content-encoding", "gzip") `elem` hs'+ && decompress (fromMaybe "" $ lookup "content-type" hs')+ flushStream :: Monad m => Iteratee a m () flushStream = do x <- EL.head@@ -502,6 +522,28 @@ catchParser "End of chunk newline" iterNewline chunkedEnumeratee k' chunkedEnumeratee step = return step++chunkedTerminator :: MonadIO m => Enumeratee S.ByteString S.ByteString m a+chunkedTerminator (Continue k) = do+ len <- catchParser "Chunk header" iterChunkHeader+ k' <- sendCont k $ S8.pack $ showHex len "\r\n"+ if len == 0+ then return k'+ else do+ step <- takeLBS len k'+ catchParser "End of chunk newline" iterNewline+ case step of+ Continue k'' -> do+ k''' <- sendCont k'' "\r\n"+ chunkedTerminator k'''+ _ -> return step+chunkedTerminator step = return step++sendCont :: Monad m+ => (Stream S8.ByteString -> Iteratee S8.ByteString m a)+ -> S8.ByteString+ -> Iteratee S8.ByteString m (Step S8.ByteString m a)+sendCont k bs = lift $ runIteratee $ k $ Chunks [bs] chunkIt :: Monad m => Enumeratee Blaze.Builder Blaze.Builder m a chunkIt = checkDone $ continue . step
http-enumerator.cabal view
@@ -1,5 +1,5 @@ name: http-enumerator-version: 0.7.1.2+version: 0.7.1.3 license: BSD3 license-file: LICENSE author: Michael Snoyman <michael@snoyman.com>