Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.Web.Mvc / System.Web.Mvc / AntiForgeryTokenSerializer.cs
1 namespace System.Web.Mvc {\r
2     using System;\r
3     using System.Diagnostics.CodeAnalysis;\r
4     using System.IO;\r
5     using System.Web;\r
6     using System.Web.Mvc.Resources;\r
7     using System.Web.UI;\r
8 \r
9     internal class AntiForgeryTokenSerializer {\r
10 \r
11         private IStateFormatter _formatter;\r
12 \r
13         protected internal IStateFormatter Formatter {\r
14             get {\r
15                 if (_formatter == null) {\r
16                     _formatter = FormatterGenerator.GetFormatter();\r
17                 }\r
18                 return _formatter;\r
19             }\r
20             set {\r
21                 _formatter = value;\r
22             }\r
23         }\r
24 \r
25         private static HttpAntiForgeryException CreateValidationException(Exception innerException) {\r
26             return new HttpAntiForgeryException(MvcResources.AntiForgeryToken_ValidationFailed, innerException);\r
27         }\r
28 \r
29         public virtual AntiForgeryToken Deserialize(string serializedToken) {\r
30             if (String.IsNullOrEmpty(serializedToken)) {\r
31                 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "serializedToken");\r
32             }\r
33 \r
34             // call property getter outside try { } block so that exceptions bubble up for debugging\r
35             IStateFormatter formatter = Formatter;\r
36 \r
37             try {\r
38                 Triplet deserializedObj = (Triplet)formatter.Deserialize(serializedToken);\r
39                 return new AntiForgeryToken() {\r
40                     Salt = (string)deserializedObj.First,\r
41                     Value = (string)deserializedObj.Second,\r
42                     CreationDate = (DateTime)deserializedObj.Third\r
43                 };\r
44             }\r
45             catch (Exception ex) {\r
46                 throw CreateValidationException(ex);\r
47             }\r
48         }\r
49 \r
50         public virtual string Serialize(AntiForgeryToken token) {\r
51             if (token == null) {\r
52                 throw new ArgumentNullException("token");\r
53             }\r
54 \r
55             Triplet objToSerialize = new Triplet() {\r
56                 First = token.Salt,\r
57                 Second = token.Value,\r
58                 Third = token.CreationDate\r
59             };\r
60 \r
61             string serializedValue = Formatter.Serialize(objToSerialize);\r
62             return serializedValue;\r
63         }\r
64 \r
65         // See http://www.yoda.arachsys.com/csharp/singleton.html (fifth version - fully lazy) for the singleton pattern\r
66         // used here. We need to defer the call to TokenPersister.CreateFormatterGenerator() until we're actually\r
67         // servicing a request, else HttpContext.Current might be invalid in TokenPersister.CreateFormatterGenerator().\r
68         private static class FormatterGenerator {\r
69 \r
70             public static readonly Func<IStateFormatter> GetFormatter = TokenPersister.CreateFormatterGenerator();\r
71 \r
72             [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline",\r
73                 Justification = "This type must not be marked 'beforefieldinit'.")]\r
74             static FormatterGenerator() {\r
75             }\r
76 \r
77             // This type is very difficult to unit-test because Page.ProcessRequest() requires mocking\r
78             // much of the hosting environment. For now, we can perform functional tests of this feature.\r
79             private sealed class TokenPersister : PageStatePersister {\r
80                 private TokenPersister(Page page)\r
81                     : base(page) {\r
82                 }\r
83 \r
84                 public static Func<IStateFormatter> CreateFormatterGenerator() {\r
85                     // This code instantiates a page and tricks it into thinking that it's servicing\r
86                     // a postback scenario with encrypted ViewState, which is required to make the\r
87                     // StateFormatter properly decrypt data. Specifically, this code sets the\r
88                     // internal Page.ContainsEncryptedViewState flag.\r
89                     TextWriter writer = TextWriter.Null;\r
90                     HttpResponse response = new HttpResponse(writer);\r
91                     HttpRequest request = new HttpRequest("DummyFile.aspx", HttpContext.Current.Request.Url.ToString(), "__EVENTTARGET=true&__VIEWSTATEENCRYPTED=true");\r
92                     HttpContext context = new HttpContext(request, response);\r
93 \r
94                     Page page = new Page() {\r
95                         EnableViewStateMac = true,\r
96                         ViewStateEncryptionMode = ViewStateEncryptionMode.Always\r
97                     };\r
98                     page.ProcessRequest(context);\r
99 \r
100                     return () => new TokenPersister(page).StateFormatter;\r
101                 }\r
102 \r
103                 public override void Load() {\r
104                     throw new NotImplementedException();\r
105                 }\r
106 \r
107                 public override void Save() {\r
108                     throw new NotImplementedException();\r
109                 }\r
110             }\r
111         }\r
112 \r
113     }\r
114 }\r