X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Web%2FSystem.Web%2FHttpUtility.cs;h=fe54758eac0e2d5631dca95d962b402b2083d411;hb=f838727b8f37e0bb1f6ce092be9d768163afd03f;hp=0a627266f1982c9df8d2e503a0a2fb177216a170;hpb=043997723e5f78bd94f7d8b67a9488c9b062cd2c;p=mono.git diff --git a/mcs/class/System.Web/System.Web/HttpUtility.cs b/mcs/class/System.Web/System.Web/HttpUtility.cs index 0a627266f19..fe54758eac0 100644 --- a/mcs/class/System.Web/System.Web/HttpUtility.cs +++ b/mcs/class/System.Web/System.Web/HttpUtility.cs @@ -3,7 +3,7 @@ // // Authors: // Patrik Torstensson (Patrik.Torstensson@labs2.com) -// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se) +// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se) // Tim Coleman (tim@timcoleman.com) // Gonzalo Paniagua Javier (gonzalo@ximian.com) // @@ -37,12 +37,15 @@ using System.Security.Permissions; using System.Text; using System.Web.Util; +#if NET_2_0 +using System.Collections.Generic; +#endif + namespace System.Web { // CAS - no InheritanceDemand here as the class is sealed [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] public sealed class HttpUtility { - #region Fields static Hashtable entities; @@ -340,20 +343,32 @@ namespace System.Web { if (null == s) return null; - if (s.IndexOf ('&') == -1 && s.IndexOf ('"') == -1) + bool needEncode = false; + for (int i = 0; i < s.Length; i++) { + if (s [i] == '&' || s [i] == '"' || s [i] == '<') { + needEncode = true; + break; + } + } + + if (!needEncode) return s; StringBuilder output = new StringBuilder (); - foreach (char c in s) - switch (c) { + int len = s.Length; + for (int i = 0; i < len; i++) + switch (s [i]) { case '&' : output.Append ("&"); break; case '"' : output.Append ("""); break; + case '<': + output.Append ("<"); + break; default: - output.Append (c); + output.Append (s [i]); break; } @@ -365,11 +380,20 @@ namespace System.Web { return UrlDecode(str, Encoding.UTF8); } - private static char [] GetChars (MemoryStream b, Encoding e) + static char [] GetChars (MemoryStream b, Encoding e) { return e.GetChars (b.GetBuffer (), 0, (int) b.Length); } + static void WriteCharBytes (IList buf, char ch, Encoding e) + { + if (ch > 255) { + foreach (byte b in e.GetBytes (new char[] { ch })) + buf.Add (b); + } else + buf.Add ((byte)ch); + } + public static string UrlDecode (string s, Encoding e) { if (null == s) @@ -377,57 +401,53 @@ namespace System.Web { if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1) return s; - + if (e == null) e = Encoding.UTF8; - - StringBuilder output = new StringBuilder (); + long len = s.Length; - MemoryStream bytes = new MemoryStream (); +#if NET_2_0 + var bytes = new List (); +#else + ArrayList bytes = new ArrayList (); +#endif int xchar; - + char ch; + for (int i = 0; i < len; i++) { - if (s [i] == '%' && i + 2 < len && s [i + 1] != '%') { + ch = s [i]; + if (ch == '%' && i + 2 < len && s [i + 1] != '%') { if (s [i + 1] == 'u' && i + 5 < len) { - if (bytes.Length > 0) { - output.Append (GetChars (bytes, e)); - bytes.SetLength (0); - } - + // unicode hex sequence xchar = GetChar (s, i + 2, 4); if (xchar != -1) { - output.Append ((char) xchar); + WriteCharBytes (bytes, (char)xchar, e); i += 5; - } else { - output.Append ('%'); - } + } else + WriteCharBytes (bytes, '%', e); } else if ((xchar = GetChar (s, i + 1, 2)) != -1) { - bytes.WriteByte ((byte) xchar); + WriteCharBytes (bytes, (char)xchar, e); i += 2; } else { - output.Append ('%'); + WriteCharBytes (bytes, '%', e); } continue; } - if (bytes.Length > 0) { - output.Append (GetChars (bytes, e)); - bytes.SetLength (0); - } - - if (s [i] == '+') { - output.Append (' '); - } else { - output.Append (s [i]); - } - } - - if (bytes.Length > 0) { - output.Append (GetChars (bytes, e)); + if (ch == '+') + WriteCharBytes (bytes, ' ', e); + else + WriteCharBytes (bytes, ch, e); } - + +#if NET_2_0 + byte[] buf = bytes.ToArray (); +#else + byte[] buf = (byte[])bytes.ToArray (typeof (byte)); +#endif bytes = null; - return output.ToString (); + return e.GetString (buf); + } public static string UrlDecode (byte [] bytes, Encoding e) @@ -438,7 +458,7 @@ namespace System.Web { return UrlDecode (bytes, 0, bytes.Length, e); } - private static int GetInt (byte b) + static int GetInt (byte b) { char c = (char) b; if (c >= '0' && c <= '9') @@ -453,7 +473,7 @@ namespace System.Web { return -1; } - private static int GetChar (byte [] bytes, int offset, int length) + static int GetChar (byte [] bytes, int offset, int length) { int value = 0; int end = length + offset; @@ -467,7 +487,7 @@ namespace System.Web { return value; } - private static int GetChar (string str, int offset, int length) + static int GetChar (string str, int offset, int length) { int val = 0; int end = length + offset; @@ -616,8 +636,26 @@ namespace System.Web { if (s == "") return ""; - byte [] bytes = Enc.GetBytes (s); - return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, bytes.Length)); + bool needEncode = false; + int len = s.Length; + for (int i = 0; i < len; i++) { + char c = s [i]; + if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z')) { + if (NotEncoded (c)) + continue; + + needEncode = true; + break; + } + } + + if (!needEncode) + return s; + + // avoided GetByteCount call + byte [] bytes = new byte[Enc.GetMaxByteCount(s.Length)]; + int realLen = Enc.GetBytes (s, 0, s.Length, bytes, 0); + return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, realLen)); } public static string UrlEncode (byte [] bytes) @@ -671,7 +709,11 @@ namespace System.Web { } static char [] hexChars = "0123456789abcdef".ToCharArray (); - const string notEncoded = "!'()*-._"; + + static bool NotEncoded (char c) + { + return (c == '!' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_'); + } static void UrlEncodeChar (char c, Stream result, bool isUnicode) { if (c > 255) { @@ -694,7 +736,7 @@ namespace System.Web { return; } - if (c>' ' && notEncoded.IndexOf (c)!=-1) { + if (c > ' ' && NotEncoded (c)) { result.WriteByte ((byte)c); return; } @@ -900,10 +942,23 @@ namespace System.Web { if (s == null) return null; + bool needEncode = false; + for (int i = 0; i < s.Length; i++) { + char c = s [i]; + if (c == '&' || c == '"' || c == '<' || c == '>' || c > 159) { + needEncode = true; + break; + } + } + + if (!needEncode) + return s; + StringBuilder output = new StringBuilder (); - foreach (char c in s) - switch (c) { + int len = s.Length; + for (int i = 0; i < len; i++) + switch (s [i]) { case '&' : output.Append ("&"); break; @@ -920,12 +975,16 @@ namespace System.Web { // MS starts encoding with &# from 160 and stops at 255. // We don't do that. One reason is the 65308/65310 unicode // characters that look like '<' and '>'. - if (c > 159) { +#if TARGET_JVM + if (s [i] > 159 && s [i] < 256) { +#else + if (s [i] > 159) { +#endif output.Append ("&#"); - output.Append (((int) c).ToString (CultureInfo.InvariantCulture)); + output.Append (((int) s [i]).ToString (CultureInfo.InvariantCulture)); output.Append (";"); } else { - output.Append (c); + output.Append (s [i]); } break; } @@ -946,7 +1005,7 @@ namespace System.Web { #if NET_1_1 public static string UrlPathEncode (string s) { - if(String.IsNullOrEmpty(s)) + if (s == null || s.Length == 0) return s; MemoryStream result = new MemoryStream (); @@ -958,7 +1017,11 @@ namespace System.Web { } static void UrlPathEncodeChar (char c, Stream result) { +#if NET_2_0 + if (c < 33 || c > 126) { +#else if (c > 127) { +#endif byte [] bIn = Encoding.UTF8.GetBytes (c.ToString ()); for (int i = 0; i < bIn.Length; i++) { result.WriteByte ((byte) '%'); @@ -979,6 +1042,23 @@ namespace System.Web { #endif #if NET_2_0 + class HttpQSCollection : NameValueCollection { + public override string ToString () + { + int count = Count; + if (count == 0) + return ""; + StringBuilder sb = new StringBuilder (); + string [] keys = AllKeys; + for (int i = 0; i < count; i++) { + sb.AppendFormat ("{0}={1}&", keys [i], this [keys [i]]); + } + if (sb.Length > 0) + sb.Length--; + return sb.ToString (); + } + } + public static NameValueCollection ParseQueryString (string query) { return ParseQueryString (query, Encoding.UTF8); @@ -995,7 +1075,7 @@ namespace System.Web { if (query[0] == '?') query = query.Substring (1); - NameValueCollection result = new NameValueCollection (); + NameValueCollection result = new HttpQSCollection (); ParseQueryString (query, encoding, result); return result; } @@ -1006,35 +1086,45 @@ namespace System.Web { if (query.Length == 0) return; + string decoded = HtmlDecode (query); + int decodedLength = decoded.Length; int namePos = 0; - while (namePos <= query.Length) { + bool first = true; + while (namePos <= decodedLength) { int valuePos = -1, valueEnd = -1; - for (int q = namePos; q < query.Length; q++) { - if (valuePos == -1 && query[q] == '=') { + for (int q = namePos; q < decodedLength; q++) { + if (valuePos == -1 && decoded [q] == '=') { valuePos = q + 1; - } else if (query[q] == '&') { + } else if (decoded [q] == '&') { valueEnd = q; break; } } + if (first) { + first = false; + if (decoded [namePos] == '?') + namePos++; + } + string name, value; if (valuePos == -1) { name = null; valuePos = namePos; } else { - name = UrlDecode (query.Substring (namePos, valuePos - namePos - 1), encoding); + name = UrlDecode (decoded.Substring (namePos, valuePos - namePos - 1), encoding); } if (valueEnd < 0) { namePos = -1; - valueEnd = query.Length; + valueEnd = decoded.Length; } else { namePos = valueEnd + 1; } - value = UrlDecode (query.Substring (valuePos, valueEnd - valuePos), encoding); + value = UrlDecode (decoded.Substring (valuePos, valueEnd - valuePos), encoding); result.Add (name, value); - if (namePos == -1) break; + if (namePos == -1) + break; } } #endregion // Methods