2006-05-22
■ [scheme] GaucheでHTTPサーバを書いてみる
- GaucheでCGIを書いてみたい。
- けどこのマシンはWindowsだなぁ。
- 適当にHTTPサーバを拾ってくるって手もあるけど、せっかくだからGaucheで書いてみるか。
- (GaucheでHTTPサーバを書くためのライブラリ*1を探したんだけど、見つからず)
というわけで。
- とりあえずリファレンスを眺める。www.cgiはCGIを書くためのものだから違うな。rfc.httpはHTTP「クライアント」って書いてあるから違うな。うーん、gauche.net使って頑張るのか。
- 高レベルインターフェイスにHTTP「クライアント」の例はあるな。サーバは…そうか、bindとかlistenとかするのか。実習でやったなぁ。
- socket(),bind(),listen(),accept(),read/write/send/recv(),close()らしい
- 今回は、socket,bind,listenまでmake-server-socketがやってくれそう。
というわけでhttpserv.scmできたよー。
(use gauche.net) (define sock #f) (define (server-start) (make-server-socket 10800)) (define (server-accept sock) (let ((new-sock (socket-accept sock))) (display (socket-status new-sock)) (display (socket-recv new-sock 100000)) (socket-send new-sock "HTTP/1.1 200 OK\ncontent-type: text/html;\n\nasdf,fdsa") (socket-close new-sock))) (define (main arg) (let ((server (server-start))) (server-accept server)))
gosh httpserv.scmとやって、ブラウザでhttp://localhost:10800/を開くとasdf,fdsaと表示されます。
*1 Rubyのwebrickのような
■ [scheme] GaucheでHTTP
次はCGIか。
…あれ、GaucheでRubyの「$0==__FILE__」(そのファイルをインタプリタで実行されたときは真に、requireされたときは偽に なる)ってどう書くんだろう。
まあいいや、CGIのリクエスト文字列を引数に取るようなmain関数をCGIスクリプト側で書くようにしよう。 サーバからはそのmainを呼ぶ、と。
cgitest.scm:
(use www.cgi) (define (main arg) ...
httpserv.scm:
(use gauche.net) (load "./cgitest.scm") ... (socket-send new-sock (main req_str))
■ [scheme] GaucheでHTTP(3)
いろんなデータを文字列に直すのはどうするのかな?(Rubyのto_sやinspectみたいな)
(x->string hoge) を使えばいいのか。
■ [scheme] GaucheでHTTP(4)
さて、じゃあHTTPのリクエストのパースをするか。
文字列処理だから6.10(文字列)と10.9(srfi-13)あたりを読んどけば大丈夫かな。正規表現使うなら6.11と9.16(gauche.regexp)か。 *1
うあ、caseの同値判定はeqv?か!文字列には使えないじゃん。cond使うか…。
こんな感じでいいか。
(use gauche.net) (use srfi-1) (use srfi-13) (load "./cgitest.scm") (define (parse-request request) (rxmatch-let (rxmatch #/^(GET|POST)/ (car request)) (method) (cond ((string= "GET" method) ((#/^GET \/?([^\?]+\?)?(\S+) HTTP/ (car request)) 2)) ((string= "POST" method) (last request)) (else "error: unknown method")))) ... (socket-send new-sock (main (parse-request request)))
*1 「あれ、この処理標準ライブラリにあるじゃん!」という経験はRubyで何回かやってるので、リファレンスはちゃんと読むことにしています(^^;