[Zope] Example: How I handle Virtual Hosts and mixed static/dynamic serving

Evan Simpson evan@tokenexchange.com
Wed, 23 Jun 1999 14:16:49 -0500


I am serving a set of websites with different domain names from a single
server, using Apache (1.3.2)'s Virtual Hosts feature.  For reasons too
irrelevent to go into here, I serve some URLs (mostly images and other
binary files) statically through Apache, and the rest from Zope.  All
dynamic content is served from a single Zope server, from root folders each
of whose ID is the 'site name'.  Most static and dynamic pages must be able
to refer to each other with relative paths, so I can't always distinguish
them by hostname, port, or URL prefix (the usual /Zope/ hack).

All pages, including those from Zope, must be reachable with URLs which end
in '.html', since the pages are being edited (and the links maintained) in
Dreamweaver, which uses Windows file extension associations <choke>.  On the
other hand, I don't want to have to go around making Zope objects with IDs
ending in ".html'

I came up with the following framework:

1.  I can force a static URL by prefixing it with the 'site name'.
2.  No Zope object has a period in its ID, so any URL with a period is
static and any without is dynamic (but see #3).  The default homepage (a
bare "/") is also static.
3.  In Dreamweaver, all dynamic pages end in '.py.html', but they're stored
in Zope with no extension.  Apache strips all occurrences of '.py.html', and
hands the stripped URL back to the client.
4.  A dynamic URL is automatically prefixed with the 'site name', unless it
already starts with '/Zope/' (for root access).

For the site named "4am", I have:

#1 and stop
RewriteRule ^/(4am/.*) /home/httpd/html/$1 [L]
#3, repeat and show to browser
RewriteRule ^/(.*)\.py\.html(.*)$ $1$2 [R,N]
#2 and stop
RewriteRule !^/([^.]+)$ - [L]
#4
RewriteRule ^/Zope/(.*) /$1 [S=1]
RewriteRule ^/(.*) /4am/$1
RewriteCond %{HTTP:Authorization}  ^(.*)
# All on one line:
RewriteRule ^/(.*) /home/httpd/cgi-bin/Zope.cgi/$1
[E=HTTP_CGI_AUTHORIZATION:%1,E=ZOPE_RAW_URI:SCRIPT_URI,T=application/x-httpd
-cgi,L]

Now, one problem remains; Zope uses the path constructed by object traversal
to construct BASEn and URLn variables and to auto-insert BASE links.  This
means that my framework causes "http://4-am.com/parrot/is/dead" to have an
incorrect <!--#var URL--> of "http://4am.com/4am/parrot/is/dead".  Following
multiple links could lead someone to something like
"http://4am.com/4am/4am/4am/4am/4am/parrot/is/dead".  I had to patch
ZPublisher to use SCRIPT_URI (indirectly, through ZOPE_RAW_URI) as follows:

In ZPublisher/Publisher.py, around line 360, find line "URL=request.script".
Directly after this line, insert:

        rawURI=request.environ.get('ZOPE_RAW_URI')
        if rawURI:
            def cvtpart(part, envget = request.environ.get):
                return envget(part, part)
            rawURI=join(map(cvtpart, split(rawURI)), '')

then change "setBase(URL)" to "setBase(rawURI or URL)" around lines 380 and
460.  Finally, directly before "request['URL']=URL" (around line 570-580),
insert:

         URL=rawURI or URL

This all *seems* to work just fine, although I may have missed a corner case
or two (do I need to worry about  __bobo_traverse__, for example?).  In case
the above is too abstract, here's some examples:

http://4am.com/  == static homepage
http://4am.com/images/squishfoot.png == static image
http://4am.com/4am/images/squishfoot.png == same static image
http://4am.com/Zope/manage == Manage all of Zope
http://4am.com/manage == Manage "4am" folder in Zope
http://4am.com/manage.py.html == same
http://4am.com/Zope/4am/manage == same