Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / HttpProcessUtility.cs / 1407647 / HttpProcessUtility.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a utility class to help in processing HTTP requests. // // // @owner [....] //--------------------------------------------------------------------- #if ASTORIA_CLIENT namespace System.Data.Services.Client #else namespace System.Data.Services #endif { using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; ///Provides helper methods for processing HTTP requests. internal static class HttpProcessUtility { ///UTF-8 encoding, without the BOM preamble. ////// While a BOM preamble on UTF8 is generally benign, it seems that some MIME handlers under IE6 will not /// process the payload correctly when included. /// /// Because the data service should include the encoding as part of the Content-Type in the response, /// there should be no ambiguity as to what encoding is being used. /// /// For further information, see http://www.unicode.org/faq/utf_bom.html#BOM. /// internal static readonly UTF8Encoding EncodingUtf8NoPreamble = new UTF8Encoding(false, true); ///Encoding to fall back to an appropriate encoding is not available. internal static Encoding FallbackEncoding { get { return EncodingUtf8NoPreamble; } } ///Encoding implied by an unspecified encoding value. ///See http://tools.ietf.org/html/rfc2616#section-3.4.1 for details. private static Encoding MissingEncoding { get { #if ASTORIA_LIGHT // ISO-8859-1 not available return Encoding.UTF8; #else return Encoding.GetEncoding("ISO-8859-1", new EncoderExceptionFallback(), new DecoderExceptionFallback()); #endif } } #if !ASTORIA_CLIENT ///Builds a Content-Type header which includes MIME type and encoding information. /// MIME type to be used. /// Encoding to be used in response, possibly null. ///The value for the Content-Type header. internal static string BuildContentType(string mime, Encoding encoding) { Debug.Assert(mime != null, "mime != null"); if (encoding == null) { return mime; } else { return mime + ";charset=" + encoding.WebName; } } ///Selects an acceptable MIME type that satisfies the Accepts header. /// Text for Accepts header. /// /// Types that the server is willing to return, in descending order /// of preference. /// ///The best MIME type for the client internal static string SelectMimeType(string acceptTypesText, string[] availableTypes) { Debug.Assert(availableTypes != null, "acceptableTypes != null"); string selectedContentType = null; int selectedMatchingParts = -1; int selectedQualityValue = 0; int selectedPreferenceIndex = Int32.MaxValue; bool acceptable = false; bool acceptTypesEmpty = true; if (!String.IsNullOrEmpty(acceptTypesText)) { IEnumerableacceptTypes = MimeTypesFromAcceptHeader(acceptTypesText); foreach (MediaType acceptType in acceptTypes) { acceptTypesEmpty = false; for (int i = 0; i < availableTypes.Length; i++) { string availableType = availableTypes[i]; int matchingParts = acceptType.GetMatchingParts(availableType); if (matchingParts < 0) { continue; } if (matchingParts > selectedMatchingParts) { // A more specific type wins. selectedContentType = availableType; selectedMatchingParts = matchingParts; selectedQualityValue = acceptType.SelectQualityValue(); selectedPreferenceIndex = i; acceptable = selectedQualityValue != 0; } else if (matchingParts == selectedMatchingParts) { // A type with a higher q-value wins. int candidateQualityValue = acceptType.SelectQualityValue(); if (candidateQualityValue > selectedQualityValue) { selectedContentType = availableType; selectedQualityValue = candidateQualityValue; selectedPreferenceIndex = i; acceptable = selectedQualityValue != 0; } else if (candidateQualityValue == selectedQualityValue) { // A type that is earlier in the availableTypes array wins. if (i < selectedPreferenceIndex) { selectedContentType = availableType; selectedPreferenceIndex = i; } } } } } } if (acceptTypesEmpty) { selectedContentType = availableTypes[0]; } else if (!acceptable) { selectedContentType = null; } return selectedContentType; } /// Gets the appropriate MIME type for the request, throwing if there is none. /// Text as it appears in an HTTP Accepts header. /// Preferred content type to match if an exact media type is given - this is in descending order of preference. /// Preferred fallback content type for inexact matches. ///One of exactContentType or inexactContentType. internal static string SelectRequiredMimeType( string acceptTypesText, string[] exactContentType, string inexactContentType) { Debug.Assert(exactContentType != null && exactContentType.Length != 0, "exactContentType != null && exactContentType.Length != 0"); Debug.Assert(inexactContentType != null, "inexactContentType != null"); string selectedContentType = null; int selectedMatchingParts = -1; int selectedQualityValue = 0; bool acceptable = false; bool acceptTypesEmpty = true; bool foundExactMatch = false; if (!String.IsNullOrEmpty(acceptTypesText)) { IEnumerableacceptTypes = MimeTypesFromAcceptHeader(acceptTypesText); foreach (MediaType acceptType in acceptTypes) { acceptTypesEmpty = false; for (int i = 0; i < exactContentType.Length; i++) { if (WebUtil.CompareMimeType(acceptType.MimeType, exactContentType[i])) { selectedContentType = exactContentType[i]; selectedQualityValue = acceptType.SelectQualityValue(); acceptable = selectedQualityValue != 0; foundExactMatch = true; break; } } if (foundExactMatch) { break; } int matchingParts = acceptType.GetMatchingParts(inexactContentType); if (matchingParts < 0) { continue; } if (matchingParts > selectedMatchingParts) { // A more specific type wins. selectedContentType = inexactContentType; selectedMatchingParts = matchingParts; selectedQualityValue = acceptType.SelectQualityValue(); acceptable = selectedQualityValue != 0; } else if (matchingParts == selectedMatchingParts) { // A type with a higher q-value wins. int candidateQualityValue = acceptType.SelectQualityValue(); if (candidateQualityValue > selectedQualityValue) { selectedContentType = inexactContentType; selectedQualityValue = candidateQualityValue; acceptable = selectedQualityValue != 0; } } } } if (!acceptable && !acceptTypesEmpty) { throw Error.HttpHeaderFailure(415, Strings.DataServiceException_UnsupportedMediaType); } if (acceptTypesEmpty) { Debug.Assert(selectedContentType == null, "selectedContentType == null - otherwise accept types were not empty"); selectedContentType = inexactContentType; } Debug.Assert(selectedContentType != null, "selectedContentType != null - otherwise no selection was made"); return selectedContentType; } /// Gets the best encoding available for the specified charset request. /// /// The Accept-Charset header value (eg: "iso-8859-5, unicode-1-1;q=0.8"). /// ///An Encoding object appropriate to the specifed charset request. internal static Encoding EncodingFromAcceptCharset(string acceptCharset) { // Determines the appropriate encoding mapping according to // RFC 2616.14.2 (http://tools.ietf.org/html/rfc2616#section-14.2). Encoding result = null; if (!string.IsNullOrEmpty(acceptCharset)) { // PERF: keep a cache of original strings to resolved Encoding. Listparts = new List (AcceptCharsetParts(acceptCharset)); parts.Sort(delegate(CharsetPart x, CharsetPart y) { return y.Quality - x.Quality; }); var encoderFallback = new EncoderExceptionFallback(); var decoderFallback = new DecoderExceptionFallback(); foreach (CharsetPart part in parts) { if (part.Quality > 0) { // When UTF-8 is specified, select the version that doesn't use the BOM. if (String.Compare("utf-8", part.Charset, StringComparison.OrdinalIgnoreCase) == 0) { result = FallbackEncoding; break; } else { try { result = Encoding.GetEncoding(part.Charset, encoderFallback, decoderFallback); break; } catch (ArgumentException) { // This exception is thrown when the character // set isn't supported - it is ignored so // other possible charsets are evaluated. } } } } } // No Charset was specifed, or if charsets were specified, no valid charset was found. // Returning a different charset is also valid. if (result == null) { result = FallbackEncoding; } return result; } #endif /// Reads a Content-Type header and extracts the MIME type/subtype and encoding. /// The Content-Type header. /// The MIME type in standard type/subtype form, without parameters. /// Encoding (possibly null). ///parameters of content type internal static KeyValuePair[] ReadContentType(string contentType, out string mime, out Encoding encoding) { if (String.IsNullOrEmpty(contentType)) { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_ContentTypeMissing); } MediaType mediaType = ReadMediaType(contentType); mime = mediaType.MimeType; encoding = mediaType.SelectEncoding(); return mediaType.Parameters; } #if !ASTORIA_CLIENT /// /// Given the parameters, search for the parameter with the given name and returns its value. /// /// list of parameters specified. /// name of the parameter whose value needs to be returned. ///returns the value of the parameter with the given name. Returns null, if the parameter is not found. internal static string GetParameterValue(KeyValuePair[] parameters, string parameterName) { if (parameters == null) { return null; } foreach (KeyValuePair parameterInfo in parameters) { if (parameterInfo.Key == parameterName) { return parameterInfo.Value; } } return null; } #endif /// Tries to read a WCF Data Service version string. /// Text to read. /// Parsed version and trailing text. ///true if the version was read successfully; false otherwise. internal static bool TryReadVersion(string text, out KeyValuePairresult) { Debug.Assert(text != null, "text != null"); // Separate version number and extra string. int separator = text.IndexOf(';'); string versionText, libraryName; if (separator >= 0) { versionText = text.Substring(0, separator); libraryName = text.Substring(separator + 1).Trim(); } else { versionText = text; libraryName = null; } result = default(KeyValuePair ); versionText = versionText.Trim(); // The Version constructor allows for a more complex syntax, including // build, revisions, and major/minor for revisions. We only take two // number parts separated by a single dot. bool dotFound = false; for (int i = 0; i < versionText.Length; i++) { if (versionText[i] == '.') { if (dotFound) { return false; } dotFound = true; } else if (versionText[i] < '0' || versionText[i] > '9') { return false; } } try { result = new KeyValuePair (new Version(versionText), libraryName); return true; } catch (Exception e) { if (e is FormatException || e is OverflowException || e is ArgumentException) { return false; } throw; } } /// Gets the named encoding if specified. /// Name (possibly null or empty). ////// The named encoding if specified; the encoding for HTTP missing /// charset specification otherwise. /// ////// See http://tools.ietf.org/html/rfc2616#section-3.4.1 for details. /// private static Encoding EncodingFromName(string name) { if (name == null) { return MissingEncoding; } name = name.Trim(); if (name.Length == 0) { return MissingEncoding; } else { try { #if ASTORIA_LIGHT // SQLBU 641147: Silverlight client failing with FireFox 3.0 // we know we can do this with Silverlight because our http stack // lets the browser convert from "ISO-8859-1" to string and then the stack // converts the string into UTF8 for streaming into the client. // it works for both nested payloads in batch and direct requests. // Coordinate any change to this with the HttpWebRequest.ReadResponse() return Encoding.UTF8; #else return Encoding.GetEncoding(name); #endif } catch (ArgumentException) { // 400 - Bad Request throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_EncodingNotSupported(name)); } } } #if !ASTORIA_CLIENT ///Creates a new exception for parsing errors. /// Message for error. ///A new exception that can be thrown for a parsing error. private static DataServiceException CreateParsingException(string message) { // Status code "400" ; Section 10.4.1: Bad Request return Error.HttpHeaderFailure(400, message); } #endif ///Reads the type and subtype specifications for a MIME type. /// Text in which specification exists. /// Pointer into text. /// Type of media found. /// Subtype of media found. private static void ReadMediaTypeAndSubtype(string text, ref int textIndex, out string type, out string subType) { Debug.Assert(text != null, "text != null"); int textStart = textIndex; if (ReadToken(text, ref textIndex)) { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeUnspecified); } if (text[textIndex] != '/') { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSlash); } type = text.Substring(textStart, textIndex - textStart); textIndex++; int subTypeStart = textIndex; ReadToken(text, ref textIndex); if (textIndex == subTypeStart) { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSubType); } subType = text.Substring(subTypeStart, textIndex - subTypeStart); } ///Reads a media type definition as used in a Content-Type header. /// Text to read. ///The ///defined by the specified All syntactic errors will produce a 400 - Bad Request status code. private static MediaType ReadMediaType(string text) { Debug.Assert(text != null, "text != null"); string type; string subType; int textIndex = 0; ReadMediaTypeAndSubtype(text, ref textIndex, out type, out subType); KeyValuePair[] parameters = null; while (!SkipWhitespace(text, ref textIndex)) { if (text[textIndex] != ';') { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter); } textIndex++; if (SkipWhitespace(text, ref textIndex)) { // ';' should be a leading separator, but we choose to be a // bit permissive and allow it as a final delimiter as well. break; } ReadMediaTypeParameter(text, ref textIndex, ref parameters); } return new MediaType(type, subType, parameters); } /// /// Reads a token on the specified text by advancing an index on it. /// /// Text to read token from. /// Index for the position being scanned on text. ///true if the end of the text was reached; false otherwise. private static bool ReadToken(string text, ref int textIndex) { while (textIndex < text.Length && IsHttpToken(text[textIndex])) { textIndex++; } return (textIndex == text.Length); } ////// Skips whitespace in the specified text by advancing an index to /// the next non-whitespace character. /// /// Text to scan. /// Index to begin scanning from. ///true if the end of the string was reached, false otherwise. private static bool SkipWhitespace(string text, ref int textIndex) { Debug.Assert(text != null, "text != null"); Debug.Assert(text.Length >= 0, "text >= 0"); Debug.Assert(textIndex <= text.Length, "text <= text.Length"); while (textIndex < text.Length && Char.IsWhiteSpace(text, textIndex)) { textIndex++; } return (textIndex == text.Length); } #if !ASTORIA_CLIENT ////// Verfies whether the specified character is a valid separator in /// an HTTP header list of element. /// /// Character to verify. ///true if c is a valid character for separating elements; false otherwise. private static bool IsHttpElementSeparator(char c) { return c == ',' || c == ' ' || c == '\t'; } ////// "Reads" a literal from the specified string by verifying that /// the exact text can be found at the specified position. /// /// Text within which a literal should be checked. /// Index in text where the literal should be found. /// Literal to check at the specified position. ///true if the end of string is found; false otherwise. private static bool ReadLiteral(string text, int textIndex, string literal) { if (String.Compare(text, textIndex, literal, 0, literal.Length, StringComparison.Ordinal) != 0) { // Failed to find expected literal. throw CreateParsingException(Strings.HttpContextServiceHost_MalformedHeaderValue); } return textIndex + literal.Length == text.Length; } ////// Converts the specified character from the ASCII range to a digit. /// /// Character to convert. ////// The Int32 value for c, or -1 if it is an element separator. /// private static int DigitToInt32(char c) { if (c >= '0' && c <= '9') { return (int)(c - '0'); } else { if (IsHttpElementSeparator(c)) { return -1; } else { throw CreateParsingException(Strings.HttpContextServiceHost_MalformedHeaderValue); } } } ///Returns all MIME types from the specified (non-blank) /// Non-blank text, as it appears on an HTTP Accepts header. ///. An enumerable object with media type descriptions. private static IEnumerableMimeTypesFromAcceptHeader(string text) { Debug.Assert(!String.IsNullOrEmpty(text), "!String.IsNullOrEmpty(text)"); List mediaTypes = new List (); int textIndex = 0; while (!SkipWhitespace(text, ref textIndex)) { string type; string subType; ReadMediaTypeAndSubtype(text, ref textIndex, out type, out subType); KeyValuePair [] parameters = null; while (!SkipWhitespace(text, ref textIndex)) { if (text[textIndex] == ',') { textIndex++; break; } if (text[textIndex] != ';') { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter); } textIndex++; if (SkipWhitespace(text, ref textIndex)) { // ';' should be a leading separator, but we choose to be a // bit permissive and allow it as a final delimiter as well. break; } ReadMediaTypeParameter(text, ref textIndex, ref parameters); } mediaTypes.Add(new MediaType(type, subType, parameters)); } return mediaTypes; } #endif /// Read a parameter for a media type/range. /// Text to read from. /// Pointer in text. /// Array with parameters to grow as necessary. private static void ReadMediaTypeParameter(string text, ref int textIndex, ref KeyValuePair[] parameters) { int startIndex = textIndex; if (ReadToken(text, ref textIndex)) { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeMissingValue); } string parameterName = text.Substring(startIndex, textIndex - startIndex); if (text[textIndex] != '=') { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeMissingValue); } textIndex++; string parameterValue = ReadQuotedParameterValue(parameterName, text, ref textIndex); // Add the parameter name/value pair to the list. if (parameters == null) { parameters = new KeyValuePair [1]; } else { KeyValuePair [] grow = new KeyValuePair [parameters.Length + 1]; Array.Copy(parameters, grow, parameters.Length); parameters = grow; } parameters[parameters.Length - 1] = new KeyValuePair (parameterName, parameterValue); } /// /// Reads Mime type parameter value for a particular parameter in the Content-Type/Accept headers. /// /// Name of parameter. /// Header text. /// Parsing index in. /// String representing the value of the private static string ReadQuotedParameterValue(string parameterName, string headerText, ref int textIndex) { StringBuilder parameterValue = new StringBuilder(); // Check if the value is quoted. bool valueIsQuoted = false; if (textIndex < headerText.Length) { if (headerText[textIndex] == '\"') { textIndex++; valueIsQuoted = true; } } while (textIndex < headerText.Length) { char currentChar = headerText[textIndex]; if (currentChar == '\\' || currentChar == '\"') { if (!valueIsQuoted) { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_EscapeCharWithoutQuotes(parameterName)); } textIndex++; // End of quoted parameter value. if (currentChar == '\"') { valueIsQuoted = false; break; } if (textIndex >= headerText.Length) { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_EscapeCharAtEnd(parameterName)); } currentChar = headerText[textIndex]; } else if (!IsHttpToken(currentChar)) { // If the given character is special, we stop processing. break; } parameterValue.Append(currentChar); textIndex++; } if (valueIsQuoted) { throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_ClosingQuoteNotFound(parameterName)); } return parameterValue.ToString(); } #if !ASTORIA_CLIENT ///parameter. /// Reads the numeric part of a quality value substring, normalizing it to 0-1000 /// rather than the standard 0.000-1.000 ranges. /// /// Text to read qvalue from. /// Index into text where the qvalue starts. /// After the method executes, the normalized qvalue. ////// For more information, see RFC 2616.3.8. /// private static void ReadQualityValue(string text, ref int textIndex, out int qualityValue) { char digit = text[textIndex++]; if (digit == '0') { qualityValue = 0; } else if (digit == '1') { qualityValue = 1; } else { throw CreateParsingException(Strings.HttpContextServiceHost_MalformedHeaderValue); } if (textIndex < text.Length && text[textIndex] == '.') { textIndex++; int adjustFactor = 1000; while (adjustFactor > 1 && textIndex < text.Length) { char c = text[textIndex]; int charValue = DigitToInt32(c); if (charValue >= 0) { textIndex++; adjustFactor /= 10; qualityValue *= 10; qualityValue += charValue; } else { break; } } qualityValue = qualityValue *= adjustFactor; if (qualityValue > 1000) { // Too high of a value in qvalue. throw CreateParsingException(Strings.HttpContextServiceHost_MalformedHeaderValue); } } else { qualityValue *= 1000; } } ////// Enumerates each charset part in the specified Accept-Charset header. /// /// Non-null and non-empty header value for Accept-Charset. ////// A (non-sorted) enumeration of CharsetPart elements, which include /// a charset name and a quality (preference) value, normalized to 0-1000. /// private static IEnumerableAcceptCharsetParts(string headerValue) { Debug.Assert(!String.IsNullOrEmpty(headerValue), "!String.IsNullOrEmpty(headerValuer)"); // PERF: optimize for common patterns. bool commaRequired = false; // Whether a comma should be found int headerIndex = 0; // Index of character being procesed on headerValue. int headerStart; // Index into headerValue for the start of the charset name. int headerNameEnd; // Index into headerValue for the end of the charset name (+1). int headerEnd; // Index into headerValue for this charset part (+1). int qualityValue; // Normalized qvalue for this charset. while (headerIndex < headerValue.Length) { if (SkipWhitespace(headerValue, ref headerIndex)) { yield break; } if (headerValue[headerIndex] == ',') { commaRequired = false; headerIndex++; continue; } if (commaRequired) { // Comma missing between charset elements. throw CreateParsingException(Strings.HttpContextServiceHost_MalformedHeaderValue); } headerStart = headerIndex; headerNameEnd = headerStart; bool endReached = ReadToken(headerValue, ref headerNameEnd); if (headerNameEnd == headerIndex) { // Invalid charset name. throw CreateParsingException(Strings.HttpContextServiceHost_MalformedHeaderValue); } if (endReached) { qualityValue = 1000; headerEnd = headerNameEnd; } else { char afterNameChar = headerValue[headerNameEnd]; if (IsHttpSeparator(afterNameChar)) { if (afterNameChar == ';') { if (ReadLiteral(headerValue, headerNameEnd, ";q=")) { // Unexpected end of qvalue. throw CreateParsingException(Strings.HttpContextServiceHost_MalformedHeaderValue); } headerEnd = headerNameEnd + 3; ReadQualityValue(headerValue, ref headerEnd, out qualityValue); } else { qualityValue = 1000; headerEnd = headerNameEnd; } } else { // Invalid separator character. throw CreateParsingException(Strings.HttpContextServiceHost_MalformedHeaderValue); } } yield return new CharsetPart(headerValue.Substring(headerStart, headerNameEnd - headerStart), qualityValue); // Prepare for next charset; we require at least one comma before we process it. commaRequired = true; headerIndex = headerEnd; } } #endif /// /// Determines whether the specified character is a valid HTTP separator. /// /// Character to verify. ///true if c is a separator; false otherwise. ////// See RFC 2616 2.2 for further information. /// private static bool IsHttpSeparator(char c) { return c == '(' || c == ')' || c == '<' || c == '>' || c == '@' || c == ',' || c == ';' || c == ':' || c == '\\' || c == '"' || c == '/' || c == '[' || c == ']' || c == '?' || c == '=' || c == '{' || c == '}' || c == ' ' || c == '\x9'; } ////// Determines whether the specified character is a valid HTTP header token character. /// /// Character to verify. ///true if c is a valid HTTP header token character; false otherwise. private static bool IsHttpToken(char c) { // A token character is any character (0-127) except control (0-31) or // separators. 127 is DEL, a control character. return c < '\x7F' && c > '\x1F' && !IsHttpSeparator(c); } #if !ASTORIA_CLIENT ///Provides a struct to encapsulate a charset name and its relative desirability. private struct CharsetPart { ///Name of the charset. internal readonly string Charset; ///Charset quality (desirability), normalized to 0-1000. internal readonly int Quality; ////// Initializes a new CharsetPart with the specified values. /// /// Name of charset. /// Charset quality (desirability), normalized to 0-1000. internal CharsetPart(string charset, int quality) { Debug.Assert(charset != null, "charset != null"); Debug.Assert(charset.Length > 0, "charset.Length > 0"); Debug.Assert(0 <= quality && quality <= 1000, "0 <= quality && quality <= 1000"); this.Charset = charset; this.Quality = quality; } } #endif ///Use this class to represent a media type definition. [DebuggerDisplay("MediaType [{type}/{subType}]")] private sealed class MediaType { ///Parameters specified on the media type. private readonly KeyValuePair[] parameters; /// Sub-type specification (for example, 'plain'). private readonly string subType; ///Type specification (for example, 'text'). private readonly string type; ////// Initializes a new /// Type specification (for example, 'text'). /// Sub-type specification (for example, 'plain'). /// Parameters specified on the media type. internal MediaType(string type, string subType, KeyValuePairread-only instance. /// [] parameters) { Debug.Assert(type != null, "type != null"); Debug.Assert(subType != null, "subType != null"); this.type = type; this.subType = subType; this.parameters = parameters; } /// Returns the MIME type in standard type/subtype form, without parameters. internal string MimeType { get { return this.type + "/" + this.subType; } } ///media type parameters internal KeyValuePair[] Parameters { get { return this.parameters; } } #if !ASTORIA_CLIENT /// Gets a number of non-* matching types, or -1 if not matching at all. /// Candidate MIME type to match. ///The number of non-* matching types, or -1 if not matching at all. internal int GetMatchingParts(string candidate) { Debug.Assert(candidate != null, "candidate must not be null."); int result = -1; if (candidate.Length > 0) { if (this.type == "*") { result = 0; } else { int separatorIdx = candidate.IndexOf('/'); if (separatorIdx >= 0) { string candidateType = candidate.Substring(0, separatorIdx); if (WebUtil.CompareMimeType(this.type, candidateType)) { if (this.subType == "*") { result = 1; } else { string candidateSubType = candidate.Substring(candidateType.Length + 1); if (WebUtil.CompareMimeType(this.subType, candidateSubType)) { result = 2; } } } } } } return result; } ///Selects a quality value for the specified type. ///The quality value, in range from 0 through 1000. ///See http://tools.ietf.org/html/rfc2616#section-14.1 for further details. internal int SelectQualityValue() { if (this.parameters != null) { foreach (KeyValuePairparameter in this.parameters) { if (String.Equals(parameter.Key, XmlConstants.HttpQValueParameter, StringComparison.OrdinalIgnoreCase)) { string qvalueText = parameter.Value.Trim(); if (qvalueText.Length > 0) { int result; int textIndex = 0; ReadQualityValue(qvalueText, ref textIndex, out result); return result; } } } } return 1000; } #endif /// /// Selects the encoding appropriate for this media type specification /// (possibly null). /// ////// The encoding explicitly defined on the media type specification, or /// the default encoding for well-known media types. /// ////// As per http://tools.ietf.org/html/rfc2616#section-3.7, the type, /// subtype and parameter name attributes are case-insensitive. /// internal Encoding SelectEncoding() { if (this.parameters != null) { foreach (KeyValuePairparameter in this.parameters) { if (String.Equals(parameter.Key, XmlConstants.HttpCharsetParameter, StringComparison.OrdinalIgnoreCase)) { string encodingName = parameter.Value.Trim(); if (encodingName.Length > 0) { return EncodingFromName(parameter.Value); } } } } // Select the default encoding for this media type. if (String.Equals(this.type, XmlConstants.MimeTextType, StringComparison.OrdinalIgnoreCase)) { // HTTP 3.7.1 Canonicalization and Text Defaults // "text" subtypes default to ISO-8859-1 // // Unless the subtype is XML, in which case we should default // to us-ascii. Instead we return null, to let the encoding // in the PI win (http://tools.ietf.org/html/rfc3023#section-3.1) if (String.Equals(this.subType, XmlConstants.MimeXmlSubType, StringComparison.OrdinalIgnoreCase)) { return null; } else { return MissingEncoding; } } else if (String.Equals(this.type, XmlConstants.MimeApplicationType, StringComparison.OrdinalIgnoreCase) && String.Equals(this.subType, XmlConstants.MimeJsonSubType, StringComparison.OrdinalIgnoreCase)) { // http://tools.ietf.org/html/rfc4627#section-3 // The default encoding is UTF-8. return FallbackEncoding; } else { return null; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HyperLink.cs
- ObjectListGeneralPage.cs
- DataKey.cs
- NativeWindow.cs
- HWStack.cs
- ColumnWidthChangingEvent.cs
- ValidationRuleCollection.cs
- SiteMapNodeItem.cs
- invalidudtexception.cs
- HttpRequestBase.cs
- ParallelEnumerable.cs
- FixedDocumentPaginator.cs
- PocoEntityKeyStrategy.cs
- QueuePathEditor.cs
- _UriSyntax.cs
- SQLCharsStorage.cs
- OdbcParameter.cs
- XamlParser.cs
- LinearQuaternionKeyFrame.cs
- ToolboxItemCollection.cs
- ControlUtil.cs
- MetaChildrenColumn.cs
- CFGGrammar.cs
- JsonFormatReaderGenerator.cs
- SafeTimerHandle.cs
- RegisteredScript.cs
- CustomErrorsSectionWrapper.cs
- DescendentsWalkerBase.cs
- LocalBuilder.cs
- XmlArrayAttribute.cs
- SettingsSection.cs
- GeometryModel3D.cs
- ToolStripProgressBar.cs
- TrustLevelCollection.cs
- ValidatedControlConverter.cs
- GraphicsState.cs
- COM2PropertyBuilderUITypeEditor.cs
- IntPtr.cs
- TextSimpleMarkerProperties.cs
- PeerToPeerException.cs
- SqlWorkflowInstanceStore.cs
- NativeRecognizer.cs
- BulletedList.cs
- DynamicDataRoute.cs
- KoreanLunisolarCalendar.cs
- ClientBuildManagerCallback.cs
- IDReferencePropertyAttribute.cs
- FunctionImportMapping.cs
- WebResponse.cs
- SqlDelegatedTransaction.cs
- LogStore.cs
- InternalConfigSettingsFactory.cs
- Imaging.cs
- TransactionWaitAsyncResult.cs
- KeySplineConverter.cs
- GPRECTF.cs
- QueryReaderSettings.cs
- XmlEnumAttribute.cs
- SchemaManager.cs
- FtpCachePolicyElement.cs
- DataSourceXmlClassAttribute.cs
- PrivilegeNotHeldException.cs
- Scene3D.cs
- XmlCharType.cs
- ColumnHeader.cs
- TextServicesContext.cs
- x509utils.cs
- CollectionBuilder.cs
- HttpSysSettings.cs
- CardSpaceSelector.cs
- cookieexception.cs
- UriSection.cs
- BinaryUtilClasses.cs
- ReferencedAssemblyResolver.cs
- PageRanges.cs
- FillBehavior.cs
- FormsAuthenticationUserCollection.cs
- Size3DConverter.cs
- BitmapEffectInputData.cs
- WebPartConnectVerb.cs
- HandlerBase.cs
- RequestCacheEntry.cs
- SwitchElementsCollection.cs
- XPathDocumentNavigator.cs
- SchemaElementLookUpTable.cs
- CollectionDataContract.cs
- ExtensionDataReader.cs
- mda.cs
- RenderDataDrawingContext.cs
- ImageIndexConverter.cs
- _BaseOverlappedAsyncResult.cs
- GPPOINTF.cs
- SignedXml.cs
- InternalsVisibleToAttribute.cs
- ValidatingPropertiesEventArgs.cs
- ScriptMethodAttribute.cs
- SafeWaitHandle.cs
- CacheMemory.cs
- OleDbConnectionInternal.cs
- NamespaceMapping.cs