// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Runtime.Serialization; 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, short year "dddd, d'-'MMM'-'yy H:m:s", // RFC 850 no zone "ddd, d'-'MMM'-'yyyy H:m:s 'GMT'", // RFC 850, long year "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 = "()<>@,;:\\\"/[]?={}"; /// /// Quality factor to indicate a perfect match. /// public const double Match = 1.0; /// /// Quality factor to indicate no match. /// public const double NoMatch = 0.0; /// /// 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 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<>); #if !NETFX_CORE // XsdDataContractExporter is not supported in portable libraries /// /// An instance of . /// public static readonly XsdDataContractExporter XsdDataContractExporter = new XsdDataContractExporter(); #endif /// /// 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; } /// /// Create a default reader quotas with a default depth quota of 1K /// /// public static XmlDictionaryReaderQuotas CreateDefaultReaderQuotas() { #if NETFX_CORE // MaxDepth is a DOS mitigation. We don't support MaxDepth in portable libraries because it is strictly client side. return XmlDictionaryReaderQuotas.Max; #else return new XmlDictionaryReaderQuotas() { MaxArrayLength = Int32.MaxValue, MaxBytesPerRead = Int32.MaxValue, MaxDepth = DefaultMaxDepth, MaxNameTableCharCount = Int32.MaxValue, MaxStringContentLength = Int32.MaxValue }; #endif } /// /// 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) { if (token == null) { return false; } foreach (char c in token) { if (c < 0x21 || c > 0x7E || NonTokenChars.IndexOf(c) != -1) { return false; } } return true; } 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); } } }