2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Web / System.Web.SessionState / SessionInProcHandler.cs
index ac560d49458bbb1059a187c61a1a84df673f70c3..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.
-*/
 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;
-               // The length of a session, in minutes. After this length, it's abandoned due to idle.
-               const int SESSION_LIFETIME = 45;
-
-               private SessionConfig config;
+               SessionConfig config;
+               CacheItemRemovedCallback removedCB;
                
-               public void Dispose ()
-               {
-                       _sessionTable = null;
-               }
+               public void Dispose () { }
 
-               public void Init (HttpApplication context, SessionConfig config)
+               public void Init (SessionStateModule module, HttpApplication context, SessionConfig config)
                {
+                       removedCB = new CacheItemRemovedCallback (module.OnSessionRemoved);
                        this.config = config;
-                       _sessionTable = (Hashtable) AppDomain.CurrentDomain.GetData (".MonoSessionInProc");
-                       if (_sessionTable == null)
-                               _sessionTable = new Hashtable();
                }
 
-               public void UpdateHandler (HttpContext context, SessionStateModule module)
-               {
-               }
+               public void UpdateHandler (HttpContext context, SessionStateModule module) { }
 
-               //this is the code that actually do stuff.
-               public bool UpdateContext (HttpContext context, SessionStateModule module)
+               public HttpSessionState UpdateContext (HttpContext context, SessionStateModule module,
+                                                       bool required, bool read_only, ref bool isNew)
                {
-                       SessionContainer container = null;
+                       if (!required)
+                               return null;
+
+                       Cache cache = HttpRuntime.Cache;
+                       HttpSessionState state = null;
                        string id = SessionId.Lookup (context.Request, config.CookieLess);
                        
-                       //first we try to get the cookie.
-                       // if we have a cookie, we look it up in the table.
                        if (id != null) {
-                               container = (SessionContainer) _sessionTable [id];
-
-                               // 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) {
-                                       _sessionTable.Remove (id);
-                               }
+                               state = (HttpSessionState) cache ["@@@InProc@" + id];
+                               if (state != null)
+                                       return state;
                        }
 
-                       // else we create a new session.
+                       // Create a new session.
                        string sessionID = SessionId.Create (module.Rng);
-                       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,
-                                                                               module.IsReadOnly)); //readonly
-                       // puts it in the table.
-                       _sessionTable [sessionID]=container;
-                       AppDomain.CurrentDomain.SetData (".MonoSessionInProc", _sessionTable);
-
-                       // and returns it.
-                       context.SetSession (container.SessionState);
-                       context.Session.IsNewSession = true;
-
-                       // And we're done!
-                       return true;
+                       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;
                }
        }
 }