source: publico/il.spdo/trunk/Paste-1.7.5.1-py2.6.egg/paste/session.py @ 5327

Última Alteração nesse arquivo desde 5327 foi 5327, incluída por fabianosantos, 8 anos atrás

Import inicial.

File size: 11.1 KB
Linha 
1# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
2# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
3
4"""
5Creates a session object in your WSGI environment.
6
7Use like:
8
9..code-block:: Python
10
11    environ['paste.session.factory']()
12
13This will return a dictionary.  The contents of this dictionary will
14be saved to disk when the request is completed.  The session will be
15created when you first fetch the session dictionary, and a cookie will
16be sent in that case.  There's current no way to use sessions without
17cookies, and there's no way to delete a session except to clear its
18data.
19
20@@: This doesn't do any locking, and may cause problems when a single
21session is accessed concurrently.  Also, it loads and saves the
22session for each request, with no caching.  Also, sessions aren't
23expired.
24"""
25
26from Cookie import SimpleCookie
27import time
28import random
29import os
30import datetime
31import threading
32import tempfile
33
34try:
35    import cPickle
36except ImportError:
37    import pickle as cPickle
38try:
39    from hashlib import md5
40except ImportError:
41    from md5 import md5
42from paste import wsgilib
43from paste import request
44
45class SessionMiddleware(object):
46
47    def __init__(self, application, global_conf=None, **factory_kw):
48        self.application = application
49        self.factory_kw = factory_kw
50
51    def __call__(self, environ, start_response):
52        session_factory = SessionFactory(environ, **self.factory_kw)
53        environ['paste.session.factory'] = session_factory
54        remember_headers = []
55
56        def session_start_response(status, headers, exc_info=None):
57            if not session_factory.created:
58                remember_headers[:] = [status, headers]
59                return start_response(status, headers)
60            headers.append(session_factory.set_cookie_header())
61            return start_response(status, headers, exc_info)
62
63        app_iter = self.application(environ, session_start_response)
64        def start():
65            if session_factory.created and remember_headers:
66                # Tricky bastard used the session after start_response
67                status, headers = remember_headers
68                headers.append(session_factory.set_cookie_header())
69                exc = ValueError(
70                    "You cannot get the session after content from the "
71                    "app_iter has been returned")
72                start_response(status, headers, (exc.__class__, exc, None))
73        def close():
74            if session_factory.used:
75                session_factory.close()
76        return wsgilib.add_start_close(app_iter, start, close)
77
78
79class SessionFactory(object):
80
81
82    def __init__(self, environ, cookie_name='_SID_',
83                 session_class=None,
84                 session_expiration=60*12, # in minutes
85                 **session_class_kw):
86
87        self.created = False
88        self.used = False
89        self.environ = environ
90        self.cookie_name = cookie_name
91        self.session = None
92        self.session_class = session_class or FileSession
93        self.session_class_kw = session_class_kw
94
95        self.expiration = session_expiration
96
97    def __call__(self):
98        self.used = True
99        if self.session is not None:
100            return self.session.data()
101        cookies = request.get_cookies(self.environ)
102        session = None
103        if cookies.has_key(self.cookie_name):
104            self.sid = cookies[self.cookie_name].value
105            try:
106                session = self.session_class(self.sid, create=False,
107                                             **self.session_class_kw)
108            except KeyError:
109                # Invalid SID
110                pass
111        if session is None:
112            self.created = True
113            self.sid = self.make_sid()
114            session = self.session_class(self.sid, create=True,
115                                         **self.session_class_kw)
116        session.clean_up()
117        self.session = session
118        return session.data()
119
120    def has_session(self):
121        if self.session is not None:
122            return True
123        cookies = request.get_cookies(self.environ)
124        if cookies.has_key(self.cookie_name):
125            return True
126        return False
127
128    def make_sid(self):
129        # @@: need better algorithm
130        return (''.join(['%02d' % x for x in time.localtime(time.time())[:6]])
131                + '-' + self.unique_id())
132
133    def unique_id(self, for_object=None):
134        """
135        Generates an opaque, identifier string that is practically
136        guaranteed to be unique.  If an object is passed, then its
137        id() is incorporated into the generation.  Relies on md5 and
138        returns a 32 character long string.
139        """
140        r = [time.time(), random.random()]
141        if hasattr(os, 'times'):
142            r.append(os.times())
143        if for_object is not None:
144            r.append(id(for_object))
145        md5_hash = md5(str(r))
146        try:
147            return md5_hash.hexdigest()
148        except AttributeError:
149            # Older versions of Python didn't have hexdigest, so we'll
150            # do it manually
151            hexdigest = []
152            for char in md5_hash.digest():
153                hexdigest.append('%02x' % ord(char))
154            return ''.join(hexdigest)
155
156    def set_cookie_header(self):
157        c = SimpleCookie()
158        c[self.cookie_name] = self.sid
159        c[self.cookie_name]['path'] = '/'
160
161        gmt_expiration_time = time.gmtime(time.time() + (self.expiration * 60))
162        c[self.cookie_name]['expires'] = time.strftime("%a, %d-%b-%Y %H:%M:%S GMT", gmt_expiration_time)
163
164        name, value = str(c).split(': ', 1)
165        return (name, value)
166
167    def close(self):
168        if self.session is not None:
169            self.session.close()
170
171
172last_cleanup = None
173cleaning_up = False
174cleanup_cycle = datetime.timedelta(seconds=15*60) #15 min
175
176class FileSession(object):
177
178    def __init__(self, sid, create=False, session_file_path=tempfile.gettempdir(),
179                 chmod=None,
180                 expiration=2880, # in minutes: 48 hours
181                 ):
182        if chmod and isinstance(chmod, basestring):
183            chmod = int(chmod, 8)
184        self.chmod = chmod
185        if not sid:
186            # Invalid...
187            raise KeyError
188        self.session_file_path = session_file_path
189        self.sid = sid
190        if not create:
191            if not os.path.exists(self.filename()):
192                raise KeyError
193        self._data = None
194
195        self.expiration = expiration
196
197
198    def filename(self):
199        return os.path.join(self.session_file_path, self.sid)
200
201    def data(self):
202        if self._data is not None:
203            return self._data
204        if os.path.exists(self.filename()):
205            f = open(self.filename(), 'rb')
206            self._data = cPickle.load(f)
207            f.close()
208        else:
209            self._data = {}
210        return self._data
211
212    def close(self):
213        if self._data is not None:
214            filename = self.filename()
215            exists = os.path.exists(filename)
216            if not self._data:
217                if exists:
218                    os.unlink(filename)
219            else:
220                f = open(filename, 'wb')
221                cPickle.dump(self._data, f)
222                f.close()
223                if not exists and self.chmod:
224                    os.chmod(filename, self.chmod)
225
226    def _clean_up(self):
227        global cleaning_up
228        try:
229            exp_time = datetime.timedelta(seconds=self.expiration*60)
230            now = datetime.datetime.now()
231
232            #Open every session and check that it isn't too old
233            for root, dirs, files in os.walk(self.session_file_path):
234                for f in files:
235                    self._clean_up_file(f, exp_time=exp_time, now=now)
236        finally:
237            cleaning_up = False
238
239    def _clean_up_file(self, f, exp_time, now):
240        t = f.split("-")
241        if len(t) != 2:
242            return
243        t = t[0]
244        try:
245            sess_time = datetime.datetime(
246                    int(t[0:4]),
247                    int(t[4:6]),
248                    int(t[6:8]),
249                    int(t[8:10]),
250                    int(t[10:12]),
251                    int(t[12:14]))
252        except ValueError:
253            # Probably not a session file at all
254            return
255
256        if sess_time + exp_time < now:
257            os.remove(os.path.join(self.session_file_path, f))
258
259    def clean_up(self):
260        global last_cleanup, cleanup_cycle, cleaning_up
261        now = datetime.datetime.now()
262
263        if cleaning_up:
264            return
265
266        if not last_cleanup or last_cleanup + cleanup_cycle < now:
267            if not cleaning_up:
268                cleaning_up = True
269                try:
270                    last_cleanup = now
271                    t = threading.Thread(target=self._clean_up)
272                    t.start()
273                except:
274                    # Normally _clean_up should set cleaning_up
275                    # to false, but if something goes wrong starting
276                    # it...
277                    cleaning_up = False
278                    raise
279
280class _NoDefault(object):
281    def __repr__(self):
282        return '<dynamic default>'
283NoDefault = _NoDefault()
284
285def make_session_middleware(
286    app, global_conf,
287    session_expiration=NoDefault,
288    expiration=NoDefault,
289    cookie_name=NoDefault,
290    session_file_path=NoDefault,
291    chmod=NoDefault):
292    """
293    Adds a middleware that handles sessions for your applications.
294    The session is a peristent dictionary.  To get this dictionary
295    in your application, use ``environ['paste.session.factory']()``
296    which returns this persistent dictionary.
297
298    Configuration:
299
300      session_expiration:
301          The time each session lives, in minutes.  This controls
302          the cookie expiration.  Default 12 hours.
303
304      expiration:
305          The time each session lives on disk.  Old sessions are
306          culled from disk based on this.  Default 48 hours.
307
308      cookie_name:
309          The cookie name used to track the session.  Use different
310          names to avoid session clashes.
311
312      session_file_path:
313          Sessions are put in this location, default /tmp.
314
315      chmod:
316          The octal chmod you want to apply to new sessions (e.g., 660
317          to make the sessions group readable/writable)
318
319    Each of these also takes from the global configuration.  cookie_name
320    and chmod take from session_cookie_name and session_chmod
321    """
322    if session_expiration is NoDefault:
323        session_expiration = global_conf.get('session_expiration', 60*12)
324    session_expiration = int(session_expiration)
325    if expiration is NoDefault:
326        expiration = global_conf.get('expiration', 60*48)
327    expiration = int(expiration)
328    if cookie_name is NoDefault:
329        cookie_name = global_conf.get('session_cookie_name', '_SID_')
330    if session_file_path is NoDefault:
331        session_file_path = global_conf.get('session_file_path', '/tmp')
332    if chmod is NoDefault:
333        chmod = global_conf.get('session_chmod', None)
334    return SessionMiddleware(
335        app, session_expiration=session_expiration,
336        expiration=expiration, cookie_name=cookie_name,
337        session_file_path=session_file_path, chmod=chmod)
Note: Veja TracBrowser para ajuda no uso do navegador do trac.
 

The contents and data of this website are published under license:
Creative Commons 4.0 Brasil - Atribuir Fonte - Compartilhar Igual.