[Zope-Checkins] CVS: Zope/lib/python/Products/Sessions - BrowserIdManager.py:1.15 SessionDataManager.py:1.22 SessionInterfaces.py:1.12

Chris McDonough chrism@zope.com
Mon, 19 Aug 2002 15:50:47 -0400


Update of /cvs-repository/Zope/lib/python/Products/Sessions
In directory cvs.zope.org:/tmp/cvs-serv24326

Modified Files:
	BrowserIdManager.py SessionDataManager.py SessionInterfaces.py 
Log Message:
Added the capability for browser ids to be encoded in URLs.

When a set of knobs is set on the browser_id_manager "settings" screen,
("look for browser id name in..." and 'automatically encode browser ids..."),
a traversal hook is installed in the browser id manager's container which
causes a) the request to be searched for a browser id name and a browser
id as the first two elements of the URL path and b) for Zope-generated URLs
to contain these path elements.

Various documentation and interface updates.  No interface methods
were harmed in the filming of this checkin, but a few were added or extended
with defaults.



=== Zope/lib/python/Products/Sessions/BrowserIdManager.py 1.14 => 1.15 === (456/556 lines abridged)
--- Zope/lib/python/Products/Sessions/BrowserIdManager.py:1.14	Wed Aug 14 18:25:09 2002
+++ Zope/lib/python/Products/Sessions/BrowserIdManager.py	Mon Aug 19 15:50:17 2002
@@ -1,5 +1,5 @@
 ############################################################################
-#
+# 
 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -15,7 +15,7 @@
 import Globals
 from Persistence import Persistent
 from ZODB import TimeStamp
-from Acquisition import Implicit
+from Acquisition import Implicit, aq_base, aq_parent, aq_inner
 from AccessControl.Owned import Owned
 from AccessControl.Role import RoleManager
 from App.Management import Tabs
@@ -27,6 +27,11 @@
 from common import DEBUG
 import os, time, random, string, binascii, sys, re
 from cgi import escape
+from urllib import quote
+from urlparse import urlparse, urlunparse
+from ZPublisher.BeforeTraverse import registerBeforeTraverse, \
+    unregisterBeforeTraverse, queryBeforeTraverse
+import zLOG
 
 b64_trans = string.maketrans('+/', '-.')
 b64_untrans = string.maketrans('-.', '+/')
@@ -39,23 +44,27 @@
 
 constructBrowserIdManagerForm = Globals.DTMLFile('dtml/addIdManager',globals())
 
+BROWSERID_MANAGER_NAME = 'browser_id_manager'# imported by SessionDataManager
+ALLOWED_BID_NAMESPACES = ('form', 'cookies', 'url')
 ADD_BROWSER_ID_MANAGER_PERM="Add Browser Id Manager"
+TRAVERSAL_APPHANDLE = 'BrowserIdManager'
 
 def constructBrowserIdManager(
-    self, id, title='', idname='_ZopeId', location='cookiethenform',
-    cookiepath='/', cookiedomain='', cookielifedays=0, cookiesecure=0,
-    REQUEST=None
+    self, id=BROWSERID_MANAGER_NAME, title='', idname='_ZopeId',
+    location=('cookies', 'url', 'form'), cookiepath='/', cookiedomain='',
+    cookielifedays=0, cookiesecure=0, auto_url_encoding=0, REQUEST=None
     ):
     """ """
     ob = BrowserIdManager(id, title, idname, location, cookiepath,
-                          cookiedomain, cookielifedays, cookiesecure)

[-=- -=- -=- 456 lines omitted -=- -=- -=-]

+    TimeStamp=TimeStamp.TimeStamp, translate=string.translate
+    ):
+    t=time()
+    ts=split(b2a(`apply(TimeStamp,(gmtime(t)[:5]+(t%60,)))`)[:-1],'=')[0]
+    return translate(ts, b64_trans)
+
+def getB64TStampToInt(
+    ts, TimeStamp=TimeStamp.TimeStamp, b64_untrans=b64_untrans,
+    a2b=binascii.a2b_base64, translate=string.translate
+    ):
+    return TimeStamp(a2b(translate(ts+'=',b64_untrans))).timeTime()
+
+def getBrowserIdPieces(bid):
+    """ returns browser id parts in a tuple consisting of rand_id,
+    timestamp
+    """
+    return (bid[:8], bid[8:19])
+
+
+def isAWellFormedBrowserId(bid, binerr=binascii.Error,
+                            timestamperr=TimeStamp.error):
+    try:
+        rnd, ts = getBrowserIdPieces(bid)
+        int(rnd)
+        getB64TStampToInt(ts)
+        return bid
+    except (TypeError, ValueError, AttributeError, IndexError, binerr,
+            timestamperr):
+        return None
+
+
+def getNewBrowserId(randint=random.randint, maxint=99999999):
+    """ Returns 19-character string browser id
+    'AAAAAAAABBBBBBBB'
+    where:
+
+    A == leading-0-padded 8-char string-rep'd random integer
+    B == modified base64-encoded 11-char timestamp
+
+    To be URL-compatible, base64 encoding is modified as follows:
+      '=' end-padding is stripped off
+      '+' is translated to '-'
+      '/' is translated to '.'
+
+    An example is: 89972317A0C3EHnUi90w
+    """
+    return '%08i%s' % (randint(0, maxint-1), getB64TStamp())
 
 
 Globals.InitializeClass(BrowserIdManager)


