//
// Authors:
// Stefan Görling (stefan@gorling.se)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
//
// (C) 2003 Stefan Görling
+// Copyright (c) 2004 Novell, Inc. (http://www.novell.com)
//
-/*
- This is a rather lazy implementation, but it does the trick for me.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
- TODO:
- * Remove abandoned sessions., preferably by a worker thread sleeping most of the time.
- * Increase session security, for example by using UserAgent i hashcode.
- * Generate SessionID:s in a good (more random) way.
-*/
using System;
+using System.IO;
using System.Collections;
+using System.Web.Caching;
namespace System.Web.SessionState
{
- // Container object, containing the current session state and when it was last accessed.
- internal class SessionContainer
- {
- private HttpSessionState _state;
- private DateTime last_access;
-
- public SessionContainer (HttpSessionState state)
- {
- _state = state;
- this.Touch ();
- }
-
- public void Touch ()
- {
- last_access = DateTime.Now;
- }
-
- public HttpSessionState SessionState {
- get {
- //Check if we should abandon it.
- if (_state != null && last_access.AddMinutes (_state.Timeout) < DateTime.Now)
- _state.Abandon ();
-
- return _state;
- }
- set {
- _state=value;
- this.Touch ();
- }
- }
- }
-
-
- internal class SessionInProcHandler : ISessionHandler
+ class SessionInProcHandler : ISessionHandler
{
- protected Hashtable _sessionTable;
- const string COOKIE_NAME = "ASPSESSION"; // The name of the cookie.
- // The length of a session, in minutes. After this length, it's abandoned due to idle.
- const int SESSION_LIFETIME = 45;
+ SessionConfig config;
+ CacheItemRemovedCallback removedCB;
+
+ public void Dispose () { }
- public void Dispose ()
+ public void Init (SessionStateModule module, HttpApplication context, SessionConfig config)
{
- _sessionTable = null;
+ removedCB = new CacheItemRemovedCallback (module.OnSessionRemoved);
+ this.config = config;
}
- public void Init (HttpApplication context, SessionConfig config)
- {
- _sessionTable = new Hashtable();
- }
-
- public void UpdateHandler (HttpContext context)
- {
- }
+ public void UpdateHandler (HttpContext context, SessionStateModule module) { }
- //this is the code that actually do stuff.
- public bool UpdateContext (HttpContext context)
+ public HttpSessionState UpdateContext (HttpContext context, SessionStateModule module,
+ bool required, bool read_only, ref bool isNew)
{
- SessionContainer container = null;
-
- //first we try to get the cookie.
- // if we have a cookie, we look it up in the table.
- if (context.Request.Cookies [COOKIE_NAME] != null) {
- container = (SessionContainer) _sessionTable [context.Request.Cookies [COOKIE_NAME].Value];
-
- // if we have a session, and it is not expired, set isNew to false and return it.
- if (container!=null && container.SessionState!=null && !container.SessionState.IsAbandoned) {
- // Can we do this? It feels safe, but what do I know.
- container.SessionState.IsNewSession = false;
- // update the timestamp.
- container.Touch ();
- // Can we do this? It feels safe, but what do I know.
- context.SetSession (container.SessionState);
- return false; // and we're done
- } else if(container!=null) {
- //A empty or expired session, lets kill it.
- _sessionTable[context.Request.Cookies[COOKIE_NAME]]=null;
- }
+ if (!required)
+ return null;
+
+ Cache cache = HttpRuntime.Cache;
+ HttpSessionState state = null;
+ string id = SessionId.Lookup (context.Request, config.CookieLess);
+
+ if (id != null) {
+ state = (HttpSessionState) cache ["@@@InProc@" + id];
+ if (state != null)
+ return state;
}
- // else we create a new session.
- string sessionID = System.Guid.NewGuid ().ToString ();
- container = new SessionContainer (new HttpSessionState (sessionID, // unique identifier
- new SessionDictionary(), // dictionary
- new HttpStaticObjectsCollection(),
- SESSION_LIFETIME, //lifetime befor death.
- true, //new session
- false, // is cookieless
- SessionStateMode.InProc,
- false)); //readonly
- // puts it in the table.
- _sessionTable [sessionID]=container;
-
- // and returns it.
- context.SetSession (container.SessionState);
- context.Session.IsNewSession = true;
-
-
- // sets the session cookie. We're assuming that session scope is the default mode.
- context.Response.AppendCookie (new HttpCookie (COOKIE_NAME,sessionID));
-
- // And we're done!
- return true;
+ // Create a new session.
+ string sessionID = SessionId.Create (module.Rng);
+ state = new HttpSessionState (sessionID, // unique identifier
+ new SessionDictionary(), // dictionary
+ HttpApplicationFactory.ApplicationState.SessionObjects,
+ config.Timeout, //lifetime before death.
+ true, //new session
+ false, // is cookieless
+ SessionStateMode.InProc,
+ read_only); //readonly
+
+ TimeSpan timeout = new TimeSpan (0, config.Timeout, 0);
+ cache.Insert ("@@@InProc@" + sessionID, state, null, DateTime.Now + timeout,
+ timeout, CacheItemPriority.AboveNormal, removedCB);
+
+ isNew = true;
+ return state;
}
}
}