Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Base / MS / Internal / ContentType.cs / 1 / ContentType.cs
//------------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// Description:
// ContentType class parses and validates the content-type string.
// It provides functionality to compare the type/subtype values.
//
// Details:
// Grammar which this class follows -
//
// Content-type grammar MUST conform to media-type grammar as per
// RFC 2616 (ABNF notation):
//
// media-type = type "/" subtype *( ";" parameter )
// type = token
// subtype = token
// parameter = attribute "=" value
// attribute = token
// value = token | quoted-string
// quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
// qdtext = >
// quoted-pair = "\" CHAR
// token = 1*
// separators = "(" | ")" | "<" | ">" | "@"
// | "," | ";" | ":" | "\" | <">
// | "/" | "[" | "]" | "?" | "="
// | "{" | "}" | SP | HT
// TEXT =
// OCTET =
// CHAR =
// CTL =
// CR =
// LF =
// SP =
// HT =
// <"> =
// LWS = [CRLF] 1*( SP | HT )
// CRLF = CR LF
// Linear white space (LWS) MUST NOT be used between the type and subtype, nor
// between an attribute and its value. Leading and trailing LWS are prohibited.
//
//
// History:
// 04/26/2004: [....]: Initial Creation
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic; // For Dictionary
using System.Text; // For StringBuilder
using System.Windows; // For Exception strings - SRID
using MS.Internal.WindowsBase; // For FriendAccessAllowed
using System.Diagnostics; // For Debug.Assert
namespace MS.Internal
{
///
/// Content Type class
///
[FriendAccessAllowed]
internal sealed class ContentType
{
//-----------------------------------------------------
//
// Internal Constructors
//
//-----------------------------------------------------
#region Internal Constructors
///
/// This constructor creates a ContentType object that represents
/// the content-type string. At construction time we validate the
/// string as per the grammar specified in RFC 2616.
/// Note: We allow empty strings as valid input. Empty string should
/// we used more as an indication of an absent/unknown ContentType.
///
/// content-type
/// If the contentType parameter is null
/// If the contentType string has leading or
/// trailing Linear White Spaces(LWS) characters
/// If the contentType string invalid CR-LF characters
internal ContentType(string contentType)
{
if (contentType == null)
throw new ArgumentNullException("contentType");
if (String.CompareOrdinal(contentType, String.Empty) == 0)
{
_contentType = String.Empty;
}
else
{
if (IsLinearWhiteSpaceChar(contentType[0]) || IsLinearWhiteSpaceChar(contentType[contentType.Length - 1]))
throw new ArgumentException(SR.Get(SRID.ContentTypeCannotHaveLeadingTrailingLWS));
//Carriage return can be expressed as '\r\n' or '\n\r'
//We need to make sure that a \r is accompanied by \n
ValidateCarriageReturns(contentType);
//Begin Parsing
int semiColonIndex = contentType.IndexOf(_semicolonSeparator);
if (semiColonIndex == -1)
{
// Parse content type similar to - type/subtype
ParseTypeAndSubType(contentType);
}
else
{
// Parse content type similar to - type/subtype ; param1=value1 ; param2=value2 ; param3="value3"
ParseTypeAndSubType(contentType.Substring(0, semiColonIndex));
ParseParameterAndValue(contentType.Substring(semiColonIndex));
}
}
// keep this untouched for return from OriginalString property
_originalString = contentType;
//This variable is used to print out the correct content type string representation
//using the ToString method. This is mainly important while debugging and seeing the
//value of the content type object in the debugger.
_isInitialized = true;
}
#endregion Internal Constructors
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Properties
///
/// TypeComponent of the Content Type
/// If the content type is "text/xml". This property will return "text"
///
internal string TypeComponent
{
get
{
return _type;
}
}
///
/// SubType component
/// If the content type is "text/xml". This property will return "xml"
///
internal string SubTypeComponent
{
get
{
return _subType;
}
}
///
/// Enumerator which iterates over the Parameter and Value pairs which are stored
/// in a dictionary. We hand out just the enumerator in order to make this property
/// ReadOnly
/// Consider following Content type -
/// type/subtype ; param1=value1 ; param2=value2 ; param3="value3"
/// This will return a enumerator over a dictionary of the parameter/value pairs.
///
internal Dictionary.Enumerator ParameterValuePairs
{
get
{
EnsureParameterDictionary();
return _parameterDictionary.GetEnumerator();
}
}
///
/// Static property that represents a content type that is empty ""
/// This is not a valid content type as per the grammar and should be used
/// in places where the content type is missing or not available.
///
internal static ContentType Empty
{
get
{
return _emptyContentType;
}
}
///
/// Original string provided to constructor
///
internal string OriginalString
{
get
{
return _originalString;
}
}
#endregion Internal Properties
//------------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
#region Internal Methods
///
/// This method does a strong comparison of the content types, as parameters are not allowed.
/// We only compare the type and subType values in an ASCII case-insensitive manner.
/// Parameters are not allowed to be present on any of the content type operands.
///
/// Content type to be compared with
///
internal bool AreTypeAndSubTypeEqual(ContentType contentType)
{
return AreTypeAndSubTypeEqual(contentType, false);
}
///
/// This method does a weak comparison of the content types. We only compare the
/// type and subType values in an ASCII case-insensitive manner.
/// Parameter and value pairs are not used for the comparison.
/// If you wish to compare the paramters too, then you must get the ParameterValuePairs from
/// both the ContentType objects and compare each parameter entry.
/// The allowParameterValuePairs parameter is used to indicate whether the
/// comparison is tolerant to parameters being present or no.
///
/// Content type to be compared with
/// If true, allows the presence of parameter value pairs.
/// If false, parameter/value pairs cannot be present in the content type string.
/// In either case, the parameter value pair is not used for the comparison.
///
internal bool AreTypeAndSubTypeEqual(ContentType contentType, bool allowParameterValuePairs)
{
bool result = false;
if (contentType != null)
{
if (!allowParameterValuePairs)
{
//Return false if this content type object has parameters
if (_parameterDictionary != null && _parameterDictionary.Count > 0)
return false;
//Return false if the content type object passed in has parameters
Dictionary.Enumerator contentTypeEnumerator;
contentTypeEnumerator = contentType.ParameterValuePairs;
contentTypeEnumerator.MoveNext();
if (contentTypeEnumerator.Current.Key != null)
return false;
}
// Perform a case-insensitive comparison on the type/subtype strings. This is a
// safe comparison because the _type and _subType strings have been restricted to
// ASCII characters, digits, and a small set of symbols. This is not a safe comparison
// for the broader set of strings that have not been restricted in the same way.
result = (String.Compare(_type, contentType.TypeComponent, StringComparison.OrdinalIgnoreCase) == 0 &&
String.Compare(_subType, contentType.SubTypeComponent, StringComparison.OrdinalIgnoreCase) == 0);
}
return result;
}
///
/// ToString - outputs a normalized form of the content type string
///
///
public override string ToString()
{
if (_contentType == null)
{
//This is needed so that while debugging we get the correct
//string
if (!_isInitialized)
return String.Empty;
Debug.Assert(String.CompareOrdinal(_type, String.Empty) != 0
|| String.CompareOrdinal(_subType, String.Empty) != 0);
StringBuilder stringBuilder = new StringBuilder(_type);
stringBuilder.Append(_forwardSlashSeparator[0]);
stringBuilder.Append(_subType);
if (_parameterDictionary != null && _parameterDictionary.Count > 0)
{
foreach (string paramterKey in _parameterDictionary.Keys)
{
stringBuilder.Append(_LinearWhiteSpaceChars[0]);
stringBuilder.Append(_semicolonSeparator);
stringBuilder.Append(_LinearWhiteSpaceChars[0]);
stringBuilder.Append(paramterKey);
stringBuilder.Append(_equalSeparator);
stringBuilder.Append(_parameterDictionary[paramterKey]);
}
}
_contentType = stringBuilder.ToString();
}
return _contentType;
}
#endregion Internal Methods
//-----------------------------------------------------
//
// Nested Classes
//
//------------------------------------------------------
#region Nested Classes
///
/// Comparer class makes it easier to put ContentType objects in collections.
/// Only compares type and subtype components of the ContentType. Could be
/// expanded to optionally compare parameters as well.
///
internal class StrongComparer : IEqualityComparer
{
///
/// This method does a strong comparison of the content types.
/// Only compares the ContentTypes' type and subtype components.
///
public bool Equals(ContentType x, ContentType y)
{
if (x == null)
{
return (y == null);
}
else
{
return x.AreTypeAndSubTypeEqual(y);
}
}
///
/// We lower case the results of ToString() because it returns the original
/// casing passed into the constructor. ContentTypes that are equal (which
/// ignores casing) must have the same hash code.
///
public int GetHashCode(ContentType obj)
{
return obj.ToString().ToUpperInvariant().GetHashCode();
}
}
internal class WeakComparer : IEqualityComparer
{
///
/// This method does a weak comparison of the content types.
/// Parameter and value pairs are not used for the comparison.
///
public bool Equals(ContentType x, ContentType y)
{
if (x == null)
{
return (y == null);
}
else
{
return x.AreTypeAndSubTypeEqual(y, true);
}
}
///
/// We lower case the results of ToString() because it returns the original
/// casing passed into the constructor. ContentTypes that are equal (which
/// ignores casing) must have the same hash code.
///
public int GetHashCode(ContentType obj)
{
return obj._type.ToUpperInvariant().GetHashCode() ^ obj._subType.ToUpperInvariant().GetHashCode();
}
}
#endregion Nested Classes
//-----------------------------------------------------
//
// Private Methods
//
//-----------------------------------------------------
#region Private Methods
///
/// This method validates if the content type string has
/// valid CR-LF characters. Specifically we test if '\r' is
/// accompanied by a '\n' in the string, else its an error.
///
///
private static void ValidateCarriageReturns(string contentType)
{
Debug.Assert(!IsLinearWhiteSpaceChar(contentType[0]) && !IsLinearWhiteSpaceChar(contentType[contentType.Length - 1]));
//Prior to calling this method we have already checked that first and last
//character of the content type are not Linear White Spaces. So its safe to
//assume that the index will be greater than 0 and less that length-2.
int index = contentType.IndexOf(_LinearWhiteSpaceChars[2]);
while (index != -1)
{
if (contentType[index - 1] == _LinearWhiteSpaceChars[1] || contentType[index + 1] == _LinearWhiteSpaceChars[1])
{
index = contentType.IndexOf(_LinearWhiteSpaceChars[2], ++index);
}
else
throw new ArgumentException(SR.Get(SRID.InvalidLinearWhiteSpaceCharacter));
}
}
///
/// Parses the type ans subType tokens from the string.
/// Also verifies if the Tokens are valid as per the grammar.
///
/// substring that has the type and subType of the content type
/// If the typeAndSubType parameter does not have the "/" character
private void ParseTypeAndSubType(string typeAndSubType)
{
//okay to trim at this point the end of the string as Linear White Spaces(LWS) chars are allowed here.
typeAndSubType = typeAndSubType.TrimEnd(_LinearWhiteSpaceChars);
string[] splitBasedOnForwardSlash = typeAndSubType.Split(_forwardSlashSeparator);
if (splitBasedOnForwardSlash.Length != 2)
throw new ArgumentException(SR.Get(SRID.InvalidTypeSubType));
_type = ValidateToken(splitBasedOnForwardSlash[0]);
_subType = ValidateToken(splitBasedOnForwardSlash[1]);
}
///
/// Parse the individual parameter=value strings
///
/// This string has the parameter and value pair of the form
/// parameter=value
/// If the string does not have the required "="
private void ParseParameterAndValue(string parameterAndValue)
{
while (String.CompareOrdinal(parameterAndValue, String.Empty) != 0)
{
//At this point the first character MUST be a semi-colon
//First time through this test is serving more as an assert.
if (parameterAndValue[0] != _semicolonSeparator)
throw new ArgumentException(SR.Get(SRID.ExpectingSemicolon));
//At this point if we have just one semicolon, then its an error.
//Also, there can be no trailing LWS characters, as we already checked for that
//in the constructor.
if (parameterAndValue.Length == 1)
throw new ArgumentException(SR.Get(SRID.ExpectingParameterValuePairs));
//Removing the leading ; from the string
parameterAndValue = parameterAndValue.Substring(1);
//okay to trim start as there can be spaces before the begining
//of the parameter name.
parameterAndValue = parameterAndValue.TrimStart(_LinearWhiteSpaceChars);
int equalSignIndex = parameterAndValue.IndexOf(_equalSeparator);
if (equalSignIndex <= 0 || equalSignIndex == (parameterAndValue.Length - 1))
throw new ArgumentException(SR.Get(SRID.InvalidParameterValuePair));
int parameterStartIndex = equalSignIndex + 1;
//Get length of the parameter value
int parameterValueLength = GetLengthOfParameterValue(parameterAndValue, parameterStartIndex);
EnsureParameterDictionary();
_parameterDictionary.Add(
ValidateToken(parameterAndValue.Substring(0, equalSignIndex)),
ValidateQuotedStringOrToken(parameterAndValue.Substring(parameterStartIndex, parameterValueLength)));
parameterAndValue = parameterAndValue.Substring(parameterStartIndex + parameterValueLength).TrimStart(_LinearWhiteSpaceChars);
}
}
///
/// This method returns the length of the first parameter value in the input string.
///
///
/// Starting index for parsing
///
private static int GetLengthOfParameterValue(string s, int startIndex)
{
Debug.Assert(s != null);
int length = 0;
//if the parameter value does not start with a '"' then,
//we expect a valid token. So we look for Linear White Spaces or
//a ';' as the terminator for the token value.
if (s[startIndex] != '"')
{
int semicolonIndex = s.IndexOf(_semicolonSeparator, startIndex);
if (semicolonIndex != -1)
{
int lwsIndex = s.IndexOfAny(_LinearWhiteSpaceChars, startIndex);
if (lwsIndex != -1 && lwsIndex < semicolonIndex)
length = lwsIndex;
else
length = semicolonIndex;
}
else
length = semicolonIndex;
//If there is no linear white space found we treat the entire remaining string as
//parameter value.
if (length == -1)
length = s.Length;
}
else
{
//if the parameter value starts with a '"' then, we need to look for the
//pairing '"' that is not preceded by a "\" ["\" is used to escape the '"']
bool found = false;
length = startIndex;
while (!found)
{
length = s.IndexOf('"', ++length);
if (length == -1)
throw new ArgumentException(SR.Get(SRID.InvalidParameterValue));
if (s[length - 1] != '\\')
{
found = true;
length++;
}
}
}
return length - startIndex;
}
///
/// Validating the given token
/// The following checks are being made -
/// 1. If all the characters in the token are either ASCII letter or digit.
/// 2. If all the characters in the token are either from the remaining allowed characeter set.
///
/// string token
/// validated string token
/// If the token is Empty
private static string ValidateToken(string token)
{
if (String.CompareOrdinal(token, String.Empty)==0)
throw new ArgumentException(SR.Get(SRID.InvalidToken));
for (int i = 0; i < token.Length; i++)
{
if (IsAsciiLetterOrDigit(token[i]))
continue;
else
if (IsAllowedCharacter(token[i]))
continue;
else
throw new ArgumentException(SR.Get(SRID.InvalidToken));
}
return token;
}
///
/// Validating if the value of a parameter is either a valid token or a
/// valid quoted string
///
/// paramter value string
/// validate parameter value string
/// If the paramter value is empty
private static string ValidateQuotedStringOrToken(string parameterValue)
{
if (String.CompareOrdinal(parameterValue, String.Empty) == 0)
throw new ArgumentException(SR.Get(SRID.InvalidParameterValue));
if (parameterValue.Length >= 2 &&
parameterValue.StartsWith(_quote, StringComparison.Ordinal) &&
parameterValue.EndsWith(_quote, StringComparison.Ordinal))
ValidateQuotedText(parameterValue.Substring(1, parameterValue.Length-2));
else
ValidateToken(parameterValue);
return parameterValue;
}
///
/// This method validates if the text in the quoted string
///
///
private static void ValidateQuotedText(string quotedText)
{
//empty is okay
for (int i = 0; i < quotedText.Length; i++)
{
if (IsLinearWhiteSpaceChar(quotedText[i]))
continue;
if (quotedText[i] <= ' ' || quotedText[i] >= 0xFF)
throw new ArgumentException(SR.Get(SRID.InvalidParameterValue));
else
if (quotedText[i] == '"' &&
(i==0 || quotedText[i-1] != '\\'))
throw new ArgumentException(SR.Get(SRID.InvalidParameterValue));
}
}
///
/// Returns true if the input character is an allowed character
/// Returns false if the input characeter is not an allowed character
///
/// input character
///
private static bool IsAllowedCharacter(char character)
{
//We did not use any of the .Contains methods as
//it will result in boxing costs.
foreach (char c in _allowedCharacters)
{
if (c == character)
return true;
}
return false;
}
///
/// Returns true if the input character is an ASCII digit or letter
/// Returns false if the input character is not an ASCII digit or letter
///
/// input character
///
private static bool IsAsciiLetterOrDigit(char character)
{
if (IsAsciiLetter(character))
{
return true;
}
if (character >= '0')
{
return (character <= '9');
}
return false;
}
///
/// Returns true if the input character is an ASCII letter
/// Returns false if the input character is not an ASCII letter
///
/// input character
///
private static bool IsAsciiLetter(char character)
{
if ((character >= 'a') && (character <= 'z'))
{
return true;
}
if (character >= 'A')
{
return (character <= 'Z');
}
return false;
}
///
/// Returns true if the input character is one of the Linear White Space characters -
/// ' ', '\t', '\n', '\r'
/// Returns false if the input character is none of the above
///
/// input character
///
private static bool IsLinearWhiteSpaceChar(char ch)
{
if (ch > ' ')
{
return false;
}
foreach (char c in _LinearWhiteSpaceChars)
{
if (ch == c)
return true;
}
return false;
}
///
/// Lazy initialization for the ParameterDictionary
///
private void EnsureParameterDictionary()
{
if (_parameterDictionary == null)
{
_parameterDictionary = new Dictionary(); //initial size 0
}
}
#endregion Private Methods
//-----------------------------------------------------
//
// Private Members
//
//------------------------------------------------------
#region Private Members
private string _contentType = null;
private string _type = String.Empty;
private string _subType = String.Empty;
private string _originalString;
private Dictionary _parameterDictionary = null;
private bool _isInitialized = false;
private const string _quote = "\"";
private const char _semicolonSeparator = ';';
private const char _equalSeparator = '=';
//This array is sorted by the ascii value of these characters.
private static readonly char[] _allowedCharacters =
{ '!' /*33*/, '#' /*35*/ , '$' /*36*/,
'%' /*37*/, '&' /*38*/ , '\'' /*39*/,
'*' /*42*/, '+' /*43*/ , '-' /*45*/,
'.' /*46*/, '^' /*94*/ , '_' /*95*/,
'`' /*96*/, '|' /*124*/, '~' /*126*/,
};
private static readonly char[] _forwardSlashSeparator = { '/' };
//Linear White Space characters
private static readonly char[] _LinearWhiteSpaceChars =
{ ' ', // space - \x20
'\n', // new line - \x0A
'\r', // carriage return - \x0D
'\t' // horizontal tab - \x09
};
private static readonly ContentType _emptyContentType = new ContentType("");
#endregion Private Members
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlStringTable.cs
- ModuleBuilder.cs
- StyleBamlTreeBuilder.cs
- ElasticEase.cs
- AlternateViewCollection.cs
- HttpProfileGroupBase.cs
- SchemaImporter.cs
- PrimitiveType.cs
- SqlWriter.cs
- CheckBoxPopupAdapter.cs
- ToolStripSystemRenderer.cs
- Vertex.cs
- Padding.cs
- SystemIPv6InterfaceProperties.cs
- ServiceDescriptionContext.cs
- NullableFloatMinMaxAggregationOperator.cs
- TreeWalker.cs
- CopyOfAction.cs
- ClientTargetCollection.cs
- BitmapEffectInputData.cs
- FamilyMapCollection.cs
- CompatibleComparer.cs
- DesignTimeDataBinding.cs
- InertiaExpansionBehavior.cs
- DefaultIfEmptyQueryOperator.cs
- EventProviderBase.cs
- GeneratedCodeAttribute.cs
- Button.cs
- ProcessManager.cs
- EncryptedType.cs
- SslStream.cs
- PropertyOverridesTypeEditor.cs
- HostAdapter.cs
- SqlDataSourceDesigner.cs
- ReferencedAssembly.cs
- TimeManager.cs
- ErrorLog.cs
- ThumbButtonInfo.cs
- SiteMapProvider.cs
- MethodCallTranslator.cs
- designeractionlistschangedeventargs.cs
- WebExceptionStatus.cs
- Duration.cs
- MD5CryptoServiceProvider.cs
- InputBuffer.cs
- FieldNameLookup.cs
- FontCacheUtil.cs
- HwndMouseInputProvider.cs
- UpWmlPageAdapter.cs
- TlsSspiNegotiation.cs
- Pointer.cs
- SyndicationSerializer.cs
- Menu.cs
- SchemaType.cs
- UriTemplateVariableQueryValue.cs
- CFGGrammar.cs
- ProxyGenerator.cs
- WebServiceEndpoint.cs
- LateBoundBitmapDecoder.cs
- ImageDrawing.cs
- Base64Decoder.cs
- ValidatorUtils.cs
- DynamicResourceExtensionConverter.cs
- RemotingConfigParser.cs
- FillRuleValidation.cs
- CompressedStack.cs
- BinHexDecoder.cs
- KeyValueSerializer.cs
- Script.cs
- XmlSchemaFacet.cs
- CodeNamespaceCollection.cs
- MemoryMappedFileSecurity.cs
- XmlNotation.cs
- SystemPens.cs
- PermissionToken.cs
- AsymmetricSignatureDeformatter.cs
- XmlArrayItemAttribute.cs
- CharacterShapingProperties.cs
- ConditionValidator.cs
- XmlAttributeAttribute.cs
- Message.cs
- DurationConverter.cs
- WebServiceClientProxyGenerator.cs
- GCHandleCookieTable.cs
- ConfigurationElementProperty.cs
- RefType.cs
- _SslState.cs
- RegexGroup.cs
- TypeSchema.cs
- EntityDataSourceWizardForm.cs
- TrustLevel.cs
- control.ime.cs
- DeviceSpecificDesigner.cs
- Command.cs
- WebPartHeaderCloseVerb.cs
- HttpClientCertificate.cs
- ObjectFactoryCodeDomTreeGenerator.cs
- CredentialCache.cs
- StateManagedCollection.cs
- SoapAttributes.cs