From: Masatoshi SEKI Date: 1998-12-10T01:24:39+09:00 Subject: [ruby-list:11253] shttpsrv-1.0.4 + servlet ----Next_Part(Thu_Dec_10_01:20:03_1998_893)-- Content-Type: Text/Plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit postgreSQLのデータをWebで公開しようといろいろ作ってるうちに おもしろいのができました。 原さんの公開された shttpsrv を改造して、rubyのモジュールを サーバに動的にロードできるようにしました。 設定ファイルで指定したURLを要求すると、htmlファイルを転送する 代わりに、rubyのモジュールが動的に生成したページを転送します。 また、SSIの中で使うこともできます。 最初のリクエストでは、ロードする時間が必要ですが、 二度目以降は、CGIよりもずっとレスポンスが早いです。 また、httpのリクエストを越えて長生きする(?)オブジェクトを 使いたい時にも便利です。 conf.rbに ServletAlias = [ # [仮想パス, requireする名前, モジュール名], ['/rb/', 'testserv.rb', 'TestServ'], #1 ['counter', 'counter.rb', 'Counter'] #2 ] の様に指定します。 #1 では http://localhost:8088/rb/arg1/arg2/ という要求があると require 'testserv.rb' TestServ.service('arg1/arg2') という文が評価されます。 #2 では foo.shtml 中に という文があると requrie 'counter.rb' Counter.service_ssi('args', 'foo.shtml') が評価されます。 service(arg)ではヘッダを含んだ一ページを生成することを期待し、 service_ssi(arg, filename)ではHTMLの一部を生成することを期待しています。 -- 咳 ----Next_Part(Thu_Dec_10_01:20:03_1998_893)-- Content-Type: Text/Plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=testserv.rb #!/usr/local/bin/ruby require 'thread' module TestServ @origin = Time.now @count = 0 @mutex = Mutex.new =begin 次のメソッドはServletDir の次のエントリに対応する。 ['/rb/testserv/', 'testserv.rb', 'TestServ'] URL "http://localhost:8088/rb/testserv/foo/bar" が要求されると、 TestServ.service('foo/bar') という式が評価される。 serviceメソッドは http 一ページを返す。 =end def service(param) args = param.split('/') getpage(args) end module_function :service def service_ssi(param, fname = nil) countUp s = "このサービスに#{@count}回目のアクセスです。引数は#{param}です。" if fname s += "--- このページは#{File.ctime(fname).to_s}に更新されました" end s end module_function :service_ssi def countUp @mutex.synchronize do @count += 1 end end module_function :countUp private :countUp def getpage(args) countUp s = < testserv.rb

testserv.rb

"#{@origin.to_s}から#{@count}回目のアクセスです"

\n" s end module_function :getpage private :getpage end module Counter @counter = {} @m = Mutex.new def countUp(name) @m.synchronize do @counter[name] = @counter.fetch(name, 1) + 1 end @counter[name] end module_function :countUp private :countUp =begin 次のメソッドはServletDir の次のエントリに対応する。 ['counter', 'testserv.rb', 'Counter'] foo.shtmlファイル中の と 置換される。 Counter.service_ssi('foo', 'htdocs/foo.shtml') という式が評価される。 service_ssiメソッドは http の一部を返す =end def service_ssi(param, fname = nil) param = '' unless param countUp(param).to_s end module_function :service_ssi end module Modified def service_ssi(param, fname = nil) return '' unless fname if param.nil? or param == '' t = File.ctime(fname) else dir = File.dirname(fname) t = File.ctime(dir + "/" + param) end t.strftime("%y %m %d") end module_function :service_ssi end if __FILE__ == $0 begin print TestServ.service('arg1/arg2/arg3') print TestServ.service_ssi('arg1/arg2/arg3') end end ----Next_Part(Thu_Dec_10_01:20:03_1998_893)-- Content-Type: Text/Plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=ssi-test.shtml SSI TEST

SSI TEST

<!--#exec cmd="ruby -e 'print Time.now'"-->

<!--#ruby service="counter A"-->

<!--#ruby service="counter B"-->

<!--#ruby service="modified index.html"-->
home … 更新 ----Next_Part(Thu_Dec_10_01:20:03_1998_893)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=servlet.patch Only in shttpsrv-p: CVS diff -c shttpsrv-1.0.4/conf.rb shttpsrv-p/conf.rb *** shttpsrv-1.0.4/conf.rb Tue Sep 29 13:58:28 1998 --- shttpsrv-p/conf.rb Thu Dec 10 01:07:59 1998 *************** *** 28,33 **** --- 28,45 ---- ["/img/", ServerRoot+"/img/"] ] + # servlet alias + # format : [virtual, require, module] + ServletAlias = [ + ['/rb/testserv/', 'testserv.rb', 'TestServ'], + # requrie 'testserv.rb' + # TestServ.service(param) + # TestServ.service_ssi(param, file) + ['counter', 'testserv.rb', 'Counter'], # SSI + ['modified', 'testserv.rb', 'Modified'], # SSI + ['/tinyyahoo/', 'tinyyahoo.rb', 'TinyYahoo'] + ] + # directory aliases for executable scripts ScriptAlias = [ ["/cgi-bin/", ServerRoot+"/cgi-bin/"], *************** *** 88,94 **** #LogFile = "shttpsrv.log" # set it FALSE, if the machine stands alone (recieve no DNS service) ! #Offline = TRUE # HTTP PROXY # To activate proxy function --- 100,106 ---- #LogFile = "shttpsrv.log" # set it FALSE, if the machine stands alone (recieve no DNS service) ! Offline = TRUE # HTTP PROXY # To activate proxy function Common subdirectories: shttpsrv-1.0.4/omake and shttpsrv-p/omake Common subdirectories: shttpsrv-1.0.4/sample and shttpsrv-p/sample diff -c shttpsrv-1.0.4/shttpsrv.rb shttpsrv-p/shttpsrv.rb *** shttpsrv-1.0.4/shttpsrv.rb Tue Sep 29 13:52:25 1998 --- shttpsrv-p/shttpsrv.rb Thu Dec 10 01:08:00 1998 *************** *** 223,228 **** --- 223,239 ---- nil end + def set_servlet + for servlet_dir in ServletAlias + if @target =~ /^#{servlet_dir[0]}(.*)/ + if servlet_dir.size == 3 + return [servlet_dir, $1] + end + end + end + nil + end + def ssi?(fname) return nil unless defined? SSIhtml SSIhtml.each do |ext| *************** *** 601,606 **** --- 612,678 ---- [heads, body] end + def do_servlet(t) + servlet_dir, param = t + req = "require '#{servlet_dir[1]}'" + servlet = servlet_dir[2] + script = "#{servlet}.service(param)" + heads, data = [], '' + begin + $m.synchronize do + eval(req) + end + data = eval(script) + cgimsg = Rfc822h.new(data) + location = cgimsg['Location'] + heads1, body = cgimsg.header, cgimsg.body + if location + if location =~ /http:\/\// + heads << "HTTP/1.0 302 Found" + else + throw(:aloc, location) + end + else + heads << "HTTP/1.0 200 Script output follows" + end + heads << "Content-length: #{body.length}" + heads << ("Date: " + strdate()) + rescue + print "Error(Servlet): #$!\n" + print $@.join("\n"), "\n" if $debug + heads1, body = [], "

