3c1f479b9d
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
287 lines
8.7 KiB
C#
287 lines
8.7 KiB
C#
//
|
|
// System.Web.SessionStateServerHandler
|
|
//
|
|
// Authors:
|
|
// Marek Habersack (grendello@gmail.com)
|
|
//
|
|
// (C) 2006 Marek Habersack
|
|
// (C) 2007-2010 Novell, Inc (http://novell.com/)
|
|
//
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
using System.Collections.Specialized;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Web;
|
|
using System.Web.Configuration;
|
|
using System.Runtime.Remoting;
|
|
using System.Diagnostics;
|
|
|
|
namespace System.Web.SessionState
|
|
{
|
|
internal class SessionStateServerHandler : SessionStateStoreProviderBase
|
|
{
|
|
const Int32 lockAcquireTimeout = 30000;
|
|
|
|
SessionStateSection config;
|
|
RemoteStateServer stateServer;
|
|
|
|
public override SessionStateStoreData CreateNewStoreData (HttpContext context, int timeout)
|
|
{
|
|
return new SessionStateStoreData (new SessionStateItemCollection (),
|
|
HttpApplicationFactory.ApplicationState.SessionObjects,
|
|
timeout);
|
|
}
|
|
|
|
public override void CreateUninitializedItem (HttpContext context, string id, int timeout)
|
|
{
|
|
EnsureGoodId (id, true);
|
|
stateServer.CreateUninitializedItem (id, timeout);
|
|
}
|
|
|
|
public override void Dispose ()
|
|
{
|
|
}
|
|
|
|
public override void EndRequest (HttpContext context)
|
|
{
|
|
}
|
|
|
|
SessionStateStoreData GetItemInternal (HttpContext context,
|
|
string id,
|
|
out bool locked,
|
|
out TimeSpan lockAge,
|
|
out object lockId,
|
|
out SessionStateActions actions,
|
|
bool exclusive)
|
|
{
|
|
locked = false;
|
|
lockAge = TimeSpan.MinValue;
|
|
lockId = Int32.MinValue;
|
|
actions = SessionStateActions.None;
|
|
|
|
if (id == null)
|
|
return null;
|
|
|
|
StateServerItem item = stateServer.GetItem (id,
|
|
out locked,
|
|
out lockAge,
|
|
out lockId,
|
|
out actions,
|
|
exclusive);
|
|
|
|
if (item == null)
|
|
return null;
|
|
|
|
if (actions == SessionStateActions.InitializeItem)
|
|
return CreateNewStoreData (context, item.Timeout);
|
|
|
|
SessionStateItemCollection items = null;
|
|
HttpStaticObjectsCollection sobjs = null;
|
|
MemoryStream stream = null;
|
|
BinaryReader reader = null;
|
|
Stream input = null;
|
|
GZipStream gzip = null;
|
|
try {
|
|
if (item.CollectionData != null && item.CollectionData.Length > 0) {
|
|
stream = new MemoryStream (item.CollectionData);
|
|
if (config.CompressionEnabled)
|
|
input = gzip = new GZipStream (stream, CompressionMode.Decompress, true);
|
|
else
|
|
input = stream;
|
|
reader = new BinaryReader (input);
|
|
items = SessionStateItemCollection.Deserialize (reader);
|
|
if (gzip != null)
|
|
gzip.Close ();
|
|
reader.Close ();
|
|
} else
|
|
items = new SessionStateItemCollection ();
|
|
if (item.StaticObjectsData != null && item.StaticObjectsData.Length > 0)
|
|
sobjs = HttpStaticObjectsCollection.FromByteArray (item.StaticObjectsData);
|
|
else
|
|
sobjs = new HttpStaticObjectsCollection ();
|
|
} catch (Exception ex) {
|
|
throw new HttpException ("Failed to retrieve session state.", ex);
|
|
} finally {
|
|
if (stream != null)
|
|
stream.Dispose ();
|
|
if (reader != null)
|
|
reader.Dispose ();
|
|
if (gzip != null)
|
|
gzip.Dispose ();
|
|
}
|
|
|
|
return new SessionStateStoreData (items,
|
|
sobjs,
|
|
item.Timeout);
|
|
}
|
|
|
|
public override SessionStateStoreData GetItem (HttpContext context,
|
|
string id,
|
|
out bool locked,
|
|
out TimeSpan lockAge,
|
|
out object lockId,
|
|
out SessionStateActions actions)
|
|
{
|
|
EnsureGoodId (id, false);
|
|
return GetItemInternal (context, id, out locked, out lockAge, out lockId, out actions, false);
|
|
}
|
|
|
|
public override SessionStateStoreData GetItemExclusive (HttpContext context,
|
|
string id,
|
|
out bool locked,
|
|
out TimeSpan lockAge,
|
|
out object lockId,
|
|
out SessionStateActions actions)
|
|
{
|
|
EnsureGoodId (id, false);
|
|
return GetItemInternal (context, id, out locked, out lockAge, out lockId, out actions, true);
|
|
}
|
|
|
|
public override void Initialize (string name, NameValueCollection config)
|
|
{
|
|
this.config = (SessionStateSection) WebConfigurationManager.GetSection ("system.web/sessionState");
|
|
if (String.IsNullOrEmpty (name))
|
|
name = "Session Server handler";
|
|
RemotingConfiguration.Configure (null);
|
|
string cons = null, proto = null, server = null, port = null;
|
|
GetConData (out proto, out server, out port);
|
|
cons = String.Format ("{0}://{1}:{2}/StateServer", proto, server, port);
|
|
stateServer = Activator.GetObject (typeof (RemoteStateServer), cons) as RemoteStateServer;
|
|
|
|
base.Initialize (name, config);
|
|
}
|
|
|
|
public override void InitializeRequest (HttpContext context)
|
|
{
|
|
// nothing to do here
|
|
}
|
|
|
|
public override void ReleaseItemExclusive (HttpContext context,
|
|
string id,
|
|
object lockId)
|
|
{
|
|
EnsureGoodId (id, true);
|
|
stateServer.ReleaseItemExclusive (id, lockId);
|
|
}
|
|
|
|
public override void RemoveItem (HttpContext context,
|
|
string id,
|
|
object lockId,
|
|
SessionStateStoreData item)
|
|
{
|
|
EnsureGoodId (id, true);
|
|
stateServer.Remove (id, lockId);
|
|
}
|
|
|
|
public override void ResetItemTimeout (HttpContext context, string id)
|
|
{
|
|
EnsureGoodId (id, true);
|
|
stateServer.ResetItemTimeout (id);
|
|
}
|
|
|
|
public override void SetAndReleaseItemExclusive (HttpContext context,
|
|
string id,
|
|
SessionStateStoreData item,
|
|
object lockId,
|
|
bool newItem)
|
|
{
|
|
if (item == null)
|
|
return;
|
|
|
|
EnsureGoodId (id, true);
|
|
byte[] collection_data = null;
|
|
byte[] sobjs_data = null;
|
|
MemoryStream stream = null;
|
|
BinaryWriter writer = null;
|
|
Stream output = null;
|
|
GZipStream gzip = null;
|
|
|
|
try {
|
|
SessionStateItemCollection items = item.Items as SessionStateItemCollection;
|
|
if (items != null && items.Count > 0) {
|
|
stream = new MemoryStream ();
|
|
if (config.CompressionEnabled)
|
|
output = gzip = new GZipStream (stream, CompressionMode.Compress, true);
|
|
else
|
|
output = stream;
|
|
writer = new BinaryWriter (output);
|
|
items.Serialize (writer);
|
|
if (gzip != null)
|
|
gzip.Close ();
|
|
writer.Close ();
|
|
collection_data = stream.ToArray ();
|
|
}
|
|
HttpStaticObjectsCollection sobjs = item.StaticObjects;
|
|
if (sobjs != null && sobjs.Count > 0)
|
|
sobjs_data = sobjs.ToByteArray ();
|
|
} catch (Exception ex) {
|
|
throw new HttpException ("Failed to store session data.", ex);
|
|
} finally {
|
|
|
|
if (writer != null)
|
|
writer.Dispose ();
|
|
if (gzip != null)
|
|
gzip.Dispose ();
|
|
if (stream != null)
|
|
stream.Dispose ();
|
|
}
|
|
|
|
stateServer.SetAndReleaseItemExclusive (id, collection_data, sobjs_data, lockId, item.Timeout, newItem);
|
|
}
|
|
|
|
public override bool SetItemExpireCallback (SessionStateItemExpireCallback expireCallback)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void EnsureGoodId (string id, bool throwOnNull)
|
|
{
|
|
if (id == null)
|
|
if (throwOnNull)
|
|
throw new HttpException ("Session ID is invalid");
|
|
else
|
|
return;
|
|
|
|
if (id.Length > SessionIDManager.SessionIDMaxLength)
|
|
throw new HttpException ("Session ID too long");
|
|
}
|
|
|
|
void GetConData (out string proto, out string server, out string port)
|
|
{
|
|
string cons = config.StateConnectionString;
|
|
int ei = cons.IndexOf ('=');
|
|
int ci = cons.IndexOf (':');
|
|
|
|
if (ei < 0 || ci < 0)
|
|
throw new HttpException ("Invalid StateConnectionString");
|
|
|
|
proto = cons.Substring (0, ei);
|
|
server = cons.Substring (ei+1, ci - ei - 1);
|
|
port = cons.Substring (ci+1, cons.Length - ci - 1);
|
|
|
|
if (proto == "tcpip")
|
|
proto = "tcp";
|
|
}
|
|
}
|
|
}
|