PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/referencesource/System.Web/Security/AntiXss/HtmlParameterEncoder.cs

https://github.com/pruiz/mono
C# | 239 lines | 106 code | 42 blank | 91 comment | 20 complexity | ef185bd209d487409dded2627f14f8c0 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //------------------------------------------------------------------------------
  2. // <copyright file="HtmlParameterEncoder.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. //------------------------------------------------------------------------------
  6. namespace System.Web.Security.AntiXss {
  7. using System;
  8. using System.Collections;
  9. using System.Text;
  10. using System.Threading;
  11. /// <summary>
  12. /// The type of space encoding to use.
  13. /// </summary>
  14. internal enum EncodingType {
  15. /// <summary>
  16. /// Encode spaces for use in query strings
  17. /// </summary>
  18. QueryString = 1,
  19. /// <summary>
  20. /// Encode spaces for use in form data
  21. /// </summary>
  22. HtmlForm = 2
  23. }
  24. /// <summary>
  25. /// Provides Html Parameter Encoding methods.
  26. /// </summary>
  27. internal static class HtmlParameterEncoder {
  28. /// <summary>
  29. /// The value to use when encoding a space for query strings.
  30. /// </summary>
  31. private static readonly char[] QueryStringSpace = "%20".ToCharArray();
  32. /// <summary>
  33. /// The value to use when encoding a space for form data.
  34. /// </summary>
  35. private static readonly char[] FormStringSpace = "+".ToCharArray();
  36. /// <summary>
  37. /// The values to output for each character.
  38. /// </summary>
  39. private static Lazy<char[][]> characterValuesLazy = new Lazy<char[][]>(InitialiseSafeList);
  40. /// <summary>
  41. /// Encodes a string for query string encoding and returns the encoded string.
  42. /// </summary>
  43. /// <param name="s">The text to URL-encode.</param>
  44. /// <param name="encoding">The encoding for the text parameter.</param>
  45. /// <returns>The URL-encoded text.</returns>
  46. /// <remarks>URL encoding ensures that all browsers will correctly transmit text in URL strings.
  47. /// Characters such as a question mark (?), ampersand (&amp;), slash mark (/), and spaces might be truncated or corrupted by some browsers.
  48. /// As a result, these characters must be encoded in &lt;a&gt; tags or in query strings where the strings can be re-sent by a browser
  49. /// in a request string.</remarks>
  50. /// <exception cref="ArgumentNullException">Thrown if the encoding is null.</exception>
  51. internal static string QueryStringParameterEncode(string s, Encoding encoding) {
  52. return FormQueryEncode(s, encoding, EncodingType.QueryString);
  53. }
  54. /// <summary>
  55. /// Encodes a string for form URL encoding and returns the encoded string.
  56. /// </summary>
  57. /// <param name="s">The text to URL-encode.</param>
  58. /// <param name="encoding">The encoding for the text parameter.</param>
  59. /// <returns>The URL-encoded text.</returns>
  60. /// <remarks>URL encoding ensures that all browsers will correctly transmit text in URL strings.
  61. /// Characters such as a question mark (?), ampersand (&amp;), slash mark (/), and spaces might be truncated or corrupted by some browsers.
  62. /// As a result, these characters must be encoded in &lt;a&gt; tags or in query strings where the strings can be re-sent by a browser
  63. /// in a request string.</remarks>
  64. /// <exception cref="ArgumentNullException">Thrown if the encoding is null.</exception>
  65. internal static string FormStringParameterEncode(string s, Encoding encoding) {
  66. return FormQueryEncode(s, encoding, EncodingType.HtmlForm);
  67. }
  68. /// <summary>
  69. /// Encodes a string for Query String or Form Data encoding.
  70. /// </summary>
  71. /// <param name="s">The text to URL-encode.</param>
  72. /// <param name="encoding">The encoding for the text parameter.</param>
  73. /// <param name="encodingType">The encoding type to use.</param>
  74. /// <returns>The encoded text.</returns>
  75. private static string FormQueryEncode(string s, Encoding encoding, EncodingType encodingType) {
  76. return FormQueryEncode(s, encoding, encodingType, characterValuesLazy);
  77. }
  78. private static string FormQueryEncode(string s, Encoding encoding, EncodingType encodingType, Lazy<char[][]> characterValuesLazy) {
  79. if (string.IsNullOrEmpty(s)) {
  80. return s;
  81. }
  82. if (encoding == null) {
  83. throw new ArgumentNullException("encoding");
  84. }
  85. var characterValues = characterValuesLazy.Value;
  86. // RFC 3986 states strings must be converted to their UTF8 value before URL encoding.
  87. // See http://tools.ietf.org/html/rfc3986
  88. // Conversion to char[] keeps null characters inline.
  89. byte[] utf8Bytes = encoding.GetBytes(s.ToCharArray());
  90. char[] encodedInput = new char[utf8Bytes.Length * 3]; // Each byte can potentially be encoded as %xx
  91. int outputLength = 0;
  92. for (int characterPosition = 0; characterPosition < utf8Bytes.Length; characterPosition++) {
  93. byte currentCharacter = utf8Bytes[characterPosition];
  94. if (currentCharacter == 0x00 || currentCharacter == 0x20 || currentCharacter > characterValues.Length || characterValues[currentCharacter] != null) {
  95. // character needs to be encoded
  96. char[] encodedCharacter;
  97. if (currentCharacter == 0x20) {
  98. switch (encodingType) {
  99. case EncodingType.QueryString:
  100. encodedCharacter = QueryStringSpace;
  101. break;
  102. // Special case for Html Form data, from http://www.w3.org/TR/html401/appendix/notes.html#non-ascii-chars
  103. case EncodingType.HtmlForm:
  104. encodedCharacter = FormStringSpace;
  105. break;
  106. default:
  107. throw new ArgumentOutOfRangeException("encodingType");
  108. }
  109. }
  110. else {
  111. encodedCharacter = characterValues[currentCharacter];
  112. }
  113. for (int j = 0; j < encodedCharacter.Length; j++) {
  114. encodedInput[outputLength++] = encodedCharacter[j];
  115. }
  116. }
  117. else {
  118. // character does not need encoding
  119. encodedInput[outputLength++] = (char)currentCharacter;
  120. }
  121. }
  122. return new string(encodedInput, 0, outputLength);
  123. }
  124. /// <summary>
  125. /// Initializes the HTML safe list.
  126. /// </summary>
  127. private static char[][] InitialiseSafeList() {
  128. char[][] result = SafeList.Generate(255, SafeList.PercentThenHexValueGenerator);
  129. SafeList.PunchSafeList(ref result, UrlParameterSafeList());
  130. return result;
  131. }
  132. /// <summary>
  133. /// Provides the safe characters for URL parameter encoding.
  134. /// </summary>
  135. /// <returns>The safe characters for URL parameter encoding.</returns>
  136. private static IEnumerable UrlParameterSafeList() {
  137. // Hyphen
  138. yield return 0x2D;
  139. // Full stop/period
  140. yield return 0x2E;
  141. // Digits
  142. for (int i = 0x30; i <= 0x39; i++) {
  143. yield return i;
  144. }
  145. // Upper case alphabet
  146. for (int i = 0x41; i <= 0x5A; i++) {
  147. yield return i;
  148. }
  149. // Underscore
  150. yield return 0x5F;
  151. // Lower case alphabet
  152. for (int i = 0x61; i <= 0x7A; i++) {
  153. yield return i;
  154. }
  155. // Tilde
  156. yield return 0x7E;
  157. }
  158. #region UrlPathEncode Helpers
  159. /// <summary>
  160. /// The values to output for each character.
  161. /// </summary>
  162. private static Lazy<char[][]> pathCharacterValuesLazy = new Lazy<char[][]>(InitialisePathSafeList);
  163. internal static string UrlPathEncode(string s, Encoding encoding) {
  164. return FormQueryEncode(s, encoding, EncodingType.QueryString, pathCharacterValuesLazy);
  165. }
  166. /// <summary>
  167. /// Initializes the HTML safe list.
  168. /// </summary>
  169. private static char[][] InitialisePathSafeList() {
  170. char[][] result = SafeList.Generate(255, SafeList.PercentThenHexValueGenerator);
  171. SafeList.PunchSafeList(ref result, UrlPathSafeList());
  172. return result;
  173. }
  174. /// <summary>
  175. /// Provides the safe characters for URL path encoding.
  176. /// </summary>
  177. /// <returns>The safe characters for URL path encoding.</returns>
  178. private static IEnumerable UrlPathSafeList() {
  179. foreach (var c in UrlParameterSafeList()) {
  180. yield return c;
  181. }
  182. // Hash
  183. yield return 0x23;
  184. // Percent
  185. yield return 0x25;
  186. // Forward slash
  187. yield return 0x2F;
  188. // Backwards slash
  189. yield return 0x5C;
  190. // Left parenthesis
  191. yield return 0x28;
  192. //Right parenthesis
  193. yield return 0x29;
  194. }
  195. #endregion
  196. }
  197. }