[Checkins] SVN: zope.app.session/trunk/src/zope/app/session/ Make
progress with moving core components
Roger Ineichen
roger at projekt01.ch
Tue Sep 25 17:28:40 EDT 2007
Log message for revision 80054:
Make progress with moving core components
from zope.app.session to zope.session
Changed:
D zope.app.session/trunk/src/zope/app/session/DEPENDENCIES.cfg
D zope.app.session/trunk/src/zope/app/session/bootstrap.py
U zope.app.session/trunk/src/zope/app/session/browser.zcml
U zope.app.session/trunk/src/zope/app/session/configure.zcml
D zope.app.session/trunk/src/zope/app/session/design.txt
U zope.app.session/trunk/src/zope/app/session/ftesting.zcml
U zope.app.session/trunk/src/zope/app/session/http.py
U zope.app.session/trunk/src/zope/app/session/interfaces.py
U zope.app.session/trunk/src/zope/app/session/session.py
U zope.app.session/trunk/src/zope/app/session/tests.py
-=-
Deleted: zope.app.session/trunk/src/zope/app/session/DEPENDENCIES.cfg
===================================================================
--- zope.app.session/trunk/src/zope/app/session/DEPENDENCIES.cfg 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/DEPENDENCIES.cfg 2007-09-25 21:28:40 UTC (rev 80054)
@@ -1,12 +0,0 @@
-BTrees
-ZODB
-persistent
-zope.component
-zope.interface
-zope.minmax
-zope.publisher
-zope.schema
-
-# TODO This dependency is bad. It reflects use of a utility function
-# that should be copied elsewhere:
-zope.server
Deleted: zope.app.session/trunk/src/zope/app/session/bootstrap.py
===================================================================
--- zope.app.session/trunk/src/zope/app/session/bootstrap.py 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/bootstrap.py 2007-09-25 21:28:40 UTC (rev 80054)
@@ -1,54 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002, 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Bootstrap code.
-
-This module contains code to bootstrap a Zope3 instance. For example
-it makes sure a root folder exists and creates and configures some
-essential utilities.
-
-$Id$
-"""
-
-import transaction
-
-from zope.app.appsetup.bootstrap import ensureUtility, getInformationFromEvent
-
-from zope.app.session.interfaces import \
- IClientIdManager, ISessionDataContainer
-from zope.app.session.http import CookieClientIdManager
-from zope.app.session.session import PersistentSessionDataContainer
-
-def bootStrapSubscriber(event):
- """Subscriber to the IDataBaseOpenedEvent
-
- Create utility at that time if not yet present
- """
-
- db, connection, root, root_folder = getInformationFromEvent(event)
-
- ensureUtility(
- root_folder,
- IClientIdManager, 'CookieClientIdManager',
- CookieClientIdManager,
- asObject=True,
- )
- ensureUtility(
- root_folder,
- ISessionDataContainer, 'PersistentSessionDataContainer',
- PersistentSessionDataContainer,
- asObject=True,
- )
-
- transaction.commit()
- connection.close()
Modified: zope.app.session/trunk/src/zope/app/session/browser.zcml
===================================================================
--- zope.app.session/trunk/src/zope/app/session/browser.zcml 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/browser.zcml 2007-09-25 21:28:40 UTC (rev 80054)
@@ -9,11 +9,11 @@
title="Cookie Client Id Manager"
description="Uses a cookie to uniquely identify a client, allowing
state to be maintained between requests"
- class=".http.CookieClientIdManager"
+ class="zope.session.http.CookieClientIdManager"
permission="zope.ManageServices" />
<editform
- schema=".http.ICookieClientIdManager"
+ schema="zope.session.http.ICookieClientIdManager"
label="Cookie Client Id Manager Properties"
name="edit.html" menu="zmi_views" title="Edit"
permission="zope.ManageServices" />
@@ -23,7 +23,7 @@
<addMenuItem
title="Persistent Session Data Container"
description="Stores session data persistently in the ZODB"
- class=".session.PersistentSessionDataContainer"
+ class="zope.session.session.PersistentSessionDataContainer"
permission="zope.ManageServices" />
<!-- RAMSessionDataContainer -->
@@ -31,12 +31,12 @@
<addMenuItem
title="RAM Session Data Container"
description="Stores session data in RAM"
- class=".session.RAMSessionDataContainer"
+ class="zope.session.session.RAMSessionDataContainer"
permission="zope.ManageServices" />
<!-- ISessionDataContainer -->
<editform
- schema=".interfaces.ISessionDataContainer"
+ schema="zope.session.interfaces.ISessionDataContainer"
label="Session Data Container Properties"
name="edit.html" menu="zmi_views" title="Edit"
permission="zope.ManageServices" />
Modified: zope.app.session/trunk/src/zope/app/session/configure.zcml
===================================================================
--- zope.app.session/trunk/src/zope/app/session/configure.zcml 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/configure.zcml 2007-09-25 21:28:40 UTC (rev 80054)
@@ -1,114 +1,9 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
- i18n_domain="zope"
- >
-
- <adapter
- factory=".session.ClientId"
- permission="zope.Public"
- />
+ i18n_domain="zope">
- <adapter
- factory=".session.Session"
- provides="zope.app.session.interfaces.ISession"
- permission="zope.Public"
- />
-
- <adapter
- factory=".session.Session"
- provides="zope.traversing.interfaces.IPathAdapter"
- name="session"
- />
-
- <class class=".session.Session">
- <allow interface=".interfaces.ISession" />
- <implements interface="zope.traversing.interfaces.IPathAdapter" />
- </class>
-
- <class class=".http.CookieClientIdManager">
- <require
- interface=".http.ICookieClientIdManager"
- permission="zope.Public" />
- <require
- set_schema=".http.ICookieClientIdManager"
- permission="zope.ManageServices" />
- <require
- interface="zope.location.ILocation"
- permission="zope.Public" />
- <require
- set_schema="zope.location.ILocation"
- permission="zope.ManageServices" />
- </class>
-
- <class class=".session.PersistentSessionDataContainer">
- <require
- interface=".interfaces.ISessionDataContainer"
- permission="zope.Public" />
- <require
- set_schema=".interfaces.ISessionDataContainer"
- permission="zope.ManageServices" />
- <require
- interface="zope.location.ILocation"
- permission="zope.Public" />
- <require
- set_schema="zope.location.ILocation"
- permission="zope.ManageServices" />
- </class>
-
- <class class=".session.RAMSessionDataContainer">
- <require
- interface=".interfaces.ISessionDataContainer"
- permission="zope.Public" />
- <require
- set_schema=".interfaces.ISessionDataContainer"
- permission="zope.ManageServices" />
- <require
- interface="zope.location.ILocation"
- permission="zope.Public" />
- <require
- set_schema="zope.location.ILocation"
- permission="zope.ManageServices" />
- </class>
-
- <class class=".session.SessionData">
- <allow interface=".interfaces.ISessionData" />
- </class>
-
- <class class=".session.SessionPkgData">
- <allow interface=".interfaces.ISessionPkgData" />
- </class>
-
- <subscriber
- for="zope.app.appsetup.IDatabaseOpenedEvent"
- handler=".bootstrap.bootStrapSubscriber"
- />
-
- <subscriber
- for="zope.publisher.interfaces.http.IHTTPVirtualHostChangedEvent"
- handler=".http.notifyVirtualHostChanged"
- />
-
+ <include package="zope.session" />
<include file="browser.zcml" />
- <!-- Registering documentation with API doc -->
- <configure
- xmlns:apidoc="http://namespaces.zope.org/apidoc"
- xmlns:zcml="http://namespaces.zope.org/zcml"
- zcml:condition="have apidoc">
-
- <apidoc:bookchapter
- id="session"
- title="Sessions"
- doc_path="design.txt"
- />
- <apidoc:bookchapter
- id="api"
- title="API"
- doc_path="api.txt"
- parent="session"
- />
-
- </configure>
-
</configure>
Deleted: zope.app.session/trunk/src/zope/app/session/design.txt
===================================================================
--- zope.app.session/trunk/src/zope/app/session/design.txt 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/design.txt 2007-09-25 21:28:40 UTC (rev 80054)
@@ -1,146 +0,0 @@
-Sessions
-========
-
-Sessions provide a way to temporarily associate information with a
-client without requiring the authentication of a principal. We
-associate an identifier with a particular client. Whenever we get a
-request from that client, we compute the identifier and use the
-identifier to look up associated information, which is stored on the
-server.
-
-A major disadvantage of sessions is that they require management of
-information on the server. This can have major implications for
-scalability. It is possible for a framework to make use of session
-data very easy for the developer. This is great if scalability is not
-an issue, otherwise, it is a booby trap.
-
-Design Issues
--------------
-
-Sessions introduce a number of issues to be considered:
-
-- Clients have to be identified. A number of approaches are possible,
- including:
-
- o Using HTTP cookies. The application assigns a client identifier,
- which is stored in a cookie. This technique is the most
- straightforward, but can be defeated if the client does not
- support HTTP cookies (usually because the feature has been
- disabled).
-
- o Using URLs. The application assigns a client identifier, which is
- stored in the URL. This makes URLs a bit uglier and requires some
- care. If people copy URLs and send them to others, then you could
- end up with multiple clients with the same session
- identifier. There are a number of ways to reduce the risk of
- accidental reuse of session identifiers:
-
- - Embed the client IP address in the identifier
-
- - Expire the identifier
-
- o Use hidden form variables. This complicates applications. It
- requires all requests to be POST requests and requires the
- maintenance of the hidden variables.
-
- o Use the client IP address
-
- This doesn't work very well, because an IP address may be shared by
- many clients.
-
-- Data storage
-
- Data can be simply stored in the object database. This provides lots
- of flexibility. You can store pretty much anything you want as long
- as it is persistent. You get the full benefit of the object database,
- such as transactions, transparency, clustering, and so on. Using
- the object database is especially useful when:
-
- - Writes are infrequent
-
- - Data are complex
-
- If writes are frequent, then the object database introduces
- scalability problems. Really, any transactional database is likely
- to introduce problems with frequent writes. If you are tempted to
- update session data on every request, think very hard about it. You
- are creating a scalability problem.
-
- If you know that scalability is not (and never will be) an issue,
- you can just use the object database.
-
- If you have client data that needs to be updated often (as in every
- request), consider storing the data on the client. (Like all data
- received from a client, it may be tainted and, in most instances,
- should not be trusted. Sensitive information that the user should
- not see should likewise not be stored on the client, unless
- encrypted with a key the client has no access to.) If you can't
- store it on the client, then consider some other storage mechanism,
- like a fast database, possibly without transaction support.
-
- You may be tempted to store session data in memory for speed. This
- doesn't turn out to work very well. If you need scalability, then
- you need to be able to use an application-server cluster and storage
- of session data in memory defeats that. You can use
- "server-affinity" to assure that requests from a client always go
- back to the same server, but not all load balancers support server
- affinity, and, for those that do, enabling server affinity tends to
- defeat load balancing.
-
-- Session expiration
-
- You may wish to ensure that sessions terminate after some period of
- time. This may be for security reasons, or to avoid accidental
- sharing of a session among multiple clients. The policy might be
- expressed in terms of total session time, or maximum inactive time,
- or some combination.
-
- There are a number of ways to approach this. You can expire client
- ids. You can expire session data.
-
-- Data expiration
-
- Because HTTP is a stateless protocol, you can't tell whether a user
- is thinking about a task or has simply stopped working on it. Some
- means is needed to free server session storage that is no-longer needed.
-
- The simplest strategy is to never remove data. This strategy has
- some obvious disadvantages. Other strategies can be viewed as
- optimizations of the basic strategy. It is important to realize that
- a data expiration strategy can be informed by, but need not be
- constrained by a session-expiration strategy.
-
-Application programming interface
----------------------------------
-
-Application code will merely adapt request objects to a session data
-interface. Initially, we will define the session data interface
-``ISession``. It provides a mapping interface. Keys in the mapping
-are application identifiers. Values are persistent mapping objects.
-
-Application code that wants to get object session data for a request
-adapts the request to ``ISession``::
-
- appkey = "mycorp.actionplan"
- data = ISession(request)[appkey]
-
-where ``appkey`` is a dotted name that identifies the application.
-Given the session data, the application can then store data in it::
-
- data['original'] = original_actions
- data['new'] = new_actions
-
-From ZPT, you can access session data using adapter syntax::
-
- request/session:key
-
-So, for example, to access the ``old`` key for the session data for
-the sample key above:
-
- request/session:mycorp.actionplan/old
-
-In this example, the data for an aplication key was a mapping object.
-The semantics of a session data for a particular application key are
-determined by the session data type interface. ``ISession`` defines
-the application data to be a mapping object by default. Other data
-interfaces could specify different bahavior.
Modified: zope.app.session/trunk/src/zope/app/session/ftesting.zcml
===================================================================
--- zope.app.session/trunk/src/zope/app/session/ftesting.zcml 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/ftesting.zcml 2007-09-25 21:28:40 UTC (rev 80054)
@@ -11,6 +11,9 @@
<include package="zope.app.securitypolicy" file="meta.zcml" />
<include package="zope.app.zcmlfiles" />
+
+ <include package="zope.session" />
+
<include package="zope.app.authentication" />
<include package="zope.app.zptpage"/>
<include package="zope.app.securitypolicy" />
Modified: zope.app.session/trunk/src/zope/app/session/http.py
===================================================================
--- zope.app.session/trunk/src/zope/app/session/http.py 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/http.py 2007-09-25 21:28:40 UTC (rev 80054)
@@ -15,401 +15,15 @@
$Id$
"""
-import hmac
-import logging
-import random
-import re
-import sha
-import string
-import time
-from cStringIO import StringIO
-import zope.location
-from persistent import Persistent
-from zope import schema, component
-from zope.interface import implements
-from zope.publisher.interfaces.http import IHTTPRequest
-from zope.publisher.interfaces.http import IHTTPApplicationRequest
-from zope.annotation.interfaces import IAttributeAnnotatable
-from zope.i18nmessageid import ZopeMessageFactory as _
+import zope.deferredimport
-from zope.app.session.interfaces import IClientIdManager
-from zope.schema.fieldproperty import FieldProperty
-from zope.app.http.httpdate import build_http_date
-
-__docformat__ = 'restructuredtext'
-
-cookieSafeTrans = string.maketrans("+/", "-.")
-
-logger = logging.getLogger()
-
-def digestEncode(s):
- """Encode SHA digest for cookie."""
- return s.encode("base64")[:-2].translate(cookieSafeTrans)
-
-class MissingClientIdException(Exception):
- """No ClientId found in Request"""
-
-class ICookieClientIdManager(IClientIdManager):
- """Manages sessions using a cookie"""
-
- namespace = schema.TextLine(
- title=_('Cookie Name'),
- description=_(
- "Name of cookie used to maintain state. "
- "Must be unique to the site domain name, and only contain "
- "ASCII letters, digits and '_'"
- ),
- required=True,
- min_length=1,
- max_length=30,
- constraint=re.compile("^[\d\w_]+$").search,
- )
-
- cookieLifetime = schema.Int(
- title=_('Cookie Lifetime'),
- description=_(
- "Number of seconds until the browser expires the cookie. "
- "Leave blank expire the cookie when the browser is quit. "
- "Set to 0 to never expire. "
- ),
- min=0,
- required=False,
- default=None,
- missing_value=None,
- )
-
- thirdparty = schema.Bool(
- title=_('Third party cookie'),
- description=_(
- "Is a third party issuing the identification cookie? "
- "Servers like Apache or Nginx have capabilities to issue "
- "identification cookies too. If Third party cookies are "
- "beeing used, Zope will never send a cookie back, just check "
- "for them."
- ),
- required=False,
- default=False,
- )
-
-
-class CookieClientIdManager(zope.location.Location, Persistent):
- """Session utility implemented using cookies."""
-
- implements(IClientIdManager, ICookieClientIdManager, IAttributeAnnotatable)
-
- thirdparty = FieldProperty(ICookieClientIdManager['thirdparty'])
- cookieLifetime = FieldProperty(ICookieClientIdManager['cookieLifetime'])
-
- def __init__(self):
- self.namespace = "zope3_cs_%x" % (int(time.time()) - 1000000000)
- self.secret = "%.20f" % random.random()
-
- def getClientId(self, request):
- """Get the client id
-
- This creates one if necessary:
-
- >>> from zope.publisher.http import HTTPRequest
- >>> request = HTTPRequest(StringIO(''), {}, None)
- >>> bim = CookieClientIdManager()
- >>> id = bim.getClientId(request)
- >>> id == bim.getClientId(request)
- True
-
- The id is retained accross requests:
-
- >>> request2 = HTTPRequest(StringIO(''), {}, None)
- >>> request2._cookies = dict(
- ... [(name, cookie['value'])
- ... for (name, cookie) in request.response._cookies.items()
- ... ])
- >>> id == bim.getClientId(request2)
- True
- >>> bool(id)
- True
-
- Note that the return value of this function is a string, not
- an IClientId. This is because this method is used to implement
- the IClientId Adapter.
-
- >>> type(id) == type('')
- True
-
- It's also possible to use third-party cookies. E.g. Apache `mod_uid`
- or Nginx `ngx_http_userid_module` are able to issue user tracking
- cookies in front of Zope. In case thirdparty is activated Zope may
- not set a cookie.
-
- >>> bim.thirdparty = True
- >>> request3 = HTTPRequest(StringIO(''), {}, None)
- >>> bim.getClientId(request3)
- Traceback (most recent call last):
- ...
- MissingClientIdException
- >>> cookie = request3.response.getCookie(bim.namespace)
- >>> cookie is None
- True
-
- """
- sid = self.getRequestId(request)
- if sid is None:
- if self.thirdparty:
- raise MissingClientIdException
- else:
- sid = self.generateUniqueId()
-
- if not self.thirdparty:
- self.setRequestId(request, sid)
-
- return sid
-
- def generateUniqueId(self):
- """Generate a new, random, unique id.
-
- >>> bim = CookieClientIdManager()
- >>> id1 = bim.generateUniqueId()
- >>> id2 = bim.generateUniqueId()
- >>> id1 != id2
- True
-
- """
- data = "%.20f%.20f%.20f" % (random.random(), time.time(), time.clock())
- digest = sha.sha(data).digest()
- s = digestEncode(digest)
- # we store a HMAC of the random value together with it, which makes
- # our session ids unforgeable.
- mac = hmac.new(s, self.secret, digestmod=sha).digest()
- return s + digestEncode(mac)
-
- def getRequestId(self, request):
- """Return the browser id encoded in request as a string
-
- Return None if an id is not set.
-
- For example:
-
- >>> from zope.publisher.http import HTTPRequest
- >>> request = HTTPRequest(StringIO(''), {}, None)
- >>> bim = CookieClientIdManager()
-
- Because no cookie has been set, we get no id:
-
- >>> bim.getRequestId(request) is None
- True
-
- We can set an id:
-
- >>> id1 = bim.generateUniqueId()
- >>> bim.setRequestId(request, id1)
-
- And get it back:
-
- >>> bim.getRequestId(request) == id1
- True
-
- When we set the request id, we also set a response cookie. We
- can simulate getting this cookie back in a subsequent request:
-
- >>> request2 = HTTPRequest(StringIO(''), {}, None)
- >>> request2._cookies = dict(
- ... [(name, cookie['value'])
- ... for (name, cookie) in request.response._cookies.items()
- ... ])
-
- And we get the same id back from the new request:
-
- >>> bim.getRequestId(request) == bim.getRequestId(request2)
- True
-
- If another server is managing the ClientId cookies (Apache, Nginx)
- we're returning their value without checking:
-
- >>> bim.namespace = 'uid'
- >>> bim.thirdparty = True
- >>> request3 = HTTPRequest(StringIO(''), {}, None)
- >>> request3._cookies = {'uid': 'AQAAf0Y4gjgAAAQ3AwMEAg=='}
- >>> bim.getRequestId(request3)
- 'AQAAf0Y4gjgAAAQ3AwMEAg=='
-
- """
- response_cookie = request.response.getCookie(self.namespace)
- if response_cookie:
- sid = response_cookie['value']
- else:
- request = IHTTPApplicationRequest(request)
- sid = request.getCookies().get(self.namespace, None)
- if self.thirdparty:
- return sid
- else:
- # If there is an id set on the response, use that but don't trust it.
- # We need to check the response in case there has already been a new
- # session created during the course of this request.
- if sid is None or len(sid) != 54:
- return None
- s, mac = sid[:27], sid[27:]
- if (digestEncode(hmac.new(s, self.secret, digestmod=sha).digest())
- != mac):
- return None
- else:
- return sid
-
- def setRequestId(self, request, id):
- """Set cookie with id on request.
-
- This sets the response cookie:
-
- See the examples in getRequestId.
-
- Note that the id is checkec for validity. Setting an
- invalid value is silently ignored:
-
- >>> from zope.publisher.http import HTTPRequest
- >>> request = HTTPRequest(StringIO(''), {}, None)
- >>> bim = CookieClientIdManager()
- >>> bim.getRequestId(request)
- >>> bim.setRequestId(request, 'invalid id')
- >>> bim.getRequestId(request)
-
- For now, the cookie path is the application URL:
-
- >>> cookie = request.response.getCookie(bim.namespace)
- >>> cookie['path'] == request.getApplicationURL(path_only=True)
- True
-
- In the future, it should be the site containing the
- CookieClientIdManager
-
- By default, session cookies don't expire:
-
- >>> cookie.has_key('expires')
- False
-
- Expiry time of 0 means never (well - close enough)
-
- >>> bim.cookieLifetime = 0
- >>> request = HTTPRequest(StringIO(''), {}, None)
- >>> bid = bim.getClientId(request)
- >>> cookie = request.response.getCookie(bim.namespace)
- >>> cookie['expires']
- 'Tue, 19 Jan 2038 00:00:00 GMT'
-
- A non-zero value means to expire after than number of seconds:
-
- >>> bim.cookieLifetime = 3600
- >>> request = HTTPRequest(StringIO(''), {}, None)
- >>> bid = bim.getClientId(request)
- >>> cookie = request.response.getCookie(bim.namespace)
- >>> import rfc822
- >>> expires = time.mktime(rfc822.parsedate(cookie['expires']))
- >>> expires > time.mktime(time.gmtime()) + 55*60
- True
-
- If another server in front of Zope (Apache, Nginx) is managing the
- cookies we won't set any ClientId cookies:
-
- >>> request = HTTPRequest(StringIO(''), {}, None)
- >>> bim.thirdparty = True
- >>> bim.setRequestId(request, '1234')
- >>> cookie = request.response.getCookie(bim.namespace)
- >>> cookie
- """
- # TODO: Currently, the path is the ApplicationURL. This is reasonable,
- # and will be adequate for most purposes.
- # A better path to use would be that of the folder that contains
- # the site manager this service is registered within. However,
- # that would be expensive to look up on each request, and would
- # have to be altered to take virtual hosting into account.
- # Seeing as this utility instance has a unique namespace for its
- # cookie, using ApplicationURL shouldn't be a problem.
-
- if self.thirdparty:
- logger.warning('ClientIdManager is using thirdparty cookies, '
- 'ignoring setIdRequest call')
- else:
- if self.cookieLifetime is not None:
- if self.cookieLifetime:
- expires = build_http_date(time.time() + self.cookieLifetime)
- else:
- expires = 'Tue, 19 Jan 2038 00:00:00 GMT'
- request.response.setCookie(
- self.namespace, id, expires=expires,
- path=request.getApplicationURL(path_only=True)
- )
- else:
- request.response.setCookie(
- self.namespace, id,
- path=request.getApplicationURL(path_only=True)
- )
-
-def notifyVirtualHostChanged(event):
- """Adjust cookie paths when IVirtualHostRequest information changes.
-
- Given a event, this method should call a CookieClientIdManager's
- setRequestId if a cookie is present in the response for that manager. To
- demonstrate we create a dummy manager object and event:
-
- >>> class DummyManager(object):
- ... implements(ICookieClientIdManager)
- ... namespace = 'foo'
- ... thirdparty = False
- ... request_id = None
- ... def setRequestId(self, request, id):
- ... self.request_id = id
- ...
- >>> manager = DummyManager()
- >>> component.provideUtility(manager, IClientIdManager)
- >>> from zope.publisher.http import HTTPRequest
- >>> class DummyEvent (object):
- ... request = HTTPRequest(StringIO(''), {}, None)
- >>> event = DummyEvent()
-
- With no cookies present, the manager should not be called:
-
- >>> notifyVirtualHostChanged(event)
- >>> manager.request_id is None
- True
-
- However, when a cookie *has* been set, the manager is called so it can
- update the cookie if need be:
-
- >>> event.request.response.setCookie('foo', 'bar')
- >>> notifyVirtualHostChanged(event)
- >>> manager.request_id
- 'bar'
-
- If a server in front of Zope manages the ClientIds (Apache, Nginx), we
- don't need to take care about the cookies
-
- >>> manager2 = DummyManager()
- >>> manager2.thirdparty = True
- >>> event2 = DummyEvent()
-
- However, when a cookie *has* been set, the manager is called so it can
- update the cookie if need be:
-
- >>> event2.request.response.setCookie('foo2', 'bar2')
- >>> notifyVirtualHostChanged(event2)
- >>> id = manager2.request_id
- >>> id is None
- True
-
- Cleanup of the utility registration:
-
- >>> import zope.component.testing
- >>> zope.component.testing.tearDown()
-
- """
- # the event sends us a IHTTPApplicationRequest, but we need a
- # IHTTPRequest for the response attribute, and so does the cookie-
- # manager.
- request = IHTTPRequest(event.request, None)
- if event.request is None:
- return
- for name, manager in component.getUtilitiesFor(IClientIdManager):
- if manager and ICookieClientIdManager.providedBy(manager):
- # Third party ClientId Managers need no modification at all
- if not manager.thirdparty:
- cookie = request.response.getCookie(manager.namespace)
- if cookie:
- manager.setRequestId(request, cookie['value'])
\ No newline at end of file
+zope.deferredimport.deprecated(
+ "It has moved to zope.session.http This reference will be gone sometimes.",
+ ICookieClientIdManager = 'zope.session.http:ICookieClientIdManager',
+ MissingClientIdException = 'zope.session.http:MissingClientIdException',
+ notifyVirtualHostChanged = 'zope.session.http:notifyVirtualHostChanged',
+ CookieClientIdManager = 'zope.session.http:CookieClientIdManager',
+ digestEncode = 'zope.session.http:digestEncode',
+ cookieSafeTrans = 'zope.session.http:cookieSafeTrans',
+ )
Modified: zope.app.session/trunk/src/zope/app/session/interfaces.py
===================================================================
--- zope.app.session/trunk/src/zope/app/session/interfaces.py 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/interfaces.py 2007-09-25 21:28:40 UTC (rev 80054)
@@ -15,140 +15,15 @@
$Id$
"""
-from zope.interface import Interface
-from zope.interface.common.mapping import IMapping, IReadMapping, IWriteMapping
-from zope import schema
-from zope.i18nmessageid import ZopeMessageFactory as _
-__docformat__ = 'restructuredtext'
+import zope.deferredimport
-class IClientIdManager(Interface):
- """Manages sessions - fake state over multiple client requests."""
-
- def getClientId(request):
- """Return the client id for the given request as a string.
-
- If the request doesn't have an attached sessionId a new one will be
- generated.
-
- This will do whatever is possible to do the HTTP request to ensure the
- session id will be preserved. Depending on the specific method,
- further action might be necessary on the part of the user. See the
- documentation for the specific implementation and its interfaces.
-
- """
-
-
-class IClientId(Interface):
- """A unique id representing a session"""
-
- def __str__():
- """As a unique ASCII string"""
-
-
-class ISessionDataContainer(IReadMapping, IWriteMapping):
- """Stores data objects for sessions.
-
- The object implementing this interface is responsible for expiring data as
- it feels appropriate.
-
- Usage::
-
- session_data_container[client_id][product_id][key] = value
-
- Note that this interface does not support the full mapping interface -
- the keys need to remain secret so we can't give access to keys(),
- values() etc.
-
- """
- timeout = schema.Int(
- title=_(u"Timeout"),
- description=_(
- "Number of seconds before data becomes stale and may "
- "be removed. A value of '0' means no expiration."),
- default=3600,
- required=True,
- min=0,
- )
- resolution = schema.Int(
- title=_("Timeout resolution (in seconds)"),
- description=_(
- "Defines what the 'resolution' of item timeout is. "
- "Setting this higher allows the transience machinery to "
- "do fewer 'writes' at the expense of causing items to time "
- "out later than the 'Data object timeout value' by a factor "
- "of (at most) this many seconds."
- ),
- default=5*60,
- required=True,
- min=0,
- )
-
- def __getitem__(self, product_id):
- """Return an ISessionPkgData"""
-
- def __setitem__(self, product_id, value):
- """Store an ISessionPkgData"""
-
-
-class ISession(Interface):
- """This object allows retrieval of the correct ISessionData
- for a particular product id
-
- >>> session = ISession(request)[product_id]
- >>> session['color'] = 'red'
- True
-
- >>> ISessionData.providedBy(session)
- True
-
- """
-
- def __getitem__(product_id):
- """Return the relevant ISessionPkgData
-
- This involves locating the correct ISessionDataContainer for the
- given product id, determining the client id, and returning the
- relevant ISessionPkgData.
-
- """
-
- def get(product_id, default=None):
- """Return the relevant ISessionPkgData or default if not
- available"""
-
-
-class ISessionData(IReadMapping, IMapping):
- """Storage for a particular product id's session data
-
- Contains 0 or more ISessionPkgData instances
-
- """
-
- lastAccessTime = schema.Int(
- title=_("Last Access Time"),
- description=_(
- "Approximate epoch time this ISessionData was last retrieved "
- "from its ISessionDataContainer"
- ),
- default=0,
- required=True,
- )
-
- # Note that only IReadMapping and IWriteMaping are implemented.
- # We cannot give access to the keys, as they need to remain secret.
-
- def __getitem__(self, client_id):
- """Return an ISessionPkgData"""
-
- def __setitem__(self, client_id, session_pkg_data):
- """Store an ISessionPkgData"""
-
-
-class ISessionPkgData(IMapping):
- """Storage for a particular product id and browser id's session data
-
- Data is stored persistently and transactionally. Data stored must
- be persistent or picklable.
-
- """
+zope.deferredimport.deprecated(
+ "It has moved to zope.session.interfaces This reference will be gone sometimes.",
+ IClientIdManager = 'zope.session.interfaces:IClientIdManager',
+ IClientId = 'zope.session.interfaces:IClientId',
+ ISessionDataContainer = 'zope.session.interfaces:ISessionDataContainer',
+ ISession = 'zope.session.interfaces:ISession',
+ ISessionData = 'zope.session.interfaces:ISessionData',
+ ISessionPkgData = 'zope.session.interfaces:ISessionPkgData',
+ )
Modified: zope.app.session/trunk/src/zope/app/session/session.py
===================================================================
--- zope.app.session/trunk/src/zope/app/session/session.py 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/session.py 2007-09-25 21:28:40 UTC (rev 80054)
@@ -15,512 +15,17 @@
$Id$
"""
-from cStringIO import StringIO
-import time, string, random, thread
-from UserDict import IterableUserDict
-from heapq import heapify, heappop
-import ZODB
-import ZODB.MappingStorage
-import zope.location
-import zope.minmax
-from persistent import Persistent
-from BTrees.OOBTree import OOBTree
+import zope.deferredimport
-from zope.interface import implements
-from zope.component import getUtility, adapts
-from zope.component.interfaces import ComponentLookupError
-from zope.publisher.interfaces import IRequest
-from zope.annotation.interfaces import IAttributeAnnotatable
-
-from interfaces import \
- IClientIdManager, IClientId, ISession, ISessionDataContainer, \
- ISessionPkgData, ISessionData
-
-__docformat__ = 'restructuredtext'
-
-cookieSafeTrans = string.maketrans("+/", "-.")
-
-def digestEncode(s):
- """Encode SHA digest for cookie."""
- return s.encode("base64")[:-2].translate(cookieSafeTrans)
-
-
-class ClientId(str):
- """See zope.app.interfaces.utilities.session.IClientId
-
- >>> import tests
- >>> request = tests.setUp()
-
- >>> id1 = ClientId(request)
- >>> id2 = ClientId(request)
- >>> id1 == id2
- True
-
- >>> tests.tearDown()
-
- """
- implements(IClientId)
- adapts(IRequest)
-
- def __new__(cls, request):
- return str.__new__(
- cls, getUtility(IClientIdManager).getClientId(request)
- )
-
-
-class PersistentSessionDataContainer(zope.location.Location, Persistent,
- IterableUserDict):
- """A SessionDataContainer that stores data in the ZODB"""
-
- implements(ISessionDataContainer, IAttributeAnnotatable)
-
- _v_last_sweep = 0 # Epoch time sweep last run
-
- def __init__(self):
- self.data = OOBTree()
- self.timeout = 1 * 60 * 60
- self.resolution = 50*60
-
- def __getitem__(self, pkg_id):
- """Retrieve an ISessionData
-
- >>> sdc = PersistentSessionDataContainer()
-
- >>> sdc.timeout = 60
- >>> sdc.resolution = 3
- >>> sdc['clientid'] = sd = SessionData()
-
- To ensure stale data is removed, we can wind
- back the clock using undocumented means...
-
- >>> sd.lastAccessTime = sd.lastAccessTime - 64
- >>> sdc._v_last_sweep = sdc._v_last_sweep - 4
-
- Now the data should be garbage collected
-
- >>> sdc['clientid']
- Traceback (most recent call last):
- [...]
- KeyError: 'clientid'
-
- Ensure lastAccessTime on the ISessionData is being updated
- occasionally. The ISessionDataContainer maintains this whenever
- the ISessionData is set or retrieved.
-
- lastAccessTime on the ISessionData is set when it is added
- to the ISessionDataContainer
-
- >>> sdc['client_id'] = sd = SessionData()
- >>> sd.lastAccessTime > 0
- True
-
- lastAccessTime is also updated whenever the ISessionData
- is retrieved through the ISessionDataContainer, at most
- once every 'resolution' seconds.
-
- >>> then = sd.lastAccessTime = sd.lastAccessTime - 4
- >>> now = sdc['client_id'].lastAccessTime
- >>> now > then
- True
- >>> time.sleep(1)
- >>> now == sdc['client_id'].lastAccessTime
- True
-
- Ensure lastAccessTime is not modified and no garbage collection
- occurs when timeout == 0. We test this by faking a stale
- ISessionData object.
-
- >>> sdc.timeout = 0
- >>> sd.lastAccessTime = sd.lastAccessTime - 5000
- >>> lastAccessTime = sd.lastAccessTime
- >>> sdc['client_id'].lastAccessTime == lastAccessTime
- True
-
- Next, we test session expiration functionality beyond transactions.
-
- >>> import transaction
- >>> from ZODB.DB import DB
- >>> from ZODB.DemoStorage import DemoStorage
- >>> sdc = PersistentSessionDataContainer()
- >>> sdc.timeout = 60
- >>> sdc.resolution = 3
- >>> db = DB(DemoStorage('test_storage'))
- >>> c = db.open()
- >>> c.root()['sdc'] = sdc
- >>> sdc['pkg_id'] = sd = SessionData()
- >>> sd['name'] = 'bob'
- >>> transaction.commit()
-
- Access immediately. the data should be accessible.
-
- >>> c.root()['sdc']['pkg_id']['name']
- 'bob'
-
- Change the clock time and stale the session data.
-
- >>> sdc = c.root()['sdc']
- >>> sd = sdc['pkg_id']
- >>> sd.lastAccessTime = sd.lastAccessTime - 64
- >>> sdc._v_last_sweep = sdc._v_last_sweep - 4
- >>> transaction.commit()
-
- The data should be garbage collected.
-
- >>> c.root()['sdc']['pkg_id']['name']
- Traceback (most recent call last):
- [...]
- KeyError: 'pkg_id'
-
- Then abort transaction and access the same data again.
- The previous GC was cancelled, but deadline is over.
- The data should be garbage collected again.
-
- >>> transaction.abort()
- >>> c.root()['sdc']['pkg_id']['name']
- Traceback (most recent call last):
- [...]
- KeyError: 'pkg_id'
-
- """
- if self.timeout == 0:
- return IterableUserDict.__getitem__(self, pkg_id)
-
- now = time.time()
-
- # TODO: When scheduler exists, sweeping should be done by
- # a scheduled job since we are currently busy handling a
- # request and may end up doing simultaneous sweeps
-
- # If transaction is aborted after sweep. _v_last_sweep keep
- # incorrect sweep time. So when self.data is ghost, revert the time
- # to the previous _v_last_sweep time(_v_old_sweep).
- if self.data._p_state < 0:
- try:
- self._v_last_sweep = self._v_old_sweep
- del self._v_old_sweep
- except AttributeError:
- pass
-
- if self._v_last_sweep + self.resolution < now:
- self.sweep()
- if getattr(self, '_v_old_sweep', None) is None:
- self._v_old_sweep = self._v_last_sweep
- self._v_last_sweep = now
-
- rv = IterableUserDict.__getitem__(self, pkg_id)
- # Only update lastAccessTime once every few minutes, rather than
- # every hit, to avoid ZODB bloat and conflicts
- if rv.lastAccessTime + self.resolution < now:
- rv.lastAccessTime = int(now)
- return rv
-
- def __setitem__(self, pkg_id, session_data):
- """Set an ISessionPkgData
-
- >>> sdc = PersistentSessionDataContainer()
- >>> sad = SessionData()
-
- __setitem__ sets the ISessionData's lastAccessTime
-
- >>> sad.lastAccessTime
- 0
- >>> sdc['1'] = sad
- >>> 0 < sad.lastAccessTime <= time.time()
- True
-
- We can retrieve the same object we put in
-
- >>> sdc['1'] is sad
- True
-
- """
- session_data.lastAccessTime = int(time.time())
- return IterableUserDict.__setitem__(self, pkg_id, session_data)
-
- def sweep(self):
- """Clean out stale data
-
- >>> sdc = PersistentSessionDataContainer()
- >>> sdc['1'] = SessionData()
- >>> sdc['2'] = SessionData()
-
- Wind back the clock on one of the ISessionData's
- so it gets garbage collected
-
- >>> sdc['2'].lastAccessTime -= sdc.timeout * 2
-
- Sweep should leave '1' and remove '2'
-
- >>> sdc.sweep()
- >>> sd1 = sdc['1']
- >>> sd2 = sdc['2']
- Traceback (most recent call last):
- [...]
- KeyError: '2'
-
- """
- # We only update the lastAccessTime every 'resolution' seconds.
- # To compensate for this, we factor in the resolution when
- # calculating the expiry time to ensure that we never remove
- # data that has been accessed within timeout seconds.
- expire_time = time.time() - self.timeout - self.resolution
- heap = [(v.lastAccessTime, k) for k,v in self.data.items()]
- heapify(heap)
- while heap:
- lastAccessTime, key = heappop(heap)
- if lastAccessTime < expire_time:
- del self.data[key]
- else:
- return
-
-
-class RAMSessionDataContainer(PersistentSessionDataContainer):
- """A SessionDataContainer that stores data in RAM.
-
- Currently session data is not shared between Zope clients, so
- server affinity will need to be maintained to use this in a ZEO cluster.
-
- >>> sdc = RAMSessionDataContainer()
- >>> sdc['1'] = SessionData()
- >>> sdc['1'] is sdc['1']
- True
- >>> ISessionData.providedBy(sdc['1'])
- True
-
- """
- def __init__(self):
- self.resolution = 5*60
- self.timeout = 1 * 60 * 60
- # Something unique
- self.key = '%s.%s.%s' % (time.time(), random.random(), id(self))
-
- _ram_storage = ZODB.MappingStorage.MappingStorage()
- _ram_db = ZODB.DB(_ram_storage)
- _conns = {}
-
- def _getData(self):
-
- # Open a connection to _ram_storage per thread
- tid = thread.get_ident()
- if not self._conns.has_key(tid):
- self._conns[tid] = self._ram_db.open()
-
- root = self._conns[tid].root()
- if not root.has_key(self.key):
- root[self.key] = OOBTree()
- return root[self.key]
-
- data = property(_getData, None)
-
- def sweep(self):
- super(RAMSessionDataContainer, self).sweep()
- self._ram_db.pack(time.time())
-
-
-class Session(object):
- """See zope.app.session.interfaces.ISession"""
- implements(ISession)
- adapts(IRequest)
-
- def __init__(self, request):
- self.client_id = str(IClientId(request))
-
- def _sdc(self, pkg_id):
- # Locate the ISessionDataContainer by looking up the named
- # Utility, and falling back to the unnamed one.
- try:
- return getUtility(ISessionDataContainer, pkg_id)
- except ComponentLookupError:
- return getUtility(ISessionDataContainer)
-
- def get(self, pkg_id, default=None):
-
- """See zope.app.session.interfaces.ISession
-
- >>> import tests
- >>> request = tests.setUp(PersistentSessionDataContainer)
-
- If we use get we get None or default returned if the pkg_id
- is not there.
-
- >>> session = Session(request).get('not.there', 'default')
- >>> session
- 'default'
-
- This method is lazy and does not create the session data.
- >>> session = Session(request).get('not.there')
- >>> session is None
- True
-
- The __getitem__ method instead creates the data.
- >>> session = Session(request)['not.there']
- >>> session is None
- False
- >>> session = Session(request).get('not.there')
- >>> session is None
- False
- >>> tests.tearDown()
-
- """
-
-
- # The ISessionDataContainer contains two levels:
- # ISessionDataContainer[client_id] == ISessionData
- # ISessionDataContainer[client_id][pkg_id] == ISessionPkgData
- sdc = self._sdc(pkg_id)
- try:
- sd = sdc[self.client_id]
- except KeyError:
- return default
- try:
- return sd[pkg_id]
- except KeyError:
- return default
-
-
- def __getitem__(self, pkg_id):
- """See zope.app.session.interfaces.ISession
-
- >>> import tests
- >>> request = tests.setUp(PersistentSessionDataContainer)
- >>> request2 = tests.HTTPRequest(StringIO(''), {}, None)
-
- >>> ISession.providedBy(Session(request))
- True
-
- Setup some sessions, each with a distinct namespace
-
- >>> session1 = Session(request)['products.foo']
- >>> session2 = Session(request)['products.bar']
- >>> session3 = Session(request2)['products.bar']
-
- If we use the same parameters, we should retrieve the
- same object
-
- >>> session1 is Session(request)['products.foo']
- True
-
- Make sure it returned sane values
-
- >>> ISessionPkgData.providedBy(session1)
- True
-
- Make sure that pkg_ids don't share a namespace.
-
- >>> session1['color'] = 'red'
- >>> session2['color'] = 'blue'
- >>> session3['color'] = 'vomit'
- >>> session1['color']
- 'red'
- >>> session2['color']
- 'blue'
- >>> session3['color']
- 'vomit'
-
- >>> tests.tearDown()
-
- """
- sdc = self._sdc(pkg_id)
-
- # The ISessionDataContainer contains two levels:
- # ISessionDataContainer[client_id] == ISessionData
- # ISessionDataContainer[client_id][pkg_id] == ISessionPkgData
- try:
- sd = sdc[self.client_id]
- except KeyError:
- sd = sdc[self.client_id] = SessionData()
-
- try:
- return sd[pkg_id]
- except KeyError:
- spd = sd[pkg_id] = SessionPkgData()
- return spd
-
-
-class SessionData(Persistent, IterableUserDict):
- """See zope.app.session.interfaces.ISessionData
-
- >>> session = SessionData()
- >>> ISessionData.providedBy(session)
- True
- >>> session.lastAccessTime
- 0
-
- Before the zope.minmax package this class used to have an attribute
- lastAccessTime initialized in the class itself to zero.
- To avoid changing the interface, that attribute has been turned into a
- property. This part tests the behavior of a legacy session which would
- have the lastAccessTime attribute loaded from the database.
- The implementation should work for that case as well as with the new
- session where lastAccessTime is a property. These tests will
- be removed in a later release (see the comments in the code below).
-
- First, create an instance of SessionData and remove a protected attribute
- _lastAcessTime from it to make it more like the legacy SessionData. The
- subsequent attempt to get lastAccessTime will return a 0, because the
- lastAccessTime is not there and the dictionary returns the default value
- zero supplied to its get() method.
-
- >>> legacy_session = SessionData()
- >>> del legacy_session._lastAccessTime
- >>> legacy_session.lastAccessTime
- 0
-
- Now, artificially add lastAccessTime to the instance's dictionary.
- This should make it exactly like the legacy SessionData().
-
- >>> legacy_session.__dict__['lastAccessTime'] = 42
- >>> legacy_session.lastAccessTime
- 42
-
- Finally, assign to lastAccessTime. Since the instance now looks like a
- legacy instance, this will trigger, through the property mechanism, a
- creation of a zope.minmax.Maximum() object which will take over the
- handling of this value and its conflict resolution from now on.
-
- >>> legacy_session.lastAccessTime = 13
- >>> legacy_session._lastAccessTime.value
- 13
-
- """
- implements(ISessionData)
-
- # this is for support of legacy sessions; this comment and
- # the next line will be removed in a later release
- _lastAccessTime = None
-
- def __init__(self):
- self.data = OOBTree()
- self._lastAccessTime = zope.minmax.Maximum(0)
-
- def _getLastAccessTime(self):
- # this conditional is for legacy sessions; this comment and
- # the next two lines will be removed in a later release
- if self._lastAccessTime is None:
- return self.__dict__.get('lastAccessTime', 0)
- return self._lastAccessTime.value
-
- def _setLastAccessTime(self, value):
- # this conditional is for legacy sessions; this comment and
- # the next two lines will be removed in a later release
- if self._lastAccessTime is None:
- self._lastAccessTime = zope.minmax.Maximum(0)
- self._lastAccessTime.value = value
-
- lastAccessTime = property(fget=_getLastAccessTime,
- fset=_setLastAccessTime,
- doc='integer value of the last access time')
-
-
-class SessionPkgData(Persistent, IterableUserDict):
- """See zope.app.session.interfaces.ISessionData
-
- >>> session = SessionPkgData()
- >>> ISessionPkgData.providedBy(session)
- True
- """
- implements(ISessionPkgData)
- def __init__(self):
- self.data = OOBTree()
-
+zope.deferredimport.deprecated(
+ "It has moved to zope.session.session This reference will be gone sometimes.",
+ SessionData = 'zope.session.session:SessionData',
+ SessionPkgData = 'zope.session.session:SessionPkgData',
+ Session = 'zope.session.session:Session',
+ RAMSessionDataContainer = 'zope.session.session:RAMSessionDataContainer',
+ PersistentSessionDataContainer = 'zope.session.session:PersistentSessionDataContainer',
+ ClientId = 'zope.session.session:ClientId',
+ digestEncode = 'zope.session.session:digestEncode',
+ cookieSafeTrans = 'zope.session.session:cookieSafeTrans',
+ )
Modified: zope.app.session/trunk/src/zope/app/session/tests.py
===================================================================
--- zope.app.session/trunk/src/zope/app/session/tests.py 2007-09-25 21:28:25 UTC (rev 80053)
+++ zope.app.session/trunk/src/zope/app/session/tests.py 2007-09-25 21:28:40 UTC (rev 80054)
@@ -22,30 +22,24 @@
from zope.app.testing import ztapi, placelesssetup
import transaction
-from zope.app.session.interfaces import IClientId, IClientIdManager, ISession
-from zope.app.session.interfaces import ISessionDataContainer
-from zope.app.session.interfaces import ISessionPkgData, ISessionData
+import zope.component
+from zope.session.interfaces import IClientId, IClientIdManager, ISession
+from zope.session.interfaces import ISessionDataContainer
+from zope.session.interfaces import ISessionPkgData, ISessionData
+from zope.session.session import ClientId, Session
+from zope.session.session import PersistentSessionDataContainer
+from zope.session.session import RAMSessionDataContainer
+from zope.session.http import CookieClientIdManager
-from zope.app.session.session import ClientId, Session
-from zope.app.session.session import PersistentSessionDataContainer
-from zope.app.session.session import RAMSessionDataContainer
-
-from zope.app.session.http import CookieClientIdManager
-
from zope.publisher.interfaces import IRequest
from zope.publisher.http import HTTPRequest
-from zope.app.appsetup.tests import TestBootstrapSubscriber, EventStub
-from zope.app.appsetup.bootstrap import bootStrapSubscriber
-from zope.app.session.bootstrap import bootStrapSubscriber as \
- sessionBootstrapSubscriber
-
-from zope.component import provideHandler, getGlobalSiteManager
from zope.app.folder import Folder
from zope.app.folder.interfaces import IRootFolder
from zope.app.publication.interfaces import IBeforeTraverseEvent
from zope.app.testing.functional import BrowserTestCase
from zope.app.zptpage.zptpage import ZPTPage
+
from zope.app.session.testing import SessionLayer
@@ -63,28 +57,7 @@
def tearDown():
placelesssetup.tearDown()
-class TestBootstrap(TestBootstrapSubscriber):
- def test_bootstrapSusbcriber(self):
- bootStrapSubscriber(EventStub(self.db))
-
- sessionBootstrapSubscriber(EventStub(self.db))
-
- from zope.app.publication.zopepublication import ZopePublication
- from zope.app.component.hooks import setSite
- from zope.app import zapi
-
- cx = self.db.open()
- root = cx.root()
- root_folder = root[ZopePublication.root_name]
- setSite(root_folder)
-
- zapi.getUtility(IClientIdManager)
- zapi.getUtility(ISessionDataContainer)
-
-
- cx.close()
-
# Test the code in our API documentation is correct
def test_documentation():
pass
@@ -102,10 +75,6 @@
transaction.abort()
-
-
-from interfaces import ISession
-
class ZPTSessionTest(BrowserTestCase):
content = u'''
<div tal:define="
@@ -145,6 +114,7 @@
response3 = self.fetch()
self.failUnlessEqual(response3, u'3')
+
class VirtualHostSessionTest(BrowserTestCase):
def setUp(self):
super(VirtualHostSessionTest, self).setUp()
@@ -156,11 +126,11 @@
root['folder']['page'] = page
self.commit()
- provideHandler(self.accessSessionOnRootTraverse,
+ zope.component.provideHandler(self.accessSessionOnRootTraverse,
(IBeforeTraverseEvent,))
def tearDown(self):
- getGlobalSiteManager().unregisterHandler(
+ zope.component.getGlobalSiteManager().unregisterHandler(
self.accessSessionOnRootTraverse, (IBeforeTraverseEvent,))
def accessSessionOnRootTraverse(self, event):
@@ -191,13 +161,7 @@
ZPTSessionTest.layer = SessionLayer
VirtualHostSessionTest.layer = SessionLayer
suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(TestBootstrap))
suite.addTest(doctest.DocTestSuite())
- suite.addTest(doctest.DocTestSuite('zope.app.session.session',
- tearDown=tearDownTransaction))
- suite.addTest(doctest.DocTestSuite('zope.app.session.http',
- optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,)
- )
suite.addTest(unittest.makeSuite(ZPTSessionTest))
suite.addTest(unittest.makeSuite(VirtualHostSessionTest))
return suite
More information about the Checkins
mailing list