http-client 0.7.9 → 0.7.10
raw patch · 5 files changed
+68/−9 lines, 5 files
Files
- ChangeLog.md +5/−0
- Network/HTTP/Client/Body.hs +13/−1
- http-client.cabal +1/−1
- test-nonet/Network/HTTP/Client/BodySpec.hs +48/−6
- test-nonet/Network/HTTP/Client/ResponseSpec.hs +1/−1
ChangeLog.md view
@@ -1,5 +1,10 @@ # Changelog for http-client +## 0.7.10++* Consume trailers and last CRLF of chunked body. The trailers are not exposed,+ unless the raw body is requested.+ ## 0.7.9 * Exceptions from streamed request body now cause the request to fail. Previously they were
Network/HTTP/Client/Body.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE MultiWayIf #-} module Network.HTTP.Client.Body ( makeChunkedReader , makeLengthReader@@ -166,8 +167,11 @@ else return (empty, count0) if count <= 0 then do+ -- count == -1 indicates that all chunks have been consumed writeIORef icount (-1)- return $ if count /= (-1) && raw then rawCount else empty+ if | count /= -1 && raw -> S.append rawCount <$> readTrailersRaw+ | count /= -1 -> consumeTrailers *> pure empty+ | otherwise -> pure empty else do (bs, count') <- readChunk count writeIORef icount count'@@ -222,3 +226,11 @@ | 65 <= w && w <= 70 = Just $ fromIntegral w - 55 | 97 <= w && w <= 102 = Just $ fromIntegral w - 87 | otherwise = Nothing++ readTrailersRaw = do+ bs <- connectionReadLine conn+ if S.null bs+ then pure "\r\n"+ else (bs `S.append` "\r\n" `S.append`) <$> readTrailersRaw++ consumeTrailers = connectionDropTillBlankLine conn
http-client.cabal view
@@ -1,5 +1,5 @@ name: http-client-version: 0.7.9+version: 0.7.10 synopsis: An HTTP client engine description: Hackage documentation generation is not reliable. For up to date documentation, please see: <http://www.stackage.org/package/http-client>. homepage: https://github.com/snoyberg/http-client
test-nonet/Network/HTTP/Client/BodySpec.hs view
@@ -20,7 +20,7 @@ spec = describe "BodySpec" $ do it "chunked, single" $ do (conn, _, input) <- dummyConnection- [ "5\r\nhello\r\n6\r\n world\r\n0\r\nnot consumed"+ [ "5\r\nhello\r\n6\r\n world\r\n0\r\n\r\nnot consumed" ] reader <- makeChunkedReader (return ()) False conn body <- brConsume reader@@ -29,9 +29,20 @@ S.concat input' `shouldBe` "not consumed" brComplete reader `shouldReturn` True + it "chunked, single, with trailers" $ do+ (conn, _, input) <- dummyConnection+ [ "5\r\nhello\r\n6\r\n world\r\n0\r\ntrailers-are: ignored\r\nbut: consumed\r\n\r\nnot consumed"+ ]+ reader <- makeChunkedReader (return ()) False conn+ body <- brConsume reader+ S.concat body `shouldBe` "hello world"+ input' <- input+ S.concat input' `shouldBe` "not consumed"+ 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"+ "5\r\nhello\r\n6\r\n world\r\n0\r\n\r\nnot consumed" reader <- makeChunkedReader (return ()) False conn body <- brConsume reader S.concat body `shouldBe` "hello world"@@ -39,23 +50,54 @@ S.concat input' `shouldBe` "not consumed" brComplete reader `shouldReturn` True + it "chunked, pieces, with trailers" $ do+ (conn, _, input) <- dummyConnection $ map S.singleton $ S.unpack+ "5\r\nhello\r\n6\r\n world\r\n0\r\ntrailers-are: ignored\r\nbut: consumed\r\n\r\nnot consumed"+ reader <- makeChunkedReader (return ()) False conn+ body <- brConsume reader+ S.concat body `shouldBe` "hello world"+ input' <- input+ S.concat input' `shouldBe` "not consumed"+ brComplete reader `shouldReturn` True+ it "chunked, raw" $ do (conn, _, input) <- dummyConnection- [ "5\r\nhello\r\n6\r\n world\r\n0\r\nnot consumed"+ [ "5\r\nhello\r\n6\r\n world\r\n0\r\n\r\nnot consumed" ] reader <- makeChunkedReader (return ()) True conn body <- brConsume reader- S.concat body `shouldBe` "5\r\nhello\r\n6\r\n world\r\n0\r\n"+ S.concat body `shouldBe` "5\r\nhello\r\n6\r\n world\r\n0\r\n\r\n" input' <- input S.concat input' `shouldBe` "not consumed" brComplete reader `shouldReturn` True + it "chunked, raw, with trailers" $ do+ (conn, _, input) <- dummyConnection+ [ "5\r\nhello\r\n6\r\n world\r\n0\r\ntrailers-are: returned\r\nin-raw: body\r\n\r\nnot consumed"+ ]+ reader <- makeChunkedReader (return ()) True conn+ body <- brConsume reader+ S.concat body `shouldBe` "5\r\nhello\r\n6\r\n world\r\n0\r\ntrailers-are: returned\r\nin-raw: body\r\n\r\n"+ input' <- input+ S.concat input' `shouldBe` "not consumed"+ 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"+ "5\r\nhello\r\n6\r\n world\r\n0\r\n\r\nnot consumed" reader <- makeChunkedReader (return ()) True conn body <- brConsume reader- S.concat body `shouldBe` "5\r\nhello\r\n6\r\n world\r\n0\r\n"+ S.concat body `shouldBe` "5\r\nhello\r\n6\r\n world\r\n0\r\n\r\n"+ input' <- input+ S.concat input' `shouldBe` "not consumed"+ brComplete reader `shouldReturn` True++ it "chunked, pieces, raw, with trailers" $ do+ (conn, _, input) <- dummyConnection $ map S.singleton $ S.unpack+ "5\r\nhello\r\n6\r\n world\r\n0\r\ntrailers-are: returned\r\nin-raw: body\r\n\r\nnot consumed"+ reader <- makeChunkedReader (return ()) True conn+ body <- brConsume reader+ S.concat body `shouldBe` "5\r\nhello\r\n6\r\n world\r\n0\r\ntrailers-are: returned\r\nin-raw: body\r\n\r\n" input' <- input S.concat input' `shouldBe` "not consumed" brComplete reader `shouldReturn` True
test-nonet/Network/HTTP/Client/ResponseSpec.hs view
@@ -59,7 +59,7 @@ , "Transfer-encoding: chunked\r\n\r\n" , "5\r\nHello\r" , "\n2\r\n W"- , "\r\n4 ignored\r\norld\r\n0\r\nHTTP/1.1"+ , "\r\n4 ignored\r\norld\r\n0\r\n\r\nHTTP/1.1" ] Response {..} <- getResponse' conn responseStatus `shouldBe` status200