頂いたラムを飲みながらお送りしております。
で、前の続きです。
前の:Wai + WarpでWebサーバを作る - yunomuのブログ
Waiのマニュアルを見てるとちょっと面白い型があって
Network.Wai
type Application = Request -> ResourceT IO Response type Middleware = Application -> Application
Applicationは前回出てきたとおりで、今回は下のMiddleware型。
Applicationを取ってApplicationを返すということで、多分引数として受け取ったApplicationに機能追加したり入力や出力を加工したりするために使うんでしょう。マニュアルにもGZIP encodingに使うとか書いてあるし。
でも役割的にMiddlewareっていうよりこれWrapperだよねぇと思わなくもない。
ということで、今回は前回作った超適当なWebサーバに機能を追加して遊んでみようと思います。
基本は前回のこれ。
{-# LANGUAGE OverloadedStrings #-} import Network.Wai import Network.Wai.Handler.Warp import Network.HTTP.Types import Blaze.ByteString.Builder.Char.Utf8 server :: Application server _ = return $ ResponseBuilder status200 [] $ fromString "hello" main :: IO () main = do run 8080 server
これに新機能を追加する。入出力の加工の方がわかりやすいかもしれないんだけど、ここではとりあえずHTTPの新しいメソッドを定義してみます。
{-# LANGUAGE OverloadedStrings #-} import Network.Wai import Network.Wai.Handler.Warp import Network.HTTP.Types import Blaze.ByteString.Builder.Char.Utf8 server :: Application server _ = return $ ResponseBuilder status200 [] $ fromString "hello" middleware :: Middleware middleware app request = do if requestMethod request == "MOGE" then return $ ResponseBuilder status200 [] $ fromString res else app request where res = show $ pathInfo request main :: IO () main = run 8080 $ middleware server
MOGEメソッドを作った。
機能は、ようはECHOです。パスをそのまま返す。メソッド名もECHOにすればよかった……。
Applicationの時もそうだったけど、今回のMiddlewareもやっぱりなんか型がわかりづらくて、
middleware :: Middleware
というのはtypeを展開すると要するに
middleware :: Application -> Request -> ResourceT IO Response
という事になります。
やってることは見ての通り、メソッドがMOGEだったらechoして、そうじゃなかったらWAIに任せるという感じです。
動作確認は、curlではできないのでtelnetでやります。
% telnet localhost 8080 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. MOGE harukasanmoe HTTP/1.0 HTTP/1.0 200 OK Server: Warp/1.3.0 ["harukasanmoe"]Connection closed by foreign host.
つつがなく成功しているようですね。
ちなみにWarpはHTTPのバージョン指定をしないとちゃんと動かないみたいです。勝手に0.9だと解釈してくれたりはしない。律儀な奴だ。
けどバージョン番号の部分は"3.0"でも"aaa"でも”^D"でもいいみたいで、なんか適当に0.9だか1.0だかだと判断して返してくれます。ただ1.1にするとちゃんとKeepAliveが働く。なんとなくパーサ書くのを中途半端に面倒臭がった形跡が見え隠れする。HTTPの仕様をそんなに詳しく知らないのでなんとも言えないけども。
あ、MOGEメソッドもバージョン番号を1.1にするとちゃんと1.1相当に動きます。話のわかる奴だ。
ということで、これでWebDAVの実装も余裕ですね。いや全然余裕じゃないっていうか、Warpの半分を書き換えた上でそれ以上の機能を追加する羽目になるような気がしますけども。
あとは、Network.Wai.Testを使ったりなんたり、というのは面倒くさいのでコードの参照で。
exercises/wai-example at master · yunomu/exercises · GitHub
あくまでもWaiのテストであって、Warpのテストではない点は注意です。Wai的にオッケーなら未知の形式のメソッドでも普通に通っちゃいますので。