Server Erorr (^^;

#$!\n" + heads << "HTTP/1.0 500 Server Error" + end + heads << Version + heads.concat heads1 + [heads, body] + end + + def do_servlet_ssi(str, fname) + if str =~ /^(\S+)\s*(.*)$/ + serv_name = $1 + param = $2 + p(serv_name) + p(param) + servlet_dir = ServletAlias.assoc(serv_name) + return '' unless servlet_dir + else + return '' + end + req = "require '#{servlet_dir[1]}'" + servlet = servlet_dir[2] + script = "#{servlet}.service_ssi(param, fname)" + begin + eval(req) + data = eval(script) + rescue + print "Error(Servlet): #$!\n" + print $@.join("\n"), "\n" if $debug + data = '' + end + data + end + def dir_head(dir) headfile = dir.sub(/\/?$/, "/" + HeaderName) if File.file?(headfile) *************** *** 700,705 **** --- 772,780 ---- ensure f.close end + when "ruby" + raise "unknown parameter" unless opt == "service" + result = do_servlet_ssi(script, fname) when "include" if opt == "file" begin *************** *** 887,892 **** --- 962,969 ---- client.authenticate(auth) elsif cgi = client.set_cgi client.do_cgi(cgi) + elsif servlet = client.set_servlet + client.do_servlet(servlet) else client.get_image(target) end Only in shttpsrv-p: testserv.rb ----Next_Part(Thu_Dec_10_01:20:03_1998_893)----