Gauche:HTTPD
インターネットエイジのこの時代、HTTP サーバの実装の一つや二つないと モダーンなプログラミング言語とはいえないんじゃなかろうか...
(長くなってきたので、トピック毎にまとめてみました。 コメント毎に時間を入れておいて頂くと良いかも。--Shiro (2002/11/22 22:04:59 PST))
参考資料
- http://www.jaist.ac.jp/~kiyoshiy/software/kumonoito/spec.txt
大学生のプログラミングの課題。ミニマルな仕様。
- http://www.w3.org/Protocols/
HTTP
- http://www.w3.org/Protocols/rfc2616/rfc2616.html
HTTP1.1
- http://www.pugo.org:8080/
Postscript による実装。 skimu 版の参考にした。
nekoie による実装
- すいません、宣伝させてください…‥。
skimu による実装
- 上記のミニマル仕様すらちゃんと実装してないけど、サーブレットで Gauche のマニュアルが検索できるので遊んでみて下さい
- Shiro: をを、すごい。こんなに短く書けるのか。んー、もじらだと 何も出ないが… w3mだと見られました。なんでだろ。(2002/11/15 23:40:10 PST)
- skimu: あれれ Chimera では 問題ありませんでした。もちろん IE でもオッケイ。スクリーンショット
- skimu: しばらく、HTTP と html の勉強で更新してませんでしたが、なんとなく方針が見えてきたので、改造に着手しました。(2002/12/01 19:42:27 PST)
SIGPIPE問題
- sakae です。お願いすると出てきますね。ひょっとして、scheme-undergroundな人? 私の所で試したら、こんなエラーがでました。
cons:sakae$ /www/bin/ab -c 5 -n 100 http://localhost:8081/ : ("GET" "/" "HTTP/1.0") ("GET" "/" "HTTP/1.0") *** ERROR: unhandled signal 13 (SIGPIPE) Stack Trace: _______________________________________ 0 (zap (mime-type->Content-type mime-type)) At line 134 of "./httpd.scm" 1 (let ((in (socket-input-port s)) (out (socket-output-port s))) (le ... At line 146 of "./httpd.scm" 2 (do-http cnl) At line 174 of "./httpd.scm" 環境は cons:sakae$ gosh -V Gauche scheme interpreter, version 0.6.4 [euc-jp] cons:sakae$ uname -a FreeBSD 4.7-STABLE FreeBSD 4.7-STABLE #0: Mon Oct 14 20:15:12 JST
- skimu: うぅ、エラーハンドリングはいい加減です (_o_) つーか, ちゃんとしたのができたら gauche-develで宣伝します:-) しかし、こんなところで SIGPIPE はいやっぽいですね... だけど、僕の NetBSD 1.6 では再現しませんでした。 ところで、scheme-underground って聞くとまっさきに ここ を思い浮かべてしまうのですが、ほかにもあるのでしょうか?(面白そうだから案内ください。)
- Shiro: SIGPIPE問題ですが、クライアントがリプライを全部受け取る前に 接続を切ってしまうと発生すると思います。これはシグナルハンドラで救済して ソケットを閉じるようにするしかないかな。
("GET" "/" "HTTP/1.0") (("user-agent" "ApacheBench/1.3d") ("host" "localhost:8080") ("accept" "*/ "One reqest processed" "Waiting for a client" "A Client accepted" "My handler: bad type of argument for s: #<eof>" "Waiting for a client"
MacOSX10.2.2で落ちる
skimu MacOSX10.2.2 だとなんとバスエラーで落ちました。
Program received signal EXC_BAD_ACCESS, Could not access memory. Scm_ClassOf (obj=0x0) at class.c:398 398 return SCM_CLASS_OF(obj); (gdb) bt #0 Scm_ClassOf (obj=0x0) at class.c:398 #1 0x00020124 in Scm_ComputeApplicableMethods (gf=0x0, args=0x2e41b0, nargs=2) at class.c:1301 #2 0x000084b8 in run_loop () at vm.c:585 #3 0x0000b2bc in user_eval_inner (program=0x4700d0) at vm.c:1707 #4 0x0000318c in main (argc=3, argv=0xbffffdc0) at main.c:275 #5 0x000024f4 in _start (argc=3, argv=0xbffffdc0, envp=0xbffffdd0) at /SourceCache/Csu/Csu-45/crt.c:267 #6 0x00002374 in start ()
- ひさしぶりに gosh を落とすのに成功してしまった。
(let loop ((cs #f)) (with-error-handler (lambda (e) (print-log LOG_ERR #`"My handler: ,(slot-ref e 'message)") (report-error e))
...
(loop #f)
- と書き替えると MacOSX でも動く様になりました。ちなみに loop () というように変数をいれないと、やはり Bus error でおちました。機種によってバグがでたり出なかったりする問題だったのかしら。(2002/11/22 21:36:05 PST)
- Shiro: 貴重な情報をありがとうございます。これでだいたい見当がついた、 という気がします。(2002/11/22 21:57:32 PST)
- Shiro: 解決しました。MacOS固有の問題ではなく、他のプラットフォームで たまたま症状が出ない問題でした。次のパッチで直ります。(2002/11/30 12:05:59 PST)
*** ext/net/addr.c 6 Jul 2002 23:01:17 -0000 1.12 --- ext/net/addr.c 30 Nov 2002 09:19:03 -0000 *************** *** 77,83 **** /* creates sockaddr from struct sockaddr. */ ScmObj Scm_MakeSockAddr(ScmClass *klass, struct sockaddr *saddr, int len) { ! ScmSockAddr *addr = SCM_NEW2(ScmSockAddr*, sizeof(ScmObj)+len); SCM_SET_CLASS(addr, klass); addr->addrlen = len; memset(&addr->addr, len, 0); --- 77,85 ---- /* creates sockaddr from struct sockaddr. */ ScmObj Scm_MakeSockAddr(ScmClass *klass, struct sockaddr *saddr, int len) { ! ScmSockAddr *addr; ! addr = SCM_NEW2(ScmSockAddr*, ! sizeof(ScmSockAddr) - sizeof(struct sockaddr) + len); SCM_SET_CLASS(addr, klass); addr->addrlen = len; memset(&addr->addr, len, 0);
もじらで見られない問題
- Shiro: もじらで見られない問題ですが、リクエストヘッダを全部読むように
したら見られるようになりました。
- (use rfc.822)を最初に追加
- do-httpの本体で、リクエストが"GET"の場合のブランチを次のようにする
(begin (rfc822-header->list in) (receive (text type len) (gen-text path) (reply text type len out)))
- 反映して頂きました。
エラーハンドラ
- skimu: エラーハンドラ付けてみたのでいじめてあげて下さい。ところで、当初
(define (httpd-main nport) (let ((ss (make-server-socket 'inet nport :reuse-addr? #t)) (cs #f)) (set-signal-handler! SIGPIPE (lambda (n) (error #`"Catched signal ,|n|"))) (do () (#f) (with-error-handler (lambda (e) (print-log #`"My handler: ,(slot-ref e 'message)")) (lambda () (dynamic-wind (lambda () #f) (lambda () (print-log "Waiting for a client") (set! cs (socket-accept ss)) (print-log "A Client accepted") (do-http cs) (print-log "One reqest processed") ) (lambda () (socket-close cs))))))))
- というように signal-handler のなかで error を出して My handler で受け取ろうとしたのですが、どうもデフォルトのエラーハンドラが呼ばれてしまいます。最新版のソースでは単にメッセージを印字してそのまま戻って、閉じたポートに対する書き込みエラーを捕まえてます。それと、set-signal-handler する前は SIGINT のハンドラーの中のエラー呼び出しが My handler で捕まえられなかったのが、set-signal-handler SIGPIPE を入れただけで、SIGINT の方も My handler で捕まるようになりました。
ログの方法
- Shiro: print-logはgauche.loggerを使っておくと後で何かと便利なのでは… と思ったのですがファイルロック絡みで動かないプラットフォームがあるんでしたっけ。 回避コードを入れた方がいいなあ。(2002/11/18 22:06:34 PST)
- skimu: 何れにしても現バージョンは MacOSX では Bus error で動かないので gauche.logger を使う様にしてみました。なんか、本物のサーバみたいになてきた。今後は www.cgi をつかってヘッダを吐かせてたり、サーブレットでヘッダを指定できる様に do-http をリストラ予定。
- Shiro: MacOSXではgauche.loggerがfcntlではなくロックファイルによる ロックを使うようにしてみました (logger.scm, v1.5, file/util.scm, v1.18も必要)。(2002/12/01 18:21:27 PST)
- skimu: 動作確認しました。ばっちりです。 main を次のように変えてみました。 (2002/12/01 19:39:00 PST)
(define (main args) (case (length args) ((2) ;; ログファイルを指定しなければ、デバッグモードで stderr に詳しいログ (set! log-level 4) (httpd-main (string->number (cadr args)) #t)) ((3) ;; 二番目の引数はログファイル。 syslog を指定すれば syslog へログ。 (close-input-port (current-input-port)) (close-output-port (current-output-port)) (close-output-port (current-error-port)) (if (string=? (caddr args) "syslog") (httpd-main (string->number (cadr args)) 'syslog) (httpd-main (string->number (cadr args)) (caddr args)))) (else (display "Usage: httpd port [logfile]\n" (current-error-port)))))
kawによる実装
子プロセス起動による並行サーバ(の雛型)を書いてみたのですが、Memory faultで落ちてしまいます。
LinuxとOpenBSDでやってみてどちらでも落ちる。なにが悪いんだろう?
... というわけで、詳細は kaw へ。
Shiroによる実装
https://github.com/shirok/Gauche-makiki
仕事で使ってて、必要に応じて機能を少しづつ足してます。