on master help sign in
6 files changed+77−31
since splitsnapshots
unifiedsplit
wai-extra/ChangeLog.md+4 wai-extra/Network/Wai/Test.hs+22−14 wai-extra/test/Network/Wai/TestSpec.hs+41−11 wai-extra/wai-extra.cabal+1−1 warp-tls/Network/Wai/Handler/WarpTLS.hs+2−2 warp/Network/Wai/Handler/Warp/Run.hs+7−3
wai-extra/ChangeLog.md+4
@@ -1,5 +1,9 @@
11# Changelog for wai-extra
22
3+## 3.0.29.1
4+
5+* Fix `Network.Wai.Test.request` always sending an empty request body [#794](https://github.com/yesodweb/wai/pull/794)
6+
37## 3.0.29
48
59* Export `Network.Wai.EventSource.eventStreamAppRaw` [#786](https://github.com/yesodweb/wai/pull/786)
wai-extra/Network/Wai/Test.hs+22−14
@@ -99,6 +99,10 @@ runSession session app = ST.evalStateT (runReaderT session app) initState
9999data SRequest = SRequest
100100 { simpleRequest :: Request
101101 , simpleRequestBody :: L.ByteString
102+ -- ^ Request body that will override the one set in 'simpleRequest'.
103+ --
104+ -- This is usually simpler than setting the body as a stateful IO-action
105+ -- in 'simpleRequest'.
102106 }
103107data SResponse = SResponse
104108 { simpleStatus :: H.Status
@@ -106,8 +110,16 @@ data SResponse = SResponse
106110 , simpleBody :: L.ByteString
107111 }
108112 deriving (Show, Eq)
113+
109114request :: Request -> Session SResponse
110−request = srequest . flip SRequest L.empty
115+request req = do
116+ app <- ask
117+ req' <- addCookiesToRequest req
118+ response <- liftIO $ do
119+ ref <- newIORef $ error "runResponse gave no result"
120+ ResponseReceived <- app req' (runResponse ref)
121+ readIORef ref
122+ extractSetCookieFromSResponse response
111123
112124-- | Set whole path (request path + query string).
113125setPath :: Request -> S8.ByteString -> Request
@@ -166,22 +178,18 @@ extractSetCookieFromSResponse response = do
166178 (Map.fromList [(Cookie.setCookieName c, c) | c <- newClientCookies ]))
167179 return response
168180
181+-- | Similar to 'request', but allows setting the request body as a plain
182+-- 'L.ByteString'.
169183srequest :: SRequest -> Session SResponse
170184srequest (SRequest req bod) = do
171− app <- ask
172185 refChunks <- liftIO $ newIORef $ L.toChunks bod
173− let req' = req
174− { requestBody = atomicModifyIORef refChunks $ \bss ->
175− case bss of
176− [] -> ([], S.empty)
177− x:y -> (y, x)
178− }
179− req'' <- addCookiesToRequest req'
180− response <- liftIO $ do
181− ref <- newIORef $ error "runResponse gave no result"
182− ResponseReceived <- app req'' (runResponse ref)
183− readIORef ref
184− extractSetCookieFromSResponse response
186+ request $
187+ req
188+ { requestBody = atomicModifyIORef refChunks $ \bss ->
189+ case bss of
190+ [] -> ([], S.empty)
191+ x:y -> (y, x)
192+ }
185193
186194runResponse :: IORef SResponse -> Response -> IO ResponseReceived
187195runResponse ref res = do
wai-extra/test/Network/Wai/TestSpec.hs+41−11
@@ -3,6 +3,8 @@ module Network.Wai.TestSpec (main, spec) where
33
44import Control.Monad (void)
55
6+import qualified Data.IORef as IORef
7+
68import qualified Data.Text.Encoding as TE
79
810import Data.Time.Calendar (fromGregorian)
@@ -53,25 +55,53 @@ spec = do
5355 it "sets rawQueryString to empty string" $ do
5456 rawQueryString (setPath defaultRequest "/foo/bar/baz") `shouldBe` ""
5557
58+ describe "srequest" $ do
59+
60+ let echoApp req respond = do
61+ reqBody <- L8.fromStrict <$> getRequestBodyChunk req
62+ let reqHeaders = requestHeaders req
63+ respond $
64+ responseLBS
65+ status200
66+ reqHeaders
67+ reqBody
68+
69+ it "returns the response body of an echo app" $ do
70+ sresp <- flip runSession echoApp $
71+ srequest $ SRequest defaultRequest "request body"
72+ simpleBody sresp `shouldBe` "request body"
73+
5674 describe "request" $ do
5775
58− let simpleApp _req respond =
76+ let echoApp req respond = do
77+ reqBody <- L8.fromStrict <$> getRequestBodyChunk req
78+ let reqHeaders = requestHeaders req
5979 respond $
6080 responseLBS
6181 status200
62− [("foo", "bar")]
63− "simple"
82+ reqHeaders
83+ reqBody
6484
65− it "returns the status code of a simple app on default request" $ do
66− sresp <- runSession (request defaultRequest) simpleApp
85+ it "returns the status code of an echo app on default request" $ do
86+ sresp <- runSession (request defaultRequest) echoApp
6787 simpleStatus sresp `shouldBe` status200
6888
69− it "returns the response body of a simple app on default request" $ do
70− sresp <- runSession (request defaultRequest) simpleApp
71− simpleBody sresp `shouldBe` "simple"
72−
73− it "returns the response headers of a simple app on default request" $ do
74− sresp <- runSession (request defaultRequest) simpleApp
89+ it "returns the response body of an echo app" $ do
90+ bodyRef <- IORef.newIORef "request body"
91+ let getBodyChunk = IORef.atomicModifyIORef bodyRef $ \leftover -> ("", leftover)
92+ sresp <- flip runSession echoApp $
93+ request $
94+ defaultRequest
95+ { requestBody = getBodyChunk
96+ }
97+ simpleBody sresp `shouldBe` "request body"
98+
99+ it "returns the response headers of an echo app" $ do
100+ sresp <- flip runSession echoApp $
101+ request $
102+ defaultRequest
103+ { requestHeaders = [("foo", "bar")]
104+ }
75105 simpleHeaders sresp `shouldBe` [("foo", "bar")]
76106
77107 let cookieApp req respond =
wai-extra/wai-extra.cabal+1−1
@@ -1,5 +1,5 @@
11Name: wai-extra
2−Version: 3.0.29
2+Version: 3.0.29.1
33Synopsis: Provides some basic WAI handlers and middleware.
44description:
55 Provides basic WAI handler and middleware functionality:
warp-tls/Network/Wai/Handler/WarpTLS.hs+2−2
@@ -483,9 +483,9 @@ tryIO = try
483483----------------------------------------------------------------
484484
485485plainHTTP :: TLSSettings -> Settings -> Socket -> S.ByteString -> IO (Connection, Transport)
486−plainHTTP TLSSettings{..} _ s bs0 = case onInsecure of
486+plainHTTP TLSSettings{..} set s bs0 = case onInsecure of
487487 AllowInsecure -> do
488− conn' <- socketConnection s
488+ conn' <- socketConnection set s
489489 cachedRef <- I.newIORef bs0
490490 let conn'' = conn'
491491 { connRecv = recvPlain cachedRef (connRecv conn')
warp/Network/Wai/Handler/Warp/Run.hs+7−3
@@ -58,8 +58,12 @@ import Network.Socket (fdSocket)
5858#endif
5959
6060-- | Creating 'Connection' for plain HTTP based on a given socket.
61−socketConnection :: Socket -> IO Connection
62−socketConnection s = do
61+socketConnection :: Settings -> Socket -> IO Connection
62+#if MIN_VERSION_network(3,1,1)
63+socketConnection set s = do
64+#else
65+socketConnection _ s = do
66+#endif
6367 bufferPool <- newBufferPool
6468 writeBuf <- allocateBuffer bufferSize
6569 let sendall = Sock.sendAll s
@@ -147,7 +151,7 @@ runSettingsSocket set socket app = do
147151 setSocketCloseOnExec s
148152 -- NoDelay causes an error for AF_UNIX.
149153 setSocketOption s NoDelay 1 `E.catch` \(E.SomeException _) -> return ()
150− conn <- socketConnection s
154+ conn <- socketConnection set s
151155 return (conn, sa)
152156
153157 closeListenSocket = close socket