web/lib/django/contrib/sessions/backends/file.py
changeset 0 0d40e90630ef
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     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