File: State\SessionStateUtil.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <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);
        }
    }
 
}