fixed tests
[mono.git] / mcs / class / System.Web / System.Web.SessionState_2.0 / SessionInProcHandler.cs
1 //
2 // System.Web.SessionState.SessionInProcHandler
3 //
4 // Authors:
5 //      Marek Habersack <grendello@gmail.com
6 //
7 // (C) 2006 Marek Habersack
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 #if NET_2_0
31 using System;
32 using System.IO;
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.Configuration.Provider;
36 using System.Web.Caching;
37 using System.Web.Configuration;
38 using System.Threading;
39
40 namespace System.Web.SessionState
41 {
42         internal sealed class InProcSessionItem
43         {
44                 public bool locked;
45                 public bool cookieless;
46                 public ISessionStateItemCollection items;
47                 public DateTime lockedTime;
48                 public DateTime expiresAt;
49                 public ReaderWriterLock rwlock;
50                 public Int32 lockId;
51                 public int timeout;
52                 
53                 internal InProcSessionItem ()
54                 {
55                         this.locked = false;
56                         this.cookieless = false;
57                         this.items = null;
58                         this.lockedTime = DateTime.MinValue;
59                         this.expiresAt = DateTime.MinValue;
60                         this.rwlock = new ReaderWriterLock ();
61                         this.lockId = Int32.MinValue;
62                         this.timeout = 0;
63                 }
64         }
65         
66         internal class SessionInProcHandler : SessionStateStoreProviderBase
67         {
68                 private const string CachePrefix = "@@@InProc@";
69                 private const Int32 lockAcquireTimeout = 30000;
70                 
71                 CacheItemRemovedCallback removedCB;
72                 //NameValueCollection privateConfig;
73                 SessionStateItemExpireCallback expireCallback;
74
75                 public override SessionStateStoreData CreateNewStoreData (HttpContext context, int timeout)
76                 {
77                         return new SessionStateStoreData (new SessionStateItemCollection (),
78                                                           SessionStateUtility.GetSessionStaticObjects(context),
79                                                           timeout);
80                 }
81
82                 void InsertSessionItem (InProcSessionItem item, int timeout, string id)
83                 {
84                         HttpRuntime.Cache.InsertPrivate (id,
85                                                          item,
86                                                          null,
87                                                          Cache.NoAbsoluteExpiration,
88                                                          TimeSpan.FromMinutes (timeout),
89                                                          CacheItemPriority.AboveNormal,
90                                                          removedCB);
91                 }
92                 
93                 public override void CreateUninitializedItem (HttpContext context, string id, int timeout)
94                 {
95                         EnsureGoodId (id, true);
96                         InProcSessionItem item = new InProcSessionItem ();
97                         item.expiresAt = DateTime.UtcNow.AddMinutes (timeout);
98                         item.timeout = timeout;
99                         InsertSessionItem (item, timeout, CachePrefix + id);
100                 }
101                 
102                 public override void Dispose ()
103                 {
104                 }
105                 
106                 public override void EndRequest (HttpContext context)
107                 {
108                 }
109
110                 SessionStateStoreData GetItemInternal (HttpContext context,
111                                                        string id,
112                                                        out bool locked,
113                                                        out TimeSpan lockAge,
114                                                        out object lockId,
115                                                        out SessionStateActions actions,
116                                                        bool exclusive)
117                 {
118                         locked = false;
119                         lockAge = TimeSpan.MinValue;
120                         lockId = Int32.MinValue;
121                         actions = SessionStateActions.None;
122
123                         if (id == null)
124                                 return null;
125                         
126                         Cache cache = HttpRuntime.Cache;
127                         string CacheId = CachePrefix + id;
128                         InProcSessionItem item = cache [CacheId] as InProcSessionItem;
129                         
130                         if (item == null)
131                                 return null;
132                         
133                         try {
134                                 item.rwlock.AcquireReaderLock (lockAcquireTimeout);
135                                 if (item.locked) {
136                                         locked = true;
137                                         lockAge = DateTime.UtcNow.Subtract (item.lockedTime);
138                                         lockId = item.lockId;
139                                         return null;
140                                 }
141                                 item.rwlock.ReleaseReaderLock ();
142                                 if (exclusive) {
143                                         item.rwlock.AcquireWriterLock (lockAcquireTimeout);
144                                         item.locked = true;
145                                         item.lockedTime = DateTime.UtcNow;
146                                         item.lockId++;
147                                         lockId = item.lockId;
148                                 }
149                                 if (item.items == null) {
150                                         actions = SessionStateActions.InitializeItem;
151                                         item.items = new SessionStateItemCollection ();
152                                 }
153                                 return new SessionStateStoreData (item.items,
154                                                                   SessionStateUtility.GetSessionStaticObjects(context),
155                                                                   item.timeout);
156                         } catch {
157                                 // we want such errors to be passed to the application.
158                                 throw;
159                         } finally {
160                                 if (item.rwlock.IsReaderLockHeld) 
161                                         item.rwlock.ReleaseReaderLock ();
162                                 if (item.rwlock.IsWriterLockHeld) 
163                                         item.rwlock.ReleaseWriterLock ();
164                         }
165                 }
166                 
167                 public override SessionStateStoreData GetItem (HttpContext context,
168                                                                string id,
169                                                                out bool locked,
170                                                                out TimeSpan lockAge,
171                                                                out object lockId,
172                                                                out SessionStateActions actions)
173                 {
174                         EnsureGoodId (id, false);
175                         return GetItemInternal (context, id, out locked, out lockAge, out lockId, out actions, false);
176                 }
177                 
178                 public override SessionStateStoreData GetItemExclusive (HttpContext context,
179                                                                         string id,
180                                                                         out bool locked,
181                                                                         out TimeSpan lockAge,
182                                                                         out object lockId,
183                                                                         out SessionStateActions actions)
184                 {
185                         EnsureGoodId (id, false);
186                         return GetItemInternal (context, id, out locked, out lockAge, out lockId, out actions, true);
187                 }
188
189                 public override void Initialize (string name, NameValueCollection config)
190                 {
191                         if (String.IsNullOrEmpty (name))
192                                 name = "Session InProc handler";
193                         removedCB = new CacheItemRemovedCallback (OnSessionRemoved);
194                         //privateConfig = config;
195                         base.Initialize (name, config);
196                 }
197                 
198                 public override void InitializeRequest (HttpContext context)
199                 {
200                         // nothing to do here
201                 }
202                 
203                 public override void ReleaseItemExclusive (HttpContext context,
204                                                            string id,
205                                                            object lockId)
206                 {
207                         EnsureGoodId (id, true);
208                         string CacheId = CachePrefix + id;
209                         InProcSessionItem item = HttpRuntime.Cache [CacheId] as InProcSessionItem;
210                         
211                         if (item == null || lockId == null || lockId.GetType() != typeof(Int32) || item.lockId != (Int32)lockId)
212                                 return;
213
214                         try {
215                                 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
216                                 item.locked = false;
217                         } catch {
218                                 throw;
219                         } finally {
220                                 if (item.rwlock.IsWriterLockHeld)
221                                         item.rwlock.ReleaseWriterLock ();
222                         }
223                 }
224                 
225                 public override void RemoveItem (HttpContext context,
226                                                  string id,
227                                                  object lockId,
228                                                  SessionStateStoreData item)
229                 {
230                         EnsureGoodId (id, true);
231                         string CacheId = CachePrefix + id;
232                         Cache cache = HttpRuntime.Cache;
233                         InProcSessionItem inProcItem = cache [CacheId] as InProcSessionItem;
234
235                         if (inProcItem == null || lockId == null || lockId.GetType() != typeof(Int32) || inProcItem.lockId != (Int32)lockId)
236                                 return;
237
238                         try {
239                                 inProcItem.rwlock.AcquireWriterLock (lockAcquireTimeout);
240                                 cache.Remove (CacheId);
241                         } catch {
242                                 throw;
243                         } finally {
244                                 if (inProcItem.rwlock.IsWriterLockHeld)
245                                         inProcItem.rwlock.ReleaseWriterLock ();
246                         }
247                 }
248                 
249                 public override void ResetItemTimeout (HttpContext context, string id)
250                 {
251                         EnsureGoodId (id, true);
252                         string CacheId = CachePrefix + id;
253                         Cache cache = HttpRuntime.Cache;
254                         InProcSessionItem item = cache [CacheId] as InProcSessionItem;
255                         
256                         if (item == null)
257                                 return;
258
259                         try {
260                                 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
261                                 cache.Remove (CacheId);
262                                 InsertSessionItem (item, item.timeout, CacheId);
263                         } catch {
264                                 throw;
265                         } finally {
266                                 if (item.rwlock.IsWriterLockHeld)
267                                         item.rwlock.ReleaseWriterLock ();
268                         }
269                 }
270                 
271                 public override void SetAndReleaseItemExclusive (HttpContext context,
272                                                                  string id,
273                                                                  SessionStateStoreData item,
274                                                                  object lockId,
275                                                                  bool newItem)
276                 {
277                         EnsureGoodId (id, true);
278                         string CacheId = CachePrefix + id;
279                         Cache cache = HttpRuntime.Cache;
280                         InProcSessionItem inProcItem = cache [CacheId] as InProcSessionItem;
281                         
282                         if (newItem || inProcItem == null) {
283                                 inProcItem = new InProcSessionItem ();
284                                 inProcItem.timeout = item.Timeout;
285                                 inProcItem.expiresAt = DateTime.UtcNow.AddMinutes (item.Timeout);
286                                 if (lockId.GetType() == typeof(Int32))
287                                         inProcItem.lockId = (Int32)lockId;
288                         } else {
289                                 if (lockId == null || lockId.GetType() != typeof(Int32) || inProcItem.lockId != (Int32)lockId)
290                                         return;
291                                 cache.Remove (CacheId);
292                         }
293                         
294                         try {
295                                 inProcItem.rwlock.AcquireWriterLock (lockAcquireTimeout);
296                                 inProcItem.locked = false;
297                                 inProcItem.items = item.Items;
298                                 InsertSessionItem (inProcItem, item.Timeout, CacheId);
299                         } catch {
300                                 throw;
301                         } finally {
302                                 if (inProcItem.rwlock.IsWriterLockHeld)
303                                         inProcItem.rwlock.ReleaseWriterLock ();
304                         }
305                 }
306                 
307                 public override bool SetItemExpireCallback (SessionStateItemExpireCallback expireCallback)
308                 {
309                         this.expireCallback = expireCallback;
310                         return true;
311                 }
312
313                 void EnsureGoodId (string id, bool throwOnNull)
314                 {
315                         if (id == null)
316                                 if (throwOnNull)
317                                         throw new HttpException ("Session ID is invalid");
318                                 else
319                                         return;
320                         
321                         if (id.Length > SessionIDManager.SessionIDMaxLength)
322                                 throw new HttpException ("Session ID too long");
323                 }
324
325                 void OnSessionRemoved (string key, object value, CacheItemRemovedReason reason)
326                 {
327                         if (expireCallback != null)
328                                 expireCallback (key, value as SessionStateStoreData);
329                 }
330         }
331 }
332 #endif