New tests.
[mono.git] / mcs / class / System.Web.Mvc2 / System.Web.Mvc / MvcHtmlString.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\r
5  * This software is subject to the Microsoft Public License (Ms-PL). \r
6  * A copy of the license can be found in the license.htm file included \r
7  * in this distribution.\r
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc {\r
14     using System;\r
15     using System.ComponentModel;\r
16     using System.Linq.Expressions;\r
17     using System.Web;\r
18 \r
19     // In ASP.NET 4, a new syntax <%: %> is being introduced in WebForms pages, where <%: expression %> is equivalent to\r
20     // <%= HttpUtility.HtmlEncode(expression) %>. The intent of this is to reduce common causes of XSS vulnerabilities\r
21     // in WebForms pages (WebForms views in the case of MVC). This involves the addition of an interface\r
22     // System.Web.IHtmlString and a static method overload System.Web.HttpUtility::HtmlEncode(object).  The interface\r
23     // definition is roughly:\r
24     //   public interface IHtmlString {\r
25     //     string ToHtmlString();\r
26     //   }\r
27     // And the HtmlEncode(object) logic is roughly:\r
28     //   - If the input argument is an IHtmlString, return argument.ToHtmlString(),\r
29     //   - Otherwise, return HtmlEncode(Convert.ToString(argument)).\r
30     //\r
31     // Unfortunately this has the effect that calling <%: Html.SomeHelper() %> in an MVC application running on .NET 4\r
32     // will end up encoding output that is already HTML-safe. As a result, we're changing out HTML helpers to return\r
33     // MvcHtmlString where appropriate. <%= Html.SomeHelper() %> will continue to work in both .NET 3.5 and .NET 4, but\r
34     // changing the return types to MvcHtmlString has the added benefit that <%: Html.SomeHelper() %> will also work\r
35     // properly in .NET 4 rather than resulting in a double-encoded output. MVC developers in .NET 4 will then be able\r
36     // to use the <%: %> syntax almost everywhere instead of having to remember where to use <%= %> and where to use\r
37     // <%: %>. This should help developers craft more secure web applications by default.\r
38     //\r
39     // To create an MvcHtmlString, use the static Create() method instead of calling the protected constructor.\r
40 \r
41     public class MvcHtmlString {\r
42 \r
43         private delegate MvcHtmlString MvcHtmlStringCreator(string value);\r
44         private static readonly MvcHtmlStringCreator _creator = GetCreator();\r
45 \r
46         // imporant: this declaration must occur after the _creator declaration\r
47         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes",\r
48             Justification = "MvcHtmlString is immutable")]\r
49         public static readonly MvcHtmlString Empty = Create(String.Empty);\r
50 \r
51         private readonly string _value;\r
52 \r
53         // This constructor is only protected so that we can subclass it in a dynamic module. In practice,\r
54         // nobody should ever call this constructor, and it is likely to be removed in a future version\r
55         // of the framework. Use the static Create() method instead.\r
56         [EditorBrowsable(EditorBrowsableState.Never)]\r
57         [Obsolete("The recommended alternative is the static MvcHtmlString.Create(String value) method.")]\r
58         protected MvcHtmlString(string value) {\r
59             _value = value ?? String.Empty;\r
60         }\r
61 \r
62         public static MvcHtmlString Create(string value) {\r
63             return _creator(value);\r
64         }\r
65 \r
66         // in .NET 4, we dynamically create a type that subclasses MvcHtmlString and implements IHtmlString\r
67         private static MvcHtmlStringCreator GetCreator() {\r
68             Type iHtmlStringType = typeof(HttpContext).Assembly.GetType("System.Web.IHtmlString");\r
69             if (iHtmlStringType != null) {\r
70                 // first, create the dynamic type\r
71                 Type dynamicType = DynamicTypeGenerator.GenerateType("DynamicMvcHtmlString", typeof(MvcHtmlString), new Type[] { iHtmlStringType });\r
72 \r
73                 // then, create the delegate to instantiate the dynamic type\r
74                 ParameterExpression valueParamExpr = Expression.Parameter(typeof(string), "value");\r
75                 NewExpression newObjExpr = Expression.New(dynamicType.GetConstructor(new Type[] { typeof(string) }), valueParamExpr);\r
76                 Expression<MvcHtmlStringCreator> lambdaExpr = Expression.Lambda<MvcHtmlStringCreator>(newObjExpr, valueParamExpr);\r
77                 return lambdaExpr.Compile();\r
78             }\r
79             else {\r
80                 // disabling 0618 allows us to call the MvcHtmlString() constructor\r
81 #pragma warning disable 0618\r
82                 return value => new MvcHtmlString(value);\r
83 #pragma warning restore 0618\r
84             }\r
85         }\r
86 \r
87         public static bool IsNullOrEmpty(MvcHtmlString value) {\r
88             return (value == null || value._value.Length == 0);\r
89         }\r
90 \r
91         // IHtmlString.ToHtmlString()\r
92         public string ToHtmlString() {\r
93             return _value;\r
94         }\r
95 \r
96         public override string ToString() {\r
97             return _value;\r
98         }\r
99 \r
100     }\r
101 }\r