[Twisted-web] VHostMonsterResource for url-context instead of
subdomain
Steven Armstrong
sa at c-area.ch
Wed Jan 19 04:57:56 MST 2005
Hello twisted hackers
I've been playing arround with nevow and twisted for a while now.
While looking for a way to use twisted with apache I came across the
following problem and hacked together a possible solution.
In the twisted docs
(http://twisted.sourceforge.net/TwistedDocs-1.3.0/howto/using-twistedweb.html#auto21)
it sais to use VHostMonsterResource and proxy the documentroot to
twisted. In my setup I can't do this. What I need is a way to proxy only
a specific url-context to twisted while the rest of the domain remains
under apache's control.
This is what I came up with. It seems to work well, the nevow examples
are all working with this setup. All except those that don't work in
native twisted/nevow eather that is.
Code is attached as vhostlocation.txt to prevent linebreaks from beeing
hosed.
Do you guys see any problems with this approach?
Are there any implications through changing request.uri and
request.prepath that I didn't think/know of?
cheers
Steven
-------------- next part --------------
from twisted.python import log
from nevow import vhost
import re
_debug = False
_vhost_location_delim = "@"
_vhost_re = re.compile('(.*)(/'+ _vhost_location_delim +'.*'+ _vhost_location_delim +'/)(.*)')
class VHostLocation(vhost.VHostMonsterResource):
"""
Represents a single url-context of a Apache VirtualHost.
Using this you do not need to proxy an entire virtual host to twisted.
Instead you can proxy a specific location like:
<VirtualHost *>
...
ServerName www.example.com
RewriteRule ^/nevow-app$ /nevow-app/ [R=301,L]
ProxyPass /nevow-app/ http://localhost:8080/vhost/http/www.example.com:80/@nevow-app@/
# this also works
#ProxyPass /nevow/app/ http://localhost:8080/vhost/http/www.example.com:80/@nevow/app@/
...
</VirtualHost>
In this example only the http://www.example.com/nevow-app location is handled by twisted.
The rest of the VirtualHost remains under Apache's control.
The location used by Apache is passed to twisted through the trailing @location-name at .
This is then used to fix request.uri and the request.postpath list to hold the segments
needed to create a valid absolute url.
So the ProxyPass directive in the above example is seen/used as:
Apache internal:
/nevow-app/somepage
Twisted internal:
/somepage
Twisted absolute:
http://www.example.com/nevow-app/somepage
"""
def _fix_segments(self, segments):
"""
Removes the vhost_location from the given segments if necessary.
Returns the modified segments and the vhost_location.
vhost_location would be "nevow-app" in the example mentioned above.
segments before: ('http', 'www.example.com:80', '@nevow-app@', 'somepage')
segments after: ('http', 'www.example.com:80', 'somepage')
"""
segments_string = "/".join(segments)
vhost_location = _vhost_re.sub(r'\2',segments_string)
# remove leading and trailing slash and delimiter
vhost_location = vhost_location[(len(_vhost_location_delim)+1):-(len(_vhost_location_delim)+1)]
new_segments = tuple(_vhost_re.sub(r'\1/\3',segments_string).split("/"))
return new_segments, vhost_location
def _fix_path(self, request, vhost_location):
"""
Fixes the requests uri.
Fixes the requests postpath list.
Given the above example:
request.uri before: /@nevow-app@/somepage
request.uri after: /somepage
request.postpath before: ['http', 'www.example.com:80', '@nevow-app@', 'somepage']
request.postpath after: ['http', 'www.example.com:80', 'nevow-app', 'somepage']
"""
request.uri = request.uri.replace("/"+ _vhost_location_delim + vhost_location + _vhost_location_delim, "")
#request.path = "/"+ vhost_location + request.path
postpath = "/".join(request.postpath)
postpath = postpath.replace(_vhost_location_delim + vhost_location + _vhost_location_delim, vhost_location)
request.postpath = postpath.split("/")
def locateChild(self, ctx, segments):
"""
First fixes the given segments. see _fix_segments
Then passes the method call to the superclass.
Then fixes the request.postpath. see _fix_path
returns what the superclass returned without changing it.
"""
request = inevow.IRequest(ctx)
if _debug:
log.msg("request.uri: %s" % request.uri)
log.msg("request.path: %s" % request.path)
log.msg("request.prepath: %s" % request.prepath)
log.msg("request.postpath: %s" % request.postpath)
log.msg("segments: %s" % str(segments))
segments, vhost_location = self._fix_segments(segments)
if _debug:
log.msg("segments after: %s" % str(segments))
log.msg("vhost_location: %s" % vhost_location)
res, segs = vhost.VHostMonsterResource.locateChild(self, ctx, segments)
if _debug:
log.msg("segs: %s" % str(segs))
if vhost_location:
self._fix_path(request, vhost_location)
if _debug:
log.msg("request.uri after: %s" % request.uri)
log.msg("request.postpath after: %s" % request.postpath)
return res, segs
application = service.Application("examples-vhost")
page = Examples()
#vResource = vhost.VHostMonsterResource()
vResource = VHostLocation()
page.putChild('vhost', vResource)
More information about the Twisted-web
mailing list