【发布时间】:2013-04-18 19:09:12
【问题描述】:
问题
我正在尝试使用 Haskell 和 Pipes 库实现一个简单的 Web 服务器。我现在明白循环或菱形拓扑对于管道是不可能的,但是我认为我想要的是。因此,我想要的拓扑是:
-GET--> handleGET >-> packRequest >-> socketWriteD
|
socketReadS >-> parseRequest >-routeRequest
|
-POST-> handlePOST >-> packRequest >-> socketWriteD
我有 HTTPRequest RequestLine Headers Message 和 HTTPResponse StatusLine Headers Message 在链中使用的类型。 socketReadS 从套接字中获取字节并将它们转发给 parseRequest,后者使用 Attoparsec 将字节解析为 HTTPRequest 对象。然后,我希望管道至少分支两次,并且可能更多,这取决于我实现了多少 HTTP 方法。每个handle<method> 函数应该从上游接收HTTPRequest 对象并将HTTPResponse 对象转发到packRequest,这只是将HTTPResponse 对象打包在ByteString 中,准备好与socketWriteS 一起发送。
如果我让 GHC 推断 routeRequest''' 的类型,则以下代码类型检查(我的似乎有点偏离)。然而,parseRequest 之后似乎没有任何执行。谁能帮我弄清楚为什么?
代码
我有以下 routeRequest 的代码,它应该处理分支。
routeRequest''' ::
(Monad m, Proxy p1, Proxy p2, Proxy p3)
=> () -> Consumer p1 HTTPRequest (Pipe p2 HTTPRequest HTTPRequest (Pipe p3 HTTPRequest HTTPRequest m)) r
routeRequest''' () = runIdentityP . hoist (runIdentityP . hoist runIdentityP) $ forever $ do
httpReq <- request ()
let method = getMethod httpReq
let (URI uri) = getURI httpReq
case method of
GET -> lift $ respond httpReq
POST -> lift $ lift $ respond httpReq
routeRequest'' = runProxyK $ routeRequest''' <-< unitU
routeRequest' socket = runProxyK $ raiseK (p4 socket <-< handleGET) <-< routeRequest''
routeRequest socket = (p4 socket <-< handlePOST) <-< (routeRequest' socket)
handleGET 和 handlePOST 是这样实现的:
handleGET :: Proxy p => () -> p () HTTPRequest r ByteString IO r
handleGET () = runIdentityP $ do
httpReq <- request ()
let (URI uri) = getURI httpReq
lift $ Prelude.putStrLn "GET"
respond $ B.append (B.pack "GET ") uri
handlePOST :: Proxy p => () -> p () HTTPRequest r ByteString IO r
handlePOST () = runIdentityP $ do
httpReq <- request ()
let (URI uri) = getURI httpReq
lift $ Prelude.putStrLn "POST"
respond $ B.append (B.pack "POST ") uri
我有以下代理的简写:
p1 socket = socketReadS 32 socket
p2 = parseRequestProxy
p4 socket = socketWriteD socket
最后,我像这样运行整个事情:
main = serveFork (Host "127.0.0.1") "8080" $
\(socket, remoteAddr) -> do
ret <- runProxy $ runEitherK $ p1 socket >-> printD >-> p2 >-> printD >-> routeRequest socket
Prelude.putStrLn $ show ret
parseRequestProxy 的类型签名是这样的:
parseRequestProxy
:: (Monad m, Proxy p) =>
()
-> Pipe
(EitherP Control.Proxy.Attoparsec.Types.BadInput p)
ByteString
HTTPRequest
m
r
编辑
这是包含源代码的存储库。请注意,它没有经过修饰,因此使用风险自负。 https://bitbucket.org/Dwilson1234/haskell-web-server/overview
【问题讨论】:
-
Dwilson 你打算分享这个http服务器的源码吗?
-
谢谢你提醒我,我的意思是等学期结束就打开存储库。现在问题来了。
-
感谢您的分享!您应该添加许可证。顺便说一句......它看起来非常可读!恭喜!
-
谢谢!如果您有任何问题,可以通过 gmail dot com 的 wilsonhardrock 给我发电子邮件。
标签: haskell haskell-pipes