mirror of https://github.com/django/django.git
Fixed #8616 -- Fixed a race condition in the file-based session backend.
Thanks to warren@wandrsmith.net for the patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8688 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
6e841ca767
commit
02f86a1c7c
1
AUTHORS
1
AUTHORS
|
@ -363,6 +363,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Ben Slavin <benjamin.slavin@gmail.com>
|
Ben Slavin <benjamin.slavin@gmail.com>
|
||||||
sloonz <simon.lipp@insa-lyon.fr>
|
sloonz <simon.lipp@insa-lyon.fr>
|
||||||
SmileyChris <smileychris@gmail.com>
|
SmileyChris <smileychris@gmail.com>
|
||||||
|
Warren Smith <warren@wandrsmith.net>
|
||||||
smurf@smurf.noris.de
|
smurf@smurf.noris.de
|
||||||
Vsevolod Solovyov
|
Vsevolod Solovyov
|
||||||
sopel
|
sopel
|
||||||
|
|
|
@ -5,7 +5,9 @@ import tempfile
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.sessions.backends.base import SessionBase, CreateError
|
from django.contrib.sessions.backends.base import SessionBase, CreateError
|
||||||
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
|
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
|
||||||
|
from django.core.files import locks
|
||||||
|
|
||||||
|
IO_LOCK_SUFFIX = "_iolock"
|
||||||
|
|
||||||
class SessionStore(SessionBase):
|
class SessionStore(SessionBase):
|
||||||
"""
|
"""
|
||||||
|
@ -42,8 +44,22 @@ class SessionStore(SessionBase):
|
||||||
|
|
||||||
return os.path.join(self.storage_path, self.file_prefix + session_key)
|
return os.path.join(self.storage_path, self.file_prefix + session_key)
|
||||||
|
|
||||||
|
def _key_to_io_lock_file(self, session_key=None):
|
||||||
|
"""
|
||||||
|
Get the I/O lock file associated with this session key.
|
||||||
|
"""
|
||||||
|
return self._key_to_file(session_key) + IO_LOCK_SUFFIX
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
session_data = {}
|
session_data = {}
|
||||||
|
try:
|
||||||
|
# Open and acquire a shared lock on the I/O lock file before
|
||||||
|
# attempting to read the session file. This makes us wait to read
|
||||||
|
# the session file until another thread or process is finished
|
||||||
|
# writing it.
|
||||||
|
lock_path = self._key_to_io_lock_file()
|
||||||
|
io_lock_file = open(lock_path, "rb")
|
||||||
|
locks.lock(io_lock_file, locks.LOCK_SH)
|
||||||
try:
|
try:
|
||||||
session_file = open(self._key_to_file(), "rb")
|
session_file = open(self._key_to_file(), "rb")
|
||||||
try:
|
try:
|
||||||
|
@ -53,6 +69,10 @@ class SessionStore(SessionBase):
|
||||||
self.create()
|
self.create()
|
||||||
finally:
|
finally:
|
||||||
session_file.close()
|
session_file.close()
|
||||||
|
finally:
|
||||||
|
locks.unlock(io_lock_file)
|
||||||
|
io_lock_file.close()
|
||||||
|
os.unlink(lock_path)
|
||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
return session_data
|
return session_data
|
||||||
|
@ -75,12 +95,24 @@ class SessionStore(SessionBase):
|
||||||
# Because this may trigger a load from storage, we must do it before
|
# Because this may trigger a load from storage, we must do it before
|
||||||
# truncating the file to save.
|
# truncating the file to save.
|
||||||
session_data = self._get_session(no_load=must_create)
|
session_data = self._get_session(no_load=must_create)
|
||||||
|
try:
|
||||||
|
# Open and acquire an exclusive lock on the I/O lock file before
|
||||||
|
# attempting to write the session file. This makes other threads
|
||||||
|
# or processes wait to read or write the session file until we are
|
||||||
|
# finished writing it.
|
||||||
|
lock_path = self._key_to_io_lock_file()
|
||||||
|
io_lock_file = open(lock_path, "wb")
|
||||||
|
locks.lock(io_lock_file, locks.LOCK_EX)
|
||||||
try:
|
try:
|
||||||
fd = os.open(self._key_to_file(self.session_key), flags)
|
fd = os.open(self._key_to_file(self.session_key), flags)
|
||||||
try:
|
try:
|
||||||
os.write(fd, self.encode(session_data))
|
os.write(fd, self.encode(session_data))
|
||||||
finally:
|
finally:
|
||||||
os.close(fd)
|
os.close(fd)
|
||||||
|
finally:
|
||||||
|
locks.unlock(io_lock_file)
|
||||||
|
io_lock_file.close()
|
||||||
|
os.unlink(lock_path)
|
||||||
except OSError, e:
|
except OSError, e:
|
||||||
if must_create and e.errno == errno.EEXIST:
|
if must_create and e.errno == errno.EEXIST:
|
||||||
raise CreateError
|
raise CreateError
|
||||||
|
|
Loading…
Reference in New Issue