〜Gauche on Railsへの道〜 3. ActiveController 風のものを作る。その2 〜
今日は少し時間が取れたのですが、あまり進展しませんでした。
小型 http サーバーに HTML,画像などを扱う機能を追加しました。
#!/usr/bin/env gosh ;;; ;;; 小型httpサーバー ;;; (use gauche.reload) (use gauche.net) (use util.match) (use file.util) (use rfc.822) (use rfc.uri) (use www.cgi) (define *mini-server-port* 8080) (define (run-server) (add-load-path ".") (let1 server-sock (make-server-socket 'inet *mini-server-port* :reuse-addr? #t) (print #`"Start mini-server port=,*mini-server-port*") (guard (e (else (socket-close server-sock) (raise e))) (let loop ((client (socket-accept server-sock))) (guard (e (else (socket-close client) (raise e))) (handle-request (get-request (socket-input-port client)) (socket-output-port client)) (socket-close client)) (loop (socket-accept server-sock)))))) (define (get-request iport) (rxmatch-case (read-line iport) [test eof-object? 'bad-request] [#/^(GET)\s+(\S+)\s+HTTP\/\d+\.\d+$/ (_ method abs-path) (list* method abs-path #f (rfc822-header->list iport))] [#/^(POST)\s+(\S+)\s+HTTP\/\d+\.\d+$/ (_ method abs-path) (let* ((headers (rfc822-header->list iport)) (post-data (string-incomplete->complete (read-block (x->integer (rfc822-header-ref headers "content-length")) iport)))) (list* method abs-path post-data headers))] [#/^[A-Z]+/ () 'not-implemented] [else 'bad-request])) (define (handle-request request oport) (match request ['bad-request (display "HTTP/1.1 400 Bad Request\r\n\r\n" oport)] ['not-implemented (display "HTTP/1.1 501 Not Implemented\r\n\r\n" oport)] [(method abs-path post-data . headers) (receive (auth path q frag) (uri-decompose-hierarchical abs-path) (receive (status mime-type content) (render-content method path (cgi-parse-parameters :query-string (or post-data q "")) headers) (print #`" response : ,status ,mime-type size=,(string-size content)") (display #`"HTTP/1.1 ,status\r\n" oport) (display #`"Content-Type: ,mime-type\r\n" oport) (display #`"Content-Length: ,(string-size content)\r\n" oport) (display "\r\n" oport) (display content oport)))])) (define (render-content method path params headers) (cond ((string=? path "/") (render-by-file "/index.html")) ((#/\.\w+$/ path) (render-by-file path)) (else (print #`"-- application : ,method ,path ,params") (reload-modified-modules) (use web-appl) (values "200 OK" "text/html; charset=utf-8" (do-method method path params headers))))) (define (render-by-file path) (let ((ext (regexp-replace #/^.*\.(\w+)$/ path "\\1")) (file-path (regexp-replace #/^\/(.*)$/ path "\\1"))) (cond ((open-input-file file-path :if-does-not-exist #f) => (lambda(port) (print #`"-- static content: ,file-path") (values "200 OK" (hash-table-get *mini-mime-types* ext) (read-block (file-size file-path) port)))) (else (print #`"++ conten not found: ,file-path") (values "404 Not Found" "text/html" "<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1></body></html>"))))) (define (main args) (run-server) 0) (define *mini-mime-types* (make-hash-table 'string=?)) (hash-table-put! *mini-mime-types* "html" "text/html; charset=utf-8") (hash-table-put! *mini-mime-types* "htm" "text/html; charset=utf-8") (hash-table-put! *mini-mime-types* "css" "text/css") (hash-table-put! *mini-mime-types* "js" "text/javascript") (hash-table-put! *mini-mime-types* "gif" "image/gif") (hash-table-put! *mini-mime-types* "gif" "image/gif") (hash-table-put! *mini-mime-types* "gif" "image/gif") (hash-table-put! *mini-mime-types* "jpg" "image/jpeg") (hash-table-put! *mini-mime-types* "jpeg" "image/jpeg") (hash-table-put! *mini-mime-types* "png" "image/png")