root/galaxy-central/eggs/Paste-1.6-py2.6.egg/paste/session.py

リビジョン 3, 10.9 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

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