PageRenderTime 39ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/django/contrib/sessions/backends/file.py

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