eigenclass logo
MAIN  Index  Search  Changes  PageRank  Login

URL rewriting with WEBrick

WEBrick isn't as fashionable as it once was, but it's still invaluable for development and testing. I recently needed it to handle rewrite rules, and google didn't return anything better than Simon Strandgaard's code.

On that same thread, GOTOU Yuuzou indicated that he wanted to add proper URL rewriting support to HEAD (1.9). It's been two years, but grep -r rewrite webrick says it hasn't happened yet.

Simon's code choked on query arguments, so I extended it as follows:

class WEBrick::HTTPServer
  alias :__rewrite_old_initialize :initialize
  alias :__rewrite_old_service :service
  def initialize(config={}, default=WEBrick::Config::HTTP)
    __rewrite_old_initialize(config, default)
    @rewrite_rules = []
  end
  def rewrite(pattern, subst)
    @logger.info("rewrite rule %s -> %s." % 
                  [pattern.inspect, subst])
    @rewrite_rules << [pattern, subst]
  end
  def service(req, res)
    olduri = URI.parse(req.path)
    olduri.query = req.query_string
    old = olduri.to_s
    @rewrite_rules.each do |pattern, subst|
      if pattern =~ old
        uri = URI.parse(old.gsub(pattern, subst))
        req.instance_variable_set("@path", uri.path)
        req.instance_variable_set("@query_string", uri.query)
        req.instance_variable_set("@query", nil)  # so it gets reparsed
        @logger.info("Rewrote URL %s -> %s" % [olduri.to_s, uri.to_s])
        break
      end
    end
    __rewrite_old_service(req, res)
  end
end

Yes, it doesn't use define_method to redefine the instance methods while keeping the old definitions*1, but it doesn't matter since the above code is sitting in a 50LoC file and there's no danger of it being loaded twice.

Usage

Here's how I'm using it to test my hiki setup locally and rewrite all /hiki/whatever.html requests to /hiki.rb?whatever:

module WEBrick::HTTPServlet
  FileHandler.add_handler("rb", CGIHandle)
end

s = HTTPServer.new(
  :Port            => port,
  :DocumentRoot    => dir
)

s.mount("/", HTTPServlet::FileHandler, File.join(ENV["HOME"], "public_html"),
        :FancyIndexing => true)
s.rewrite(%r{^/hiki/hiki\.rb$}, '/hiki.rb')
s.rewrite(%r{^/hiki/theme/}, '/theme/')
s.rewrite(%r{^/hiki/hiki.rb\?(.*)}, '/hiki.rb?\1')
s.rewrite(%r{^/hiki/(.*)\.html}, '/hiki.rb?\1')
s.rewrite(%r{^/hiki(/?)$}, '/hiki.rb')

trap("INT"){ s.shutdown }
s.start



Firefox rendering weirdness - hgs (2007-01-16 (Tue) 08:26:24)

When I mouseover the code, the black boxes expand, which should allow me to see the whole line. However, it appears under the menu at the right. Any idea how to make it appear over the "menu" (or list) at the right? With a large font there is code I can't read. Thank you.

mfp 2007-01-16 (Tue) 09:22:58

Typo in the z-index property, should look OK now (works for me with Firefox).

Thanks.

hgs 2007-01-17 (Wed) 03:12:14

That's working for me now. Thank you.


Last modified:2007/01/16 04:05:54
Keyword(s):[blog] [ruby] [frontpage] [webrick] [url] [rewrite] [subpar]
References:

*1 Simon also used alias instead of alias_method, which I much prefer