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
- MailAddressCollection.cs
- CodeTypeMemberCollection.cs
- SafeRightsManagementPubHandle.cs
- BrowserCapabilitiesCompiler.cs
- KnownBoxes.cs
- TraceEventCache.cs
- SmtpDateTime.cs
- ResourceReader.cs
- ServerType.cs
- SimpleHandlerFactory.cs
- Transform.cs
- GPPOINTF.cs
- ComMethodElement.cs
- SecurityContext.cs
- TextSelectionProcessor.cs
- VBCodeProvider.cs
- ConfigurationManagerInternalFactory.cs
- VersionedStream.cs
- VisualTreeUtils.cs
- IPEndPoint.cs
- WriteLine.cs
- ValidationError.cs
- ProvidersHelper.cs
- DataGridViewCellStyleEditor.cs
- FileRecordSequenceCompletedAsyncResult.cs
- BulletDecorator.cs
- EventSetter.cs
- ObjectQueryExecutionPlan.cs
- Pens.cs
- XmlSerializerFaultFormatter.cs
- MaxSessionCountExceededException.cs
- ObjectStateEntryOriginalDbUpdatableDataRecord.cs
- TextDocumentView.cs
- ScrollData.cs
- DataGridBoolColumn.cs
- Zone.cs
- WindowHelperService.cs
- HandledMouseEvent.cs
- ServiceObjectContainer.cs
- nulltextnavigator.cs
- ContractMethodParameterInfo.cs
- UpdatableGenericsFeature.cs
- PaperSize.cs
- Cell.cs
- CodeGenerator.cs
- COM2FontConverter.cs
- DetailsViewUpdatedEventArgs.cs
- DataServices.cs
- UserInitiatedRoutedEventPermission.cs
- PersonalizationStateQuery.cs
- BaseUriHelper.cs
- DrawingGroup.cs
- DataRecordObjectView.cs
- SharedHttpTransportManager.cs
- FormsAuthenticationEventArgs.cs
- SQLBinaryStorage.cs
- Helpers.cs
- TextTreeUndo.cs
- RelatedCurrencyManager.cs
- UrlAuthorizationModule.cs
- Quaternion.cs
- RepeatBehaviorConverter.cs
- SizeIndependentAnimationStorage.cs
- StorageMappingItemCollection.cs
- ConfigsHelper.cs
- ConditionalExpression.cs
- HttpStreams.cs
- TransformCollection.cs
- ProfileGroupSettingsCollection.cs
- ItemChangedEventArgs.cs
- ViewManager.cs
- GroupDescription.cs
- NullReferenceException.cs
- CmsInterop.cs
- WCFServiceClientProxyGenerator.cs
- HtmlInputButton.cs
- ClientOptions.cs
- Rules.cs
- KoreanLunisolarCalendar.cs
- QueryInterceptorAttribute.cs
- LinearKeyFrames.cs
- Encoder.cs
- HttpListenerRequestUriBuilder.cs
- ReadOnlyNameValueCollection.cs
- Pts.cs
- VectorAnimation.cs
- Interlocked.cs
- IncrementalHitTester.cs
- HierarchicalDataTemplate.cs
- BCLDebug.cs
- XmlTypeMapping.cs
- ContentDisposition.cs
- storepermissionattribute.cs
- CodeTypeParameter.cs
- ConfigXmlComment.cs
- ItemContainerGenerator.cs
- ValidationPropertyAttribute.cs
- _SslSessionsCache.cs
- HttpClientChannel.cs
- XmlException.cs