2 // System.Web.HttpUtility
5 // Patrik Torstensson (Patrik.Torstensson@labs2.com)
6 // Wictor Wilén (decode/encode functions) (wictor@ibizkit.se)
7 // Tim Coleman (tim@timcoleman.com)
8 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 // Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Collections.Specialized;
35 using System.Globalization;
37 using System.Security.Permissions;
39 using System.Web.Util;
41 namespace System.Web {
44 // CAS - no InheritanceDemand here as the class is sealed
45 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47 public sealed class HttpUtility
49 sealed class HttpQSCollection : NameValueCollection
51 public override string ToString ()
56 StringBuilder sb = new StringBuilder ();
57 string [] keys = AllKeys;
58 for (int i = 0; i < count; i++) {
59 sb.AppendFormat ("{0}={1}&", keys [i], UrlEncode (this [keys [i]]));
63 return sb.ToString ();
73 #endregion // Constructors
77 public static void HtmlAttributeEncode (string s, TextWriter output)
80 throw new ArgumentNullException ("output");
82 HttpEncoder.Current.HtmlAttributeEncode (s, output);
85 public static string HtmlAttributeEncode (string s)
90 using (var sw = new StringWriter ()) {
91 HttpEncoder.Current.HtmlAttributeEncode (s, sw);
92 return sw.ToString ();
96 public static string UrlDecode (string str)
98 return UrlDecode(str, Encoding.UTF8);
101 static char [] GetChars (MemoryStream b, Encoding e)
103 return e.GetChars (b.GetBuffer (), 0, (int) b.Length);
106 static void WriteCharBytes (IList buf, char ch, Encoding e)
109 foreach (byte b in e.GetBytes (new char[] { ch }))
115 public static string UrlDecode (string s, Encoding e)
120 if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1)
127 var bytes = new List <byte> ();
131 for (int i = 0; i < len; i++) {
133 if (ch == '%' && i + 2 < len && s [i + 1] != '%') {
134 if (s [i + 1] == 'u' && i + 5 < len) {
135 // unicode hex sequence
136 xchar = GetChar (s, i + 2, 4);
138 WriteCharBytes (bytes, (char)xchar, e);
141 WriteCharBytes (bytes, '%', e);
142 } else if ((xchar = GetChar (s, i + 1, 2)) != -1) {
143 WriteCharBytes (bytes, (char)xchar, e);
146 WriteCharBytes (bytes, '%', e);
152 WriteCharBytes (bytes, ' ', e);
154 WriteCharBytes (bytes, ch, e);
157 byte[] buf = bytes.ToArray ();
159 return e.GetString (buf);
163 public static string UrlDecode (byte [] bytes, Encoding e)
168 return UrlDecode (bytes, 0, bytes.Length, e);
171 static int GetInt (byte b)
174 if (c >= '0' && c <= '9')
177 if (c >= 'a' && c <= 'f')
180 if (c >= 'A' && c <= 'F')
186 static int GetChar (byte [] bytes, int offset, int length)
189 int end = length + offset;
190 for (int i = offset; i < end; i++) {
191 int current = GetInt (bytes [i]);
194 value = (value << 4) + current;
200 static int GetChar (string str, int offset, int length)
203 int end = length + offset;
204 for (int i = offset; i < end; i++) {
209 int current = GetInt ((byte) c);
212 val = (val << 4) + current;
218 public static string UrlDecode (byte [] bytes, int offset, int count, Encoding e)
226 throw new ArgumentNullException ("bytes");
228 if (offset < 0 || offset > bytes.Length)
229 throw new ArgumentOutOfRangeException ("offset");
231 if (count < 0 || offset + count > bytes.Length)
232 throw new ArgumentOutOfRangeException ("count");
234 StringBuilder output = new StringBuilder ();
235 MemoryStream acc = new MemoryStream ();
237 int end = count + offset;
239 for (int i = offset; i < end; i++) {
240 if (bytes [i] == '%' && i + 2 < count && bytes [i + 1] != '%') {
241 if (bytes [i + 1] == (byte) 'u' && i + 5 < end) {
242 if (acc.Length > 0) {
243 output.Append (GetChars (acc, e));
246 xchar = GetChar (bytes, i + 2, 4);
248 output.Append ((char) xchar);
252 } else if ((xchar = GetChar (bytes, i + 1, 2)) != -1) {
253 acc.WriteByte ((byte) xchar);
259 if (acc.Length > 0) {
260 output.Append (GetChars (acc, e));
264 if (bytes [i] == '+') {
267 output.Append ((char) bytes [i]);
271 if (acc.Length > 0) {
272 output.Append (GetChars (acc, e));
276 return output.ToString ();
279 public static byte [] UrlDecodeToBytes (byte [] bytes)
284 return UrlDecodeToBytes (bytes, 0, bytes.Length);
287 public static byte [] UrlDecodeToBytes (string str)
289 return UrlDecodeToBytes (str, Encoding.UTF8);
292 public static byte [] UrlDecodeToBytes (string str, Encoding e)
298 throw new ArgumentNullException ("e");
300 return UrlDecodeToBytes (e.GetBytes (str));
303 public static byte [] UrlDecodeToBytes (byte [] bytes, int offset, int count)
310 int len = bytes.Length;
311 if (offset < 0 || offset >= len)
312 throw new ArgumentOutOfRangeException("offset");
314 if (count < 0 || offset > len - count)
315 throw new ArgumentOutOfRangeException("count");
317 MemoryStream result = new MemoryStream ();
318 int end = offset + count;
319 for (int i = offset; i < end; i++){
320 char c = (char) bytes [i];
323 } else if (c == '%' && i < end - 2) {
324 int xchar = GetChar (bytes, i + 1, 2);
330 result.WriteByte ((byte) c);
333 return result.ToArray ();
336 public static string UrlEncode(string str)
338 return UrlEncode(str, Encoding.UTF8);
341 public static string UrlEncode (string s, Encoding Enc)
346 if (s == String.Empty)
349 bool needEncode = false;
351 for (int i = 0; i < len; i++) {
353 if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z')) {
354 if (HttpEncoder.NotEncoded (c))
365 // avoided GetByteCount call
366 byte [] bytes = new byte[Enc.GetMaxByteCount(s.Length)];
367 int realLen = Enc.GetBytes (s, 0, s.Length, bytes, 0);
368 return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, realLen));
371 public static string UrlEncode (byte [] bytes)
376 if (bytes.Length == 0)
379 return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, bytes.Length));
382 public static string UrlEncode (byte [] bytes, int offset, int count)
387 if (bytes.Length == 0)
390 return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, offset, count));
393 public static byte [] UrlEncodeToBytes (string str)
395 return UrlEncodeToBytes (str, Encoding.UTF8);
398 public static byte [] UrlEncodeToBytes (string str, Encoding e)
406 byte [] bytes = e.GetBytes (str);
407 return UrlEncodeToBytes (bytes, 0, bytes.Length);
410 public static byte [] UrlEncodeToBytes (byte [] bytes)
415 if (bytes.Length == 0)
418 return UrlEncodeToBytes (bytes, 0, bytes.Length);
421 public static byte [] UrlEncodeToBytes (byte [] bytes, int offset, int count)
425 return HttpEncoder.Current.UrlEncode (bytes, offset, count);
428 public static string UrlEncodeUnicode (string str)
433 return Encoding.ASCII.GetString (UrlEncodeUnicodeToBytes (str));
436 public static byte [] UrlEncodeUnicodeToBytes (string str)
444 MemoryStream result = new MemoryStream (str.Length);
445 foreach (char c in str){
446 HttpEncoder.UrlEncodeChar (c, result, true);
448 return result.ToArray ();
452 /// Decodes an HTML-encoded string and returns the decoded string.
454 /// <param name="s">The HTML string to decode. </param>
455 /// <returns>The decoded text.</returns>
456 public static string HtmlDecode (string s)
461 using (var sw = new StringWriter ()) {
462 HttpEncoder.Current.HtmlDecode (s, sw);
463 return sw.ToString ();
468 /// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
470 /// <param name="s">The HTML string to decode</param>
471 /// <param name="output">The TextWriter output stream containing the decoded string. </param>
472 public static void HtmlDecode(string s, TextWriter output)
474 if (output == null) {
475 throw new ArgumentNullException ("output");
478 if (!String.IsNullOrEmpty (s)) {
479 HttpEncoder.Current.HtmlDecode (s, output);
483 public static string HtmlEncode (string s)
488 using (var sw = new StringWriter ()) {
489 HttpEncoder.Current.HtmlEncode (s, sw);
490 return sw.ToString ();
495 /// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
497 /// <param name="s">The string to encode. </param>
498 /// <param name="output">The TextWriter output stream containing the encoded string. </param>
499 public static void HtmlEncode(string s, TextWriter output)
501 if (output == null) {
502 throw new ArgumentNullException ("output");
505 if (!String.IsNullOrEmpty (s)) {
506 HttpEncoder.Current.HtmlEncode (s, output);
509 public static string HtmlEncode (object value)
514 #if !(MOBILE || NO_SYSTEM_WEB_DEPENDENCY)
515 IHtmlString htmlString = value as IHtmlString;
516 if (htmlString != null)
517 return htmlString.ToHtmlString ();
520 return HtmlEncode (value.ToString ());
523 public static string JavaScriptStringEncode (string value)
525 return JavaScriptStringEncode (value, false);
528 public static string JavaScriptStringEncode (string value, bool addDoubleQuotes)
530 if (String.IsNullOrEmpty (value))
531 return addDoubleQuotes ? "\"\"" : String.Empty;
533 int len = value.Length;
534 bool needEncode = false;
536 for (int i = 0; i < len; i++) {
539 if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92) {
546 return addDoubleQuotes ? "\"" + value + "\"" : value;
548 var sb = new StringBuilder ();
552 for (int i = 0; i < len; i++) {
554 if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62)
555 sb.AppendFormat ("\\u{0:x4}", (int)c);
556 else switch ((int)c) {
594 return sb.ToString ();
596 public static string UrlPathEncode (string s)
598 return HttpEncoder.Current.UrlPathEncode (s);
601 public static NameValueCollection ParseQueryString (string query)
603 return ParseQueryString (query, Encoding.UTF8);
606 public static NameValueCollection ParseQueryString (string query, Encoding encoding)
609 throw new ArgumentNullException ("query");
610 if (encoding == null)
611 throw new ArgumentNullException ("encoding");
612 if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
613 return new HttpQSCollection ();
615 query = query.Substring (1);
617 NameValueCollection result = new HttpQSCollection ();
618 ParseQueryString (query, encoding, result);
622 internal static void ParseQueryString (string query, Encoding encoding, NameValueCollection result)
624 if (query.Length == 0)
627 string decoded = HtmlDecode (query);
628 int decodedLength = decoded.Length;
631 while (namePos <= decodedLength) {
632 int valuePos = -1, valueEnd = -1;
633 for (int q = namePos; q < decodedLength; q++) {
634 if (valuePos == -1 && decoded [q] == '=') {
636 } else if (decoded [q] == '&') {
644 if (decoded [namePos] == '?')
649 if (valuePos == -1) {
653 name = UrlDecode (decoded.Substring (namePos, valuePos - namePos - 1), encoding);
657 valueEnd = decoded.Length;
659 namePos = valueEnd + 1;
661 value = UrlDecode (decoded.Substring (valuePos, valueEnd - valuePos), encoding);
663 result.Add (name, value);
668 #endregion // Methods