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で何回かやってるので、リファレンスはちゃんと読むことにしています(^^;
[ツッコミを入れる]