# gonzui wrapper for Rack unless defined?(GONZUIRC) GONZUIRC = File.expand_path('~/.gonzuirc') end require 'gonzui' require 'gonzui/webapp' class GonzuiWEBrickServletApp class Request def initialize(rack_req) @req = rack_req end def self.map(sym, key) define_method(sym) do @req.env[key] end end def self.map_var(sym) map(sym, sym.to_s.upcase) end map_var :request_method map_var :path_info map :peeraddr, 'REMOTE_ADDR' def query @req.params end def accept_language WEBrick::HTTPUtils.parse_qvalues(@req.env['HTTP_ACCEPT_LANGUAGE']) end def gzip_encoding_supported? /\bgzip\b/.match(@req.env['HTTP_ACCEPT_ENCODING']) end end class Response def initialize(rack_resp, env) @resp = rack_resp @env = env end def body @resp.body end def body=(body) @resp.body = body end def [](key, value) @resp[key] end def []=(key, value) @resp[key] = value end def set_redirect(status, url) @resp.status = status.code self['Location'] = url.to_s self.body = "#{url.to_s}.\n" raise status end end def initialize(servlet, *options) @servlet = servlet @config = options.first @options = options @bmp_patt = %r,(?:(?!\A)/)?#{Regexp.quote(@servlet.mount_point)}\z, end def call(env) # gonzuiはgonzuircの:base_mount_pointの値を使って # リンクを常にフルパスで生成する。 # Rackではスクリプトを/とする仮想的なパスを扱うため # CGIやFastCGIでは一般にミスマッチが起きる # (gonzui.{,f}cgiが/にマップされている場合は除く)。 # このため、SCRIPT_NAMEと:base_mount_pointが # マッチしない場合に調整を行う。 # $stderr.puts [[[@config.base_mount_point,env['SCRIPT_NAME'],env['SCRIPT_NAME'].sub(@bmp_patt, '')]]].inspect if !env['SCRIPT_NAME'].empty? && (bmp = env['SCRIPT_NAME'].sub(@bmp_patt, '')) != @config.base_mount_point @config.base_mount_point = bmp end req = Rack::Request.new(env) wreq = Request.new(req) res = Rack::Response.new wres = Response.new(res, env) # WEBrickのHTTPサーバ機能は使わないため # サーブレットにはデフォルト設定を与えておく。 si = @servlet.get_instance(WEBrick::Config::HTTP, *@options) begin si.service(wreq, wres) rescue WEBrick::HTTPStatus::Redirect # noop rescue WEBrick::HTTPStatus::ClientError, WEBrick::HTTPStatus::ServerError res.status = $!.code res.body << $!.reason_phrase # rescue WEBrick::HTTPStatus::Status end res.finish end end class NullLogger def log(*arg) end end def build_gonzui_app config = Gonzui::Config.new config.load(GONZUIRC) if GONZUIRC yield(config) if block_given? catalog_repository = Gonzui::CatalogRepository.new(config.catalog_directory) dbm = Gonzui::DBM.open(config, true) null_logger = NullLogger.new Rack::Builder.new do # f = open(config.access_log_file + '.ru', 'a') # use Rack::CommonLogger, f use Rack::Recursive # URLMapを使う場合、これがないとCommonLogger上でパスが空になったりする。 # 本来はリクエストの内部回送をするときに使う。 Gonzui::GonzuiServlet.servlets.each do |klass| # Rackがリクエストパスの調整をしてくれる。 # たとえばMongrelなら/の下に、CGIならSCRIPT_NAMEの下に、 # WEBrickでいうところのmountが行われる。 # このためgonzuircの:base_mount_pointに/fooを指定したとすると # Mongrelなら/foo/statで統計情報に # CGIなら/path/to/gonzui.cgi/statで統計情報にアクセスできる。 abs_mount_point = URI.path_join(config.base_mount_point, klass.mount_point) map abs_mount_point do if klass == Gonzui::FileHandler run Rack::File.new(config.doc_directory) else run GonzuiWEBrickServletApp.new(klass, config, null_logger, dbm, catalog_repository) end end end end.to_app end