[Haskell-cafe] Input request: which interface for Web Application
Interface
Michael Snoyman
michael at snoyman.com
Fri Jan 29 07:17:25 EST 2010
Skipped content of type multipart/alternative-------------- next part --------------
diff --git a/Network/Wai.hs b/Network/Wai.hs
index 9807c44..4466b2c 100644
--- a/Network/Wai.hs
+++ b/Network/Wai.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE Rank2Types #-}
module Network.Wai
( -- * Data types
-- ** Request method
@@ -23,6 +23,8 @@ module Network.Wai
, Status (..)
, statusCode
, statusMessage
+ -- * Enumerator
+ , Enumerator
-- * WAI interface
, Request (..)
, Response (..)
@@ -233,6 +235,8 @@ statusMessage Status405 = B8.pack "Method Not Allowed"
statusMessage Status500 = B8.pack "Internal Server Error"
statusMessage (Status _ m) = m
+type Enumerator a = (a -> B.ByteString -> IO (Either a a)) -> a -> IO a
+
data Request = Request
{ requestMethod :: Method
, httpVersion :: HttpVersion
@@ -242,7 +246,7 @@ data Request = Request
, serverPort :: Int
, httpHeaders :: [(RequestHeader, B.ByteString)]
, urlScheme :: UrlScheme
- , requestBody :: IO (Maybe B.ByteString)
+ , requestBody :: forall a. Enumerator a
, errorHandler :: String -> IO ()
, remoteHost :: String
}
@@ -250,7 +254,7 @@ data Request = Request
data Response = Response
{ status :: Status
, headers :: [(ResponseHeader, B.ByteString)]
- , body :: Either FilePath ((B.ByteString -> IO ()) -> IO ())
+ , body :: forall a. Either FilePath (Enumerator a)
}
type Application = Request -> IO Response
diff --git a/Network/Wai/Handler/SimpleServer.hs b/Network/Wai/Handler/SimpleServer.hs
index 72f7280..6e4d3ba 100644
--- a/Network/Wai/Handler/SimpleServer.hs
+++ b/Network/Wai/Handler/SimpleServer.hs
@@ -21,7 +21,6 @@ import Network.Wai
import qualified System.IO
import qualified Data.ByteString as BS
-import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Char8 as B8
import Network
( listenOn, accept, sClose, PortID(PortNumber), Socket
@@ -135,14 +134,16 @@ parseRequest port lines' handle remoteHost' = do
, remoteHost = remoteHost'
}
-requestBodyHandle :: Handle -> MVar Int -> IO (Maybe BS.ByteString)
-requestBodyHandle h mlen = modifyMVar mlen helper where
- helper :: Int -> IO (Int, Maybe BS.ByteString)
- helper 0 = return (0, Nothing)
- helper len = do
+requestBodyHandle :: Handle -> MVar Int -> Enumerator a
+requestBodyHandle h mlen iter accum = modifyMVar mlen (helper accum) where
+ helper a 0 = return (0, a)
+ helper a len = do
bs <- BS.hGet h len
let newLen = len - BS.length bs
- return (newLen, Just bs)
+ ea' <- iter a bs
+ case ea' of
+ Left a' -> return (newLen, a')
+ Right a' -> helper a' newLen
parseFirst :: (StringLike s, MonadFailure InvalidRequest m) =>
s
@@ -167,8 +168,9 @@ sendResponse h res = do
BS.hPut h $ SL.pack "\r\n"
case body res of
Left fp -> unsafeSendFile h fp
- Right enum -> enum $ BS.hPut h
+ Right enum -> enum myPut h >> return ()
where
+ myPut _ bs = BS.hPut h bs >> return (Right h)
putHeader (x, y) = do
BS.hPut h $ responseHeaderToBS x
BS.hPut h $ SL.pack ": "
diff --git a/test.hs b/test.hs
index 1e8b5c1..a92d1e5 100644
--- a/test.hs
+++ b/test.hs
@@ -1,7 +1,7 @@
+{-# LANGUAGE Rank2Types #-}
import Network.Wai
import Network.Wai.Handler.SimpleServer
import qualified Data.ByteString.Char8 as B8
-import qualified Data.ByteString as B
main :: IO ()
main = putStrLn "http://localhost:3000/" >> run 3000 app
@@ -18,19 +18,12 @@ indexResponse = return Response
, body = index
}
-postResponse :: IO (Maybe B.ByteString) -> IO Response
+postResponse :: (forall a. Enumerator a) -> IO Response
postResponse rb = return Response
{ status = Status200
, headers = [(ContentType, B8.pack "text/plain")]
- , body = Right $ postBody rb
+ , body = Right rb
}
index :: Either FilePath a
index = Left "index.html"
-
-postBody :: IO (Maybe B.ByteString) -> (B.ByteString -> IO ()) -> IO ()
-postBody req res = do
- mbs <- req
- case mbs of
- Nothing -> return ()
- Just bs -> res bs >> postBody req res
More information about the Haskell-Cafe
mailing list