2 // System.Web.UI.ObjectStateFormatter
5 // Ben Maurer (bmaurer@users.sourceforge.net)
6 // Gonzalo Paniagua (gonzalo@ximian.com)
9 // (c) Copyright 2004 Novell, Inc. (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Collections;
36 using System.ComponentModel;
37 using System.Globalization;
40 using System.Reflection;
41 using System.Runtime.Serialization.Formatters.Binary;
42 using System.Runtime.Serialization;
44 using System.Web.UI.WebControls;
45 using System.Web.Util;
46 using System.Diagnostics;
47 using System.Security.Cryptography;
48 using System.Web.Configuration;
50 namespace System.Web.UI {
56 sealed class ObjectStateFormatter : IFormatter, IStateFormatter
62 internal ObjectStateFormatter ()
66 internal ObjectStateFormatter (Page page)
71 internal ObjectStateFormatter (byte [] vkey)
76 internal bool EnableMac {
85 return page.EnableViewStateMac;
87 return page.EnableViewStateMacInternal;
95 internal HashAlgorithm GetAlgo ()
105 MachineKeySection mconfig = (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey");
106 algoKey = MachineKeySectionUtils.ValidationKeyBytes (mconfig);
108 MachineKeyConfig mconfig = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig;
109 algoKey = mconfig.ValidationKey;
114 return new HMACSHA1 (algoKey);
117 static int ValidateInput (HashAlgorithm algo, byte [] data, int offset, int size)
120 throw new HttpException ("Unable to validate data.");
122 int hash_size = algo.HashSize / 8;
123 if (size != 0 && size < hash_size)
124 throw new HttpException ("Unable to validate data.");
126 int data_length = size - hash_size;
127 MemoryStream data_stream = new MemoryStream (data, offset, data_length, false, false);
128 byte [] hash = algo.ComputeHash (data_stream);
129 for (int i = 0; i < hash_size; i++) {
130 if (hash [i] != data [data_length + i])
131 throw new HttpException ("Unable to validate data.");
136 public object Deserialize (Stream inputStream)
138 if (inputStream == null)
139 throw new ArgumentNullException ("inputStream");
141 return DeserializeObject (new BinaryReader (inputStream));
144 public object Deserialize (string inputString)
146 if (inputString == null)
147 throw new ArgumentNullException ("inputString");
149 if (inputString.Length == 0)
150 throw new ArgumentNullException ("inputString");
152 if (inputString == "")
155 byte [] buffer = Convert.FromBase64String (inputString);
157 if (buffer == null || (length = buffer.Length) == 0)
158 throw new ArgumentNullException ("inputString");
159 if (page != null && EnableMac)
160 length = ValidateInput (GetAlgo (), buffer, 0, length);
162 bool isEncrypted = ((int)buffer [--length] == 1)? true : false;
164 Stream ms = new MemoryStream (buffer, 0, length, false, false);
167 ms = new CryptoStream (ms, page.GetCryptoTransform (CryptoStreamMode.Read), CryptoStreamMode.Read);
169 return Deserialize (ms);
172 public string Serialize (object stateGraph)
174 if (stateGraph == null)
177 MemoryStream ms = new MemoryStream ();
180 bool needEncryption = page == null ? false : page.NeedViewStateEncryption;
182 output = new CryptoStream (output, page.GetCryptoTransform (CryptoStreamMode.Write), CryptoStreamMode.Write);
185 Serialize (output, stateGraph);
187 ms.WriteByte((byte)(needEncryption? 1 : 0));
191 ms.WriteTo (File.OpenWrite (Path.GetTempFileName ()));
193 if (EnableMac && ms.Length > 0) {
194 HashAlgorithm algo = GetAlgo ();
196 byte [] hash = algo.ComputeHash (ms.GetBuffer (), 0, (int) ms.Length);
197 ms.Write (hash, 0, hash.Length);
201 return Convert.ToBase64String (ms.GetBuffer (), 0, (int) ms.Length);
204 public void Serialize (Stream outputStream, object stateGraph)
206 if (outputStream == null)
207 throw new ArgumentNullException ("outputStream");
209 if (stateGraph == null)
210 throw new ArgumentNullException ("stateGraph");
212 SerializeValue (new BinaryWriter (outputStream), stateGraph);
215 void SerializeValue (BinaryWriter w, object o)
217 ObjectFormatter.WriteObject (w, o, new WriterContext ());
220 object DeserializeObject (BinaryReader r)
222 return ObjectFormatter.ReadObject (r, new ReaderContext ());
227 object IFormatter.Deserialize (Stream serializationStream)
229 return Deserialize (serializationStream);
232 void IFormatter.Serialize (Stream serializationStream, object stateGraph)
234 Serialize (serializationStream, stateGraph);
237 SerializationBinder IFormatter.Binder {
242 StreamingContext IFormatter.Context {
243 get { return new StreamingContext (StreamingContextStates.All); }
247 ISurrogateSelector IFormatter.SurrogateSelector {
254 #region Object Readers/Writers
266 public bool RegisterCache (object o)
269 cache = new Hashtable ();
270 cache.Add (o, key = nextKey++);
274 object posKey = cache [o];
275 if (posKey == null) {
276 cache.Add (o, key = nextKey++);
280 key = (short) posKey;
289 public void CacheItem (object o)
292 cache = new ArrayList ();
297 public object GetCache (short key)
303 abstract class ObjectFormatter
305 static readonly Hashtable writeMap = new Hashtable ();
306 static ObjectFormatter [] readMap = new ObjectFormatter [256];
307 static BinaryObjectFormatter binaryObjectFormatter;
308 static TypeFormatter typeFormatter;
309 static EnumFormatter enumFormatter;
310 static SingleRankArrayFormatter singleRankArrayFormatter;
311 static TypeConverterFormatter typeConverterFormatter;
313 static ObjectFormatter ()
315 new StringFormatter ().Register ();
316 new Int64Formatter ().Register ();
317 new Int32Formatter ().Register ();
318 new Int16Formatter ().Register ();
319 new ByteFormatter ().Register ();
320 new BooleanFormatter ().Register ();
321 new CharFormatter ().Register ();
322 new DateTimeFormatter ().Register ();
323 new PairFormatter ().Register ();
324 new TripletFormatter ().Register ();
325 new ArrayListFormatter ().Register ();
326 new HashtableFormatter ().Register ();
327 new ObjectArrayFormatter ().Register ();
328 new UnitFormatter ().Register ();
329 new FontUnitFormatter ().Register ();
331 new ColorFormatter ().Register ();
333 enumFormatter = new EnumFormatter ();
334 enumFormatter.Register ();
336 typeFormatter = new TypeFormatter ();
337 typeFormatter.Register ();
339 singleRankArrayFormatter = new SingleRankArrayFormatter ();
340 singleRankArrayFormatter.Register ();
342 typeConverterFormatter = new TypeConverterFormatter ();
343 typeConverterFormatter.Register ();
345 binaryObjectFormatter = new BinaryObjectFormatter ();
346 binaryObjectFormatter.Register ();
350 static byte nextId = 1;
352 public ObjectFormatter ()
354 PrimaryId = nextId ++;
355 if (NumberOfIds == 1)
358 SecondaryId = nextId ++;
359 if (NumberOfIds == 2)
362 TertiaryId = nextId ++;
363 if (NumberOfIds == 3)
366 throw new Exception ();
369 protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
371 protected abstract void Write (BinaryWriter w, object o, WriterContext ctx);
372 protected abstract object Read (byte token, BinaryReader r, ReaderContext ctx);
373 protected abstract Type Type { get; }
374 protected virtual int NumberOfIds { get { return 1; } }
376 public virtual void Register ()
378 writeMap [Type] = this;
379 readMap [PrimaryId] = this;
380 if (SecondaryId != 255) {
381 readMap [SecondaryId] = this;
382 if (TertiaryId != 255)
383 readMap [TertiaryId] = this;
387 public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
391 Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
394 Trace.WriteLine ("Writing null");
396 long pos = w.BaseStream.Position;
404 Type t = o.GetType ();
406 ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
408 // Handle abstract types here
414 else if (t.IsArray && ((Array) o).Rank == 1)
415 fmt = singleRankArrayFormatter;
417 TypeConverter converter;
418 converter = TypeDescriptor.GetConverter (o);
419 if (converter == null ||
420 !converter.CanConvertTo (typeof (string)) ||
421 !converter.CanConvertFrom (typeof (string))) {
422 fmt = binaryObjectFormatter;
424 typeConverterFormatter.Converter = converter;
425 fmt = typeConverterFormatter;
430 fmt.Write (w, o, ctx);
433 Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
437 public static object ReadObject (BinaryReader r, ReaderContext ctx)
439 byte sig = r.ReadByte ();
444 return readMap [sig].Read (sig, r, ctx);
447 protected void Write7BitEncodedInt (BinaryWriter w, int value)
450 int high = (value >> 7) & 0x01ffffff;
451 byte b = (byte)(value & 0x7f);
454 b = (byte)(b | 0x80);
461 protected int Read7BitEncodedInt (BinaryReader r)
470 ret = ret | ((b & 0x7f) << shift);
472 } while ((b & 0x80) == 0x80);
478 #region Primitive Formatters
479 class StringFormatter : ObjectFormatter
481 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
483 if (ctx.RegisterCache (o)) {
484 w.Write (SecondaryId);
492 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
494 if (token == PrimaryId) {
495 string s = r.ReadString ();
499 return ctx.GetCache (r.ReadInt16 ());
502 protected override Type Type {
503 get { return typeof (string); }
506 protected override int NumberOfIds {
511 class Int64Formatter : ObjectFormatter
513 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
519 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
521 return r.ReadInt64 ();
523 protected override Type Type {
524 get { return typeof (long); }
528 class Int32Formatter : ObjectFormatter
530 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
533 if ((int)(byte) i == i) {
534 w.Write (SecondaryId);
542 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
544 if (token == PrimaryId)
545 return r.ReadInt32 ();
547 return (int) r.ReadByte ();
550 protected override Type Type {
551 get { return typeof (int); }
554 protected override int NumberOfIds {
559 class Int16Formatter : ObjectFormatter
561 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
567 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
569 return r.ReadInt16 ();
572 protected override Type Type {
573 get { return typeof (short); }
577 class ByteFormatter : ObjectFormatter
579 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
585 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
587 return r.ReadByte ();
590 protected override Type Type {
591 get { return typeof (byte); }
595 class BooleanFormatter : ObjectFormatter
597 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
602 w.Write (SecondaryId);
605 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
607 return token == PrimaryId;
610 protected override Type Type {
611 get { return typeof (bool); }
614 protected override int NumberOfIds {
619 class CharFormatter : ObjectFormatter
621 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
627 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
629 return r.ReadChar ();
632 protected override Type Type {
633 get { return typeof (char); }
637 class DateTimeFormatter : ObjectFormatter
639 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
642 w.Write (((DateTime) o).Ticks);
645 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
647 return new DateTime (r.ReadInt64 ());
650 protected override Type Type {
651 get { return typeof (DateTime); }
655 class PairFormatter : ObjectFormatter
657 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
661 WriteObject (w, p.First, ctx);
662 WriteObject (w, p.Second, ctx);
665 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
667 Pair p = new Pair ();
668 p.First = ReadObject (r, ctx);
669 p.Second = ReadObject (r, ctx);
673 protected override Type Type {
674 get { return typeof (Pair); }
678 class TripletFormatter : ObjectFormatter
680 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
682 Triplet t = (Triplet) o;
684 WriteObject (w, t.First, ctx);
685 WriteObject (w, t.Second, ctx);
686 WriteObject (w, t.Third, ctx);
689 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
691 Triplet t = new Triplet ();
692 t.First = ReadObject (r, ctx);
693 t.Second = ReadObject (r, ctx);
694 t.Third = ReadObject (r, ctx);
698 protected override Type Type {
699 get { return typeof (Triplet); }
703 class ArrayListFormatter : ObjectFormatter
705 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
707 ArrayList l = (ArrayList) o;
710 Write7BitEncodedInt (w, l.Count);
711 for (int i = 0; i < l.Count; i++)
712 WriteObject (w, l [i], ctx);
715 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
717 int len = Read7BitEncodedInt (r);
718 ArrayList l = new ArrayList (len);
720 for (int i = 0; i < len; i++)
721 l.Add (ReadObject (r, ctx));
726 protected override Type Type {
727 get { return typeof (ArrayList); }
731 class HashtableFormatter : ObjectFormatter
733 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
735 Hashtable ht = (Hashtable) o;
738 Write7BitEncodedInt (w, ht.Count);
739 foreach (DictionaryEntry de in ht) {
740 WriteObject (w, de.Key, ctx);
741 WriteObject (w, de.Value, ctx);
745 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
747 int len = Read7BitEncodedInt (r);
748 Hashtable ht = new Hashtable (len);
750 for (int i = 0; i < len; i++) {
751 object key = ReadObject (r, ctx);
752 object val = ReadObject (r, ctx);
760 protected override Type Type {
761 get { return typeof (Hashtable); }
765 class ObjectArrayFormatter : ObjectFormatter
767 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
769 object [] val = (object []) o;
772 Write7BitEncodedInt (w, val.Length);
773 for (int i = 0; i < val.Length; i++)
774 WriteObject (w, val [i], ctx);
777 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
779 int len = Read7BitEncodedInt (r);
780 object [] ret = new object [len];
782 for (int i = 0; i < len; i++)
783 ret [i] = ReadObject (r, ctx);
788 protected override Type Type {
789 get { return typeof (object []); }
795 #region System.Web Optimizations
796 class ColorFormatter : ObjectFormatter
798 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
802 if (c.IsEmpty || c.IsKnownColor) {
803 w.Write (SecondaryId);
805 w.Write (-1); //isempty marker
807 w.Write ((int) c.ToKnownColor ());
810 w.Write (c.ToArgb ());
814 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
816 int value = r.ReadInt32 ();
817 if (token == PrimaryId)
818 return Color.FromArgb (value);
820 if (value == -1) //isempty marker
822 return Color.FromKnownColor ((KnownColor)value);
826 protected override Type Type {
827 get { return typeof (Color); }
830 protected override int NumberOfIds {
837 #region Special Formatters
838 class EnumFormatter : ObjectFormatter
840 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
842 object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
844 WriteObject (w, o.GetType (), ctx);
845 WriteObject (w, value, ctx);
848 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
850 Type t = (Type) ReadObject (r, ctx);
851 object value = ReadObject (r, ctx);
853 return Enum.ToObject (t, value);
856 protected override Type Type {
857 get { return typeof (Enum); }
861 class TypeFormatter : ObjectFormatter
863 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
865 if (ctx.RegisterCache (o)) {
866 w.Write (SecondaryId);
870 w.Write (((Type) o).FullName);
872 // We should cache the name of the assembly
873 w.Write (((Type) o).Assembly.FullName);
877 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
879 if (token == PrimaryId) {
880 string type = r.ReadString ();
881 string assembly = r.ReadString ();
882 Type t = Assembly.Load (assembly).GetType (type);
886 return ctx.GetCache (r.ReadInt16 ());
890 protected override Type Type {
891 get { return typeof (Type); }
894 protected override int NumberOfIds {
899 class SingleRankArrayFormatter : ObjectFormatter
901 readonly BinaryFormatter _binaryFormatter = new BinaryFormatter ();
903 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
905 Array val = (Array) o;
906 if (val.GetType ().GetElementType ().IsPrimitive) {
907 w.Write (SecondaryId);
908 _binaryFormatter.Serialize (w.BaseStream, o);
913 WriteObject (w, val.GetType ().GetElementType (), ctx);
915 Write7BitEncodedInt (w, val.Length);
916 for (int i = 0; i < val.Length; i++)
917 WriteObject (w, val.GetValue (i), ctx);
920 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
922 if (token == SecondaryId)
923 return _binaryFormatter.Deserialize (r.BaseStream);
924 Type t = (Type) ReadObject (r, ctx);
925 int len = Read7BitEncodedInt (r);
926 Array val = Array.CreateInstance (t, len);
928 for (int i = 0; i < len; i++)
929 val.SetValue (ReadObject (r, ctx), i);
934 protected override Type Type {
935 get { return typeof (Array); }
938 protected override int NumberOfIds {
943 class FontUnitFormatter : StringFormatter
945 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
947 base.Write (w, o.ToString (), ctx);
950 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
952 return FontUnit.Parse ((string) base.Read (token, r, ctx));
955 protected override Type Type {
956 get { return typeof (FontUnit); }
960 class UnitFormatter : StringFormatter
962 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
964 base.Write (w, o.ToString (), ctx);
967 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
969 return Unit.Parse ((string) base.Read (token, r, ctx));
972 protected override Type Type {
973 get { return typeof (Unit); }
977 class TypeConverterFormatter : StringFormatter
979 TypeConverter converter;
981 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
984 ObjectFormatter.WriteObject (w, o.GetType (), ctx);
985 string v = (string) converter.ConvertTo (null, CultureInfo.InvariantCulture,
987 base.Write (w, v, ctx);
990 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
992 Type t = (Type) ObjectFormatter.ReadObject (r, ctx);
993 converter = TypeDescriptor.GetConverter (t);
994 token = r.ReadByte ();
995 string v = (string) base.Read (token, r, ctx);
996 return converter.ConvertFrom (null, CultureInfo.InvariantCulture, v);
999 protected override Type Type {
1000 get { return typeof (TypeConverter); }
1003 public TypeConverter Converter {
1004 set { converter = value; }
1008 class BinaryObjectFormatter : ObjectFormatter
1010 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
1012 w.Write (PrimaryId);
1014 MemoryStream ms = new MemoryStream (128);
1015 new BinaryFormatter ().Serialize (ms, o);
1017 byte [] buf = ms.GetBuffer ();
1018 Write7BitEncodedInt (w, buf.Length);
1019 w.Write (buf, 0, buf.Length);
1022 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
1024 int len = Read7BitEncodedInt (r);
1025 byte [] buf = r.ReadBytes (len);
1026 if (buf.Length != len)
1027 throw new Exception ();
1029 return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
1032 protected override Type Type {
1033 get { return typeof (object); }