Session class

Session that is maintained between HTTP requests.

Using sessions

A session is used to maintain state between HTTP requests. Once a session has been created, set a Session object as the request's Request.session property and it should be available to subsequent requests from that client. Sessions will be removed if the application explicitly invokes terminate on the session (and clears the Request.session property), or if it times out.

The timeout timer is automatically restarted when a new request arrives and the session is restored to it. Therefore, the session is kept alive by HTTP requests from the user.

The square bracket operators should be used to set and lookup application values associated with the session.

For example:

Future<Response> handleSuccessfulLogin(Request req) async {
  var uid = ...;
  ...
  var s = Session(req.server, new Duration(minutes: 10));
  s["user"] = uid;
  req.session = s; // important: gets the response to preserve the session
  ...
}

Future<Response> handleActivity(Request req) async {
  // the session (if available) will be automatically restored
  ...
  if (req.session != null) {
    // User is logged in
    var loggedInUser = req.session["user"];
    ...
  } else {
    // User is not logged in
  }
  ...
}

Future<Response> handleLogout(Request req) async {
  assert(req.session != null);
  await req.session.terminate();
  req.session = null; // important: gets the response to clear the session
  ...
}

Preserving sessions across HTTP requests

HTTP is a stateless protocol, so session preserving is implemented on top of HTTP using either cookies or URL rewriting. The application must perform extra steps to make this work.

Cookies

To use cookies, the package needs to find out if the client uses cookies. Not just if it supports cookies, but if cookie support has been turned on. The package detects this by seeing whether there are cookies set sent by the HTTP request (any cookies, not just the special session cookie). Therefore, the application must create a cookie in a previous HTTP response, before the HTTP request where the session will be created.

const String testCookieName = "browser-test";

Future<Response> handleShowLoginPage(Request req) async {
  var resp = ResponseBuffered(ContentType.HTML);

  // Add a test cookie to determine if cookies are supported
  var testCookie = Cookie(testCookieName, "cookies_work!");
  testCookie.path = req.server.basePath;
  testCookie.httpOnly = true;
  resp.cookieAdd(testCookie);
  ...
  return resp; // will _attempt_ to set the test cookie in the client.
}

Future<Response> handleSuccessfulLogin(Request req) async {
  // If the client uses cookies, the test cookie will have been presented
  // by the client with this HTTP request, and the package will know
  // that it can use cookies to remember the session.

  var uid = ...;
  ...
  var s = Session(req.server, new Duration(minutes: 10));
  s["user"] = uid;
  req.session = s; // important!
  ...
  var resp = ResponseBuffered(ContentType.HTML);

  // Remove the test cookie (if any) since it has done its job
  resp.cookieDelete(testCookieName, req.server.basePath);

  return resp; // the new session will be preserved using cookies if it can.
}

URL rewriting

URL rewriting can be used when cookies are not always available (such as if the client does not support cookies, or the user has disabled them).

To support URL rewriting, every URL within the application must be rewritten to add the session ID as a query parameter. This is done using the Request.rewriteUrl, Request.ura or Request.sessionHiddenInputElement methods.

   var dest = "~/foo/bar/baz";

   resp.write('<a href="${HEsc.attr(req.rewriteUrl(dest))}">link</a>);
   resp.write('<a href="${req.ura(dest)}">link</a>);

Recommendation

URL rewriting will always work as long as links containing the session ID are always followed. The client cannot go to an external page and then come back to a URL without the session ID. Cookies do not have this limitation (and the URLs look much cleaner without the session ID in them), but won't work if cookies are not used by the client. Therefore, it is recommended to use both mechanisms (i.e. try to enable cookies by creating a test coookie, and also perform URL rewriting throughout the application) unless cookie support can be guaranteed.

Lifecycle events

If the application is interested in the lifecycle events of the session, it should implement its own subclass of Session and use those objects as the session. It can then implement its own suspend, resume and finish methods, which will be invoked when those events occur. Note: there is no "start" method, because the application can use the constructor for that purpose.

An application might be interested in these events to persist session properties (e.g. save session properties in an external database). The base implementation keeps the sessions and their properties in memory.

The current API allows session properties to be saved, but the sessions themselves are still all maintained in memory. If this does not satisfy your needs, please raise an issue for the API to be enhanced.

Constructors

Session(Server server, Duration timeout)
Constructor

Properties

created DateTime
When the session was created.
no setter
expires DateTime
When the session will expire (unless refreshed or terminated early).
no setter
hashCode int
The hash code for this object.
no setterinherited
id String
Session ID
final
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
timeout Duration
Duration the session remains alive after the last HTTP request.
getter/setter pair

Methods

finish(SessionTermination endReason) Future
Invoked when a session is terminated.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
resume(Request req) Future<bool>
Invoked when a session is resumed.
suspend(Request req) Future
Invoked when the session is suspended.
terminate() Future
Explicitly terminate a session.
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited