6c80c75f3ae56f3ee0c8ab36e5332d2dfb76787b
[mono.git] / mcs / class / System.Web / System.Web.SessionState_2.0 / SessionStateServerHandler.cs
1 //
2 // System.Web.SessionStateServerHandler
3 //
4 // Authors:
5 //   Marek Habersack (grendello@gmail.com)
6 //
7 // (C) 2006 Marek Habersack
8 // (C) 2007-2010 Novell, Inc (http://novell.com/)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 using System.Collections.Specialized;
32 using System.IO;
33 using System.IO.Compression;
34 using System.Web;
35 using System.Web.Configuration;
36 using System.Runtime.Remoting;
37 using System.Diagnostics;
38
39 namespace System.Web.SessionState 
40 {
41         internal class SessionStateServerHandler : SessionStateStoreProviderBase
42         {
43                 const Int32 lockAcquireTimeout = 30000;
44                 
45                 SessionStateSection config;
46                 RemoteStateServer stateServer;
47
48                 public override SessionStateStoreData CreateNewStoreData (HttpContext context, int timeout)
49                 {
50                         return new SessionStateStoreData (new SessionStateItemCollection (),
51                                                           HttpApplicationFactory.ApplicationState.SessionObjects,
52                                                           timeout);
53                 }
54                 
55                 public override void CreateUninitializedItem (HttpContext context, string id, int timeout)
56                 {
57                         EnsureGoodId (id, true);
58                         stateServer.CreateUninitializedItem (id, timeout);
59                 }
60                 
61                 public override void Dispose ()
62                 {
63                 }
64                 
65                 public override void EndRequest (HttpContext context)
66                 {
67                 }
68
69                 SessionStateStoreData GetItemInternal (HttpContext context,
70                                                        string id,
71                                                        out bool locked,
72                                                        out TimeSpan lockAge,
73                                                        out object lockId,
74                                                        out SessionStateActions actions,
75                                                        bool exclusive)
76                 {
77                         locked = false;
78                         lockAge = TimeSpan.MinValue;
79                         lockId = Int32.MinValue;
80                         actions = SessionStateActions.None;
81
82                         if (id == null)
83                                 return null;
84                         
85                         StateServerItem item = stateServer.GetItem (id,
86                                                                     out locked,
87                                                                     out lockAge,
88                                                                     out lockId,
89                                                                     out actions,
90                                                                     exclusive);
91                         
92                         if (item == null)
93                                 return null;
94                         
95                         if (actions == SessionStateActions.InitializeItem)
96                                 return CreateNewStoreData (context, item.Timeout);
97                         
98                         SessionStateItemCollection items = null;
99                         HttpStaticObjectsCollection sobjs = null;
100                         MemoryStream stream = null;
101                         BinaryReader reader = null;
102                         Stream input = null;
103 #if NET_4_0
104                         GZipStream gzip = null;
105 #endif
106                         try {
107                                 if (item.CollectionData != null && item.CollectionData.Length > 0) {
108                                         stream = new MemoryStream (item.CollectionData);
109 #if NET_4_0                                     
110                                         if (config.CompressionEnabled)
111                                                 input = gzip = new GZipStream (stream, CompressionMode.Decompress, true);
112                                         else
113 #endif
114                                                 input = stream;
115                                         reader = new BinaryReader (input);
116                                         items = SessionStateItemCollection.Deserialize (reader);
117 #if NET_4_0
118                                         if (gzip != null)
119                                                 gzip.Close ();
120 #endif
121                                         reader.Close ();
122                                 } else
123                                         items = new SessionStateItemCollection ();
124                                 if (item.StaticObjectsData != null && item.StaticObjectsData.Length > 0)
125                                         sobjs = HttpStaticObjectsCollection.FromByteArray (item.StaticObjectsData);
126                                 else
127                                         sobjs = new HttpStaticObjectsCollection ();
128                         } catch (Exception ex) {
129                                 throw new HttpException ("Failed to retrieve session state.", ex);
130                         } finally {
131                                 if (stream != null)
132                                         stream.Dispose ();
133 #if NET_4_0
134                                 if (reader != null)
135                                         reader.Dispose ();
136                                 if (gzip != null)
137                                         gzip.Dispose ();
138 #else
139                                 if (reader != null)
140                                         ((IDisposable)reader).Dispose ();
141 #endif
142                         }
143                                 
144                         return new SessionStateStoreData (items,
145                                                           sobjs,
146                                                           item.Timeout);
147                 }
148                 
149                 public override SessionStateStoreData GetItem (HttpContext context,
150                                                                string id,
151                                                                out bool locked,
152                                                                out TimeSpan lockAge,
153                                                                out object lockId,
154                                                                out SessionStateActions actions)
155                 {
156                         EnsureGoodId (id, false);
157                         return GetItemInternal (context, id, out locked, out lockAge, out lockId, out actions, false);
158                 }
159                 
160                 public override SessionStateStoreData GetItemExclusive (HttpContext context,
161                                                                         string id,
162                                                                         out bool locked,
163                                                                         out TimeSpan lockAge,
164                                                                         out object lockId,
165                                                                         out SessionStateActions actions)
166                 {
167                         EnsureGoodId (id, false);
168                         return GetItemInternal (context, id, out locked, out lockAge, out lockId, out actions, true);
169                 }
170
171                 public override void Initialize (string name, NameValueCollection config)
172                 {
173                         this.config = (SessionStateSection) WebConfigurationManager.GetSection ("system.web/sessionState");
174                         if (String.IsNullOrEmpty (name))
175                                 name = "Session Server handler";
176                         RemotingConfiguration.Configure (null);
177                         string cons = null, proto = null, server = null, port = null;
178                         GetConData (out proto, out server, out port);
179                         cons = String.Format ("{0}://{1}:{2}/StateServer", proto, server, port);
180                         stateServer = Activator.GetObject (typeof (RemoteStateServer), cons) as RemoteStateServer;
181
182                         base.Initialize (name, config);
183                 }
184                 
185                 public override void InitializeRequest (HttpContext context)
186                 {
187                         // nothing to do here
188                 }
189                 
190                 public override void ReleaseItemExclusive (HttpContext context,
191                                                            string id,
192                                                            object lockId)
193                 {
194                         EnsureGoodId (id, true);
195                         stateServer.ReleaseItemExclusive (id, lockId);
196                 }
197                 
198                 public override void RemoveItem (HttpContext context,
199                                                  string id,
200                                                  object lockId,
201                                                  SessionStateStoreData item)
202                 {
203                         EnsureGoodId (id, true);
204                         stateServer.Remove (id, lockId);
205                 }
206                 
207                 public override void ResetItemTimeout (HttpContext context, string id)
208                 {
209                         EnsureGoodId (id, true);
210                         stateServer.ResetItemTimeout (id);
211                 }
212
213                 public override void SetAndReleaseItemExclusive (HttpContext context,
214                                                                  string id,
215                                                                  SessionStateStoreData item,
216                                                                  object lockId,
217                                                                  bool newItem)
218                 {
219                         if (item == null)
220                                 return;
221                         
222                         EnsureGoodId (id, true);
223                         byte[] collection_data = null;
224                         byte[] sobjs_data = null;
225                         MemoryStream stream = null;
226                         BinaryWriter writer = null;
227                         Stream output = null;
228 #if NET_4_0
229                         GZipStream gzip = null;
230 #endif
231                         
232                         try {
233                                 SessionStateItemCollection items = item.Items as SessionStateItemCollection;
234                                 if (items != null && items.Count > 0) {
235                                         stream = new MemoryStream ();
236 #if NET_4_0
237                                         if (config.CompressionEnabled)
238                                                 output = gzip = new GZipStream (stream, CompressionMode.Compress, true);
239                                         else
240 #endif
241                                                 output = stream;
242                                         writer = new BinaryWriter (output);
243                                         items.Serialize (writer);
244 #if NET_4_0
245                                         if (gzip != null)
246                                                 gzip.Close ();
247 #endif
248                                         writer.Close ();
249                                         collection_data = stream.ToArray ();
250                                 }
251                                 HttpStaticObjectsCollection sobjs = item.StaticObjects;
252                                 if (sobjs != null && sobjs.Count > 0)
253                                         sobjs_data = sobjs.ToByteArray ();
254                         } catch (Exception ex) {
255                                 throw new HttpException ("Failed to store session data.", ex);
256                         } finally {
257
258 #if NET_4_0
259                                 if (writer != null)
260                                         writer.Dispose ();
261                                 if (gzip != null)
262                                         gzip.Dispose ();
263 #else
264                                 if (writer != null)
265                                         ((IDisposable)writer).Dispose ();
266 #endif
267                                 if (stream != null)
268                                         stream.Dispose ();
269                         }
270                         
271                         stateServer.SetAndReleaseItemExclusive (id, collection_data, sobjs_data, lockId, item.Timeout, newItem);
272                 }
273                 
274                 public override bool SetItemExpireCallback (SessionStateItemExpireCallback expireCallback)
275                 {
276                         return false;
277                 }
278
279                 void EnsureGoodId (string id, bool throwOnNull)
280                 {
281                         if (id == null)
282                                 if (throwOnNull)
283                                         throw new HttpException ("Session ID is invalid");
284                                 else
285                                         return;
286                         
287                         if (id.Length > SessionIDManager.SessionIDMaxLength)
288                                 throw new HttpException ("Session ID too long");
289                 }
290
291                 void GetConData (out string proto, out string server, out string port)
292                 {
293                         string cons = config.StateConnectionString;
294                         int ei = cons.IndexOf ('=');
295                         int ci = cons.IndexOf (':');
296
297                         if (ei < 0 || ci < 0)
298                                 throw new HttpException ("Invalid StateConnectionString");
299                         
300                         proto = cons.Substring (0, ei);
301                         server = cons.Substring (ei+1, ci - ei - 1);
302                         port = cons.Substring (ci+1, cons.Length - ci - 1);
303                         
304                         if (proto == "tcpip")
305                                 proto = "tcp";
306                 }
307         }
308 }