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 {
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;
285 class ReaderContext {
288 public void CacheItem (object o)
291 cache = new ArrayList ();
296 public object GetCache (short key)
302 abstract class ObjectFormatter {
303 static readonly Hashtable writeMap = new Hashtable ();
304 static ObjectFormatter [] readMap = new ObjectFormatter [256];
305 static BinaryObjectFormatter binaryObjectFormatter;
306 static TypeFormatter typeFormatter;
307 static EnumFormatter enumFormatter;
308 static SingleRankArrayFormatter singleRankArrayFormatter;
309 static TypeConverterFormatter typeConverterFormatter;
311 static ObjectFormatter ()
313 new StringFormatter ().Register ();
314 new Int64Formatter ().Register ();
315 new Int32Formatter ().Register ();
316 new Int16Formatter ().Register ();
317 new ByteFormatter ().Register ();
318 new BooleanFormatter ().Register ();
319 new CharFormatter ().Register ();
320 new DateTimeFormatter ().Register ();
321 new PairFormatter ().Register ();
322 new TripletFormatter ().Register ();
323 new ArrayListFormatter ().Register ();
324 new HashtableFormatter ().Register ();
325 new ObjectArrayFormatter ().Register ();
326 new UnitFormatter ().Register ();
327 new FontUnitFormatter ().Register ();
329 new ColorFormatter ().Register ();
331 enumFormatter = new EnumFormatter ();
332 enumFormatter.Register ();
334 typeFormatter = new TypeFormatter ();
335 typeFormatter.Register ();
337 singleRankArrayFormatter = new SingleRankArrayFormatter ();
338 singleRankArrayFormatter.Register ();
340 typeConverterFormatter = new TypeConverterFormatter ();
341 typeConverterFormatter.Register ();
343 binaryObjectFormatter = new BinaryObjectFormatter ();
344 binaryObjectFormatter.Register ();
348 static byte nextId = 1;
350 public ObjectFormatter ()
352 PrimaryId = nextId ++;
353 if (NumberOfIds == 1)
356 SecondaryId = nextId ++;
357 if (NumberOfIds == 2)
360 TertiaryId = nextId ++;
361 if (NumberOfIds == 3)
364 throw new Exception ();
367 protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
369 protected abstract void Write (BinaryWriter w, object o, WriterContext ctx);
370 protected abstract object Read (byte token, BinaryReader r, ReaderContext ctx);
371 protected abstract Type Type { get; }
372 protected virtual int NumberOfIds { get { return 1; } }
374 public virtual void Register ()
376 writeMap [Type] = this;
377 readMap [PrimaryId] = this;
378 if (SecondaryId != 255) {
379 readMap [SecondaryId] = this;
380 if (TertiaryId != 255)
381 readMap [TertiaryId] = this;
385 public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
389 Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
392 Trace.WriteLine ("Writing null");
394 long pos = w.BaseStream.Position;
402 Type t = o.GetType ();
404 ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
406 // Handle abstract types here
412 else if (t.IsArray && ((Array) o).Rank == 1)
413 fmt = singleRankArrayFormatter;
415 TypeConverter converter;
416 converter = TypeDescriptor.GetConverter (o);
417 if (converter == null ||
418 !converter.CanConvertTo (typeof (string)) ||
419 !converter.CanConvertFrom (typeof (string))) {
420 fmt = binaryObjectFormatter;
422 typeConverterFormatter.Converter = converter;
423 fmt = typeConverterFormatter;
428 fmt.Write (w, o, ctx);
431 Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
435 public static object ReadObject (BinaryReader r, ReaderContext ctx)
437 byte sig = r.ReadByte ();
442 return readMap [sig].Read (sig, r, ctx);
445 protected void Write7BitEncodedInt (BinaryWriter w, int value)
448 int high = (value >> 7) & 0x01ffffff;
449 byte b = (byte)(value & 0x7f);
452 b = (byte)(b | 0x80);
460 protected int Read7BitEncodedInt (BinaryReader r)
469 ret = ret | ((b & 0x7f) << shift);
471 } while ((b & 0x80) == 0x80);
477 #region Primitive Formatters
478 class StringFormatter : ObjectFormatter {
479 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
481 if (ctx.RegisterCache (o)) {
482 w.Write (SecondaryId);
490 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
492 if (token == PrimaryId) {
493 string s = r.ReadString ();
497 return ctx.GetCache (r.ReadInt16 ());
500 protected override Type Type {
501 get { return typeof (string); }
504 protected override int NumberOfIds {
509 class Int64Formatter : ObjectFormatter {
510 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
516 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
518 return r.ReadInt64 ();
520 protected override Type Type {
521 get { return typeof (long); }
525 class Int32Formatter : ObjectFormatter {
526 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
529 if ((int)(byte) i == i) {
530 w.Write (SecondaryId);
538 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
540 if (token == PrimaryId)
541 return r.ReadInt32 ();
543 return (int) r.ReadByte ();
545 protected override Type Type {
546 get { return typeof (int); }
549 protected override int NumberOfIds {
554 class Int16Formatter : ObjectFormatter {
555 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
561 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
563 return r.ReadInt16 ();
565 protected override Type Type {
566 get { return typeof (short); }
570 class ByteFormatter : ObjectFormatter {
571 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
577 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
579 return r.ReadByte ();
581 protected override Type Type {
582 get { return typeof (byte); }
586 class BooleanFormatter : ObjectFormatter {
587 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
592 w.Write (SecondaryId);
595 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
597 return token == PrimaryId;
600 protected override Type Type {
601 get { return typeof (bool); }
604 protected override int NumberOfIds {
609 class CharFormatter : ObjectFormatter {
610 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
616 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
618 return r.ReadChar ();
621 protected override Type Type {
622 get { return typeof (char); }
626 class DateTimeFormatter : ObjectFormatter {
627 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
630 w.Write (((DateTime) o).Ticks);
633 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
635 return new DateTime (r.ReadInt64 ());
638 protected override Type Type {
639 get { return typeof (DateTime); }
643 class PairFormatter : ObjectFormatter {
644 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
648 WriteObject (w, p.First, ctx);
649 WriteObject (w, p.Second, ctx);
652 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
654 Pair p = new Pair ();
655 p.First = ReadObject (r, ctx);
656 p.Second = ReadObject (r, ctx);
660 protected override Type Type {
661 get { return typeof (Pair); }
665 class TripletFormatter : ObjectFormatter {
666 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
668 Triplet t = (Triplet) o;
670 WriteObject (w, t.First, ctx);
671 WriteObject (w, t.Second, ctx);
672 WriteObject (w, t.Third, ctx);
675 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
677 Triplet t = new Triplet ();
678 t.First = ReadObject (r, ctx);
679 t.Second = ReadObject (r, ctx);
680 t.Third = ReadObject (r, ctx);
684 protected override Type Type {
685 get { return typeof (Triplet); }
689 class ArrayListFormatter : ObjectFormatter {
690 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
692 ArrayList l = (ArrayList) o;
695 Write7BitEncodedInt (w, l.Count);
696 for (int i = 0; i < l.Count; i++)
697 WriteObject (w, l [i], ctx);
700 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
702 int len = Read7BitEncodedInt (r);
703 ArrayList l = new ArrayList (len);
705 for (int i = 0; i < len; i++)
706 l.Add (ReadObject (r, ctx));
711 protected override Type Type {
712 get { return typeof (ArrayList); }
716 class HashtableFormatter : ObjectFormatter {
717 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
719 Hashtable ht = (Hashtable) o;
722 Write7BitEncodedInt (w, ht.Count);
723 foreach (DictionaryEntry de in ht) {
724 WriteObject (w, de.Key, ctx);
725 WriteObject (w, de.Value, ctx);
729 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
731 int len = Read7BitEncodedInt (r);
732 Hashtable ht = new Hashtable (len);
734 for (int i = 0; i < len; i++) {
735 object key = ReadObject (r, ctx);
736 object val = ReadObject (r, ctx);
744 protected override Type Type {
745 get { return typeof (Hashtable); }
749 class ObjectArrayFormatter : ObjectFormatter {
750 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
752 object [] val = (object []) o;
755 Write7BitEncodedInt (w, val.Length);
756 for (int i = 0; i < val.Length; i++)
757 WriteObject (w, val [i], ctx);
760 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
762 int len = Read7BitEncodedInt (r);
763 object [] ret = new object [len];
765 for (int i = 0; i < len; i++)
766 ret [i] = ReadObject (r, ctx);
771 protected override Type Type {
772 get { return typeof (object []); }
778 #region System.Web Optimizations
779 class ColorFormatter : ObjectFormatter {
780 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
784 if (c.IsEmpty || c.IsKnownColor) {
785 w.Write (SecondaryId);
787 w.Write (-1); //isempty marker
789 w.Write ((int) c.ToKnownColor ());
793 w.Write (c.ToArgb ());
797 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
799 int value = r.ReadInt32 ();
800 if (token == PrimaryId)
801 return Color.FromArgb (value);
803 if (value == -1) //isempty marker
805 return Color.FromKnownColor ((KnownColor)value);
809 protected override Type Type {
810 get { return typeof (Color); }
813 protected override int NumberOfIds {
820 #region Special Formatters
821 class EnumFormatter : ObjectFormatter {
822 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
824 object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
826 WriteObject (w, o.GetType (), ctx);
827 WriteObject (w, value, ctx);
830 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
832 Type t = (Type) ReadObject (r, ctx);
833 object value = ReadObject (r, ctx);
835 return Enum.ToObject (t, value);
837 protected override Type Type {
838 get { return typeof (Enum); }
842 class TypeFormatter : ObjectFormatter {
843 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
845 if (ctx.RegisterCache (o)) {
846 w.Write (SecondaryId);
850 w.Write (((Type) o).FullName);
852 // We should cache the name of the assembly
853 w.Write (((Type) o).Assembly.FullName);
857 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
859 if (token == PrimaryId) {
860 string type = r.ReadString ();
861 string assembly = r.ReadString ();
862 Type t = Assembly.Load (assembly).GetType (type);
866 return ctx.GetCache (r.ReadInt16 ());
870 protected override Type Type {
871 get { return typeof (Type); }
874 protected override int NumberOfIds {
879 class SingleRankArrayFormatter : ObjectFormatter {
881 readonly BinaryFormatter _binaryFormatter = new BinaryFormatter ();
883 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
885 Array val = (Array) o;
886 if (val.GetType ().GetElementType ().IsPrimitive) {
887 w.Write (SecondaryId);
888 _binaryFormatter.Serialize (w.BaseStream, o);
893 WriteObject (w, val.GetType ().GetElementType (), ctx);
895 Write7BitEncodedInt (w, val.Length);
896 for (int i = 0; i < val.Length; i++)
897 WriteObject (w, val.GetValue (i), ctx);
900 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
902 if (token == SecondaryId) {
903 return _binaryFormatter.Deserialize (r.BaseStream);
905 Type t = (Type) ReadObject (r, ctx);
906 int len = Read7BitEncodedInt (r);
907 Array val = Array.CreateInstance (t, len);
909 for (int i = 0; i < len; i++)
910 val.SetValue (ReadObject (r, ctx), i);
915 protected override Type Type {
916 get { return typeof (Array); }
919 protected override int NumberOfIds {
924 class FontUnitFormatter : StringFormatter {
925 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
927 base.Write (w, o.ToString (), ctx);
930 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
932 return FontUnit.Parse ((string) base.Read (token, r, ctx));
935 protected override Type Type {
936 get { return typeof (FontUnit); }
940 class UnitFormatter : StringFormatter {
941 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
943 base.Write (w, o.ToString (), ctx);
946 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
948 return Unit.Parse ((string) base.Read (token, r, ctx));
951 protected override Type Type {
952 get { return typeof (Unit); }
956 class TypeConverterFormatter : StringFormatter {
957 TypeConverter converter;
959 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
962 ObjectFormatter.WriteObject (w, o.GetType (), ctx);
963 string v = (string) converter.ConvertTo (null, CultureInfo.InvariantCulture,
965 base.Write (w, v, ctx);
968 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
970 Type t = (Type) ObjectFormatter.ReadObject (r, ctx);
971 converter = TypeDescriptor.GetConverter (t);
972 token = r.ReadByte ();
973 string v = (string) base.Read (token, r, ctx);
974 return converter.ConvertFrom (null, CultureInfo.InvariantCulture, v);
977 protected override Type Type {
978 get { return typeof (TypeConverter); }
981 public TypeConverter Converter {
982 set { converter = value; }
986 class BinaryObjectFormatter : ObjectFormatter {
987 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
991 MemoryStream ms = new MemoryStream (128);
992 new BinaryFormatter ().Serialize (ms, o);
994 byte [] buf = ms.GetBuffer ();
995 Write7BitEncodedInt (w, buf.Length);
996 w.Write (buf, 0, buf.Length);
999 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
1001 int len = Read7BitEncodedInt (r);
1002 byte [] buf = r.ReadBytes (len);
1003 if (buf.Length != len)
1004 throw new Exception ();
1006 return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
1009 protected override Type Type {
1010 get { return typeof (object); }