3 changed files with 694 additions and 1 deletions
@ -0,0 +1,693 @@ |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Specialized; |
|||
using System.Globalization; |
|||
using System.IO; |
|||
using System.Security.Permissions; |
|||
using System.Text; |
|||
using System.Web.Util; |
|||
|
|||
namespace Avalonia.Shared.PlatformSupport |
|||
{ |
|||
public sealed class HttpUtility |
|||
{ |
|||
sealed 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], UrlEncode(this[keys[i]])); |
|||
} |
|||
if (sb.Length > 0) |
|||
sb.Length--; |
|||
return sb.ToString(); |
|||
} |
|||
} |
|||
|
|||
#region Constructors
|
|||
|
|||
public HttpUtility() |
|||
{ |
|||
} |
|||
|
|||
#endregion // Constructors
|
|||
|
|||
#region Methods
|
|||
|
|||
public static void HtmlAttributeEncode(string s, TextWriter output) |
|||
{ |
|||
if (output == null) |
|||
{ |
|||
throw new ArgumentNullException("output"); |
|||
} |
|||
HttpEncoder.Current.HtmlAttributeEncode(s, output); |
|||
} |
|||
|
|||
public static string HtmlAttributeEncode(string s) |
|||
{ |
|||
if (s == null) |
|||
return null; |
|||
|
|||
using (var sw = new StringWriter()) |
|||
{ |
|||
HttpEncoder.Current.HtmlAttributeEncode(s, sw); |
|||
return sw.ToString(); |
|||
} |
|||
} |
|||
|
|||
public static string UrlDecode(string str) |
|||
{ |
|||
return UrlDecode(str, Encoding.UTF8); |
|||
} |
|||
|
|||
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 str, Encoding e) |
|||
{ |
|||
if (null == str) |
|||
return null; |
|||
|
|||
if (str.IndexOf('%') == -1 && str.IndexOf('+') == -1) |
|||
return str; |
|||
|
|||
if (e == null) |
|||
e = Encoding.UTF8; |
|||
|
|||
long len = str.Length; |
|||
var bytes = new List<byte>(); |
|||
int xchar; |
|||
char ch; |
|||
|
|||
for (int i = 0; i < len; i++) |
|||
{ |
|||
ch = str[i]; |
|||
if (ch == '%' && i + 2 < len && str[i + 1] != '%') |
|||
{ |
|||
if (str[i + 1] == 'u' && i + 5 < len) |
|||
{ |
|||
// unicode hex sequence
|
|||
xchar = GetChar(str, i + 2, 4); |
|||
if (xchar != -1) |
|||
{ |
|||
WriteCharBytes(bytes, (char)xchar, e); |
|||
i += 5; |
|||
} |
|||
else |
|||
WriteCharBytes(bytes, '%', e); |
|||
} |
|||
else if ((xchar = GetChar(str, i + 1, 2)) != -1) |
|||
{ |
|||
WriteCharBytes(bytes, (char)xchar, e); |
|||
i += 2; |
|||
} |
|||
else |
|||
{ |
|||
WriteCharBytes(bytes, '%', e); |
|||
} |
|||
continue; |
|||
} |
|||
|
|||
if (ch == '+') |
|||
WriteCharBytes(bytes, ' ', e); |
|||
else |
|||
WriteCharBytes(bytes, ch, e); |
|||
} |
|||
|
|||
byte[] buf = bytes.ToArray(); |
|||
bytes = null; |
|||
return e.GetString(buf); |
|||
|
|||
} |
|||
|
|||
public static string UrlDecode(byte[] bytes, Encoding e) |
|||
{ |
|||
if (bytes == null) |
|||
return null; |
|||
|
|||
return UrlDecode(bytes, 0, bytes.Length, e); |
|||
} |
|||
|
|||
static int GetInt(byte b) |
|||
{ |
|||
char c = (char)b; |
|||
if (c >= '0' && c <= '9') |
|||
return c - '0'; |
|||
|
|||
if (c >= 'a' && c <= 'f') |
|||
return c - 'a' + 10; |
|||
|
|||
if (c >= 'A' && c <= 'F') |
|||
return c - 'A' + 10; |
|||
|
|||
return -1; |
|||
} |
|||
|
|||
static int GetChar(byte[] bytes, int offset, int length) |
|||
{ |
|||
int value = 0; |
|||
int end = length + offset; |
|||
for (int i = offset; i < end; i++) |
|||
{ |
|||
int current = GetInt(bytes[i]); |
|||
if (current == -1) |
|||
return -1; |
|||
value = (value << 4) + current; |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
|
|||
static int GetChar(string str, int offset, int length) |
|||
{ |
|||
int val = 0; |
|||
int end = length + offset; |
|||
for (int i = offset; i < end; i++) |
|||
{ |
|||
char c = str[i]; |
|||
if (c > 127) |
|||
return -1; |
|||
|
|||
int current = GetInt((byte)c); |
|||
if (current == -1) |
|||
return -1; |
|||
val = (val << 4) + current; |
|||
} |
|||
|
|||
return val; |
|||
} |
|||
|
|||
public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e) |
|||
{ |
|||
if (bytes == null) |
|||
return null; |
|||
if (count == 0) |
|||
return String.Empty; |
|||
|
|||
if (bytes == null) |
|||
throw new ArgumentNullException("bytes"); |
|||
|
|||
if (offset < 0 || offset > bytes.Length) |
|||
throw new ArgumentOutOfRangeException("offset"); |
|||
|
|||
if (count < 0 || offset + count > bytes.Length) |
|||
throw new ArgumentOutOfRangeException("count"); |
|||
|
|||
StringBuilder output = new StringBuilder(); |
|||
MemoryStream acc = new MemoryStream(); |
|||
|
|||
int end = count + offset; |
|||
int xchar; |
|||
for (int i = offset; i < end; i++) |
|||
{ |
|||
if (bytes[i] == '%' && i + 2 < count && bytes[i + 1] != '%') |
|||
{ |
|||
if (bytes[i + 1] == (byte)'u' && i + 5 < end) |
|||
{ |
|||
if (acc.Length > 0) |
|||
{ |
|||
output.Append(GetChars(acc, e)); |
|||
acc.SetLength(0); |
|||
} |
|||
xchar = GetChar(bytes, i + 2, 4); |
|||
if (xchar != -1) |
|||
{ |
|||
output.Append((char)xchar); |
|||
i += 5; |
|||
continue; |
|||
} |
|||
} |
|||
else if ((xchar = GetChar(bytes, i + 1, 2)) != -1) |
|||
{ |
|||
acc.WriteByte((byte)xchar); |
|||
i += 2; |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
if (acc.Length > 0) |
|||
{ |
|||
output.Append(GetChars(acc, e)); |
|||
acc.SetLength(0); |
|||
} |
|||
|
|||
if (bytes[i] == '+') |
|||
{ |
|||
output.Append(' '); |
|||
} |
|||
else |
|||
{ |
|||
output.Append((char)bytes[i]); |
|||
} |
|||
} |
|||
|
|||
if (acc.Length > 0) |
|||
{ |
|||
output.Append(GetChars(acc, e)); |
|||
} |
|||
|
|||
acc = null; |
|||
return output.ToString(); |
|||
} |
|||
|
|||
public static byte[] UrlDecodeToBytes(byte[] bytes) |
|||
{ |
|||
if (bytes == null) |
|||
return null; |
|||
|
|||
return UrlDecodeToBytes(bytes, 0, bytes.Length); |
|||
} |
|||
|
|||
public static byte[] UrlDecodeToBytes(string str) |
|||
{ |
|||
return UrlDecodeToBytes(str, Encoding.UTF8); |
|||
} |
|||
|
|||
public static byte[] UrlDecodeToBytes(string str, Encoding e) |
|||
{ |
|||
if (str == null) |
|||
return null; |
|||
|
|||
if (e == null) |
|||
throw new ArgumentNullException("e"); |
|||
|
|||
return UrlDecodeToBytes(e.GetBytes(str)); |
|||
} |
|||
|
|||
public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count) |
|||
{ |
|||
if (bytes == null) |
|||
return null; |
|||
if (count == 0) |
|||
return new byte[0]; |
|||
|
|||
int len = bytes.Length; |
|||
if (offset < 0 || offset >= len) |
|||
throw new ArgumentOutOfRangeException("offset"); |
|||
|
|||
if (count < 0 || offset > len - count) |
|||
throw new ArgumentOutOfRangeException("count"); |
|||
|
|||
MemoryStream result = new MemoryStream(); |
|||
int end = offset + count; |
|||
for (int i = offset; i < end; i++) |
|||
{ |
|||
char c = (char)bytes[i]; |
|||
if (c == '+') |
|||
{ |
|||
c = ' '; |
|||
} |
|||
else if (c == '%' && i < end - 2) |
|||
{ |
|||
int xchar = GetChar(bytes, i + 1, 2); |
|||
if (xchar != -1) |
|||
{ |
|||
c = (char)xchar; |
|||
i += 2; |
|||
} |
|||
} |
|||
result.WriteByte((byte)c); |
|||
} |
|||
|
|||
return result.ToArray(); |
|||
} |
|||
|
|||
public static string UrlEncode(string str) |
|||
{ |
|||
return UrlEncode(str, Encoding.UTF8); |
|||
} |
|||
|
|||
public static string UrlEncode(string str, Encoding e) |
|||
{ |
|||
if (str == null) |
|||
return null; |
|||
|
|||
if (str == String.Empty) |
|||
return String.Empty; |
|||
|
|||
bool needEncode = false; |
|||
int len = str.Length; |
|||
for (int i = 0; i < len; i++) |
|||
{ |
|||
char c = str[i]; |
|||
if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z')) |
|||
{ |
|||
if (HttpEncoder.NotEncoded(c)) |
|||
continue; |
|||
|
|||
needEncode = true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!needEncode) |
|||
return str; |
|||
|
|||
// avoided GetByteCount call
|
|||
byte[] bytes = new byte[e.GetMaxByteCount(str.Length)]; |
|||
int realLen = e.GetBytes(str, 0, str.Length, bytes, 0); |
|||
return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, realLen)); |
|||
} |
|||
|
|||
public static string UrlEncode(byte[] bytes) |
|||
{ |
|||
if (bytes == null) |
|||
return null; |
|||
|
|||
if (bytes.Length == 0) |
|||
return String.Empty; |
|||
|
|||
return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length)); |
|||
} |
|||
|
|||
public static string UrlEncode(byte[] bytes, int offset, int count) |
|||
{ |
|||
if (bytes == null) |
|||
return null; |
|||
|
|||
if (bytes.Length == 0) |
|||
return String.Empty; |
|||
|
|||
return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count)); |
|||
} |
|||
|
|||
public static byte[] UrlEncodeToBytes(string str) |
|||
{ |
|||
return UrlEncodeToBytes(str, Encoding.UTF8); |
|||
} |
|||
|
|||
public static byte[] UrlEncodeToBytes(string str, Encoding e) |
|||
{ |
|||
if (str == null) |
|||
return null; |
|||
|
|||
if (str.Length == 0) |
|||
return new byte[0]; |
|||
|
|||
byte[] bytes = e.GetBytes(str); |
|||
return UrlEncodeToBytes(bytes, 0, bytes.Length); |
|||
} |
|||
|
|||
public static byte[] UrlEncodeToBytes(byte[] bytes) |
|||
{ |
|||
if (bytes == null) |
|||
return null; |
|||
|
|||
if (bytes.Length == 0) |
|||
return new byte[0]; |
|||
|
|||
return UrlEncodeToBytes(bytes, 0, bytes.Length); |
|||
} |
|||
|
|||
public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) |
|||
{ |
|||
if (bytes == null) |
|||
return null; |
|||
return HttpEncoder.Current.UrlEncode(bytes, offset, count); |
|||
} |
|||
|
|||
public static string UrlEncodeUnicode(string str) |
|||
{ |
|||
if (str == null) |
|||
return null; |
|||
|
|||
return Encoding.ASCII.GetString(UrlEncodeUnicodeToBytes(str)); |
|||
} |
|||
|
|||
public static byte[] UrlEncodeUnicodeToBytes(string str) |
|||
{ |
|||
if (str == null) |
|||
return null; |
|||
|
|||
if (str.Length == 0) |
|||
return new byte[0]; |
|||
|
|||
MemoryStream result = new MemoryStream(str.Length); |
|||
foreach (char c in str) |
|||
{ |
|||
HttpEncoder.UrlEncodeChar(c, result, true); |
|||
} |
|||
return result.ToArray(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Decodes an HTML-encoded string and returns the decoded string.
|
|||
/// </summary>
|
|||
/// <param name="s">The HTML string to decode. </param>
|
|||
/// <returns>The decoded text.</returns>
|
|||
public static string HtmlDecode(string s) |
|||
{ |
|||
if (s == null) |
|||
return null; |
|||
|
|||
using (var sw = new StringWriter()) |
|||
{ |
|||
HttpEncoder.Current.HtmlDecode(s, sw); |
|||
return sw.ToString(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
|
|||
/// </summary>
|
|||
/// <param name="s">The HTML string to decode</param>
|
|||
/// <param name="output">The TextWriter output stream containing the decoded string. </param>
|
|||
public static void HtmlDecode(string s, TextWriter output) |
|||
{ |
|||
if (output == null) |
|||
{ |
|||
throw new ArgumentNullException("output"); |
|||
} |
|||
|
|||
if (!String.IsNullOrEmpty(s)) |
|||
{ |
|||
HttpEncoder.Current.HtmlDecode(s, output); |
|||
} |
|||
} |
|||
|
|||
public static string HtmlEncode(string s) |
|||
{ |
|||
if (s == null) |
|||
return null; |
|||
|
|||
using (var sw = new StringWriter()) |
|||
{ |
|||
HttpEncoder.Current.HtmlEncode(s, sw); |
|||
return sw.ToString(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
|
|||
/// </summary>
|
|||
/// <param name="s">The string to encode. </param>
|
|||
/// <param name="output">The TextWriter output stream containing the encoded string. </param>
|
|||
public static void HtmlEncode(string s, TextWriter output) |
|||
{ |
|||
if (output == null) |
|||
{ |
|||
throw new ArgumentNullException("output"); |
|||
} |
|||
|
|||
if (!String.IsNullOrEmpty(s)) |
|||
{ |
|||
HttpEncoder.Current.HtmlEncode(s, output); |
|||
} |
|||
} |
|||
public static string HtmlEncode(object value) |
|||
{ |
|||
if (value == null) |
|||
return null; |
|||
|
|||
#if !(MOBILE || NO_SYSTEM_WEB_DEPENDENCY)
|
|||
IHtmlString htmlString = value as IHtmlString; |
|||
if (htmlString != null) |
|||
return htmlString.ToHtmlString(); |
|||
#endif
|
|||
|
|||
return HtmlEncode(value.ToString()); |
|||
} |
|||
|
|||
public static string JavaScriptStringEncode(string value) |
|||
{ |
|||
return JavaScriptStringEncode(value, false); |
|||
} |
|||
|
|||
public static string JavaScriptStringEncode(string value, bool addDoubleQuotes) |
|||
{ |
|||
if (String.IsNullOrEmpty(value)) |
|||
return addDoubleQuotes ? "\"\"" : String.Empty; |
|||
|
|||
int len = value.Length; |
|||
bool needEncode = false; |
|||
char c; |
|||
for (int i = 0; i < len; i++) |
|||
{ |
|||
c = value[i]; |
|||
|
|||
if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92) |
|||
{ |
|||
needEncode = true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!needEncode) |
|||
return addDoubleQuotes ? "\"" + value + "\"" : value; |
|||
|
|||
var sb = new StringBuilder(); |
|||
if (addDoubleQuotes) |
|||
sb.Append('"'); |
|||
|
|||
for (int i = 0; i < len; i++) |
|||
{ |
|||
c = value[i]; |
|||
if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62) |
|||
sb.AppendFormat("\\u{0:x4}", (int)c); |
|||
else switch ((int)c) |
|||
{ |
|||
case 8: |
|||
sb.Append("\\b"); |
|||
break; |
|||
|
|||
case 9: |
|||
sb.Append("\\t"); |
|||
break; |
|||
|
|||
case 10: |
|||
sb.Append("\\n"); |
|||
break; |
|||
|
|||
case 12: |
|||
sb.Append("\\f"); |
|||
break; |
|||
|
|||
case 13: |
|||
sb.Append("\\r"); |
|||
break; |
|||
|
|||
case 34: |
|||
sb.Append("\\\""); |
|||
break; |
|||
|
|||
case 92: |
|||
sb.Append("\\\\"); |
|||
break; |
|||
|
|||
default: |
|||
sb.Append(c); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (addDoubleQuotes) |
|||
sb.Append('"'); |
|||
|
|||
return sb.ToString(); |
|||
} |
|||
public static string UrlPathEncode(string str) |
|||
{ |
|||
return HttpEncoder.Current.UrlPathEncode(str); |
|||
} |
|||
|
|||
public static NameValueCollection ParseQueryString(string query) |
|||
{ |
|||
return ParseQueryString(query, Encoding.UTF8); |
|||
} |
|||
|
|||
public static NameValueCollection ParseQueryString(string query, Encoding encoding) |
|||
{ |
|||
if (query == null) |
|||
throw new ArgumentNullException("query"); |
|||
if (encoding == null) |
|||
throw new ArgumentNullException("encoding"); |
|||
if (query.Length == 0 || (query.Length == 1 && query[0] == '?')) |
|||
return new HttpQSCollection(); |
|||
if (query[0] == '?') |
|||
query = query.Substring(1); |
|||
|
|||
NameValueCollection result = new HttpQSCollection(); |
|||
ParseQueryString(query, encoding, result); |
|||
return result; |
|||
} |
|||
|
|||
internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result) |
|||
{ |
|||
if (query.Length == 0) |
|||
return; |
|||
|
|||
string decoded = HtmlDecode(query); |
|||
int decodedLength = decoded.Length; |
|||
int namePos = 0; |
|||
bool first = true; |
|||
while (namePos <= decodedLength) |
|||
{ |
|||
int valuePos = -1, valueEnd = -1; |
|||
for (int q = namePos; q < decodedLength; q++) |
|||
{ |
|||
if (valuePos == -1 && decoded[q] == '=') |
|||
{ |
|||
valuePos = q + 1; |
|||
} |
|||
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(decoded.Substring(namePos, valuePos - namePos - 1), encoding); |
|||
} |
|||
if (valueEnd < 0) |
|||
{ |
|||
namePos = -1; |
|||
valueEnd = decoded.Length; |
|||
} |
|||
else |
|||
{ |
|||
namePos = valueEnd + 1; |
|||
} |
|||
value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding); |
|||
|
|||
result.Add(name, value); |
|||
if (namePos == -1) |
|||
break; |
|||
} |
|||
} |
|||
#endregion // Methods
|
|||
} |
|||
} |
|||
Loading…
Reference in new issue