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 () {
104 MachineKeySection mconfig = (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey");
105 algoKey = mconfig.ValidationKeyBytes;
107 MachineKeyConfig mconfig = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig;
108 algoKey = mconfig.ValidationKey;
113 return new HMACSHA1 (algoKey);
116 static int ValidateInput (HashAlgorithm algo, byte [] data, int offset, int size)
119 throw new HttpException ("Unable to validate data.");
121 int hash_size = algo.HashSize / 8;
122 if (size != 0 && size < hash_size)
123 throw new HttpException ("Unable to validate data.");
125 int data_length = size - hash_size;
126 MemoryStream data_stream = new MemoryStream (data, offset, data_length, false, false);
127 byte [] hash = algo.ComputeHash (data_stream);
128 for (int i = 0; i < hash_size; i++) {
129 if (hash [i] != data [data_length + i])
130 throw new HttpException ("Unable to validate data.");
135 public object Deserialize (Stream inputStream)
137 if (inputStream == null)
138 throw new ArgumentNullException ("inputStream");
140 return DeserializeObject (new BinaryReader (inputStream));
143 public object Deserialize (string inputString)
145 if (inputString == null)
146 throw new ArgumentNullException ("inputString");
148 if (inputString.Length == 0)
149 throw new ArgumentNullException ("inputString");
151 if (inputString == "")
154 byte [] buffer = Convert.FromBase64String (inputString);
156 if (buffer == null || (length = buffer.Length) == 0)
157 throw new ArgumentNullException ("inputString");
158 if (page != null && EnableMac)
159 length = ValidateInput (GetAlgo (), buffer, 0, length);
161 bool isEncrypted = ((int)buffer [--length] == 1)? true : false;
163 Stream ms = new MemoryStream (buffer, 0, length, false, false);
166 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
256 class WriterContext {
260 public bool RegisterCache (object o, out short key)
263 cache = new Hashtable ();
264 cache.Add (o, key = nextKey++);
268 object posKey = cache [o];
269 if (posKey == null) {
270 cache.Add (o, key = nextKey++);
274 key = (short) posKey;
279 class ReaderContext {
282 public void CacheItem (object o)
285 cache = new ArrayList ();
290 public object GetCache (short key)
296 abstract class ObjectFormatter {
297 static readonly Hashtable writeMap = new Hashtable ();
298 static ObjectFormatter [] readMap = new ObjectFormatter [256];
299 static BinaryObjectFormatter binaryObjectFormatter;
300 static TypeFormatter typeFormatter;
301 static EnumFormatter enumFormatter;
302 static SingleRankArrayFormatter singleRankArrayFormatter;
303 static TypeConverterFormatter typeConverterFormatter;
305 static ObjectFormatter ()
307 new StringFormatter ().Register ();
308 new Int64Formatter ().Register ();
309 new Int32Formatter ().Register ();
310 new Int16Formatter ().Register ();
311 new ByteFormatter ().Register ();
312 new BooleanFormatter ().Register ();
313 new CharFormatter ().Register ();
314 new DateTimeFormatter ().Register ();
315 new PairFormatter ().Register ();
316 new TripletFormatter ().Register ();
317 new ArrayListFormatter ().Register ();
318 new HashtableFormatter ().Register ();
319 new ObjectArrayFormatter ().Register ();
320 new UnitFormatter ().Register ();
321 new FontUnitFormatter ().Register ();
323 new ColorFormatter ().Register ();
325 enumFormatter = new EnumFormatter ();
326 enumFormatter.Register ();
328 typeFormatter = new TypeFormatter ();
329 typeFormatter.Register ();
331 singleRankArrayFormatter = new SingleRankArrayFormatter ();
332 singleRankArrayFormatter.Register ();
334 typeConverterFormatter = new TypeConverterFormatter ();
335 typeConverterFormatter.Register ();
337 binaryObjectFormatter = new BinaryObjectFormatter ();
338 binaryObjectFormatter.Register ();
342 static byte nextId = 1;
344 public ObjectFormatter ()
346 PrimaryId = nextId ++;
347 if (NumberOfIds == 1)
350 SecondaryId = nextId ++;
351 if (NumberOfIds == 2)
354 TertiaryId = nextId ++;
355 if (NumberOfIds == 3)
358 throw new Exception ();
361 protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
363 protected abstract void Write (BinaryWriter w, object o, WriterContext ctx);
364 protected abstract object Read (byte token, BinaryReader r, ReaderContext ctx);
365 protected abstract Type Type { get; }
366 protected virtual int NumberOfIds { get { return 1; } }
368 public virtual void Register ()
370 writeMap [Type] = this;
371 readMap [PrimaryId] = this;
372 if (SecondaryId != 255) {
373 readMap [SecondaryId] = this;
374 if (TertiaryId != 255)
375 readMap [TertiaryId] = this;
379 public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
383 Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
386 Trace.WriteLine ("Writing null");
388 long pos = w.BaseStream.Position;
396 Type t = o.GetType ();
398 ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
400 // Handle abstract types here
406 else if (t.IsArray && ((Array) o).Rank == 1)
407 fmt = singleRankArrayFormatter;
409 TypeConverter converter;
410 converter = TypeDescriptor.GetConverter (o);
411 if (converter == null ||
412 !converter.CanConvertTo (typeof (string)) ||
413 !converter.CanConvertFrom (typeof (string))) {
414 fmt = binaryObjectFormatter;
416 typeConverterFormatter.Converter = converter;
417 fmt = typeConverterFormatter;
422 fmt.Write (w, o, ctx);
425 Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
429 public static object ReadObject (BinaryReader r, ReaderContext ctx)
431 byte sig = r.ReadByte ();
436 return readMap [sig].Read (sig, r, ctx);
439 protected void Write7BitEncodedInt (BinaryWriter w, int value)
442 int high = (value >> 7) & 0x01ffffff;
443 byte b = (byte)(value & 0x7f);
446 b = (byte)(b | 0x80);
454 protected int Read7BitEncodedInt (BinaryReader r)
463 ret = ret | ((b & 0x7f) << shift);
465 } while ((b & 0x80) == 0x80);
471 #region Primitive Formatters
472 class StringFormatter : ObjectFormatter {
473 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
476 if (ctx.RegisterCache (o, out key)) {
477 w.Write (SecondaryId);
485 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
487 if (token == PrimaryId) {
488 string s = r.ReadString ();
492 return ctx.GetCache (r.ReadInt16 ());
495 protected override Type Type {
496 get { return typeof (string); }
499 protected override int NumberOfIds {
504 class Int64Formatter : ObjectFormatter {
505 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
511 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
513 return r.ReadInt64 ();
515 protected override Type Type {
516 get { return typeof (long); }
520 class Int32Formatter : ObjectFormatter {
521 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
524 if ((int)(byte) i == i) {
525 w.Write (SecondaryId);
533 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
535 if (token == PrimaryId)
536 return r.ReadInt32 ();
538 return (int) r.ReadByte ();
540 protected override Type Type {
541 get { return typeof (int); }
544 protected override int NumberOfIds {
549 class Int16Formatter : ObjectFormatter {
550 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
556 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
558 return r.ReadInt16 ();
560 protected override Type Type {
561 get { return typeof (short); }
565 class ByteFormatter : ObjectFormatter {
566 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
572 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
574 return r.ReadByte ();
576 protected override Type Type {
577 get { return typeof (byte); }
581 class BooleanFormatter : ObjectFormatter {
582 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
587 w.Write (SecondaryId);
590 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
592 return token == PrimaryId;
595 protected override Type Type {
596 get { return typeof (bool); }
599 protected override int NumberOfIds {
604 class CharFormatter : ObjectFormatter {
605 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
611 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
613 return r.ReadChar ();
616 protected override Type Type {
617 get { return typeof (char); }
621 class DateTimeFormatter : ObjectFormatter {
622 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
625 w.Write (((DateTime) o).Ticks);
628 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
630 return new DateTime (r.ReadInt64 ());
633 protected override Type Type {
634 get { return typeof (DateTime); }
638 class PairFormatter : ObjectFormatter {
639 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
643 WriteObject (w, p.First, ctx);
644 WriteObject (w, p.Second, ctx);
647 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
649 Pair p = new Pair ();
650 p.First = ReadObject (r, ctx);
651 p.Second = ReadObject (r, ctx);
655 protected override Type Type {
656 get { return typeof (Pair); }
660 class TripletFormatter : ObjectFormatter {
661 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
663 Triplet t = (Triplet) o;
665 WriteObject (w, t.First, ctx);
666 WriteObject (w, t.Second, ctx);
667 WriteObject (w, t.Third, ctx);
670 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
672 Triplet t = new Triplet ();
673 t.First = ReadObject (r, ctx);
674 t.Second = ReadObject (r, ctx);
675 t.Third = ReadObject (r, ctx);
679 protected override Type Type {
680 get { return typeof (Triplet); }
684 class ArrayListFormatter : ObjectFormatter {
685 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
687 ArrayList l = (ArrayList) o;
690 Write7BitEncodedInt (w, l.Count);
691 foreach (object i in l)
692 WriteObject (w, i, ctx);
695 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
697 int len = Read7BitEncodedInt (r);
698 ArrayList l = new ArrayList (len);
700 for (int i = 0; i < len; i++)
701 l.Add (ReadObject (r, ctx));
706 protected override Type Type {
707 get { return typeof (ArrayList); }
711 class HashtableFormatter : ObjectFormatter {
712 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
714 Hashtable ht = (Hashtable) o;
717 Write7BitEncodedInt (w, ht.Count);
718 foreach (DictionaryEntry de in ht) {
719 WriteObject (w, de.Key, ctx);
720 WriteObject (w, de.Value, ctx);
724 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
726 int len = Read7BitEncodedInt (r);
727 Hashtable ht = new Hashtable (len);
729 for (int i = 0; i < len; i++) {
730 object key = ReadObject (r, ctx);
731 object val = ReadObject (r, ctx);
739 protected override Type Type {
740 get { return typeof (Hashtable); }
744 class ObjectArrayFormatter : ObjectFormatter {
745 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
747 object [] val = (object []) o;
750 Write7BitEncodedInt (w, val.Length);
751 foreach (object i in val)
752 WriteObject (w, i, ctx);
755 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
757 int len = Read7BitEncodedInt (r);
758 object [] ret = new object [len];
760 for (int i = 0; i < len; i++)
761 ret [i] = ReadObject (r, ctx);
766 protected override Type Type {
767 get { return typeof (object []); }
773 #region System.Web Optimizations
774 class ColorFormatter : ObjectFormatter {
775 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
779 if (c.IsEmpty || c.IsKnownColor) {
780 w.Write (SecondaryId);
782 w.Write (-1); //isempty marker
784 w.Write ((int) c.ToKnownColor ());
788 w.Write (c.ToArgb ());
792 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
794 int value = r.ReadInt32 ();
795 if (token == PrimaryId)
796 return Color.FromArgb (value);
798 if (value == -1) //isempty marker
800 return Color.FromKnownColor ((KnownColor)value);
804 protected override Type Type {
805 get { return typeof (Color); }
808 protected override int NumberOfIds {
815 #region Special Formatters
816 class EnumFormatter : ObjectFormatter {
817 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
819 object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
821 WriteObject (w, o.GetType (), ctx);
822 WriteObject (w, value, ctx);
825 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
827 Type t = (Type) ReadObject (r, ctx);
828 object value = ReadObject (r, ctx);
830 return Enum.ToObject (t, value);
832 protected override Type Type {
833 get { return typeof (Enum); }
837 class TypeFormatter : ObjectFormatter {
838 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
841 if (ctx.RegisterCache (o, out key)) {
842 w.Write (SecondaryId);
846 w.Write (((Type) o).FullName);
848 // We should cache the name of the assembly
849 w.Write (((Type) o).Assembly.FullName);
853 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
855 if (token == PrimaryId) {
856 string type = r.ReadString ();
857 string assembly = r.ReadString ();
858 Type t = Assembly.Load (assembly).GetType (type);
862 return ctx.GetCache (r.ReadInt16 ());
866 protected override Type Type {
867 get { return typeof (Type); }
870 protected override int NumberOfIds {
875 class SingleRankArrayFormatter : ObjectFormatter {
877 readonly BinaryFormatter _binaryFormatter = new BinaryFormatter ();
879 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
881 Array val = (Array) o;
882 if (val.GetType ().GetElementType ().IsPrimitive) {
883 w.Write (SecondaryId);
884 _binaryFormatter.Serialize (w.BaseStream, o);
889 WriteObject (w, val.GetType ().GetElementType (), ctx);
891 Write7BitEncodedInt (w, val.Length);
892 foreach (object i in val)
893 WriteObject (w, i, ctx);
896 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
898 if (token == SecondaryId) {
899 return _binaryFormatter.Deserialize (r.BaseStream);
901 Type t = (Type) ReadObject (r, ctx);
902 int len = Read7BitEncodedInt (r);
903 Array val = Array.CreateInstance (t, len);
905 for (int i = 0; i < len; i++)
906 val.SetValue (ReadObject (r, ctx), i);
911 protected override Type Type {
912 get { return typeof (Array); }
915 protected override int NumberOfIds {
920 class FontUnitFormatter : StringFormatter {
921 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
923 base.Write (w, o.ToString (), ctx);
926 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
928 return FontUnit.Parse ((string) base.Read (token, r, ctx));
931 protected override Type Type {
932 get { return typeof (FontUnit); }
936 class UnitFormatter : StringFormatter {
937 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
939 base.Write (w, o.ToString (), ctx);
942 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
944 return Unit.Parse ((string) base.Read (token, r, ctx));
947 protected override Type Type {
948 get { return typeof (Unit); }
952 class TypeConverterFormatter : StringFormatter {
953 TypeConverter converter;
955 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
958 ObjectFormatter.WriteObject (w, o.GetType (), ctx);
959 string v = (string) converter.ConvertTo (null, CultureInfo.InvariantCulture,
961 base.Write (w, v, ctx);
964 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
966 Type t = (Type) ObjectFormatter.ReadObject (r, ctx);
967 converter = TypeDescriptor.GetConverter (t);
968 token = r.ReadByte ();
969 string v = (string) base.Read (token, r, ctx);
970 return converter.ConvertFrom (null, CultureInfo.InvariantCulture, v);
973 protected override Type Type {
974 get { return typeof (TypeConverter); }
977 public TypeConverter Converter {
978 set { converter = value; }
982 class BinaryObjectFormatter : ObjectFormatter {
983 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
987 MemoryStream ms = new MemoryStream (128);
988 new BinaryFormatter ().Serialize (ms, o);
990 byte [] buf = ms.GetBuffer ();
991 Write7BitEncodedInt (w, buf.Length);
992 w.Write (buf, 0, buf.Length);
995 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
997 int len = Read7BitEncodedInt (r);
998 byte [] buf = r.ReadBytes (len);
999 if (buf.Length != len)
1000 throw new Exception ();
1002 return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
1005 protected override Type Type {
1006 get { return typeof (object); }