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], this [keys [i]]);
63 return sb.ToString ();
73 #endregion // Constructors
77 public static void HtmlAttributeEncode (string s, TextWriter output)
81 throw new ArgumentNullException ("output");
83 throw new NullReferenceException (".NET emulation");
87 HttpEncoder.Current.HtmlAttributeEncode (s, output);
89 output.Write (HttpEncoder.HtmlAttributeEncode (s));
93 public static string HtmlAttributeEncode (string s)
99 using (var sw = new StringWriter ()) {
100 HttpEncoder.Current.HtmlAttributeEncode (s, sw);
101 return sw.ToString ();
104 return HttpEncoder.HtmlAttributeEncode (s);
108 public static string UrlDecode (string str)
110 return UrlDecode(str, Encoding.UTF8);
113 static char [] GetChars (MemoryStream b, Encoding e)
115 return e.GetChars (b.GetBuffer (), 0, (int) b.Length);
118 static void WriteCharBytes (IList buf, char ch, Encoding e)
121 foreach (byte b in e.GetBytes (new char[] { ch }))
127 public static string UrlDecode (string s, Encoding e)
132 if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1)
139 var bytes = new List <byte> ();
143 for (int i = 0; i < len; i++) {
145 if (ch == '%' && i + 2 < len && s [i + 1] != '%') {
146 if (s [i + 1] == 'u' && i + 5 < len) {
147 // unicode hex sequence
148 xchar = GetChar (s, i + 2, 4);
150 WriteCharBytes (bytes, (char)xchar, e);
153 WriteCharBytes (bytes, '%', e);
154 } else if ((xchar = GetChar (s, i + 1, 2)) != -1) {
155 WriteCharBytes (bytes, (char)xchar, e);
158 WriteCharBytes (bytes, '%', e);
164 WriteCharBytes (bytes, ' ', e);
166 WriteCharBytes (bytes, ch, e);
169 byte[] buf = bytes.ToArray ();
171 return e.GetString (buf);
175 public static string UrlDecode (byte [] bytes, Encoding e)
180 return UrlDecode (bytes, 0, bytes.Length, e);
183 static int GetInt (byte b)
186 if (c >= '0' && c <= '9')
189 if (c >= 'a' && c <= 'f')
192 if (c >= 'A' && c <= 'F')
198 static int GetChar (byte [] bytes, int offset, int length)
201 int end = length + offset;
202 for (int i = offset; i < end; i++) {
203 int current = GetInt (bytes [i]);
206 value = (value << 4) + current;
212 static int GetChar (string str, int offset, int length)
215 int end = length + offset;
216 for (int i = offset; i < end; i++) {
221 int current = GetInt ((byte) c);
224 val = (val << 4) + current;
230 public static string UrlDecode (byte [] bytes, int offset, int count, Encoding e)
238 throw new ArgumentNullException ("bytes");
240 if (offset < 0 || offset > bytes.Length)
241 throw new ArgumentOutOfRangeException ("offset");
243 if (count < 0 || offset + count > bytes.Length)
244 throw new ArgumentOutOfRangeException ("count");
246 StringBuilder output = new StringBuilder ();
247 MemoryStream acc = new MemoryStream ();
249 int end = count + offset;
251 for (int i = offset; i < end; i++) {
252 if (bytes [i] == '%' && i + 2 < count && bytes [i + 1] != '%') {
253 if (bytes [i + 1] == (byte) 'u' && i + 5 < end) {
254 if (acc.Length > 0) {
255 output.Append (GetChars (acc, e));
258 xchar = GetChar (bytes, i + 2, 4);
260 output.Append ((char) xchar);
264 } else if ((xchar = GetChar (bytes, i + 1, 2)) != -1) {
265 acc.WriteByte ((byte) xchar);
271 if (acc.Length > 0) {
272 output.Append (GetChars (acc, e));
276 if (bytes [i] == '+') {
279 output.Append ((char) bytes [i]);
283 if (acc.Length > 0) {
284 output.Append (GetChars (acc, e));
288 return output.ToString ();
291 public static byte [] UrlDecodeToBytes (byte [] bytes)
296 return UrlDecodeToBytes (bytes, 0, bytes.Length);
299 public static byte [] UrlDecodeToBytes (string str)
301 return UrlDecodeToBytes (str, Encoding.UTF8);
304 public static byte [] UrlDecodeToBytes (string str, Encoding e)
310 throw new ArgumentNullException ("e");
312 return UrlDecodeToBytes (e.GetBytes (str));
315 public static byte [] UrlDecodeToBytes (byte [] bytes, int offset, int count)
322 int len = bytes.Length;
323 if (offset < 0 || offset >= len)
324 throw new ArgumentOutOfRangeException("offset");
326 if (count < 0 || offset > len - count)
327 throw new ArgumentOutOfRangeException("count");
329 MemoryStream result = new MemoryStream ();
330 int end = offset + count;
331 for (int i = offset; i < end; i++){
332 char c = (char) bytes [i];
335 } else if (c == '%' && i < end - 2) {
336 int xchar = GetChar (bytes, i + 1, 2);
342 result.WriteByte ((byte) c);
345 return result.ToArray ();
348 public static string UrlEncode(string str)
350 return UrlEncode(str, Encoding.UTF8);
353 public static string UrlEncode (string s, Encoding Enc)
358 if (s == String.Empty)
361 bool needEncode = false;
363 for (int i = 0; i < len; i++) {
365 if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z')) {
366 if (HttpEncoder.NotEncoded (c))
377 // avoided GetByteCount call
378 byte [] bytes = new byte[Enc.GetMaxByteCount(s.Length)];
379 int realLen = Enc.GetBytes (s, 0, s.Length, bytes, 0);
380 return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, realLen));
383 public static string UrlEncode (byte [] bytes)
388 if (bytes.Length == 0)
391 return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, bytes.Length));
394 public static string UrlEncode (byte [] bytes, int offset, int count)
399 if (bytes.Length == 0)
402 return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, offset, count));
405 public static byte [] UrlEncodeToBytes (string str)
407 return UrlEncodeToBytes (str, Encoding.UTF8);
410 public static byte [] UrlEncodeToBytes (string str, Encoding e)
418 byte [] bytes = e.GetBytes (str);
419 return UrlEncodeToBytes (bytes, 0, bytes.Length);
422 public static byte [] UrlEncodeToBytes (byte [] bytes)
427 if (bytes.Length == 0)
430 return UrlEncodeToBytes (bytes, 0, bytes.Length);
433 public static byte [] UrlEncodeToBytes (byte [] bytes, int offset, int count)
438 return HttpEncoder.Current.UrlEncode (bytes, offset, count);
440 return HttpEncoder.UrlEncodeToBytes (bytes, offset, count);
444 public static string UrlEncodeUnicode (string str)
449 return Encoding.ASCII.GetString (UrlEncodeUnicodeToBytes (str));
452 public static byte [] UrlEncodeUnicodeToBytes (string str)
460 MemoryStream result = new MemoryStream (str.Length);
461 foreach (char c in str){
462 HttpEncoder.UrlEncodeChar (c, result, true);
464 return result.ToArray ();
468 /// Decodes an HTML-encoded string and returns the decoded string.
470 /// <param name="s">The HTML string to decode. </param>
471 /// <returns>The decoded text.</returns>
472 public static string HtmlDecode (string s)
478 using (var sw = new StringWriter ()) {
479 HttpEncoder.Current.HtmlDecode (s, sw);
480 return sw.ToString ();
483 return HttpEncoder.HtmlDecode (s);
488 /// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
490 /// <param name="s">The HTML string to decode</param>
491 /// <param name="output">The TextWriter output stream containing the decoded string. </param>
492 public static void HtmlDecode(string s, TextWriter output)
494 if (output == null) {
496 throw new ArgumentNullException ("output");
498 throw new NullReferenceException (".NET emulation");
502 if (!String.IsNullOrEmpty (s)) {
504 HttpEncoder.Current.HtmlDecode (s, output);
506 output.Write (HttpEncoder.HtmlDecode (s));
511 public static string HtmlEncode (string s)
517 using (var sw = new StringWriter ()) {
518 HttpEncoder.Current.HtmlEncode (s, sw);
519 return sw.ToString ();
522 return HttpEncoder.HtmlEncode (s);
527 /// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
529 /// <param name="s">The string to encode. </param>
530 /// <param name="output">The TextWriter output stream containing the encoded string. </param>
531 public static void HtmlEncode(string s, TextWriter output)
533 if (output == null) {
535 throw new ArgumentNullException ("output");
537 throw new NullReferenceException (".NET emulation");
541 if (!String.IsNullOrEmpty (s)) {
543 HttpEncoder.Current.HtmlEncode (s, output);
545 output.Write (HttpEncoder.HtmlEncode (s));
550 public static string HtmlEncode (object value)
555 IHtmlString htmlString = value as IHtmlString;
556 if (htmlString != null)
557 return htmlString.ToHtmlString ();
559 return HtmlEncode (value.ToString ());
562 public static string JavaScriptStringEncode (string value)
564 return JavaScriptStringEncode (value, false);
567 public static string JavaScriptStringEncode (string value, bool addDoubleQuotes)
569 if (String.IsNullOrEmpty (value))
570 return addDoubleQuotes ? "\"\"" : String.Empty;
572 int len = value.Length;
573 bool needEncode = false;
575 for (int i = 0; i < len; i++) {
578 if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92) {
585 return addDoubleQuotes ? "\"" + value + "\"" : value;
587 var sb = new StringBuilder ();
591 for (int i = 0; i < len; i++) {
593 if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62)
594 sb.AppendFormat ("\\u{0:x4}", (int)c);
595 else switch ((int)c) {
633 return sb.ToString ();
636 public static string UrlPathEncode (string s)
639 return HttpEncoder.Current.UrlPathEncode (s);
641 return HttpEncoder.UrlPathEncode (s);
645 public static NameValueCollection ParseQueryString (string query)
647 return ParseQueryString (query, Encoding.UTF8);
650 public static NameValueCollection ParseQueryString (string query, Encoding encoding)
653 throw new ArgumentNullException ("query");
654 if (encoding == null)
655 throw new ArgumentNullException ("encoding");
656 if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
657 return new HttpQSCollection ();
659 query = query.Substring (1);
661 NameValueCollection result = new HttpQSCollection ();
662 ParseQueryString (query, encoding, result);
666 internal static void ParseQueryString (string query, Encoding encoding, NameValueCollection result)
668 if (query.Length == 0)
671 string decoded = HtmlDecode (query);
672 int decodedLength = decoded.Length;
675 while (namePos <= decodedLength) {
676 int valuePos = -1, valueEnd = -1;
677 for (int q = namePos; q < decodedLength; q++) {
678 if (valuePos == -1 && decoded [q] == '=') {
680 } else if (decoded [q] == '&') {
688 if (decoded [namePos] == '?')
693 if (valuePos == -1) {
697 name = UrlDecode (decoded.Substring (namePos, valuePos - namePos - 1), encoding);
701 valueEnd = decoded.Length;
703 namePos = valueEnd + 1;
705 value = UrlDecode (decoded.Substring (valuePos, valueEnd - valuePos), encoding);
707 result.Add (name, value);
712 #endregion // Methods