[Zope-Checkins] CVS: Products/SiteAccess - VirtualHostMonster.py:1.5

Evan Simpson evan@zope.com
Tue, 4 Dec 2001 15:43:31 -0500


Update of /cvs-repository/Products/SiteAccess
In directory cvs.zope.org:/tmp/cvs-serv3715

Modified Files:
	VirtualHostMonster.py 
Log Message:
Removed unneeded _setId, which broke renaming.

=== Products/SiteAccess/VirtualHostMonster.py 1.4 => 1.5 ===
 from Globals import DTMLFile, MessageDialog, Persistent
 from OFS.SimpleItem import Item
-from Acquisition import Implicit, ImplicitAcquisitionWrapper
-from ExtensionClass import Base
-from string import split, strip, join
+from Acquisition import Implicit, aq_inner, aq_parent
+from string import split, strip, join, find, lower, replace
 from ZPublisher import BeforeTraverse
 import os
 
@@ -21,12 +20,79 @@
     priority = 25
 
     title = ''
+    lines = ()
+    have_map = 0
 
-    __ac_permissions__=(('View', ('manage_main',)),)
+    __ac_permissions__=(('View', ('manage_main',)),('Add Site Roots', ('manage_edit', 'set_map')))
 
-    manage_options=({'label':'View', 'action':'manage_main'},)
+    manage_options=({'label':'About', 'action':'manage_main'},
+                    {'label':'Mappings', 'action':'manage_edit'})
 
-    manage_main = DTMLFile('www/VirtualHostMonster', globals())
+    manage_main = DTMLFile('www/VirtualHostMonster', globals(),
+                           __name__='manage_main')
+    manage_edit = DTMLFile('www/manage_edit', globals())
+
+    def set_map(self, map_text, RESPONSE=None):
+        "Set domain to path mappings."
+	lines = split(map_text, '\n')
+        self.fixed_map = fixed_map = {}
+        self.sub_map = sub_map = {}
+        new_lines = []
+        for line in lines:
+            line = strip(split(line, '#!')[0])
+            if not line:
+                continue
+            try:
+                # Drop the protocol, if any
+                line = split(line, '://')[-1]
+                try:
+                    host, path = map(strip, split(line, '/', 1))
+                except:
+                    raise 'LineError', 'Needs a slash between host and path'
+	        pp = filter(None, split(path, '/'))
+                if not pp:
+                    raise 'LineError', 'Empty path'
+
+                obpath = pp[:]
+                if obpath[0] == 'VirtualHostBase':
+                    obpath = obpath[3:]
+                if 'VirtualHostRoot' in obpath:
+                    i1 = obpath.index('VirtualHostRoot')
+                    i2 = i1 + 1
+                    while i2 < len(obpath) and obpath[i2][:4] == '_vh_':
+                        i2 = i2 + 1
+                    del obpath[i1:i2]
+                try:
+                    ob = self.unrestrictedTraverse(obpath)
+                except:
+                    raise 'LineError', 'Path not found'
+                if not getattr(ob.aq_base, 'isAnObjectManager', 0):
+                    raise 'LineError', 'Path must lead to an Object Manager'
+
+                try:
+                    int(replace(host,'.',''))
+                    raise 'LineError',  'IP addresses are not mappable'
+                except ValueError:
+                    pass
+                if 'VirtualHostRoot' not in pp:
+                    pp.append('/')
+                pp.reverse()
+                if host[:2] == '*.':
+                    host_map = sub_map
+                    host = host[2:]
+                else:
+                    host_map = fixed_map
+                if not host_map.has_key(host):
+                    host_map[host] = {}
+                hostname, port = (split(host, ':', 1) + [None])[:2]
+                host_map[hostname][port] = pp
+            except 'LineError', msg:
+                line = '%s #! %s' % (line, msg)
+            new_lines.append(line)
+        self.lines = tuple(new_lines)
+        self.have_map = not not (fixed_map or sub_map) # booleanize
+        if RESPONSE is not None:
+            RESPONSE.redirect('manage_edit?manage_tabs_message=Changes%20Saved.')
 
     def addToContainer(self, container):
         container._setObject(self.id, self)
@@ -54,48 +120,83 @@
             BeforeTraverse.registerBeforeTraverse(container, hook,
                                                   self.meta_type,
                                                   self.priority)
