{% extends "base-new.html" %} {% block header-content %}

Session

Sessions are used to maintain user presence between requests.

Sessions can either be stored server side in the datastore/memcache, or be kept entirely as cookies. This is set either with the settings file or on initialization, using the writer argument/setting field. Valid values are "datastore" or "cookie".

Session can be used as a standard dictionary object.

        session = appengine_utilities.sessions.Session()
        session["keyname"] = "value" # sets keyname to value
        print session["keyname"] # will print value
    

Datastore Writer: The datastore writer was written with the focus being on security, reliability, and performance. In that order. It is based off of a session token system. All data is stored server side in the datastore and memcache. A token is given to the browser, and stored server side. Optionally (and on by default), user agent and ip checking is enabled. Tokens have a configurable time to live (TTL), which defaults to 5 seconds. The current token, plus the previous 2, are valid for any request. This is done in order to manage ajax enabled sites which may have more than on request happening at a time. This means any token is valid for 15 seconds. A request with a token who's TTL has passed will have a new token generated.

In order to take advantage of the token system for an authentication system, you will want to tie sessions to accounts, and make sure only one session is valid for an account. You can do this by setting a db.ReferenceProperty(_AppEngineUtilities_Session) attribute on your user Model, and use the get_ds_entity() method on a valid session to populate it on login.

Note that even with this complex system, sessions can still be hijacked and it will take the user logging in to retrieve the account. In the future an ssl only cookie option may be implemented for the datastore writer, which would further protect the session token from being sniffed, however it would be restricted to using cookies on the .appspot.com domain, and ssl requests are a finite resource. This is why such a thing is not currently implemented.

Session data objects are stored in the datastore pickled, so any python object is valid for storage.

Cookie Writer: Sessions using the cookie writer are stored entirely in the browser and no interaction with the datastore is required. This creates a drastic improvement in performance, but provides no security for session hijack. This is useful for requests where identity is not important, but you wish to keep state between requests.

Information is stored in a json format, as pickled data from the server is unreliable.

Note: There is no checksum validation of session data on this method, it's streamlined for pure performance. If you need to make sure data is not tampered with, use the datastore writer which stores the data server side.

django-middleware: Included with the GAEUtilties project is a django-middleware.middleware.SessionMiddleware which can be included in your settings file. This uses the cookie writer for anonymous requests, and you can switch to the datastore writer on user login. This will require an extra set in your login process of calling request.session.save() once you validated the user information. This will convert the cookie writer based session to a datastore writer.

{% endblock %} {% block content %} {% if sess.flash %}

{{ sess.flash }}

{% endif %}

Welcome to the sessions demo. You've viewed this page {{ sess.viewCount }} times during this session. Your session id is {{ sess.sid }} There are {{ session_length }} objects in your session data.
iteration test
{% for k in sess %}
  • {{ k }}
  • {% endfor %}
    items test
    {% for i in sess.items %}
  • {{ i }}
  • {% endfor %}
    keys test
    {% for k in sess.keys %}
  • {{ k }}
  • {% endfor %}
    values test
    {% for v in sess.values %}
  • {{ v }}
  • {% endfor %}
    model_test testval = {{ model_test }}
    {{ protobuf }}
    {{ testkey }}

    {% filter escape %}
    {{ model_xml }}
    {% endfilter %}
    
    When the Django template library is upgraded this demo can be modified to show the values as well. For now this is enough to demonstrate iteration support.
    view this page again
    set flash data
    delete your session and start over
    clear the test key
    set the test key

    Memcache stats: {{ memcacheStats }}

    Session str: {{ sess_str }}

    webapp class

    {% filter escape %}class SessionTestModel(db.Model):
        testval = db.StringProperty()
    
    class SessionPage(webapp.RequestHandler):
      def get(self):
        self.sess = sessions.Session()
        if not self.sess.has_key("model_test"):
            self.sess["model_test"] = SessionTestModel(testval="test")
            self.sess["model_test"].put()
            # give the datastore time to submit the commit
            time.sleep(1)
        self.cookie_sess = sessions.Session(writer="cookie")
        if self.request.get('deleteSession') == "true":
            self.sess.delete()
            print "Location: /session\n\n"
        elif self.request.get('setflash') == "true":
            self.sess['flash'] = 'You set a flash message! Refresh this page and this message is gone!'
            print "Location: /session\n\n"
        elif self.request.get('setTestKey') == "true":
            self.sess['DeletableKey'] = 'delete me'
            print "Location: /session\n\n"
        elif self.request.get('clearTestKey') == "true":
            self.sess.delete_item('DeletableKey')
            print "Location: /session\n\n"
        else:
            keyname = 'testKey'
            self.sess[keyname] = "test"
            self.sess[keyname + '2'] = "test2"
            self.sess[3] = "test3"
            self.cookie_sess['cookie_test'] = "testing cookie values"
            self.sess[u"unicode_key"] = u"unicode_value"
    
            if not 'viewCount' in self.sess:
                self.sess['viewCount'] = 1
            else:
                self.sess['viewCount'] = int(self.sess['viewCount']) + 1
            self.sess["model_test"].testval = unicode(self.sess['viewCount'])
            testkey = self.sess["model_test"].put()
            session_length = len(self.sess)
            self.memcacheStats = memcache.get_stats()
            template_values = {
                'sess': self.sess,
                'sess_str': str(self.sess),
                'cookie_sess': self.cookie_sess,
                'session_length': session_length,
                'memcacheStats': self.memcacheStats,
                'model_test': self.sess["model_test"].testval,
                'testkey': testkey,
            }
            path = os.path.join(os.path.dirname(__file__), 'templates/session-new.html')
            self.response.out.write(template.render(path, template_values)){% endfilter %}
    
    {% endblock %}