問題
Haskell と Pipes ライブラリを使用して単純な Web サーバーを実装しようとしています。循環トポロジーまたはダイヤモンド トポロジーはパイプでは不可能であることを理解しましたが、私がしようとしているのはそうであると思いました。したがって、私の望ましいトポロジは次のとおりです。
-GET--> handleGET >-> packRequest >-> socketWriteD
|
socketReadS >-> parseRequest >-routeRequest
|
-POST-> handlePOST >-> packRequest >-> socketWriteD
チェーンで使用するタイプがありますHTTPRequest RequestLine Headers Message
。は、ソケットからバイトを受け取り、Attoparsec を使用してバイトをオブジェクトに解析する に転送します。次に、実装する HTTP メソッドの数に応じて、パイプが少なくとも 2 回、場合によってはそれ以上分岐するようにします。各関数は、アップストリームからオブジェクトを受信し、オブジェクトをに転送する必要があります。これにより、HTTPResponse オブジェクトが で送信できるようにまとめられます。HTTPResponse StatusLine Headers Message
socketReadS
parseRequest
HTTPRequest
handle<method>
HTTPRequest
HTTPResponse
packRequest
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