=== Zope/lib/python/Products/Sessions/SessionDataManager.py 1.21 => 1.22 ===
--- Zope/lib/python/Products/Sessions/SessionDataManager.py:1.21	Wed Aug 14 18:25:09 2002
+++ Zope/lib/python/Products/Sessions/SessionDataManager.py	Mon Aug 19 15:50:17 2002
@@ -1,5 +1,5 @@
 ############################################################################
-#
+# 
 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -25,11 +25,11 @@
 from SessionPermissions import *
 from types import StringType
 from common import DEBUG
+from BrowserIdManager import isAWellFormedBrowserId, getNewBrowserId,\
+     BROWSERID_MANAGER_NAME
 from ZPublisher.BeforeTraverse import registerBeforeTraverse, \
     unregisterBeforeTraverse
 
-BID_MGR_NAME = 'browser_id_manager'
-
 bad_path_chars_in=re.compile('[^a-zA-Z0-9-_~\,\. \/]').search
 
 class SessionDataManagerErr(Exception): pass
@@ -103,19 +103,20 @@
     security.declareProtected(ARBITRARY_SESSIONDATA_PERM,'getSessionDataByKey')
     def getSessionDataByKey(self, key):
         return self._getSessionDataObjectByKey(key)
-
+    
     security.declareProtected(ACCESS_CONTENTS_PERM, 'getBrowserIdManager')
     def getBrowserIdManager(self):
         """ """
-        mgr = getattr(self, BID_MGR_NAME, None)
+        mgr = getattr(self, BROWSERID_MANAGER_NAME, None)
         if mgr is None:
             raise SessionDataManagerErr,(
-                'No browser id manager named %s could be found.' % BID_MGR_NAME
+                'No browser id manager named %s could be found.' %
+                BROWSERID_MANAGER_NAME
                 )
         return mgr
 
     # END INTERFACE METHODS
-
+    
     def __init__(self, id, path=None, title='', requestName=None):
         self.id = id
         self.setContainerPath(path)
@@ -160,14 +161,14 @@
             self.obpath = list(path) # sequence
         else:
             raise SessionDataManagerErr, ('Bad path value %s' % path)
-
+            
     security.declareProtected(MGMT_SCREEN_PERM, 'getContainerPath')
     def getContainerPath(self):
         """ """
         if self.obpath is not None:
             return string.join(self.obpath, '/')
         return '' # blank string represents undefined state
-
+    
     def _hasSessionDataObject(self, key):
         """ """
         c = self._getSessionDataContainer()
@@ -251,6 +252,12 @@
         self._sessionDataManager = sessionDataManagerName
 
     def __call__(self, container, request, StringType=StringType):
+        """
+        This method places a session data object reference in
+        the request.  It is called on each and every request to Zope in
+        Zopes after 2.5.0 when there is a session data manager installed
+        in the root.
+        """
         try:
             sdmName = self._sessionDataManager
             if not isinstance(sdmName, StringType):
@@ -268,7 +275,10 @@
             msg = 'Session automatic traversal failed to get session data'
             LOG('Session Tracking', WARNING, msg, error=sys.exc_info())
             return
+
+        # set the getSessionData method in the "lazy" namespace
         if self._requestSessionName is not None:
             request.set_lazy(self._requestSessionName, getSessionData)
+
 
 Globals.InitializeClass(SessionDataManager)


=== Zope/lib/python/Products/Sessions/SessionInterfaces.py 1.11 => 1.12 ===
--- Zope/lib/python/Products/Sessions/SessionInterfaces.py:1.11	Wed Aug 14 18:25:09 2002
+++ Zope/lib/python/Products/Sessions/SessionInterfaces.py	Mon Aug 19 15:50:17 2002
@@ -12,7 +12,7 @@
 ############################################################################
 """
 
-Sessioning-related Object APIs
+Session APIs
 
   See Also
 
@@ -32,12 +32,24 @@
     visitors, and for servicing requests from Session Data Managers
     related to the browser id.
     """
-    def encodeUrl(url):
+    def encodeUrl(url, style='querystring'):
         """
         Encodes a provided URL with the current request's browser id
-        and returns the result.  For example, the call
-        encodeUrl('http://foo.com/amethod') might return
-        'http://foo.com/amethod?_ZopeId=as9dfu0adfu0ad'.
+        and returns the result.  Two forms of URL-encoding are supported:
+        'querystring' and 'inline'.  'querystring' is the default.
+
+        If the 'querystring' form is used, the browser id name/value pair
+        are postfixed onto the URL as a query string.  If the 'inline'
+        form is used, the browser id name/value pair are prefixed onto
+        the URL as the first two path segment elements.
+
+        For example:
+
+         The call encodeUrl('http://foo.com/amethod', style='querystring')
+         might return 'http://foo.com/amethod?_ZopeId=as9dfu0adfu0ad'.
+
+         The call encodeUrl('http://foo.com/amethod, style='inline')
+         might return 'http://foo.com/_ZopeId/as9dfu0adfu0ad/amethod'.
 
         Permission required: Access contents information