Virtual hosting with WEBrick?

R

Robert Feldt

Hi,

I'm checking out WEBrick and it looks great.

I wonder if there is some easy way to do "virtual
hosting" so that I can host several domains on the
same machine.

So what I want is to have separate MountTables
for different domain names.

My idea is to simply write a subclass of HTTPServer
that adds a virtual_mount method that mounts servlets
on given paths and UriRegexp's. For the servlet to be invoked the uri must
match the UriRegexp and then
search_servlet is used like now.

Does this sound like a good idea or is there a better/simpler/existing
solution?

Regards,
 
C

culley harrelson

I think you could run them on different ports then use apache for the
virtual domains and mod_proxy to get each virtual domain to the correct
port. Just guessing but I think this should work...

culley
 
R

Robert Feldt

culley harrelson said:
I think you could run them on different ports then use apache for the virtual domains and mod_proxy to get each virtual domain to the correct port. Just guessing but I think this should work...
Yeah, but if you wanna use pure-Ruby/webrick you can use my approach:

require 'webrick'
module WEBrick
# A VHostServer is a HTTPServer that holds several mount tables.
# Each mount table corresponds to a regexp. The mount table to use
# for a request is the first one whose regexp matches the uri in the
# request. This allows for easy "virtual hosting".
class VHostServer < HTTPServer
def initialize(*args)
super
@mount_tables = [] # holds [UriRE, MountTable] pairs
@default_mount_table = @mount_tab
end

def vhost_mount(uriRegexp, dir, servlet, *options)
@logger.debug(sprintf("%s is mounted on %s for %s.", servlet.inspect, dir, uriRegexp.inspect))
re, mt = @mount_tables.detect {|re, mt| re == uriRegexp}
unless mt
mt = MountTable.new
@mount_tables << [ uriRegexp, mt ]
end
mt[dir] = [ servlet, options ]
end

def service(req, res)
if req.unparsed_uri == "*"
if req.request_method == "OPTIONS"
do_OPTIONS(req, res)
raise HTTPStatus::OK
end
raise HTTPStatus::NotFound, "`#{req.unparsed_uri}' not found."
end

# Only change from HTTPServer#service:
url = req.request_uri.to_s
servlet, options, script_name, path_info = search_servlet(req.path, url)
# ------------------------------------
raise HTTPStatus::NotFound, "`#{req.path}' not found." unless servlet
req.script_name = script_name
req.path_info = path_info
si = servlet.get_instance(self, *options)
@logger.debug(format("%s is invoked.", si.class.name))
si.service(req, res)
end

def search_servlet(path, url)
mount_table = search_mount_table(url)
script_name, path_info = mount_table.scan(path)
servlet, options = mount_table[script_name]
if servlet
[ servlet, options, script_name, path_info ]
end
end

def search_mount_table(url)
re, mt = @mount_tables.detect {|re, mt| re.match(url) }
mt || @default_mount_table
end
end
end

I just thought it was already in there...

Regards,

Robert
 
G

GOTOU Yuuzou

Hi,

In message said:
My idea is to simply write a subclass of HTTPServer
that adds a virtual_mount method that mounts servlets
on given paths and UriRegexp's. For the servlet to be invoked the uri must
match the UriRegexp and then
search_servlet is used like now.

I found that HTTPServer is a container of enough parameters
for virtual hosting. (ie. port, bind address, hostname and
url namespace)
In my approach, the entire server is added to another server.

In current WEBrick, access logging couldn't be separated for
each server. Please let me think more.

require 'webrick'

module WEBrick
class VirtualHostServer < HTTPServer
def initialize(config)
super(config)
@virtual_hosts = []
end

def virtual_host(server)
@virtual_hosts << server
end

def service(req, res)
if server = lookup_server(req)
server.service(req, res)
else
super
end
end

def lookup_server(req)
# this condition is a quick hacked.
# it may be a security issue. should considered more...
@virtual_hosts.find{|server|
(server[:port].nil? || req.port == server[:port]) &&
(server[:BindAddress].nil? || req.addr[3] == server[:BindAddress]) &&
(server[:ServerName].nil? || req.host == server[:ServerName])
}
end
end
end

## build default server
svr = WEBrick::VirtualHostServer.new(
:port => 10080,
:BindAddress => "0.0.0.0"
)
svr.mount_proc("/"){|req, res|
res.body = "This is default server!"
res['content-type'] = "text/plain"
}

## build a virtual server for "localhost"
localhost = WEBrick::HTTPServer.new(
:DoNotListen => true, # don't forget!
:port => nil,
:BindAddress => nil,
:ServerName => "localhost"
)
localhost.mount_proc("/"){|req, res|
res.body = "This is localhost!"
res['content-type'] = "text/plain"
}

svr.virtual_host(localhost)
svr.start
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,125
Messages
2,570,748
Members
47,302
Latest member
MitziWragg

Latest Threads

Top