// 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);
}
}
}