インターネットエイジのこの時代、HTTP サーバの実装の一つや二つないと モダーンなプログラミング言語とはいえないんじゃなかろうか...
(長くなってきたので、トピック毎にまとめてみました。 コメント毎に時間を入れておいて頂くと良いかも。--Shiro (2002/11/22 22:04:59 PST))
大学生のプログラミングの課題。ミニマルな仕様。
HTTP
HTTP1.1
Postscript による実装。 skimu 版の参考にした。
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
("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"
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 ()
(let loop ((cs #f)) (with-error-handler (lambda (e) (print-log LOG_ERR #`"My handler: ,(slot-ref e 'message)") (report-error e))
...
(loop #f)
*** 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);
(begin (rfc822-header->list in) (receive (text type len) (gen-text path) (reply text type len out)))
(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))))))))
(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)))))
子プロセス起動による並行サーバ(の雛型)を書いてみたのですが、Memory faultで落ちてしまいます。
LinuxとOpenBSDでやってみてどちらでも落ちる。なにが悪いんだろう?
... というわけで、詳細は kaw へ。
https://github.com/shirok/Gauche-makiki
仕事で使ってて、必要に応じて機能を少しづつ足してます。