khttpsvは、オブジェクト指向スクリプト言語Rubyによって実装された HTTPサーバ(Webサーバ)です。 現在のところCGIは実装されていますが、SSIやユーザ認証機能は未実装です。
差分プログラミング(*1)によって各種設定を行いますので、 種々の設定ファイルが不要になっています。 これは、サーバを作るほうにとっても 設定ファイルの解析が不要になるというすばらしい副作用があります^^;;
(*1) 機能を追加する際、従来からの変更部分だけプログラミングすれば 実装が可能になってしまうという手法
とはいえ、スクリプト言語の常として、実行速度はあまり速くはありません。 高いパフォーマンスが要求されない個人的な学習用・実験用・組み込み型 Webサーバとしてお使いいただければ幸いです。
RubyがインストールされているUNIX環境なら、たぶん動きます。
# いいかげんですいません ^^;;
なお、 Ruby1.4.6 / Linux 2.2.16(Debian GNU/Linux 2.1) で動作確認をしました。
配付は、 http://www.geocities.co.jp/Technopolis/6855/khttpsv.tar.gz にて行っています。GPL2に従ってなんなりと。
# なんなりとナニするんだ…
さきにも述べたとおり、設定ファイルは実行スクリプトでもあります。 まずは、以下の内容を持ったsample_template.rbというファイルを 適当な名前にコピーしてください。拡張子は.rbにしてください。
require 'khttpsv_simple.rb' class Sample_server < Khttpsv_simple end Sample_server.start(8080)
もし8080番以外のポートで動かしたい場合は、 Sample_server.start(8080)の数値を変更してください。 また、コンテンツは/usr/local/www/htdocs/、 または~user/.public_html/以下に置いてください。
これらの準備がすんだら、あとは
% ruby ファイル名.rbで実行するだけです。 ファイルに実行属性を付け、先頭行に#!/usr/local/bin/rubyなどの行を 付けても良いでしょう。
このように、基本的にはsample_template.rbをコピーして "class 〜"から"end"までの間を書きたしていくことによって設定を行います。
Ruby(やその他のオブジェクト指向言語)をご存知の方なら、 これが「クラスの継承」によってなされていることにお気づきかと思います。 ですから、設定はRubyの文法が許す限りどんな処理でも書くことができます(*2)。
(*2) Rubyの詳細な文法はhttp://www.ruby-lang.org/から得ることができます。
例 def initialize(s) super @server_name = 'MyPrivateServer/2.2.16' (以下略) end
デフォルトでは、アクセスを受け付けたIPアドレスを返すように定義されています。 バーチャルホスティングを実施する場合は、 このメソッドを必ず再定義する必要があります。
例: バーチャルホスティングなしの設定 def get_server_addr return 'www.tomoeda-es.ac.jp' end
例: 名前ベースのバーチャルホスティング def get_server_addr # name-based virtual hosting if @req_headers['Host'] then if @req_headers['Host'][0] =~ /^www.domain1.co.jp:/i then return 'www.domain1.co.jp' elsif @req_headers['Host'][0] =~ /^www.domain2.co.jp:/i then return 'www.domain2.co.jp' end end return 'www.default.co.jp' endホスト名ベースのバーチャルドメインを作る場合、 ネットワークインターフェースに複数のIPアドレスを割り当てる必要はありません。 ただし、古いHTTPクライアントを使っている場合は これらのバーチャルドメインを区別して扱うことができません。
例: アドレスベースのバーチャルホスティング def get_server_addr # IP-based virtual hosting if @sock.addr[3] == '192.168.2.1' then return 'www.domain1.co.jp' elsif @sock.addr[3] == '192.168.2.2' then return 'www.domain2.co.jp' else return 'www.default.co.jp' end endコンピュータが複数のIPを持っている場合、 アドレスベースのバーチャルホスティングを実施することができます。 この場合、複数のネットワークインターフェース(NIC)を持つか、 ひとつのNICに複数のIPアドレスを割り当てることになります。
例 def initialize(s) super # like an NCSA httpd @index_file = 'welcome.html' # http://server/~foo/bar/baz.html seeks for ~foo/.www/bar/baz.html @user_document_dir = '.www' ... end
例: バーチャルドメインを使わない場合 def document_root return '/var/www' end常に/var/wwwディレクトリをドキュメントルートとします。
例: バーチャルホスティングを使う場合 def document_root case @server_addr when 'www.domain1.co.jp' return '/var/www/dir1' when 'www.domain2.co.jp' return '/var/www/dir2' else return '/var/www' end endこの例の場合、 クライアントが"www.domain1.co.jp"にアクセスしていると思っているなら/var/www/dir1を、 クライアントが"www.domain2.co.jp"にアクセスしていると思っているなら/var/www/dir2を それぞれドキュメントルートとします。
例 def hook_translate_path(s) if s.sub!(%r{^/cgi-bin/}, '/usr/lib/cgi-bin/') then # translate uri into path, for exapmle # http://server/cgi-bin/foo/bar.cgi -> /usr/lib/cgi-bin/foo/bar.cgi return s end if s.sub!(%r{^/icons/}, '/usr/X11/lib/X11/pixmap/') then return s end return super endこの例では、 http://server/cgi-bin/...というURLが要求されると/usr/lib/cgi-bin/...というパスに、 http://server/icons/...というURLが要求されると/usr/X11/lib/X11/pixmap/...というパスに、 それぞれ置き換えます。
なお、Rubyではメソッド名に'?'を含めることができます。
例 def allow?(a) return true if a == 'cgi_exec' return super endこの例では、CGIの実行('cgi_exec')を明示的に許可し、 その他はデフォルトの動作に従うようになっています。
例 def cgi? if @translated_path[-4,4] == '.asp' && FileTest.executable?(@translated_path) then return true elsif @translated_path[-4,4] == '.cgi' && FileTest.executable?(@translated_path) then return true end return false endaspまたはcgiという拡張子をもつ実行ファイルをCGIであるとしています。 ちなみに、Rubyでは文字列クラスに[-4,4]という演算子を適用すると、 「うしろから数えて4バイト目から4バイトを取り出した文字列」という意味になります。
MIME_mapはmime_type.rbというファイルで定義されているので、 メソッドを再定義しなくてもこちらを変更すればよい場合があります。
例 def get_mime_type if @translated_path[-4,4].downcase == '.doc' return 'text/plain' else return super end endこの例では、拡張子がdocの場合(MS-Wordではなく)plain textであるとし、 それ以外の場合はデフォルトの動作を引き継ぎます。
デフォルトでは、LOG_INFOより重要なメッセージを、 スレッドIDと一緒に標準出力に表示します (たぶん、再定義したいでしょう)。
例 def Khttpsv_template.logger(s, lev = LOG_INFO) pri = nil case lev when LOG_NOTICE pri = 'local0.notice' when LOG_WARN pri = 'local0.warning' when LOG_ERR pri = 'local0.error' end if pri then system('logger', '-t', 'khttpsv', '-p', pri, "#{Thread.current.id}: #{s}") end STDERR.print "#{Thread.current.id}: #{s}\n" endこの例では、LOG_INFOより重要なメッセージをsyslogに出力します。 また、すべてのメッセージを標準エラーに出力します。