Parse the query string in the URI into a KeyValuePair
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SocialKit.LightRest { /// <summary> /// Provides helper methods for common tasks. /// </summary> public static class RestUtility { static string unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"; /// <summary> /// Represents the System.Text.Encoding.Default. /// </summary> public static readonly Encoding DefaultEncoding = Encoding.Default; /// <summary> /// Encodes a URL string with UTF8 encoding. /// </summary> /// <param name="source">The text to encode.</param> /// <returns></returns> public static string UrlEncode(string source) { return UrlEncode(source, Encoding.UTF8); } /// <summary> /// Encodes a URL string with the specified encoding. /// </summary> /// <param name="source">The text to encode.</param> /// <param name="encoding">The System.Text.Encoding object that specifies the encoding scheme.</param> /// <returns></returns> public static string UrlEncode(string source, Encoding encoding) { if (source == null) return null; if (string.IsNullOrEmpty(source)) return string.Empty; if (encoding == null) encoding = DefaultEncoding; var buffer = new StringBuilder(); foreach (var b in encoding.GetBytes(source)) { if (b < 128 && unreservedChars.IndexOf((char)b) != -1) { buffer.Append((char)b); } else { buffer.AppendFormat("%{0:X2}", b); } } return buffer.ToString(); } /// <summary> /// Converts a string that has been encoded for transmission in a URL into a decoded string. /// </summary> /// <param name="source">The URL-encoded string to decode.</param> /// <returns></returns> public static string UrlDecode(string source) { return UrlDecode(source, Encoding.UTF8); } /// <summary> /// Converts a URL-encoded string into a decoded string, using the specified encoding object. /// </summary> /// <param name="source">The URL-encoded string to decode.</param> /// <param name="encoding">The System.Text.Encoding object that specifies the encoding scheme.</param> /// <returns></returns> public static string UrlDecode(string source, Encoding encoding) { if (source == null) return null; if (string.IsNullOrEmpty(source)) return string.Empty; if (encoding == null) encoding = DefaultEncoding; var bytes = new List<byte>(); for (int i = 0; i < source.Length; i++) { var c = source[i]; if (unreservedChars.IndexOf(c) != -1) { bytes.Add((byte)c); } else if (c == '%' && i < source.Length - 2) { var n1 = HexToInt(source[i + 1]); var n2 = HexToInt(source[i + 2]); if (n1 >= 0 && n2 >= 0) { var b = (byte)((n1 << 4) | n2); i += 2; bytes.Add(b); } } } return encoding.GetString(bytes.ToArray(), 0, bytes.Count); } /// <summary> /// Converts an hex char to an integer. /// </summary> /// <param name="c"></param> /// <returns></returns> static int HexToInt(char c) { 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; } /// <summary> /// Parse the query string in the URI into a KeyValuePair<string, string> collection. /// The keys and values will be URL decoded. /// </summary> /// <param name="query">The query string to parse.</param> /// <returns>A keys and values collection.</returns> public static IEnumerable<KeyValuePair<string, string>> ParseQueryString(string query) { if (query == null) throw new ArgumentNullException("query"); if (query.StartsWith("?")) query = query.Substring(1); if (string.IsNullOrEmpty(query)) return new KeyValuePair<string, string>[] { }; var values = new List<KeyValuePair<string, string>>(); int length = query.Length; int startIndex, equalIndex; for (int i = 0; i < length; i++) { startIndex = i; equalIndex = -1; while (i < length) { char c = query[i]; if (c == '=') { if (equalIndex < 0) { equalIndex = i; } } else if (c == '&') { break; } i++; } string key = null; string value = null; if (equalIndex >= 0) { key = query.Substring(startIndex, equalIndex - startIndex); value = query.Substring(equalIndex + 1, (i - equalIndex) - 1); } else { //standalone value is key or value? key = query.Substring(startIndex, i - startIndex); } if (value == null) { value = string.Empty; } values.Add(new KeyValuePair<string, string>(UrlDecode(key), UrlDecode(value))); } return values; } /// <summary> /// Gets a string indicates the URI without query string. /// </summary> /// <param name="uri">The URI to normalize.</param> /// <returns>The host and path of the URI.</returns> public static string NormalizeUriWithoutQuery(Uri uri) { if (!uri.IsAbsoluteUri) throw new ArgumentOutOfRangeException("uri", "The relative URI is not supported."); var normalizedUri = string.Format("{0}://{1}", uri.Scheme, uri.Host); if (!((uri.Scheme == "http" && uri.Port == 80) || (uri.Scheme == "https" && uri.Port == 443))) { normalizedUri += ":" + uri.Port; } normalizedUri += uri.AbsolutePath; return normalizedUri; } /// <summary> /// Extract encoding from the contentType string, or returns the fallback value. /// </summary> /// <param name="contentType">The contentType string.</param> /// <param name="fallback">If no encoding found, returns this value.</param> /// <returns>A System.Text.Encoding value.</returns> public static Encoding ExtractEncoding(string contentType, Encoding fallback) { if (string.IsNullOrEmpty(contentType)) { return fallback; } //find charset var values = contentType.Split(';'); var charsetPair = values.FirstOrDefault(v => v.Trim().StartsWith("charset", StringComparison.InvariantCultureIgnoreCase)); if (charsetPair == null) return fallback; var charset = charsetPair.Split('=')[1]; return Encoding.GetEncoding(charset); } /// <summary> /// Extract encoding from the contentType string. /// </summary> /// <param name="contentType">The contentType string.</param> /// <returns>A System.Text.Encoding value.</returns> public static Encoding ExtractEncoding(string contentType) { return ExtractEncoding(contentType, Encoding.Default); } } }