1- import boto
1+ import os
2+ import time
23import logging
3- from boto .dynamodb .exceptions import DynamoDBKeyNotFoundError
4+
5+ import boto
46from django .conf import settings
5- from django .contrib .sessions .backends .base import SessionBase , CreateError
7+ from django .contrib .sessions .backends .base import SessionBase , CreateError , randrange , MAX_SESSION_KEY
8+ from django .utils .hashcompat import md5_constructor
9+ from boto .dynamodb .exceptions import DynamoDBKeyNotFoundError
10+ from boto .exception import DynamoDBResponseError
611
712TABLE_NAME = getattr (
813 settings , 'DYNAMODB_SESSIONS_TABLE_NAME' , 'sessions' )
@@ -52,6 +57,25 @@ def __init__(self, session_key=None):
5257 super (SessionStore , self ).__init__ (session_key )
5358 self .table = dynamodb_connection_factory ().get_table (TABLE_NAME )
5459
60+ def _get_new_session_key (self ):
61+ """
62+ Returns session key.
63+ """
64+ # The random module is seeded when this Apache child is created.
65+ # Use settings.SECRET_KEY as added salt.
66+ try :
67+ pid = os .getpid ()
68+ except AttributeError :
69+ # No getpid() in Jython, for example
70+ pid = 1
71+
72+ # Unlike the method this overrides, assume that the hash is good
73+ # to use. save(must_create=True) will make sure that this is
74+ # unique.
75+ return md5_constructor ("%s%s%s%s"
76+ % (randrange (0 , MAX_SESSION_KEY ), pid , time .time (),
77+ settings .SECRET_KEY )).hexdigest ()
78+
5579 def _get_or_create_session_key (self ):
5680 """
5781 This was added in Django 1.4 to SessionBase, but is simple enough to
@@ -107,8 +131,6 @@ def create(self):
107131 """
108132 logger .debug ("Creating a new session" )
109133 while True :
110- self .session_key = self ._get_new_session_key ()
111- logger .debug (" - New session key: %s" % self .session_key )
112134 try :
113135 # Save immediately to ensure we have a unique entry in the
114136 # database.
@@ -131,26 +153,40 @@ def save(self, must_create=False):
131153 :raises: ``CreateError`` if ``must_create`` is ``True`` and a session
132154 with the current session key already exists.
133155 """
134- session_key = self ._get_or_create_session_key ()
135- logger .debug ("Saving session: %s" % session_key )
156+ # This base64 encodes session data.
157+ data = self .encode (self ._get_session (no_load = must_create ))
158+
136159 if must_create :
137- logger .debug (" - Must create is True, checking for key first." )
138- key_already_exists = self .table .has_item (
139- session_key ,
140- consistent_read = ALWAYS_CONSISTENT
160+ # Force the generation of a new session key.
161+ self ._session_key = self ._get_new_session_key ()
162+ logger .debug (" - Saving new session: %s" % self ._session_key )
163+ item = self .table .new_item (
164+ self ._session_key ,
165+ # Stuff the base64 encoded stuff into the 'data' attrib.
166+ attrs = {
167+ 'data' : data ,
168+ # This will be used for session expiration.
169+ 'created' : int (time .time ()),
170+ }
141171 )
142- if key_already_exists :
172+ try :
173+ # We expect the 'data' attribute to not exist.
174+ item .put (expected_value = {'data' : False })
175+ except DynamoDBResponseError :
143176 # There's already an item with this key.
144177 raise CreateError
145-
146- # This base64 encodes session data.
147- data = self .encode (self ._get_session (no_load = must_create ))
148- item = self .table .new_item (
149- session_key ,
150- # Stuff the base64 encoded stuff into the 'data' attrib.
151- attrs = {'data' : data }
152- )
153- item .put ()
178+ else :
179+ self ._session_key = self ._get_or_create_session_key ()
180+ logger .debug ("Saving existing session: %s" % self ._session_key )
181+ # This isn't really creating a new item, just a container for
182+ # us to use put_attribute to queue an attrib update to.
183+ item = self .table .new_item (self ._session_key )
184+ # Queue up a PUT operation for UpdateItem, which preserves the
185+ # existing 'created' attribute.
186+ item .put_attribute ('data' , data )
187+ # Commits the PUT UpdateItem for the 'data' attrib, meanwhile
188+ # leaving the 'created' attrib un-touched.
189+ item .save ()
154190
155191 def delete (self , session_key = None ):
156192 """
0 commit comments