TARGET_J2EE/JVM fixes
[mono.git] / mcs / class / System.Web / System.Web.SessionState / SessionStateModule.cs
1 //
2 // System.Web.SessionState.SesionStateModule
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //      Stefan Görling (stefan@gorling.se)
7 //      Jackson Harper (jackson@ximian.com)
8 //
9 // (C) 2002,2003,2004,2005 Novell, Inc (http://www.novell.com)
10 // (C) 2003 Stefan Görling (http://www.gorling.se)
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System.Web;
34 using System.Web.Caching;
35 using System.Web.Util;
36 using System.Security.Cryptography;
37
38 namespace System.Web.SessionState
39 {
40         public sealed class SessionStateModule : IHttpModule
41         {
42                 internal static readonly string CookieName = "ASPSESSION";
43                 internal static readonly string HeaderName = "AspFilterSessionId";
44                 static object locker = new object ();
45                 
46 #if TARGET_J2EE         
47                 static private SessionConfig config {
48                         get {
49                                 return (SessionConfig)AppDomain.CurrentDomain.GetData("SessionStateModule.config");
50                         }
51                         set {
52                                 AppDomain.CurrentDomain.SetData("SessionStateModule.config", value);
53                         }
54                 }
55                 static private Type handlerType {
56                         get {
57                                 return (Type)AppDomain.CurrentDomain.GetData("SessionStateModule.handlerType");
58                         }
59                         set {
60                                 AppDomain.CurrentDomain.SetData("SessionStateModule.handlerType", value);
61                         }
62                 }
63 #else
64                 static SessionConfig config;
65                 static Type handlerType;
66 #endif          
67                 ISessionHandler handler;
68                 bool sessionForStaticFiles;
69                 
70                 static RandomNumberGenerator rng = new RNGCryptoServiceProvider ();
71                 
72                 public SessionStateModule ()
73                 {
74                 }
75
76                 internal RandomNumberGenerator Rng {
77                         get { return rng; }
78                 }
79
80                 public void Dispose ()
81                 {
82                     if (handler!=null)
83                         handler.Dispose();
84                 }
85
86                 SessionConfig GetConfig ()
87                 {
88                         lock (locker) {
89                                 if (config != null)
90                                         return config;
91
92                                 config = (SessionConfig) HttpContext.GetAppConfig ("system.web/sessionState");
93                                 if (config ==  null)
94                                         config = new SessionConfig (null);
95
96 #if TARGET_J2EE
97                                 if (config.Mode == SessionStateMode.SQLServer || config.Mode == SessionStateMode.StateServer)
98                                         throw new NotImplementedException("You must use web.xml to specify session state handling");
99 #else
100                                 if (config.Mode == SessionStateMode.StateServer)
101                                         handlerType = typeof (SessionStateServerHandler);
102
103                                 if (config.Mode == SessionStateMode.SQLServer)
104                                         handlerType = typeof (SessionSQLServerHandler);
105 #endif
106                                 if (config.Mode == SessionStateMode.InProc)
107                                         handlerType = typeof (SessionInProcHandler);
108
109                                 return config;
110                         }
111                 }
112
113                 public void Init (HttpApplication app)
114                 {
115                         sessionForStaticFiles = (Environment.GetEnvironmentVariable ("MONO_XSP_STATIC_SESSION") != null);
116                         SessionConfig cfg = GetConfig ();
117                         if (handlerType == null)
118                                 return;
119
120                         if (config.CookieLess)
121                                 app.BeginRequest += new EventHandler (OnBeginRequest);
122
123                         app.AcquireRequestState += new EventHandler (OnAcquireState);
124                         app.ReleaseRequestState += new EventHandler (OnReleaseRequestState);
125                         app.EndRequest += new EventHandler (OnEndRequest);
126                         
127                         if (handlerType != null && handler == null) {
128                                 handler = (ISessionHandler) Activator.CreateInstance (handlerType);
129                                 handler.Init (this, app, config); //initialize
130                         }
131                 }
132
133                 void OnBeginRequest (object o, EventArgs args)
134                 {
135                         HttpApplication application = (HttpApplication) o;
136                         HttpContext context = application.Context;
137                         string base_path = context.Request.BaseVirtualDir;
138                         string id = UrlUtils.GetSessionId (base_path);
139
140                         if (id == null)
141                                 return;
142                         
143                         context.Request.SetCurrentExePath (UrlUtils.RemoveSessionId (base_path,
144                                                                      context.Request.FilePath));
145                         context.Request.SetHeader (HeaderName, id);
146                         context.Response.SetAppPathModifier (String.Format ("({0})", id));
147                 }
148                 
149                 void OnReleaseRequestState (object o, EventArgs args)
150                 {
151                         if (handler == null)
152                                 return;
153
154                         HttpApplication application = (HttpApplication) o;
155                         HttpContext context = application.Context;
156                         handler.UpdateHandler (context, this);
157                 }
158
159                 void OnEndRequest (object o, EventArgs args)
160                 {
161                 }
162
163                 void OnAcquireState (object o, EventArgs args)
164                 {
165                         HttpApplication application = (HttpApplication) o;
166                         HttpContext context = application.Context;
167
168                         bool required = (context.Handler is IRequiresSessionState);
169                         
170                         // This is a hack. Sites that use Session in global.asax event handling code
171                         // are not supposed to get a Session object for static files, but seems that
172                         // IIS handles those files before getting there and thus they are served without
173                         // error.
174                         // As a workaround, setting MONO_XSP_STATIC_SESSION variable make this work
175                         // on mono, but you lose performance when serving static files.
176                         if (sessionForStaticFiles && context.Handler is StaticFileHandler)
177                                 required = true;
178                         // hack end
179
180                         bool read_only = (context.Handler is IReadOnlySessionState);
181                         
182                         bool isNew = false;
183                         HttpSessionState session = null;
184                         if (handler != null)
185                                 session = handler.UpdateContext (context, this, required, read_only, ref isNew);
186
187                         if (session != null) {
188                                 if (isNew)
189                                         session.SetNewSession (true);
190
191                                 if (read_only)
192                                         session = session.Clone ();
193                                         
194                                 context.SetSession (session);
195
196                                 if (isNew && config.CookieLess) {
197                                         string id = context.Session.SessionID;
198                                         context.Request.SetHeader (HeaderName, id);
199                                         context.Response.Redirect (UrlUtils.InsertSessionId (id,
200                                                                    context.Request.FilePath));
201                                 } else if (isNew) {
202                                         string id = context.Session.SessionID;
203                                         HttpCookie cookie = new HttpCookie (CookieName, id);
204                                         cookie.Path = UrlUtils.GetDirectory (context.Request.ApplicationPath);
205                                         context.Response.AppendCookie (cookie);
206                                 }
207                         }
208                 }
209
210                 internal void OnSessionRemoved (string key, object value, CacheItemRemovedReason reason)
211                 {
212                         OnEnd ();
213                 }
214
215                 internal void OnEnd ()
216                 {
217 #if !TARGET_J2EE                        
218                         if (End != null)
219                                 End (this, EventArgs.Empty);
220 #endif                          
221                 }
222                 
223                 public event EventHandler Start;
224                 public event EventHandler End;
225         }
226 }
227