Programming Languages, Martials Arts and Computers. The Weblog of Chris Double.
Note that this article relates to Factor 0.91 and is out of date for newer Factor versions
The Factor webserver can do virtual hosting. There is a 'vhosts' variable that holds a hashtable mapping the names of the virtual hosts to a hashtable holding the variables that that host can access.
A 'default' virtual host entry exists for any web request with a host that does not have an explicit entry.
Responders can be shared between virtual hosts and be available only from a specific one.
The following is a simple example of adding a virtual host:
vhosts get [
"bluishcoder.co.nz" H{ } clone dup [ "/var/www/bluishcoder/" "doc-root" set ] bind swap set
"double.co.nz" H{ } clone dup [ "/var/www/double/" "doc-root" set ] bind swap set
] bind
This creates a virtual host that will be used when a web request arrives for 'bluishcoder.co.nz'. Note that it must match exactly. So if you want 'www.bluishcoder.co.nz' you need to add another entry for it.
This virtual host gets its own document root. So all requests for the root responder of 'bluishcoder.co.nz' will come from files in '/var/www/bluishcoder/'.
A second virtual host is also added for 'double.co.nz' and it will serve files from '/var/www/double/'.
All virtual hosts have access to the global 'responders' variable. This means that all virtual hosts will automatically provide access along the path of '/responder/foo' where 'foo' is a globally installed responder.
It is possible to have a host have its own private set of responders. There's a bit of a trick to this. You can just add a responder from within the namespace for that vhost. This won't work for example:
vhosts get [
"factor.bluishcoder.co.nz" H{ } clone dup [
"foo-resources" [
[
"/var/www/resources/" "doc-root" set
file-responder
] with-scope
] add-simple-responder
] bind swap set
] bind
This will actually create the 'foo-resources' responder in the global responder table and all virtual hosts provide access to it.
To prevent this you need to first shadow the global responder table from within the namespace and then add the new responder. You can copy the global table if you want to have access to all its responders, or create an empty one. This example creates a copy of the global responder table:
vhosts get [
"factor.bluishcoder.co.nz" H{ } clone dup [
responders get H{ } assoc-clone-like responders set
"foo-resources" [
[
"/var/www/resources/" "doc-root" set
file-responder
] with-scope
] add-simple-responder
] bind swap set
] bind
The relevant line is:
responders get H{ } assoc-clone-like responders set
This creates a copy of the existing responder table and will shadow the global responders table.
To make it easy to load sites when restarting the Factor instance I use the Factor module system. I create a 'sites' directory underneath the 'Factor/extras' directory. Underneath 'sites' I have subdirectories for the virtual hosts:
Factor/extras/sites/bluishcoder
/sites/double
Each of these 'sites' has the main file contain code like the following:
USING: kernel http.server http.server.responders namespaces assocs ;
vhosts get [
"bluishcoder.co.nz" H{ } clone dup [
"/home/chris/www/bluishcoder.co.nz/" "doc-root" set
] bind swap set
"www.bluishcoder.co.nz" H{ } clone dup [
"/home/chris/www/bluishcoder.co.nz/" "doc-root" set
] bind swap set
] bind
From the factor instance I can then load this like a normal module:
USE: sites.bluishcoder
If I edit it to add new responders, etc I can reload it:
refresh-all
! or: "sites/bluishcoder" reload-vocab