updating to the latest module.
[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                 
45                 static SessionConfig config;
46                 static Type handlerType;
47                 ISessionHandler handler;
48                 bool sessionForStaticFiles;
49                 
50                 static RandomNumberGenerator rng = new RNGCryptoServiceProvider ();
51                 
52                 public SessionStateModule ()
53                 {
54                 }
55
56                 internal RandomNumberGenerator Rng {
57                         get { return rng; }
58                 }
59
60                 public void Dispose ()
61                 {
62                     if (handler!=null)
63                         handler.Dispose();
64                 }
65
66                 public void Init (HttpApplication app)
67                 {
68                         sessionForStaticFiles = (Environment.GetEnvironmentVariable ("MONO_XSP_STATIC_SESSION") != null);
69                         if (config == null) {
70                                 config = (SessionConfig) HttpContext.GetAppConfig ("system.web/sessionState");
71                                 if (config ==  null)
72                                         config = new SessionConfig (null);
73
74                                 if (config.Mode == SessionStateMode.StateServer)
75                                         handlerType = typeof (SessionStateServerHandler);
76
77                                 if (config.Mode == SessionStateMode.SQLServer)
78                                         handlerType = typeof (SessionSQLServerHandler);
79                                 
80                                 if (config.Mode == SessionStateMode.InProc)
81                                         handlerType = typeof (SessionInProcHandler);
82
83                                 if (config.Mode == SessionStateMode.Off)
84                                         return;
85                         }
86
87                         if (config.CookieLess)
88                                 app.BeginRequest += new EventHandler (OnBeginRequest);
89                         
90                         app.AddOnAcquireRequestStateAsync (
91                                 new BeginEventHandler (OnBeginAcquireState),
92                                 new EndEventHandler (OnEndAcquireState));
93
94                         app.ReleaseRequestState += new EventHandler (OnReleaseRequestState);
95                         app.EndRequest += new EventHandler (OnEndRequest);
96                         
97                         if (handlerType != null && handler == null) {
98                                 handler = (ISessionHandler) Activator.CreateInstance (handlerType);
99                                 handler.Init (this, app, config); //initialize
100                         }
101                 }
102
103                 void OnBeginRequest (object o, EventArgs args)
104                 {
105                         HttpApplication application = (HttpApplication) o;
106                         HttpContext context = application.Context;
107                         string base_path = context.Request.BaseVirtualDir;
108                         string id = UrlUtils.GetSessionId (base_path);
109
110                         if (id == null)
111                                 return;
112                         
113                         context.Request.SetCurrentExePath (UrlUtils.RemoveSessionId (base_path,
114                                                                      context.Request.FilePath));
115                         context.Request.SetHeader (HeaderName, id);
116                         context.Response.SetAppPathModifier (String.Format ("({0})", id));
117                 }
118                 
119                 void OnReleaseRequestState (object o, EventArgs args)
120                 {
121                         if (handler == null)
122                                 return;
123
124                         HttpApplication application = (HttpApplication) o;
125                         HttpContext context = application.Context;
126                         handler.UpdateHandler (context, this);
127                 }
128
129                 void OnEndRequest (object o, EventArgs args)
130                 {
131                 }
132
133                 IAsyncResult OnBeginAcquireState (object o, EventArgs args, AsyncCallback cb, object data)
134                 {
135                         HttpApplication application = (HttpApplication) o;
136                         HttpContext context = application.Context;
137
138                         bool required = (context.Handler is IRequiresSessionState);
139                         
140                         // This is a hack. Sites that use Session in global.asax event handling code
141                         // are not supposed to get a Session object for static files, but seems that
142                         // IIS handles those files before getting there and thus they are served without
143                         // error.
144                         // As a workaround, setting MONO_XSP_STATIC_SESSION variable make this work
145                         // on mono, but you lose performance when serving static files.
146                         if (sessionForStaticFiles && context.Handler is StaticFileHandler)
147                                 required = true;
148                         // hack end
149
150                         bool read_only = (context.Handler is IReadOnlySessionState);
151                         
152                         bool isNew = false;
153                         HttpSessionState session = null;
154                         if (handler != null)
155                                 session = handler.UpdateContext (context, this, required, read_only, ref isNew);
156
157                         if (session != null) {
158                                 if (isNew)
159                                         session.SetNewSession (true);
160
161                                 if (read_only)
162                                         session = session.Clone ();
163                                         
164                                 context.SetSession (session);
165
166                                 if (isNew && config.CookieLess) {
167                                         string id = context.Session.SessionID;
168                                         context.Request.SetHeader (HeaderName, id);
169                                         context.Response.Redirect (UrlUtils.InsertSessionId (id,
170                                                                    context.Request.FilePath));
171                                 } else if (isNew) {
172                                         string id = context.Session.SessionID;
173                                         HttpCookie cookie = new HttpCookie (CookieName, id);
174                                         cookie.Path = UrlUtils.GetDirectory (context.Request.ApplicationPath);
175                                         context.Response.AppendCookie (cookie);
176                                 }
177                         }
178                         
179                         // In the future, we might want to move the Async stuff down to
180                         // the interface level, if we're going to support other than
181                         // InProc, we might actually want to do things async, now we
182                         // simply fake it.
183                         HttpAsyncResult result=new HttpAsyncResult (cb,this);
184                         result.Complete (true, o, null);
185                         if (isNew && Start != null)
186                                 Start (this, args);
187
188                         return result;
189                 }
190
191                 void OnEndAcquireState (IAsyncResult result) { }
192
193                 internal void OnSessionRemoved (string key, object value, CacheItemRemovedReason reason)
194                 {
195                         OnEnd ();
196                 }
197
198                 internal void OnEnd ()
199                 {
200                         if (End != null)
201                                 End (this, EventArgs.Empty);
202                 }
203                 
204                 public event EventHandler Start;
205                 public event EventHandler End;
206         }
207 }
208