インターネットエイジのこの時代、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
仕事で使ってて、必要に応じて機能を少しづつ足してます。