2004-02-09 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web.SessionState / SessionInProcHandler.cs
1 //
2 // System.Web.SessionState.SessionInProcHandler
3 //
4 // Authors:
5 //      Stefan Görling (stefan@gorling.se)
6 //
7 // (C) 2003 Stefan Görling
8 //
9
10 /*
11         This is a rather lazy implementation, but it does the trick for me.
12
13         TODO:
14             * Remove abandoned sessions., preferably by a worker thread sleeping most of the time.
15             * Increase session security, for example by using UserAgent i hashcode.
16 */
17 using System;
18 using System.IO;
19 using System.Collections;
20
21 namespace System.Web.SessionState
22 {
23         // Container object, containing the current session state and when it was last accessed.
24         internal class SessionContainer
25         {
26                 private HttpSessionState _state;
27                 private DateTime last_access;
28
29                 public SessionContainer (HttpSessionState state)
30                 {
31                         _state = state;
32                         this.Touch ();
33                 }
34
35                 public void Touch ()
36                 {
37                         last_access = DateTime.Now;
38                 }
39
40                 public HttpSessionState SessionState {
41                         get {
42                                 //Check if we should abandon it.
43                                 if (_state != null && last_access.AddMinutes (_state.Timeout) < DateTime.Now)
44                                         _state.Abandon ();
45
46                                 return _state;
47                         }
48                         set {
49                                 _state=value;
50                                 this.Touch ();
51                         }
52                 }
53         }
54
55
56         internal class SessionInProcHandler : ISessionHandler
57         {
58                 protected Hashtable _sessionTable;
59                 // The length of a session, in minutes. After this length, it's abandoned due to idle.
60                 const int SESSION_LIFETIME = 45;
61
62                 private SessionConfig config;
63                 
64                 public void Dispose ()
65                 {
66                         _sessionTable = null;
67                 }
68
69                 public void Init (HttpApplication context, SessionConfig config)
70                 {
71                         this.config = config;
72                         _sessionTable = (Hashtable) AppDomain.CurrentDomain.GetData (".MonoSessionInProc");
73                         if (_sessionTable == null)
74                                 _sessionTable = new Hashtable();
75                 }
76
77                 public void UpdateHandler (HttpContext context, SessionStateModule module)
78                 {
79                 }
80
81                 //this is the code that actually do stuff.
82                 public bool UpdateContext (HttpContext context, SessionStateModule module)
83                 {
84                         SessionContainer container = null;
85                         string id = SessionId.Lookup (context.Request, config.CookieLess);
86                         
87                         //first we try to get the cookie.
88                         // if we have a cookie, we look it up in the table.
89                         if (id != null) {
90                                 container = (SessionContainer) _sessionTable [id];
91
92                                 // if we have a session, and it is not expired, set isNew to false and return it.
93                                 if (container!=null && container.SessionState!=null && !container.SessionState.IsAbandoned) {
94                                         // Can we do this? It feels safe, but what do I know.
95                                         container.SessionState.SetNewSession (false);
96                                         // update the timestamp.
97                                         container.Touch ();
98                                          // Can we do this? It feels safe, but what do I know.
99                                         context.SetSession (container.SessionState);
100                                         return false; // and we're done
101                                 } else if(container!=null) {
102                                         _sessionTable.Remove (id);
103                                 }
104                         }
105
106                         // else we create a new session.
107                         string sessionID = SessionId.Create (module.Rng);
108                         container = new SessionContainer (new HttpSessionState (sessionID, // unique identifier
109                                                                                 new SessionDictionary(), // dictionary
110                                                                                 HttpApplicationFactory.ApplicationState.SessionObjects,
111                                                                                 SESSION_LIFETIME, //lifetime befor death.
112                                                                                 true, //new session
113                                                                                 false, // is cookieless
114                                                                                 SessionStateMode.InProc,
115                                                                                 module.IsReadOnly)); //readonly
116                         // puts it in the table.
117                         _sessionTable [sessionID]=container;
118                         AppDomain.CurrentDomain.SetData (".MonoSessionInProc", _sessionTable);
119
120                         // and returns it.
121                         context.SetSession (container.SessionState);
122                         context.Session.SetNewSession (true);
123
124                         // And we're done!
125                         return true;
126                 }
127         }
128 }
129