94b2861243
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
222 lines
9.2 KiB
C#
222 lines
9.2 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="SessionStateUtil.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* SessionStateUtil
|
|
*
|
|
*/
|
|
namespace System.Web.SessionState {
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Runtime.Serialization;
|
|
using System.Security.Permissions;
|
|
using System.Web;
|
|
using System.Web.Util;
|
|
using System.Xml;
|
|
|
|
public static class SessionStateUtility {
|
|
internal const String SESSION_KEY = "AspSession";
|
|
|
|
// Used by AltSerialization's BinaryFormatter for session serialization customization
|
|
public static ISurrogateSelector SerializationSurrogateSelector {
|
|
[SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
|
|
get;
|
|
[SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
|
|
set;
|
|
}
|
|
|
|
// Called by custom session state module if they want to raise Session_End.
|
|
static public void RaiseSessionEnd(IHttpSessionState session, Object eventSource, EventArgs eventArgs) {
|
|
HttpApplicationFactory.EndSession(new HttpSessionState(session), eventSource, eventArgs);
|
|
}
|
|
|
|
// Called by custom session state module
|
|
static public void AddHttpSessionStateToContext(HttpContext context, IHttpSessionState container) {
|
|
HttpSessionState sessionState = new HttpSessionState(container);
|
|
|
|
try {
|
|
context.Items.Add(SESSION_KEY, sessionState);
|
|
}
|
|
catch (ArgumentException) {
|
|
throw new HttpException(SR.GetString(SR.Cant_have_multiple_session_module));
|
|
}
|
|
}
|
|
|
|
static internal void AddHttpSessionStateModuleToContext(HttpContext context, SessionStateModule module, bool delayed) {
|
|
context.AddHttpSessionStateModule(module, delayed);
|
|
}
|
|
|
|
static internal void RemoveHttpSessionStateFromContext(HttpContext context, bool delayed) {
|
|
if (!delayed) {
|
|
context.Items.Remove(SESSION_KEY);
|
|
}
|
|
|
|
context.RemoveHttpSessionStateModule();
|
|
}
|
|
|
|
// Called by custom session state module
|
|
static public void RemoveHttpSessionStateFromContext(HttpContext context) {
|
|
RemoveHttpSessionStateFromContext(context, false);
|
|
}
|
|
|
|
// Called by custom session state module
|
|
static public IHttpSessionState GetHttpSessionStateFromContext(HttpContext context) {
|
|
return context.Session.Container;
|
|
}
|
|
|
|
static public HttpStaticObjectsCollection GetSessionStaticObjects(HttpContext context) {
|
|
return context.Application.SessionStaticObjects.Clone();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value that indicates whether session state is required by the context.
|
|
/// </summary>
|
|
/// <param name="context">The HttpContext.</param>
|
|
/// <returns>A value that indicates whether session state is required by the context.</returns>
|
|
static public bool IsSessionStateRequired(HttpContext context) {
|
|
return context.RequiresSessionState;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value that indicates whether session state is read-only in the context.
|
|
/// </summary>
|
|
/// <param name="context">The HttpContext.</param>
|
|
/// <returns>A value that indicates whether session state is read-only in the context.</returns>
|
|
static public bool IsSessionStateReadOnly(HttpContext context) {
|
|
return context.ReadOnlySessionState;
|
|
}
|
|
|
|
internal static SessionStateStoreData CreateLegitStoreData(HttpContext context,
|
|
ISessionStateItemCollection sessionItems,
|
|
HttpStaticObjectsCollection staticObjects,
|
|
int timeout) {
|
|
if (sessionItems == null) {
|
|
sessionItems = new SessionStateItemCollection();
|
|
}
|
|
|
|
if (staticObjects == null && context != null) {
|
|
staticObjects = SessionStateUtility.GetSessionStaticObjects(context);
|
|
}
|
|
|
|
return new SessionStateStoreData(sessionItems, staticObjects, timeout);
|
|
}
|
|
|
|
|
|
// This method will take an item and serialize it
|
|
[SecurityPermission(SecurityAction.Assert, SerializationFormatter = true)]
|
|
internal static void Serialize(SessionStateStoreData item, Stream stream) {
|
|
bool hasItems = true;
|
|
bool hasStaticObjects = true;
|
|
|
|
BinaryWriter writer = new BinaryWriter(stream);
|
|
writer.Write(item.Timeout);
|
|
|
|
if (item.Items == null || item.Items.Count == 0) {
|
|
hasItems = false;
|
|
}
|
|
writer.Write(hasItems);
|
|
|
|
if (item.StaticObjects == null || item.StaticObjects.NeverAccessed) {
|
|
hasStaticObjects = false;
|
|
}
|
|
writer.Write(hasStaticObjects);
|
|
|
|
if (hasItems) {
|
|
((SessionStateItemCollection)item.Items).Serialize(writer);
|
|
}
|
|
|
|
if (hasStaticObjects) {
|
|
item.StaticObjects.Serialize(writer);
|
|
}
|
|
|
|
// Prevent truncation of the stream
|
|
writer.Write(unchecked((byte)0xff));
|
|
}
|
|
|
|
// This will deserialize and return an item.
|
|
// This version uses the default classes for SessionStateItemCollection, HttpStaticObjectsCollection
|
|
// and SessionStateStoreData
|
|
[SecurityPermission(SecurityAction.Assert, SerializationFormatter = true)]
|
|
internal static SessionStateStoreData Deserialize(HttpContext context, Stream stream) {
|
|
|
|
int timeout;
|
|
SessionStateItemCollection sessionItems;
|
|
bool hasItems;
|
|
bool hasStaticObjects;
|
|
HttpStaticObjectsCollection staticObjects;
|
|
Byte eof;
|
|
|
|
Debug.Assert(context != null);
|
|
|
|
try {
|
|
BinaryReader reader = new BinaryReader(stream);
|
|
timeout = reader.ReadInt32();
|
|
hasItems = reader.ReadBoolean();
|
|
hasStaticObjects = reader.ReadBoolean();
|
|
|
|
if (hasItems) {
|
|
sessionItems = SessionStateItemCollection.Deserialize(reader);
|
|
}
|
|
else {
|
|
sessionItems = new SessionStateItemCollection();
|
|
}
|
|
|
|
if (hasStaticObjects) {
|
|
staticObjects = HttpStaticObjectsCollection.Deserialize(reader);
|
|
}
|
|
else {
|
|
staticObjects = SessionStateUtility.GetSessionStaticObjects(context);
|
|
}
|
|
|
|
eof = reader.ReadByte();
|
|
if (eof != 0xff) {
|
|
throw new HttpException(SR.GetString(SR.Invalid_session_state));
|
|
}
|
|
}
|
|
catch (EndOfStreamException) {
|
|
throw new HttpException(SR.GetString(SR.Invalid_session_state));
|
|
}
|
|
|
|
return new SessionStateStoreData(sessionItems, staticObjects, timeout);
|
|
}
|
|
|
|
static internal void SerializeStoreData(SessionStateStoreData item, int initialStreamSize, out byte[] buf, out int length, bool compressionEnabled) {
|
|
using(MemoryStream s = new MemoryStream(initialStreamSize)) {
|
|
SessionStateUtility.Serialize(item, s);
|
|
if(compressionEnabled) {
|
|
byte[] serializedBuffer = s.GetBuffer();
|
|
int serializedLength = (int)s.Length;
|
|
// truncate the MemoryStream so we can write the compressed data in it
|
|
s.SetLength(0);
|
|
// compress the serialized bytes
|
|
using(DeflateStream zipStream = new DeflateStream(s, CompressionMode.Compress, true)) {
|
|
zipStream.Write(serializedBuffer, 0, serializedLength);
|
|
}
|
|
// if the session state tables have ANSI_PADDING disabled, last )s are trimmed.
|
|
// This shouldn't happen, but to be sure, we are padding with an extra byte
|
|
s.WriteByte((byte)0xff);
|
|
}
|
|
buf = s.GetBuffer();
|
|
length = (int) s.Length;
|
|
}
|
|
}
|
|
|
|
static internal SessionStateStoreData DeserializeStoreData(HttpContext context, Stream stream, bool compressionEnabled) {
|
|
if(compressionEnabled) {
|
|
// apply the compression decorator on top of the stream
|
|
// the data should not be bigger than 4GB - compression doesn't work for more than that
|
|
using(DeflateStream zipStream = new DeflateStream(stream, CompressionMode.Decompress, true)) {
|
|
return SessionStateUtility.Deserialize(context, zipStream);
|
|
}
|
|
}
|
|
return SessionStateUtility.Deserialize(context, stream);
|
|
}
|
|
}
|
|
|
|
}
|