Index: IStateFormatter.cs =================================================================== --- IStateFormatter.cs (revision 68748) +++ IStateFormatter.cs (working copy) @@ -28,16 +28,20 @@ // -#if NET_2_0 using System; namespace System.Web.UI { - public interface IStateFormatter +#if NET_2_0 + public +#else + internal +#endif + interface IStateFormatter { object Deserialize (string serializationState); string Serialize (object state); } } -#endif + Index: Page.cs =================================================================== --- Page.cs (revision 68748) +++ Page.cs (working copy) @@ -86,7 +86,7 @@ private HttpContext _context; private ValidatorCollection _validators; private bool renderingForm; - private object _savedViewState; + private string _savedViewState; private ArrayList _requiresPostBack; private ArrayList _requiresPostBackCopy; private ArrayList requiresPostDataChanged; @@ -100,6 +100,7 @@ string clientTarget; ClientScriptManager scriptManager; bool allow_load; // true when the Form collection belongs to this page (GetTypeHashCode) + PageStatePersister page_state_persister; [EditorBrowsable (EditorBrowsableState.Never)] #if NET_2_0 @@ -320,6 +321,13 @@ set { _viewStateMac = value; } } +#if NET_1_1 + internal bool EnableViewStateMacInternal { + get { return _viewStateMac; } + set { _viewStateMac = value; } + } +#endif + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] [Browsable (false), DefaultValue ("")] [WebSysDescription ("The URL of a page used for error redirection.")] @@ -968,45 +976,17 @@ postBackScriptRendered = true; } - if (handleViewState) { - string vs = GetViewStateString (); - writer.Write ("", vs); - } + if (handleViewState) + writer.WriteLine ("", _savedViewState); scriptManager.WriteClientScriptBlocks (writer); } - internal LosFormatter GetFormatter () + internal IStateFormatter GetFormatter () { -#if NET_2_0 - PagesSection config = (PagesSection) WebConfigurationManager.GetSection ("system.web/pages"); -#else - PagesConfiguration config = PagesConfiguration.GetInstance (_context); -#endif - byte [] vkey = null; - if (config.EnableViewStateMac) { -#if NET_2_0 - MachineKeySection mconfig = (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey"); - vkey = mconfig.ValidationKeyBytes; -#else - MachineKeyConfig mconfig = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig; - vkey = mconfig.ValidationKey; -#endif - } - - return new LosFormatter (config.EnableViewStateMac, vkey); + return new ObjectStateFormatter (this); } - string GetViewStateString () - { - if (_savedViewState == null) - return null; - - LosFormatter fmt = GetFormatter (); - return fmt.SerializeToBase64 (_savedViewState); - } - internal object GetSavedViewState () { return _savedViewState; @@ -1457,46 +1437,69 @@ [EditorBrowsable (EditorBrowsableState.Advanced)] protected virtual void SavePageStateToPersistenceMedium (object viewState) { - _savedViewState = viewState; + PageStatePersister persister = this.PageStatePersister; + if (persister == null) + return; + Pair pair = viewState as Pair; + if (pair != null) { + persister.ViewState = pair.First; + persister.ControlState = pair.Second; + } else + persister.ViewState = viewState; + persister.Save (); } + internal string RawViewState { + get { + NameValueCollection postdata = _requestValueCollection; + string view_state; + if (postdata == null || (view_state = postdata ["__VIEWSTATE"]) == null) + return null; + + if (view_state == "") + return null; + return view_state; + } + set { _savedViewState = value; } + } + +#if NET_2_0 + protected virtual +#else + internal +#endif + PageStatePersister PageStatePersister { + get { + if (page_state_persister == null) + page_state_persister = new HiddenFieldPageStatePersister (this); + return page_state_persister; + } + } + [EditorBrowsable (EditorBrowsableState.Advanced)] protected virtual object LoadPageStateFromPersistenceMedium () { - NameValueCollection postdata = _requestValueCollection; - string view_state; - if (postdata == null || (view_state = postdata ["__VIEWSTATE"]) == null) + PageStatePersister persister = this.PageStatePersister; + if (persister == null) return null; - - if (view_state == "") - return null; - - LosFormatter fmt = GetFormatter (); - try { - return fmt.Deserialize (view_state); - } catch (Exception e) { - throw new HttpException ("Error restoring page viewstate.", e); - } + persister.Load (); + return new Pair (persister.ViewState, persister.ControlState); } internal void LoadPageViewState() { - object sState = LoadPageStateFromPersistenceMedium (); + Pair sState = LoadPageStateFromPersistenceMedium () as Pair; if (sState != null) { -#if NET_2_0 - Triplet data = (Triplet) sState; if (allow_load) { - LoadPageControlState (data.Third); - LoadViewStateRecursive (data.First); - _requiresPostBack = data.Second as ArrayList; - } -#else - Pair pair = (Pair) sState; - if (allow_load) { - LoadViewStateRecursive (pair.First); - _requiresPostBack = pair.Second as ArrayList; - } +#if NET_2_0 + LoadPageControlState (sState.Second); #endif + Pair vsr = sState.First as Pair; + if (vsr != null) { + LoadViewStateRecursive (vsr.First); + _requiresPostBack = vsr.Second as ArrayList; + } + } } } @@ -1511,27 +1514,23 @@ object viewState = SaveViewStateRecursive (); object reqPostback = (_requiresPostBack != null && _requiresPostBack.Count > 0) ? _requiresPostBack : null; + Pair vsr = null; -#if NET_2_0 - Triplet triplet = new Triplet (); - triplet.First = viewState; - triplet.Second = reqPostback; - triplet.Third = controlState; - - if (triplet.First == null && triplet.Second == null && triplet.Third == null) - triplet = null; - - SavePageStateToPersistenceMedium (triplet); -#else + if (viewState != null || reqPostback != null) + vsr = new Pair (viewState, reqPostback); Pair pair = new Pair (); - pair.First = viewState; - pair.Second = reqPostback; - if (pair.First == null && pair.Second == null) - pair = null; - - SavePageStateToPersistenceMedium (pair); + pair.First = vsr; +#if NET_2_0 + pair.Second = controlState; +#else + pair.Second = null; #endif + if (pair.First == null && pair.Second == null) + SavePageStateToPersistenceMedium (null); + else + SavePageStateToPersistenceMedium (pair); + } public virtual void Validate () Index: PageStatePersister.cs =================================================================== --- PageStatePersister.cs (revision 68748) +++ PageStatePersister.cs (working copy) @@ -26,50 +26,48 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if NET_2_0 - namespace System.Web.UI { - public abstract class PageStatePersister +#if NET_2_0 + public +#else + internal +#endif + abstract class PageStatePersister { + object control_state; + object view_state; + Page page; + IStateFormatter state_formatter; + protected PageStatePersister (Page page) { + if (page == null) + throw new ArgumentNullException ("page"); + this.page = page; } - public object ControlState - { - get { - throw new NotImplementedException (); - } - set { - throw new NotImplementedException (); - } + public object ControlState { + get { return control_state; } + set { control_state = value; } } - public object ViewState - { - get { - throw new NotImplementedException (); - } - set { - throw new NotImplementedException (); - } + public object ViewState { + get { return view_state; } + set { view_state = value; } } - protected Page Page - { - get { - throw new NotImplementedException (); - } - set { - throw new NotImplementedException (); - } + protected Page Page { + get { return page; } + set { page = value; } } protected IStateFormatter StateFormatter { get { - throw new NotImplementedException (); + if (state_formatter == null) + state_formatter = page.GetFormatter (); + return state_formatter; } } @@ -78,4 +76,3 @@ public abstract void Save (); } } -#endif \ No newline at end of file Index: LosFormatter.cs =================================================================== --- LosFormatter.cs (revision 68748) +++ LosFormatter.cs (working copy) @@ -39,12 +39,11 @@ [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] public sealed class LosFormatter { - ObjectStateFormatter osf = new ObjectStateFormatter (); - bool enable_mac; - HashAlgorithm algo; + ObjectStateFormatter osf; public LosFormatter () { + osf = new ObjectStateFormatter (); } #if NET_1_1 @@ -61,27 +60,12 @@ #endif LosFormatter (bool enableMac, byte[] macKeyModifier) { - this.enable_mac = enableMac; if (enableMac) - algo = new HMACSHA1 (macKeyModifier); + osf = new ObjectStateFormatter (macKeyModifier); + else + osf = new ObjectStateFormatter (); } - int ValidateInput (byte [] data, int offset, int size) - { - int hash_size = algo.HashSize / 8; - if (size != 0 && size < hash_size) - throw new HttpException ("Unable to validate data."); - - int data_length = size - hash_size; - MemoryStream data_stream = new MemoryStream (data, offset, data_length, false, false); - byte [] hash = algo.ComputeHash (data_stream); - for (int i = 0; i < hash_size; i++) { - if (hash [i] != data [data_length + i]) - throw new HttpException ("Unable to validate data."); - } - return data_length; - } - public object Deserialize (Stream stream) { if (stream == null) @@ -116,24 +100,12 @@ if (input == null) return null; - if (!enable_mac) - return osf.Deserialize (input); - - byte [] buffer = Convert.FromBase64String (input); - int length = buffer.Length; - length = ValidateInput (buffer, 0, length); - return osf.Deserialize (new MemoryStream (buffer, 0, length, false, false)); + return osf.Deserialize (input); } internal string SerializeToBase64 (object value) { - MemoryStream ms = new MemoryStream (); - osf.Serialize (ms, value); - if (enable_mac && ms.Length > 0) { - byte [] hash = algo.ComputeHash (ms.GetBuffer (), 0, (int) ms.Length); - ms.Write (hash, 0, hash.Length); - } - return Convert.ToBase64String (ms.GetBuffer (), 0, (int) ms.Length); + return osf.Serialize (value); } public void Serialize (Stream stream, object value) Index: ClientScriptManager.cs =================================================================== --- ClientScriptManager.cs (revision 68748) +++ ClientScriptManager.cs (working copy) @@ -473,7 +473,7 @@ { if (!page.EnableEventValidation || fieldValue == null || fieldValue.Length == 0) return; - LosFormatter fmt = page.GetFormatter (); + IStateFormatter fmt = page.GetFormatter (); eventValidationValues = (List )fmt.Deserialize (fieldValue); } @@ -482,8 +482,8 @@ if (!page.EnableEventValidation || eventValidationValues == null || eventValidationValues.Count == 0) return; eventValidationValues.Sort (); - LosFormatter fmt = page.GetFormatter (); - RegisterHiddenField (EventStateFieldName, fmt.SerializeToBase64 (eventValidationValues)); + IStateFormatter fmt = page.GetFormatter (); + RegisterHiddenField (EventStateFieldName, fmt.Serialize (eventValidationValues)); } internal string EventStateFieldName Index: ObjectStateFormatter.cs =================================================================== --- ObjectStateFormatter.cs (revision 68748) +++ ObjectStateFormatter.cs (working copy) @@ -44,6 +44,8 @@ using System.Web.UI.WebControls; using System.Web.Util; using System.Diagnostics; +using System.Security.Cryptography; +using System.Web.Configuration; namespace System.Web.UI { #if NET_2_0 @@ -51,11 +53,85 @@ #else internal #endif - sealed class ObjectStateFormatter : IFormatter + sealed class ObjectStateFormatter : IFormatter, IStateFormatter + { + Page page; + HashAlgorithm algo; + byte [] vkey; + + internal ObjectStateFormatter () + { + } + + internal ObjectStateFormatter (Page page) + { + this.page = page; + } + + internal ObjectStateFormatter (byte [] vkey) + { + this.vkey = vkey; + } + + internal bool EnableMac { + get { + if (page == null) { + if (vkey == null) + return false; + return true; + } else { + #if NET_2_0 - , IStateFormatter + return page.EnableViewStateMac; +#elif NET_1_1 + return page.EnableViewStateMacInternal; +#else + return false; #endif - { + } + } + } + + internal HashAlgorithm GetAlgo () { + if (algo != null) + return algo; + if (!EnableMac) + return null; + + byte [] algoKey; + if (page != null) { +#if NET_2_0 + MachineKeySection mconfig = (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey"); + algoKey = mconfig.ValidationKeyBytes; +#else + MachineKeyConfig mconfig = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig; + algoKey = mconfig.ValidationKey; +#endif + } else + algoKey = vkey; + + return new HMACSHA1 (algoKey); + } + + static int ValidateInput (HashAlgorithm algo, byte [] data, int offset, int size) + { + if (algo == null) + throw new HttpException ("Unable to validate data."); + + int hash_size = algo.HashSize / 8; + if (size != 0 && size < hash_size) + throw new HttpException ("Unable to validate data."); + + int data_length = size - hash_size; + MemoryStream data_stream = new MemoryStream (data, offset, data_length, false, false); + byte [] hash = algo.ComputeHash (data_stream); + for (int i = 0; i < hash_size; i++) { + if (hash [i] != data [data_length + i]) + throw new HttpException ("Unable to validate data."); + } + return data_length; + } + public object Deserialize (Stream inputStream) { if (inputStream == null) @@ -68,15 +144,20 @@ { if (inputString == null) throw new ArgumentNullException ("inputString"); -#if !NET_2_0 +#if NET_2_0 + if (inputString.Length == 0) + throw new ArgumentNullException ("inputString"); +#else if (inputString == "") return ""; #endif byte [] buffer = Convert.FromBase64String (inputString); - if (buffer == null || buffer.Length == 0) + int length; + if (buffer == null || (length = buffer.Length) == 0) throw new ArgumentNullException ("inputString"); - - return Deserialize (new MemoryStream (buffer)); + if (page != null && EnableMac) + length = ValidateInput (GetAlgo (), buffer, 0, length); + return Deserialize (new MemoryStream (buffer, 0, length, false, false)); } public string Serialize (object stateGraph) @@ -90,7 +171,14 @@ #if TRACE ms.WriteTo (File.OpenWrite (Path.GetTempFileName ())); #endif - + if (EnableMac && ms.Length > 0) { + HashAlgorithm algo = GetAlgo (); + if (algo != null) { + byte [] hash = algo.ComputeHash (ms.GetBuffer (), 0, (int) ms.Length); + ms.Write (hash, 0, hash.Length); + } + + } return Convert.ToBase64String (ms.GetBuffer (), 0, (int) ms.Length); } Index: HiddenFieldPageStatePersister.cs =================================================================== --- HiddenFieldPageStatePersister.cs (revision 0) +++ HiddenFieldPageStatePersister.cs (revision 0) @@ -0,0 +1,66 @@ +// +// System.Web.Compilation.AppCodeCompiler: A compiler for the App_Code folder +// +// Authors: +// Marek Habersack (grendello@gmail.com) +// +// (C) 2006 Marek Habersack +// + +// +// 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.Security.Permissions; + +namespace System.Web.UI +{ +#if NET_2_0 + // CAS + [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] + [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] + public +#else + internal +#endif + class HiddenFieldPageStatePersister : PageStatePersister + { + public HiddenFieldPageStatePersister (Page page) + : base(page) + { + } + + public override void Load () + { + IStateFormatter formatter = StateFormatter; + Pair pair = formatter.Deserialize (Page.RawViewState) as Pair; + if (pair != null) { + ViewState = pair.First; + ControlState = pair.Second; + } + } + + public override void Save () + { + IStateFormatter formatter = StateFormatter; + Page.RawViewState = formatter.Serialize (new Pair (ViewState, ControlState)); + } + } +} +