2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Web / System.Web.SessionState / SessionInProcHandler.cs
index 0973a92ae59495a982d1f20bd1e54b6cdae50f95..e0a327f822811ab385c71a2188de3fc282113677 100644 (file)
 //
 // 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;
                }
        }
 }