Wikiエンジンの開発

13.3 CGIの処理


昨日までで、"runCGI"関数の中の"cgiEnvs"関数まで解析が終わりました。
次は"runCGI"関数の心臓部である"parseCGIRequest"関数を見ていきます。


"parseCGIRequest"関数の定義を見てみます。

parseCGIRequest env input =
    case method of
      "GET"  -> parseGET env
      "POST" -> parsePOST env input
      _      -> parseUnknown


where節は大きいのでまずは省略。
"GET"や"POST"はHTTPリクエストのメソッドでしょうね。
つまり、メソッドの種類で適用する関数を切り換えています。
また"GET"、"POST"以外のメソッドは受け付けない仕様のようです。


一番簡単そうな"parseUnknown"関数から見ていきましょうか。

parseUnknown = HTTPRequest []


"HTTPRequest"は関数ではなく、データコンストラクタです。
こんな感じ。

data HTTPRequest = HTTPRequest { params :: [(String, String)] }


予想ですが、"HTTPRequest"型は、ヘッダとその値のタプルをリスト化したものなのでしょう。
その観点からすると、"GET"、"POST"メソッド以外の場合、ヘッダは全て破棄することになります。
まぁ、仕様外ですからね。


ちょっと順番が前後しましたが、次は"method"関数。

    method = getenv "REQUEST_METHOD" env


"env"は、"parseCGIRequest"関数の第1引数です。
これは"cgiEnvs"関数の戻り値を非モナド化したものです。
つまり、

(環境変数名, 環境変数値)


というタプルのリストです。
"method"関数は"getenv"関数を呼び出しています。
すぐ下に定義があります。

    getenv key env = fromMaybe "" $ lookup key env


"lookup"関数はお初なので中身を見てみます。

  • Preludeモジュール
lookup           :: (Eq a) => a -> [(a,b)] -> Maybe b
lookup key []    =  Nothing
lookup key ((x,y):xys)
    | key == x   =  Just y
    | otherwise  =  lookup key xys


名前から察するに、
第1引数をキーとして、第2引数のタプルのリストの左側要素に一致するタプルを検索して、右側要素を返すみたいですね。
もし見つからなければ"Nothing"を返す。
簡単な例で実験してみましょう。

Prelude> lookup 1 [(1, "1"), (2, "2"), (3, "3")]
Just "1"
Prelude> lookup 4 [(1, "1"), (2, "2"), (3, "3")]
Nothing


まぁ、合ってそうですね。
定義もとってもシンプルですね。


次に"fromMaybe"関数。
定義はこんな感じ。

  • Data.Maybeモジュール
fromMaybe              :: a -> Maybe a -> a
fromMaybe d Nothing    =  d
fromMaybe d (Just a)   =  a


これもとても分かりやすいですね。
ちょっと乱暴ですが、「"Maybe"外し」という感じでしょうか。
"Nothing"の場合は第1引数を返す。
これも簡単な例で試してみましょう。

Prelude> :m + Data.Maybe
Prelude Data.Maybe> fromMaybe 1 Nothing
1
Prelude Data.Maybe> fromMaybe 1 (Just 2)
2


ということで"getenv"関数の機能はこんな感じ。
環境変数の中から、"REQUEST_METHOD"を検索します("lookup"関数)。
もしあれば、そのまま環境変数の値を返します。なければ""を返します("fromMaybe"関数)。


順調、順調。
今日はここまで!
明日は"parseGET"関数、"parsePOST"関数に進みます。