-    def _setId(self, id):
-        id = str(id)
-        if id != self.id:
-            BeforeTraverse.unregisterBeforeTraverse(container,
-            self.meta_type)
-            hook = BeforeTraverse.NameCaller(id)
-            BeforeTraverse.registerBeforeTraverse(container, hook,
-                                                  self.meta_type,
-                                                  self.priority)
 
     def __call__(self, client, request, response=None):
         '''Traversing at home'''
+        vh_used = 0
         stack = request['TraversalRequestNameStack']
-        if stack and stack[-1] == 'VirtualHostBase':
-            stack.pop()
-            protocol = stack.pop()
-            host = stack.pop()
-            if ':' in host:
-                host, port = split(host, ':')
-                request.setServerURL(protocol, host, port)
-            else:
-                request.setServerURL(protocol, host)
-        # Find and convert VirtualHostRoot directive
-        # If it is followed by one or more path elements that each
-        # start with '_vh_', use them to construct the path to the
-        # virtual root.
-        vh = -1
-        for ii in range(len(stack)):
-            if stack[ii] == 'VirtualHostRoot':
-                if vh >= 0:
-                    pp = ['']
-                    for jj in range(vh, ii):
-                        pp.insert(1, stack[jj][4:])
-                    stack[vh:ii + 1] = [join(pp, '/'), self.id]
-                elif ii > 0 and stack[ii - 1][:1] == '/':
-                    stack[ii] = self.id
+        while 1:
+            if stack and stack[-1] == 'VirtualHostBase':
+                vh_used = 1
+                stack.pop()
+                protocol = stack.pop()
+                host = stack.pop()
+                if ':' in host:
+                    host, port = split(host, ':')
+                    request.setServerURL(protocol, host, port)
                 else:
-                    stack[ii] = self.id
-                    stack.insert(ii, '/')
-                break
-            elif vh < 0 and stack[ii][:4] == '_vh_':
-                vh = ii
+                    request.setServerURL(protocol, host)
+
+            # Find and convert VirtualHostRoot directive
+            # If it is followed by one or more path elements that each
+            # start with '_vh_', use them to construct the path to the
+            # virtual root.
+            vh = -1
+            for ii in range(len(stack)):
+                if stack[ii] == 'VirtualHostRoot':
+                    vh_used = 1
+                    pp = ['']
+                    at_end = (ii == len(stack) - 1)
+                    if vh >= 0:
+                        for jj in range(vh, ii):
+                            pp.insert(1, stack[jj][4:])
+                        stack[vh:ii + 1] = [join(pp, '/'), self.id]
+                    elif ii > 0 and stack[ii - 1][:1] == '/':
+                        pp = split(stack[ii - 1], '/')
+                        stack[ii] = self.id
+                    else:
+                        stack[ii] = self.id
+                        stack.insert(ii, '/')
+                    # If the directive is on top of the stack, go ahead
+                    # and process it right away.
+                    if at_end:
+                        if pp == [''] or pp == ['', '']:
+                            pp = []
+                        request.setVirtualRoot(pp)
+                        del stack[-2:]
+                    break
+                elif vh < 0 and stack[ii][:4] == '_vh_':
+                    vh = ii
+
+            if vh_used or not self.have_map:
+                return
+            vh_used = 1 # Only retry once.
+            # Try to apply the host map if one exists, and if no
+            # VirtualHost directives were found.
+            host = lower(split(request['SERVER_URL'], '://')[1])
+            hostname, port = (split(host, ':', 1) + [None])[:2]
+            ports = self.fixed_map.get(hostname, 0)
+            if not ports and self.sub_map:
+                get = self.sub_map.get
+                while hostname:
+                    ports = get(hostname, 0)
+                    if ports:
+                        break
+                    if '.' not in hostname:
+                        return
+                    hostname = split(hostname, '.', 1)[1]
+            if ports:
+                pp = ports.get(port, 0)
+                if not pp and port is not None:
+                    # Try default port
+                    pp = ports.get(None, 0)
+                if not pp:
+                    return
+                # If there was no explicit VirtualHostRoot, add one at the end
+                if pp[0] == '/':
+                    pp = pp[:]
+                    pp.insert(1, self.id)
+                stack.extend(pp)
 
     def __bobo_traverse__(self, request, name):
         '''Traversing away'''