// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Linq; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Text; using System.Xml; using Newtonsoft.Json.Linq; namespace System.Net.Http { /// /// Provides various internal utility functions /// internal static class FormattingUtilities { // Supported date formats for input. private static readonly string[] dateFormats = new string[] { // "r", // RFC 1123, required output format but too strict for input "ddd, d MMM yyyy H:m:s 'GMT'", // RFC 1123 (r, except it allows both 1 and 01 for date and time) "ddd, d MMM yyyy H:m:s", // RFC 1123, no zone - assume GMT "d MMM yyyy H:m:s 'GMT'", // RFC 1123, no day-of-week "d MMM yyyy H:m:s", // RFC 1123, no day-of-week, no zone "ddd, d MMM yy H:m:s 'GMT'", // RFC 1123, short year "ddd, d MMM yy H:m:s", // RFC 1123, short year, no zone "d MMM yy H:m:s 'GMT'", // RFC 1123, no day-of-week, short year "d MMM yy H:m:s", // RFC 1123, no day-of-week, short year, no zone "dddd, d'-'MMM'-'yy H:m:s 'GMT'", // RFC 850 "dddd, d'-'MMM'-'yy H:m:s", // RFC 850 no zone "ddd MMM d H:m:s yyyy", // ANSI C's asctime() format "ddd, d MMM yyyy H:m:s zzz", // RFC 5322 "ddd, d MMM yyyy H:m:s", // RFC 5322 no zone "d MMM yyyy H:m:s zzz", // RFC 5322 no day-of-week "d MMM yyyy H:m:s", // RFC 5322 no day-of-week, no zone }; // Valid header token characters are within the range 0x20 < c < 0x7F excluding the following characters private const string NonTokenChars = "()<>@,;:\\\"/[]?={}"; /// /// The default max depth for our formatter is 256 /// public const int DefaultMaxDepth = 256; /// /// The default min depth for our formatter is 1 /// public const int DefaultMinDepth = 1; /// /// HTTP X-Requested-With header field name /// public const string HttpRequestedWithHeader = @"x-requested-with"; /// /// HTTP X-Requested-With header field value /// public const string HttpRequestedWithHeaderValue = @"xmlhttprequest"; /// /// HTTP Host header field name /// public const string HttpHostHeader = "Host"; /// /// HTTP Version token /// public const string HttpVersionToken = "HTTP"; /// /// A representing . /// public static readonly Type Utf8EncodingType = typeof(UTF8Encoding); /// /// A representing . /// public static readonly Type Utf16EncodingType = typeof(UnicodeEncoding); /// /// A representing . /// public static readonly Type HttpRequestMessageType = typeof(HttpRequestMessage); /// /// A representing . /// public static readonly Type HttpResponseMessageType = typeof(HttpResponseMessage); /// /// A representing . /// public static readonly Type HttpContentType = typeof(HttpContent); /// /// A representing . /// public static readonly Type DelegatingEnumerableGenericType = typeof(DelegatingEnumerable<>); /// /// A representing . /// public static readonly Type EnumerableInterfaceGenericType = typeof(IEnumerable<>); /// /// A representing . /// public static readonly Type QueryableInterfaceGenericType = typeof(IQueryable<>); /// /// Determines whether is a type. /// /// The type to test. /// /// true if is a type; otherwise, false. /// public static bool IsJTokenType(Type type) { return typeof(JToken).IsAssignableFrom(type); } /// /// Creates an empty instance. The only way is to get it from a dummy /// instance. /// /// The created instance. public static HttpContentHeaders CreateEmptyContentHeaders() { HttpContent tempContent = null; HttpContentHeaders contentHeaders = null; try { tempContent = new StringContent(String.Empty); contentHeaders = tempContent.Headers; contentHeaders.Clear(); } finally { // We can dispose the content without touching the headers if (tempContent != null) { tempContent.Dispose(); } } return contentHeaders; } /// /// Ensure the actual collection is identical to the expected one /// /// The actual collection of the instance /// The expected collection of the instance /// Returns true if they are identical public static bool ValidateCollection(Collection actual, MediaTypeHeaderValue[] expected) { if (actual.Count != expected.Length) { return false; } foreach (MediaTypeHeaderValue value in expected) { if (!actual.Contains(value)) { return false; } } return true; } /// /// Create a default reader quotas with a default depth quota of 1K /// /// public static XmlDictionaryReaderQuotas CreateDefaultReaderQuotas() { return new XmlDictionaryReaderQuotas() { MaxArrayLength = Int32.MaxValue, MaxBytesPerRead = Int32.MaxValue, MaxDepth = DefaultMaxDepth, MaxNameTableCharCount = Int32.MaxValue, MaxStringContentLength = Int32.MaxValue }; } /// /// Remove bounding quotes on a token if present /// /// Token to unquote. /// Unquoted token. public static string UnquoteToken(string token) { if (String.IsNullOrWhiteSpace(token)) { return token; } if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1) { return token.Substring(1, token.Length - 2); } return token; } public static bool ValidateHeaderToken(string token) { return token != null && !token.Any(c => c < 0x21 || c > 0x7E || NonTokenChars.IndexOf(c) != -1); } public static string DateToString(DateTimeOffset dateTime) { // Format according to RFC1123; 'r' uses invariant info (DateTimeFormatInfo.InvariantInfo) return dateTime.ToUniversalTime().ToString("r", CultureInfo.InvariantCulture); } public static bool TryParseDate(string input, out DateTimeOffset result) { return DateTimeOffset.TryParseExact(input, dateFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeUniversal, out result); } /// /// Parses valid integer strings with no leading signs, whitespace or other /// /// The value to parse /// The result /// True if value was valid; false otherwise. public static bool TryParseInt32(string value, out int result) { return Int32.TryParse(value, NumberStyles.None, NumberFormatInfo.InvariantInfo, out result); } } }