~canonical-django/canonical-django/project-template

« back to all changes in this revision

Viewing changes to trunk/python-packages/django/contrib/sessions/backends/file.py

  • Committer: Matthew Nuzum
  • Date: 2008-11-13 05:46:03 UTC
  • Revision ID: matthew.nuzum@canonical.com-20081113054603-v0kvr6z6xyexvqt3
adding to version control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import errno
 
2
import os
 
3
import tempfile
 
4
 
 
5
from django.conf import settings
 
6
from django.contrib.sessions.backends.base import SessionBase, CreateError
 
7
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
 
8
 
 
9
 
 
10
class SessionStore(SessionBase):
 
11
    """
 
12
    Implements a file based session store.
 
13
    """
 
14
    def __init__(self, session_key=None):
 
15
        self.storage_path = getattr(settings, "SESSION_FILE_PATH", None)
 
16
        if not self.storage_path:
 
17
            self.storage_path = tempfile.gettempdir()
 
18
 
 
19
        # Make sure the storage path is valid.
 
20
        if not os.path.isdir(self.storage_path):
 
21
            raise ImproperlyConfigured(
 
22
                "The session storage path %r doesn't exist. Please set your"
 
23
                " SESSION_FILE_PATH setting to an existing directory in which"
 
24
                " Django can store session data." % self.storage_path)
 
25
 
 
26
        self.file_prefix = settings.SESSION_COOKIE_NAME
 
27
        super(SessionStore, self).__init__(session_key)
 
28
 
 
29
    def _key_to_file(self, session_key=None):
 
30
        """
 
31
        Get the file associated with this session key.
 
32
        """
 
33
        if session_key is None:
 
34
            session_key = self.session_key
 
35
 
 
36
        # Make sure we're not vulnerable to directory traversal. Session keys
 
37
        # should always be md5s, so they should never contain directory
 
38
        # components.
 
39
        if os.path.sep in session_key:
 
40
            raise SuspiciousOperation(
 
41
                "Invalid characters (directory components) in session key")
 
42
 
 
43
        return os.path.join(self.storage_path, self.file_prefix + session_key)
 
44
 
 
45
    def load(self):
 
46
        session_data = {}
 
47
        try:
 
48
            session_file = open(self._key_to_file(), "rb")
 
49
            try:
 
50
                file_data = session_file.read()
 
51
                # Don't fail if there is no data in the session file.
 
52
                # We may have opened the empty placeholder file.
 
53
                if file_data:
 
54
                    try:
 
55
                        session_data = self.decode(file_data)
 
56
                    except (EOFError, SuspiciousOperation):
 
57
                        self.create()
 
58
            finally:
 
59
                session_file.close()
 
60
        except IOError:
 
61
            pass
 
62
        return session_data
 
63
 
 
64
    def create(self):
 
65
        while True:
 
66
            self._session_key = self._get_new_session_key()
 
67
            try:
 
68
                self.save(must_create=True)
 
69
            except CreateError:
 
70
                continue
 
71
            self.modified = True
 
72
            self._session_cache = {}
 
73
            return
 
74
 
 
75
    def save(self, must_create=False):
 
76
        # Get the session data now, before we start messing
 
77
        # with the file it is stored within.
 
78
        session_data = self._get_session(no_load=must_create)
 
79
 
 
80
        session_file_name = self._key_to_file()
 
81
 
 
82
        try:
 
83
            # Make sure the file exists.  If it does not already exist, an
 
84
            # empty placeholder file is created.
 
85
            flags = os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0)
 
86
            if must_create:
 
87
                flags |= os.O_EXCL
 
88
            fd = os.open(session_file_name, flags)
 
89
            os.close(fd)
 
90
 
 
91
        except OSError, e:
 
92
            if must_create and e.errno == errno.EEXIST:
 
93
                raise CreateError
 
94
            raise
 
95
 
 
96
        # Write the session file without interfering with other threads
 
97
        # or processes.  By writing to an atomically generated temporary
 
98
        # file and then using the atomic os.rename() to make the complete
 
99
        # file visible, we avoid having to lock the session file, while
 
100
        # still maintaining its integrity.
 
101
        #
 
102
        # Note: Locking the session file was explored, but rejected in part
 
103
        # because in order to be atomic and cross-platform, it required a
 
104
        # long-lived lock file for each session, doubling the number of
 
105
        # files in the session storage directory at any given time.  This
 
106
        # rename solution is cleaner and avoids any additional overhead
 
107
        # when reading the session data, which is the more common case
 
108
        # unless SESSION_SAVE_EVERY_REQUEST = True.
 
109
        #
 
110
        # See ticket #8616.
 
111
        dir, prefix = os.path.split(session_file_name)
 
112
 
 
113
        try:
 
114
            output_file_fd, output_file_name = tempfile.mkstemp(dir=dir,
 
115
                prefix=prefix + '_out_')
 
116
            renamed = False
 
117
            try:
 
118
                try:
 
119
                    os.write(output_file_fd, self.encode(session_data))
 
120
                finally:
 
121
                    os.close(output_file_fd)
 
122
                os.rename(output_file_name, session_file_name)
 
123
                renamed = True
 
124
            finally:
 
125
                if not renamed:
 
126
                    os.unlink(output_file_name)
 
127
 
 
128
        except (OSError, IOError, EOFError):
 
129
            pass
 
130
 
 
131
    def exists(self, session_key):
 
132
        if os.path.exists(self._key_to_file(session_key)):
 
133
            return True
 
134
        return False
 
135
 
 
136
    def delete(self, session_key=None):
 
137
        if session_key is None:
 
138
            if self._session_key is None:
 
139
                return
 
140
            session_key = self._session_key
 
141
        try:
 
142
            os.unlink(self._key_to_file(session_key))
 
143
        except OSError:
 
144
            pass
 
145
 
 
146
    def clean(self):
 
147
        pass